You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
243 lines
6.7 KiB
243 lines
6.7 KiB
#include "object.h" |
|
#include "globals.h" |
|
|
|
template<> EXPORT std::string ObjectSimple<bool>::type="bool"; |
|
template<> EXPORT std::string ObjectSimple<int64_t>::type="integer"; |
|
template<> EXPORT std::string ObjectSimple<double>::type="real"; |
|
template<> EXPORT std::string ObjectSimple<std::string>::type="string"; |
|
|
|
std::string DumpExprE(const ExecExpr& exp) |
|
{ |
|
std::string ret; |
|
for(const auto& i: exp) |
|
{ |
|
ret+="Element: "; |
|
switch(i.T()) |
|
{ |
|
case(StackElem::TYPE_BEGINLIST): {ret+="("; break;} |
|
case(StackElem::TYPE_ENDLIST): {ret+=")"; break;} |
|
case(StackElem::TYPE_MKPAIR): {ret+="MKPAIR: "+i.Name(); break;} |
|
case(StackElem::TYPE_OBJECT): {ret+="OBJECT: "+i.Object()->Type()+" "+i.Object()->Dump(); break;} |
|
case(StackElem::TYPE_VARIABLE): {ret+="VARIABLE: "+i.Name(); break;} |
|
case(StackElem::TYPE_FUNCTION): {ret+="FUNCTION: "+i.Name(); break;} |
|
default: ret+=" %ERROR% "; |
|
} |
|
ret+="\n"; |
|
ret+="Location: "+i.Location().filename+" "+ToString(i.Location().first_line)+" "+ToString(i.Location().first_column)+" "+ToString(i.Location().incstack.size())+"\n\n"; |
|
} |
|
return ret; |
|
} |
|
|
|
std::string DumpExpr(const ExecExpr& exp) |
|
{ |
|
std::list<std::string> stack; |
|
std::string ret; |
|
for(const auto& i: exp) |
|
{ |
|
switch(i.T()) |
|
{ |
|
case(StackElem::TYPE_BEGINLIST): {stack.push_back("("); break;} |
|
case(StackElem::TYPE_ENDLIST): {stack.push_back(")"); break;} |
|
case(StackElem::TYPE_MKPAIR): |
|
{ |
|
if(")"!=stack.back()) {auto s=stack.crbegin(); s++; stack.insert(s.base(),i.Name()+"=");} |
|
else |
|
{ |
|
ret.clear(); |
|
uint n=0; |
|
for(auto s=stack.crbegin(); s!=stack.crend();++s) |
|
{ |
|
if(ret[0]!=')' && *s!="(" && *s!=")") ret=(*s)+","+ret; |
|
else ret=(*s)+ret; |
|
if(")"==*s) n++; |
|
if("("==*s) |
|
{ |
|
n--; |
|
if(0==n) |
|
{ |
|
stack.erase((++s).base(),stack.end()); |
|
stack.push_back(i.Name()+"="+ret); |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
break; |
|
} |
|
case(StackElem::TYPE_OBJECT): {stack.push_back(i.Object()->Dump()); break;} |
|
case(StackElem::TYPE_VARIABLE): {stack.push_back(i.Name()); break;} |
|
case(StackElem::TYPE_FUNCTION): |
|
{ |
|
ret.clear(); |
|
uint n=0; |
|
for(auto s=stack.crbegin(); s!=stack.crend();++s) |
|
{ |
|
if(ret[0]!=')' && *s!="(" && *s!=")") ret=(*s)+","+ret; |
|
else ret=(*s)+ret; |
|
if(")"==*s) n++; |
|
if("("==*s) |
|
{ |
|
n--; |
|
if(0==n) |
|
{ |
|
stack.erase((++s).base(),stack.end()); |
|
stack.push_back(i.Name()+ret); |
|
break; |
|
} |
|
} |
|
} |
|
break; // Never reach this line |
|
} |
|
default: stack.push_back(" %ERROR% "); |
|
} |
|
} |
|
ret.clear(); |
|
for(const auto& s: stack) |
|
{ |
|
if('('==ret.back() || '='==ret.back() || ')'==s.front() || ret.empty()) ret+=s; |
|
else ret+=","+s; |
|
} |
|
return ret; |
|
} |
|
|
|
UsedType UsedVars(const ExecExpr& exp) |
|
{ |
|
UsedType ret; |
|
for(const auto& i: exp) if(StackElem::TYPE_VARIABLE==i.T()) ret.insert(i.Name()); |
|
return ret; |
|
} |
|
|
|
UsedType UsedFuncs(const ExecExpr& exp) |
|
{ |
|
UsedType ret; |
|
for(const auto& i: exp) if(StackElem::TYPE_FUNCTION==i.T()) ret.insert(i.Name()); |
|
return ret; |
|
} |
|
|
|
const ObjectBase* Evaluate(ExecExpr& exp, bool* err) |
|
{ |
|
ExecExpr::iterator cse=exp.begin(); |
|
while(cse!=exp.end()) |
|
{ |
|
switch(cse->T()) |
|
{ |
|
case(StackElem::TYPE_ENDLIST): // Making list |
|
{ |
|
ObjectList* ol=new ObjectList; |
|
ExecExpr::iterator bl,el; |
|
bl=el=cse++; |
|
bl--; |
|
// Reverse iteration to fill list. We know that BEGINLIST exists before ENDLIST, because grammatical parser already check it. |
|
while(StackElem::TYPE_BEGINLIST!=bl->T()) {ol->PushFront(bl->PickObject()); bl--;} |
|
// Remove all elements from BEGINLIST to ENDLIST, but not ENDLIST itself |
|
exp.erase(bl,el); |
|
// Replace ENDLIST by ObjectList |
|
el->ReplaceByObject(ol); |
|
// Go to next element |
|
continue; |
|
} |
|
case(StackElem::TYPE_MKPAIR): |
|
{ |
|
// Previous element must be OBJECT. We don't check this, we trust in grammatical parser. |
|
ExecExpr::iterator pr=cse; |
|
pr--; |
|
cse->ReplaceByObject(new ObjectPair(cse->Name(),pr->PickObject())); |
|
// Remove previous element |
|
exp.erase(pr); |
|
// Go to next element |
|
cse++; continue; |
|
} |
|
case(StackElem::TYPE_FUNCTION): |
|
{ |
|
// Previous element must be OBJECT with type ObjectList. We don't check this, we trust in grammatical parser. |
|
ExecExpr::iterator pr=cse; |
|
pr--; |
|
const ObjectList* arg=dynamic_cast<const ObjectList*>(pr->Object()); |
|
const ObjectBase* res; |
|
|
|
// Functions check already done, we know that our function exists. |
|
// Sequentally call all functions with given name |
|
auto bounds=G_funcs.equal_range(cse->Name()); |
|
std::list<const ObjectError*> errl; |
|
for(auto f=bounds.first; f!=bounds.second; ++f) |
|
{ |
|
res=(*(f->second))(arg); |
|
if( !(res==nullptr || res->isError()) ) break; |
|
if(res==nullptr) errl.push_back(new ObjectError("Some function", "unknown reason")); |
|
else errl.push_back(dynamic_cast<const ObjectError*>(res)); |
|
} |
|
// Remove previous element |
|
exp.erase(pr); |
|
|
|
// Error handling |
|
if( res==nullptr || res->isError() ) |
|
{ |
|
const struct grammatic_location& loc=cse->Location(); |
|
*err=true; // Raise error flag |
|
COUT(ERROR)<<"Can't evaluate function "<<cse->Name()<<" at line "<<loc.first_line<<", position "<<loc.first_column<<std::endl; |
|
for(const auto& inc: loc.incstack) COUT(ERROR)<<" included from "<<inc.filename<<" at line "<<inc.line<<", position "<<inc.column<<std::endl; |
|
for(auto& e: errl) |
|
{ |
|
COUT(ERROR)<<e->Function()<<": "<<e->Reason()<<std::endl; |
|
delete e; |
|
} |
|
return nullptr; |
|
} |
|
// Replace function on returned value |
|
cse->ReplaceByObject(res); |
|
// Go to next element |
|
cse++; continue; |
|
} |
|
default: {cse++; continue;} // Other cases leads to undefined behavior (VARIABLE or EMPTY) or doesn't require any action, so, skip. |
|
} |
|
} |
|
// After all, our list contains only one object. |
|
const ObjectBase* ret=exp.begin()->PickObject(); |
|
exp.clear(); |
|
return ret; |
|
} |
|
|
|
void ReplaceVar(ExecExpr& exp, const std::string& var, const ObjectBase* ob) |
|
{ |
|
for(auto& se: exp) |
|
if(se.isVar() && var==se.Name()) |
|
se.ReplaceByObject(ob->Copy()); |
|
} |
|
|
|
bool ObjectBase::Save(const char* fname) const |
|
{ |
|
size_t size,offset=0,wr; |
|
const int8_t* dptr; |
|
FILE* fd; |
|
int serrno; |
|
|
|
fd=fopen(fname,"w"); |
|
serrno=errno; |
|
if(nullptr==fd) |
|
{ |
|
COUT(ERROR)<<"Can't open file "<<fname<<" for writing: "<<strerror(serrno)<<std::endl; |
|
return false; |
|
} |
|
dptr=Blob(&size); |
|
if(nullptr==dptr) |
|
{ |
|
COUT(ERROR)<<"Can't get blob for writing to "<<fname<<std::endl; |
|
fclose(fd); |
|
return false; |
|
} |
|
while(offset!=size) |
|
{ |
|
wr=fwrite(dptr+offset,1,size-offset,fd); |
|
if(0==wr) |
|
{ |
|
COUT(ERROR)<<"Failed to write in file "<<fname<<std::endl; |
|
fclose(fd); DeallocBlob(dptr); |
|
return false; |
|
} |
|
offset+=wr; |
|
} |
|
fclose(fd); |
|
DeallocBlob(dptr); |
|
return true; |
|
} |
|
|
|
|