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

#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;
}