/** * This file is part of Gomu. * * Copyright 2016 by Jean Fromentin * * Gomu is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Gomu is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Gomu. If not, see . */ #include "interpreter.hpp" namespace Gomu{ //************************************************************ //* Definition of fundamental types declared in modules.hpp * //************************************************************ Type *type_array=new Type("Array",array_disp,array_del,array_copy,array_comp); Type *type_boolean=new Type("Boolean",boolean_disp,boolean_del,boolean_copy,boolean_comp); Type *type_context=new Type("Context",context_disp,context_del,context_copy,context_comp); Type *type_generic=new Type("Generic",nullptr,nullptr,nullptr,nullptr); Type *type_integer=new Type("Integer",integer_disp,integer_del,integer_copy,integer_comp); Type *type_function=new Type("Function",function_disp,function_del,function_copy,function_comp); Type *type_contextual_function=new Type("ContextualFunction",contextual_function_disp,contextual_function_del,contextual_function_copy,contextual_function_comp); Type *type_meta_function=new Type("MetaFunction",meta_function_disp,meta_function_del,meta_function_copy,meta_function_comp); Type *type_module=new Type("Module",module_disp,module_del,module_copy,module_comp); Type *type_set=new Type("Set",set_disp,set_del,set_copy,set_comp); Type *type_string=new Type("String",string_disp,string_del,string_copy,string_comp); Type *type_symbol=new Type("Symbol",nullptr,nullptr,nullptr,nullptr); Type *type_tuple=new Type("Tuple",tuple_disp,tuple_del,tuple_copy,tuple_comp); Type *type_type=new Type("Type",type_disp,type_del,type_copy,type_comp); Type *type_void=new Type("Void",void_disp,void_del,void_copy,void_comp); //*********************** //* Context definitions * //*********************** //-------------------- // Context::Context() //-------------------- Context::Context(Interpreter* inter){ interpreter=inter; add_symbol("context",type_context,this)->hide=true; add_symbol("Array",type_type,type_array); add_symbol("Boolean",type_type,type_boolean)->hide=true; add_symbol("Context",type_type,type_context)->hide=true; add_symbol("Generic",type_type,type_generic)->hide=true; add_symbol("Integer",type_type,type_integer)->hide=true; add_symbol("Function",type_type,type_function)->hide=true; add_symbol("ContextualFunction",type_type,type_contextual_function)->hide=true; add_symbol("Module",type_type,type_module); add_symbol("Set",type_type,type_set); add_symbol("String",type_type,type_string); add_symbol("Symbol",type_type,type_symbol)->hide=true; add_symbol("Tuple",type_type,type_tuple); add_symbol("Type",type_type,type_type)->hide=true; add_symbol("Void",type_type,type_void)->hide=true; } //-------------------------------------------------------- // Context::add_function(string,string,string_list,void*) //-------------------------------------------------------- void Context::add_function(string ret,string name,string_list args,void* ptr){ Type* tr=get_type(ret); Signature signature=get_signature(args); Symbol* symbol=get_symbol(name); if(symbol==nullptr or (symbol!=nullptr and not symbol->locked and symbol->type!=type_meta_function and symbol->type!=type_function)){ Function* function=new Function(tr,signature,ptr); add_symbol(name,type_function,function,true); return; } string fullname=function_fullname(name,args); if(symbol->type==type_meta_function){ if(not can_add(fullname)) ContextError("A locked symbol named "+fullname+" already exists"); MetaFunction* meta_function=(MetaFunction*)symbol->ptr; meta_function->functions.insert(fullname); Function* function=new Function(tr,signature,ptr); add_symbol(fullname,type_function,function,true); return; } if(symbol->type==type_function){ Function* function=new Function(tr,signature,ptr); add_symbol(fullname,type_function,function,true); MetaFunction* meta_function=new MetaFunction; meta_function->functions.insert(fullname); function=(Function*)symbol->ptr; fullname=function_fullname(name,function->signature); add_symbol(fullname,type_function,function,true); meta_function->functions.insert(fullname); symbol->type=type_meta_function; symbol->ptr=(void*)meta_function; return; } ContextError("A locked symbol named "+name+" already exist"); } //------------------------------------------------------------- // Context::add_member_function(string,string,string_list,ptr) //------------------------------------------------------------- void Context::add_member_function(string ret,string name,string_list args,void* ptr){ if(args.size()==0) ContextError("Member function must have at least one argument"); string cname=*args.begin(); Type* ctype=get_type(cname); if(ctype==nullptr) ContextError("The class type "+cname+" does not exist."); add_function(ret,cname+"."+name,args,ptr); } //-------------------------------------------- // Context::add_symbol(name,Type*,void*,bool) //-------------------------------------------- Symbol* Context::add_symbol(string name,Type* type,void* ptr,bool lock){ Symbol& s=symbols[name]; if(s.locked) ContextError("A locked symbol named "+name+" already exist"); s.pdel();s.type=type; s.ptr=ptr;s.locked=lock; s.name=name; s.hide=false; return &s; } //----------------------------------------------- // Context::can_add_function(string,string_list) //----------------------------------------------- bool Context::can_add_function(string name,string_list targs){ if(can_add(name)) return true; if(not can_add(function_fullname(name,targs))) return false; Symbol* symbol=get_symbol(name); return symbol->type==type_meta_function or symbol->type==type_function; } //------------------------------------------------------ // Context::can_add_member_function(string,string_list) //------------------------------------------------------ bool Context::can_add_member_function(string name,string_list targs){ if(targs.size()==0) ContextError("A member function must have at least one argument"); string cname=*(targs.begin()); Type* ctype=get_type(cname); if(ctype==nullptr) ContextError("The class type "+cname+" does not exist"); return can_add_function(cname+"."+name,targs); } //----------------------------------------- // Context::eval_array(size_t,Node&,Node*) //----------------------------------------- void Context::eval_array(size_t size,Node& current, Node* nodes){ ArrayValue* array; if(size==0) array=new ArrayValue(0); else{ size_t j=current.son; int k=0; Type* type=nodes[j].value.eval()->type; if(type==nullptr or type==type_void) ContextError("Non empty Array of undefinded type is forbidden"); array=new ArrayValue(size); array->type=type; while(j!=-1){ Node* node=&nodes[j]; Value* val=node->value.eval(); //Test if the type is correct if(val->type!=type){ //No -> delete array for(int i=0;idel(array->tab[i]); delete[] array->tab; delete array; current.value.ptr=nullptr; current.value.type=type_void; ContextError("Elements of an Array must have same type"); } //We cannot stole pointer of value for a symbol if(node->value.type==type_symbol){ array->tab[k++]=type->copy(val->ptr); } else{ array->tab[k++]=val->ptr; val->type=type_void; val->ptr=nullptr; } j=node->bro; } } current.value.ptr=array; current.value.type=type_array; } //----------------------------------------------------------------------- // Context::eval_contextual_function(ContextualFunction*,Value**,size_t) //----------------------------------------------------------------------- Value Context::eval_contextual_function(ContextualFunction* func,Value** args,size_t nargs){ const Signature& signature=func->signature; if(nargs!=func->signature.size()) ContextError("The number of arguments is incorect ("+to_string(nargs)+" instead of "+to_string(func->signature.size())+")."); for(size_t i=0;itype==type_symbol and signature[i]!=type_symbol and signature[i]!=type_generic){ args[i]=(Value*)args[i]->ptr; } if(signature[i]!=type_generic and signature[i]!=args[i]->type) ContextError("Argument "+to_string(i+1)+" type is incorrect ("+type_disp(args[i]->type)+" instead of "+type_disp(signature[i])+")."); } return func->eval(args,nargs,*this); } //-------------------------------------------------- // Context::eval_function(Function*,Value**,size_t) //-------------------------------------------------- Value Context::eval_function(Function* function,Value** args,size_t nargs){ if(nargs!=function->signature.size()) ContextError("Number of argument is "+to_string(nargs)+" instead of "+to_string(function->signature.size())); Type* targ; for(size_t i=0;itype==type_symbol){ targ=((Value*)(args[i]->ptr))->type; } else{ targ=args[i]->type; } if(targ!=function->signature[i]) ContextError("Argument "+to_string(i)+" is of type "+type_disp(targ)+" instead of "+type_disp(function->signature[i])); } return function->eval(args,nargs); } //------------------------------------- // Context::eval_function(Node&,Node*) //------------------------------------- void Context::eval_function(Node& current,Node* nodes){ string name=current.str; Symbol* symbol=get_symbol(name); if(symbol==nullptr) ContextError("There is no symbol named "+name); Value* args[max_arguments_number]; size_t nargs=set_arguments(current,nodes,args); current.value=eval_function(symbol,args,nargs); } //------------------------------------------------ // Context::eval_function(Symbol*,Value**,size_t) //------------------------------------------------ Value Context::eval_function(Symbol* symbol,Value** args,size_t nargs){ if(symbol->type==type_contextual_function){ return eval_contextual_function((ContextualFunction*)symbol->ptr,args,nargs); } else if(symbol->type==type_function){ return eval_function((Function*)symbol->ptr,args,nargs); } else if(symbol->type==type_meta_function){ for(size_t i=0;itype==type_symbol){ args[i]=(Value*)(args[i]->ptr); } } string fullname=function_fullname(symbol->name,args,nargs); Value *val=get_symbol(fullname); if(val==nullptr) ContextError("There is no function "+fullname); if(val->type!=type_function) Bug("This case shall be impossible!"); return eval_function((Function*)val->ptr,args,nargs); } else{ Bug("The symbol named "+symbol->name+" is not callable"); } } //-------------------------------------------- // Context::eval_member_function(Node&,Node*) //-------------------------------------------- void Context::eval_member_function(Node& current,Node* nodes){ string name=current.str; Value* args[max_arguments_number]; size_t nargs=set_arguments(current,nodes,args); Value* first=args[0]->eval(); Type* type=first->type; Symbol* symbol=get_symbol(type,name); if(symbol==nullptr){ if(type==type_type){ type=(Type*)first->ptr; symbol=get_symbol(type,name); //current.son=nodes[current.son].bro; if(symbol==nullptr) ContextError("No member function "+name+" for tyipe "+type->name); current.value=eval_function(symbol,&args[1],nargs-1); return; } else{ ContextError("No member function "+name+" for type "+type->name); } } current.value=eval_function(symbol,args,nargs); } //-------------------------------------------------------- // Context::eval_member_symbol(Node& current,Node* nodes) //-------------------------------------------------------- void Context::eval_member_symbol(Node& current,Node* nodes){ string name=current.str; Node& cnode=nodes[current.son]; Symbol* symbol=get_symbol(cnode.str); if(symbol==nullptr) ContextError("Class type unkown"); Type* type=symbol->type; if(type==type_type){ name=cnode.str+"."+name; } else{ name=type->name+"."+name; } symbol=get_symbol(name); if(symbol==nullptr) ContextError("Symbol "+name+" does not exist"); current.value.type=type_symbol; current.value.ptr=symbol; } //--------------------------------------- // Context::eval_set(size_t,Node&,Node*) //--------------------------------------- void Context::eval_set(size_t size,Node& current, Node* nodes){ SetValue* set; if(size==0) set=new SetValue(type_generic); else{ size_t j=current.son; int k=0; Type* type=nodes[j].value.eval()->type; if(type==nullptr or type==type_void) ContextError("Non empty Set of undefinded type is forbidden"); set=new SetValue(type); while(j!=-1){ Node* node=&nodes[j]; Value* val=node->value.eval(); //Test if the type is correct if(val->type!=type){ //No -> delete set for(auto it=set->data.begin();it!=set->data.end();++it) type->del(*it); delete set; current.value.ptr=nullptr; current.value.type=type_void; ContextError("Elements of a Set must have same type"); } //Check if the value is not in the set otherwise do nothing if(set->data.find(val->ptr)==set->data.end()){ if(node->value.type==type_symbol){ //We cannot stole pointer of value for a symbol set->data.insert(type->copy(val->ptr)); } else{ set->data.insert(val->ptr); val->type=type_void; val->ptr=nullptr; } } j=node->bro; } } current.value.ptr=set; current.value.type=type_set; } //----------------------------------------- // Context::eval_tuple(size_t,Node&,Node*) //----------------------------------------- void Context::eval_tuple(size_t size,Node& current, Node* nodes){ TupleValue* tuple; if(size==0) tuple=new TupleValue(0); else{ size_t j=current.son; int k=0; tuple=new TupleValue(size); while(j!=-1){ Node* node=&nodes[j]; Value* val=node->value.eval(); //We cannot stole pointer of value for a symbol if(node->value.type==type_symbol){ tuple->tab[k++]=val->copy(); } else{ tuple->tab[k++]=*val; val->type=type_void; val->ptr=nullptr; } j=node->bro; } } current.value.ptr=tuple; current.value.type=type_tuple; } //------------------------------------- // Context::get_signature(string_list) //------------------------------------- Signature Context::get_signature(string_list targs){ Signature s(targs.size()); size_t i=0; for(auto its=targs.begin();its!=targs.end();++its) s[i++]=get_type(*its); return s; } //--------------------------- // Context::get_symbol(name) //--------------------------- Symbol* Context::get_symbol(string name){ auto it=symbols.find(name); if(it==symbols.end()) return nullptr; return &it->second; } //------------------------- // Context::get_type(name) //------------------------- Type* Context::get_type(string name){ Value* v=get_symbol(name); if(v==nullptr) ContextError("Type "+name+" does not exist"); if(v->type!=type_type) ContextError(name+" does not design a type"); return (Type*)v->ptr; } //---------------------------- // Context::load_module(name) //---------------------------- void Context::load_module(string name){ string filename="ext/"+name+".so"; Symbol* symbol=get_symbol(name); if(symbol!=nullptr and symbol->locked==true) ContextError("A locked symbol "+name+" already exist"); void* handle=dlopen(filename.c_str(),RTLD_NOW); if(not handle) RuntimeError("In loading module "+name+" : "+dlerror()); Module* module=new Module; symbol=add_symbol(name,type_module,module); module->handle=handle; module->name=name; //Loading types Module::Type* types=(Module::Type*)dlsym(handle,"types"); module->functions=(Module::Function*)dlsym(handle,"functions"); module->member_functions=(Module::Function*)dlsym(handle,"member_functions"); module->contextual_functions=(Module::Function*)dlsym(handle,"contextual_functions"); module->symbols=(Module::Symbol*)dlsym(handle,"symbols"); module->init(types); //Test if we can load all types for(size_t i=0;intype;++i){ if(not can_add(types[i].name)){ dlclose(handle); delete(module); ContextError("The type "+name+" cannot be added because a locked symbol has the same name"); } } module->types=new string[module->ntype]; for(size_t i=0;intype;++i){ Type* type=new Type(types[i]); *(types[i].ptr)=type; module->types[i]=type->name; add_symbol(type->name,type_type,type); } //Call init void (*init)()=(void(*)())dlsym(handle,"init"); if(init!=nullptr) (*init)(); //Load functions and symbols load_module_functions(module,0); load_module_functions(module,1); load_module_functions(module,2); load_module_symbols(module); } //--------------------------------------------- // Context::load_module_functions(Module*,int) //--------------------------------------------- void Context::load_module_functions(Module* module,int src){ bool (Context::*can_add_func)(string,string_list); void (Context::*add_func)(string,string,string_list,void*); Module::Function* module_func_ptr; size_t n; switch(src){ case 0: can_add_func=&Context::can_add_function; add_func=&Context::add_function; module_func_ptr=module->functions; n=module->nfunc; break; case 1: can_add_func=&Context::can_add_member_function; add_func=&Context::add_member_function; module_func_ptr=module->member_functions; n=module->nmfunc; break; case 2: can_add_func=&Context::can_add_contextual_function; add_func=&Context::add_contextual_function; module_func_ptr=module->contextual_functions; n=module->ncfunc; break; default: Bug("Not yet implemented"); } for(size_t i=0;i*can_add_func)(function.name,function.targs); } catch(Error& err){ err.disp(cout,""); function.loaded=false; } if(function.loaded){ (this->*add_func)(function.tr,function.name,function.targs,function.ptr); } else{ cout<<"Warning : "; if(src==0) cout<<"Function"; else if(src==1) cout<<"Member function"; else cout<<"Contextual function"; cout<<" "<nsymb;++i){ Module::Symbol& symbol=module->symbols[i]; Type* type=get_type(symbol.type); if(type==nullptr) cout<<"Type "<type==type_function){ unload_symbol(name); return; } if(symbol->type!=type_meta_function) Bug("The symbol "+name+" is not of type Function or MetaFunction"); MetaFunction* meta=(MetaFunction*)(symbol->ptr); meta->functions.erase(fullname); if(meta->functions.empty()) //There is no more function called name unload_symbol(name); } //--------------------------------- // Context::unload_module(Module*) //--------------------------------- void Context::unload_module(Module* module){ unload_module_functions(module); for(size_t i=0;intype;++i){ unload_type(get_type(module->types[i])); } //Unload module symbols for(size_t i=0;insymb;++i){ Module::Symbol& symbol=module->symbols[i]; if(symbol.loaded) unload_symbol(symbol.name); } //Unload module itself dlclose(module->handle); unload_symbol(module->name); } //------------------------------------------- // Context::unload_module_functions(Module*) //------------------------------------------- void Context::unload_module_functions(Module* module){ for(size_t i=0;infunc;++i){ if(module->functions[i].loaded) unload_function(module->functions[i].name,module->functions[i].targs); } for(size_t i=0;inmfunc;++i){ Module::Function& func=module->member_functions[i]; if(func.loaded) unload_function(*func.targs.begin()+"."+func.name,func.targs); } for(size_t i=0;incfunc;++i){ if(module->contextual_functions[i].loaded) unload_symbol(module->contextual_functions[i].name); } } //----------------------------- // Context::unload_type(Type*) //----------------------------- void Context::unload_type(Type* type){ for(auto it=symbols.begin();it!=symbols.end();++it){ if(it->second.type==type) unload_symbol(it->first); } unload_symbol(type->name); } //-------------------------- // Context::reload(Module*) //-------------------------- void Context::reload_module(Module* module){ //** Unload some module member unload_module_functions(module); //unload functions //Unload module symbols for(size_t i=0;insymb;++i){ Module::Symbol& symbol=module->symbols[i]; if(symbol.loaded) unload_symbol(symbol.name); } if(module->handle!=nullptr){ dlclose(module->handle); //close previous module handle module->handle=nullptr; } //we postpone the unload of module->types //** Load the new version of the library string filename="ext/"+module->name+".so"; void* handle=dlopen(filename.c_str(),RTLD_NOW); if(not handle){ handle=nullptr; RuntimeError("In loading module "+module->name+" : "+dlerror()); } Module nmod; //A temporary module for the newly loaded data Module::Type* types=(Module::Type*)dlsym(handle,"types"); nmod.functions=(Module::Function*)dlsym(handle,"functions"); nmod.member_functions=(Module::Function*)dlsym(handle,"member_functions"); nmod.contextual_functions=(Module::Function*)dlsym(handle,"contextual_functions"); nmod.symbols=(Module::Symbol*)dlsym(handle,"symbols"); nmod.init(types);//init the module, ie, compute size of arrays //Test if we can load the new types int link[nmod.ntype]; for(size_t i=0;intype;++j){ if(module->types[j]==name){ link[i]=j; break; } } if(link[i]==-1){//We can't load a type //close the library dlclose(handle); ContextError("The type "+name+" cannot be added because a locked symbol has the same name"); } } } //Look for old types to unload, ie, types in the old version of the library //that are not present in the new version bool to_unload[module->ntype]; for(size_t i=0;intype;++i){ to_unload[i]=true; for(size_t j=0;jntype;++i){ if(to_unload[i]) unload_type(get_type(module->types[i])); } //Update or load the types in the new version of the library delete[] module->types; //unload types array module->types=new string[nmod.ntype]; for(size_t i=0;itypes[i]=nmod_type.name; if(link[i]==-1){ Type *type=new Type(nmod_type); *nmod_type.ptr=type; add_symbol(type->name,type_type,type); } else{ Type* type=get_type(nmod_type.name); *nmod_type.ptr=type; type->disp=nmod_type.disp; type->del=nmod_type.del; type->copy=nmod_type.copy; type->comp=nmod_type.comp; } } module->ntype=nmod.ntype; module->functions=nmod.functions; module->nfunc=nmod.nfunc; module->member_functions=nmod.member_functions; module->nmfunc=nmod.nmfunc; module->contextual_functions=nmod.contextual_functions; module->ncfunc=nmod.ncfunc; module->symbols=nmod.symbols; module->nsymb=nmod.nsymb; module->handle=handle; //Call init void (*init)()=(void(*)())dlsym(handle,"init"); if(init!=nullptr) (*init)(); load_module_functions(module,0); load_module_functions(module,1); load_module_functions(module,2); load_module_symbols(module); } //--------------------------------------------- // Context::set_arguments(Node&,Node*,Value**) //--------------------------------------------- size_t Context::set_arguments(Node& current,Node* nodes,Value** args){ size_t j=current.son; size_t nargs=0; while(j!=-1){ args[nargs++]=&nodes[j].value; j=nodes[j].bro; } return nargs; } //********************** //* ContextualFunction * //********************** //--------------------------------------------------- // ContextualFunction::eval(Value**,size_t,Context&) //--------------------------------------------------- Value ContextualFunction::eval(Value* args[8],size_t nargs,Context& context){ switch(nargs){ case 0: return (*((CFunc0)ptr))(context); case 1: return (*((CFunc1)ptr))(context,*args[0]); case 2: return (*((CFunc2)ptr))(context,*args[0],*args[1]); case 3: return (*((CFunc3)ptr))(context,*args[0],*args[1],*args[2]); case 4: return (*((CFunc4)ptr))(context,*args[0],*args[1],*args[2],*args[3]); case 5: return (*((CFunc5)ptr))(context,*args[0],*args[1],*args[2],*args[3],*args[4]); case 6: return (*((CFunc6)ptr))(context,*args[0],*args[1],*args[2],*args[3],*args[4],*args[5]); case 7: return (*((CFunc7)ptr))(context,*args[0],*args[1],*args[2],*args[3],*args[4],*args[5],*args[6]); case 8: return (*((CFunc8)ptr))(context,*args[0],*args[1],*args[2],*args[3],*args[4],*args[5],*args[6],*args[7]); default: Bug("Not yet implemented"); break; } } //************ //* Function * //************ //-------------------------------- // Function::eval(Value**,size_t) //-------------------------------- Value Function::eval(Value* args[8],size_t nargs){ Value res; res.type=tr; switch(nargs){ case 0: res.ptr=(*((Func0)ptr))(); break; case 1: res.ptr=(*((Func1)ptr))(args[0]->eval()->ptr); break; case 2: res.ptr=(*((Func2)ptr))(args[0]->eval()->ptr,args[1]->eval()->ptr); break; case 3: res.ptr=(*((Func3)ptr))(args[0]->eval()->ptr,args[1]->eval()->ptr,args[2]->eval()->ptr); break; case 4: res.ptr=(*((Func4)ptr))(args[0]->eval()->ptr,args[1]->eval()->ptr,args[2]->eval()->ptr,args[3]->eval()->ptr); break; case 5: res.ptr=(*((Func5)ptr))(args[0]->eval()->ptr,args[1]->eval()->ptr,args[2]->eval()->ptr,args[3]->eval()->ptr,args[4]->eval()->ptr); break; case 6: res.ptr=(*((Func6)ptr))(args[0]->eval()->ptr,args[1]->eval()->ptr,args[2]->eval()->ptr,args[3]->eval()->ptr,args[4]->eval()->ptr,args[5]->eval()->ptr); break; case 7: res.ptr=(*((Func7)ptr))(args[0]->eval()->ptr,args[1]->eval()->ptr,args[2]->eval()->ptr,args[3]->eval()->ptr,args[4]->eval()->ptr,args[5]->eval()->ptr,args[6]->eval()->ptr); break; case 8: res.ptr=(*((Func8)ptr))(args[0]->eval()->ptr,args[1]->eval()->ptr,args[2]->eval()->ptr,args[3]->eval()->ptr,args[4]->eval()->ptr,args[5]->eval()->ptr,args[6]->eval()->ptr,args[7]->eval()->ptr); break; default: Bug("Not yet implemented"); } return res; } //*************** //* Interpreter * //*************** //------------------------------------------------------------------------- // Interperter::add_operator(const string&,const string&,OperatorType,int) //------------------------------------------------------------------------- void Interpreter::add_operator(const string& op,const string& name,OperatorType type,int priority){ OperatorInfo* opInfo=new OperatorInfo(name,type,priority); operator_tree.add(op,opInfo); } //------------------------------------------------------------------------ // Interpreter::complete(const string&,const string&,size_t,int,Context&) //------------------------------------------------------------------------ string Interpreter::complete(const string& cmd,const string& word,size_t pos,int state,Context& context){ if(state==0){ split_to_tokens(cmd); size_t i; for(i=0;ipos) break; } if(i!=0) --i; if(i>0 and nodes[i-1].tokenType==tDot) --i; if(nodes[i].tokenType==tDot){ //*.word if(i>0 and nodes[i-1].tokenType==tName){ Symbol* symbol=context.get_symbol(nodes[i-1].str); if(symbol==nullptr) return ""; if(symbol->type==type_type){ completion.type=context.get_type(nodes[i-1].str); } else{ completion.type=symbol->type; } completion.prefix=completion.type->name+"."; completion.word=completion.prefix+word; completion.it=context.symbols.lower_bound(completion.word); } else return ""; } else{ //word completion.prefix=""; completion.word=word; completion.it=context.symbols.lower_bound(completion.word); completion.type=nullptr; } } //Omit function fullname, hidden symbol and member symbols if no member call while((completion.it!=context.symbols.end()) and ((completion.it->second.hide) or (completion.it->first.find('(')!=string::npos) or (completion.type==nullptr and completion.it->first.find('.')!=string::npos) ) ) ++completion.it; if(completion.it==context.symbols.end()) return ""; if(completion.it->first.compare(0,completion.word.size(),completion.word)==0){ string res=completion.it->first; ++completion.it; return res.substr(completion.prefix.size()); } return ""; } //------------------------------------------------- // Interpreter::construct_sequence(size_t&,size_t) //------------------------------------------------- size_t Interpreter::construct_sequence(size_t& pos,size_t last){ Node& node=nodes[pos]; BracketType bt=node.bracketType; node.expressionType=get_delimiter_expression_type(bt); int depth=1; size_t begin=pos; slong* next=&node.son; size_t i=++pos; for(;pos<=last and depth!=0;++pos){ switch(nodes[pos].tokenType){ case tOpenBracket: ++depth; break; case tCloseBracket: --depth; break; case tComma: if(depth==1){ if(i>pos-1)//Empty SyntaxError("An Expression is needed",nodes[i-1].pos,nodes[pos].pos); (*next)=construct_tree(i,pos-1,max_precedence_level); next=&(nodes[*next].bro); i=pos+1; } break; default: break; } } //Close bracket not found if(depth!=0){ switch(bt){ case bRound: SyntaxError("Tuple or list has not ending",nodes[begin].pos,nodes[last].pos); case bSquare: SyntaxError("Array has not ending",nodes[begin].pos,nodes[last].pos); case bCurly: SyntaxError("Set has not ending",nodes[begin].pos,nodes[last].pos); default: Bug("Bracket type unkown"); break; } } size_t end=pos-1; //Close bracket mismatch if(nodes[end].bracketType!=bt) SyntaxError("Close bracket mismatch the opening one",nodes[begin].pos,nodes[end].pos); //The sequence is empty if(end==begin+1) return begin; //Add the last element if(i>=end)//Empty SyntaxError("An expression is needed",nodes[i-1].pos,nodes[end].pos); (*next)=construct_tree(i,end-1,max_precedence_level); return begin; } //------------------------------------------------- // Interpreter::construct_tree(size_t&,size_t,int) //------------------------------------------------- size_t Interpreter::construct_tree(size_t& first,size_t last,int precedence_level){ Node& node=nodes[first]; size_t root=first; switch(node.tokenType){ case tInteger: case tString: node.expressionType=expLeaf; ++first; break; case tName: ++first; if(first<=last and nodes[first].tokenType==tOpenBracket){ if(nodes[first].bracketType==bRound){ //Function call node.son=nodes[construct_sequence(first,last)].son; node.expressionType=expFunction; break; } else if(nodes[first].bracketType==bSquare){ //Get or set call node.bro=nodes[construct_sequence(first,last)].son; Node& nnode=nodes[first]; nnode.son=root; nnode.str="get"; root=first; nnode.expressionType=expArrayGet; node.expressionType=expLeaf; break; } else{ Bug("Not yet implemented"); } } else if(first<=last and (nodes[first].tokenType==tDot)){ //Member function call ++first; if(first>last or nodes[first].tokenType!=tName){ if(nodes[first-1].tokenType==tDot) SyntaxError("Name missing after dot",nodes[first-1].pos,nodes[first-1].pos); SyntaxError("Name missing after .",nodes[first-1].pos,nodes[first-1].pos+1); } string name=nodes[first].str; ++first; if(first<=last and nodes[first].tokenType==tOpenBracket and nodes[first].bracketType==bRound){ Node& nnode=nodes[first-2]; nnode.son=root; nnode.str=name; nnode.expressionType=expMemberFunction; root=first-2; node.bro=nodes[construct_sequence(first,last)].son; node.expressionType=expLeaf; break; } else{ Node& nnode=nodes[first-1]; nnode.son=root; nnode.expressionType=expMemberSymbol; nnode.str=name; node.expressionType=expLeaf; root=first-1; break; } } else{ node.expressionType=expLeaf; } break; case tOpenBracket: root=construct_sequence(first,last); //(Expr) -> Expr if(node.bracketType==bRound and node.son!=-1 and nodes[node.son].bro==-1){ root=node.son; } break; case tOperator: if(node.operatorInfo->type!=opPreUnitary and node.str!="-") SyntaxError("Operator not allowed here",node.pos,node.pos+node.str.length()-1); node.expressionType=expFunction; if(node.str=="-"){ node.str="negate"; node.son=construct_tree(++first,last,1); } else{ node.str=node.operatorInfo->func; node.son=construct_tree(++first,last,node.operatorInfo->precedence); } break; case tCloseBracket: SyntaxError("Missing openning bracket",node.pos,node.pos); case tComma: SyntaxError("Unexecepted comma outside a sequence",node.pos,node.pos); case tUnkown: SyntaxError("Get unkown token",node.pos,node.pos); case tEnd: //Ignore this token break; default: Bug("not yet implemented"); break; } size_t lhs; //We already read an expression while(first<=last){//There is something on the right //At this time inly operator are allowed lhs=root; root=first; Node& node=nodes[root]; if(node.tokenType==tOperator){ if(node.operatorInfo->type==opPreUnitary){ SyntaxError("A prefixed unitary operator is not allowed here",node.pos,node.pos+node.str.length()-1); } if(node.operatorInfo->precedence>precedence_level) return lhs; if(node.operatorInfo->type==opPostUnitary){ node.expressionType=expFunction; node.son=lhs; ++first; } else if(node.operatorInfo->type==opBinary){ if(first==last) SyntaxError("An expression is needed after binary operator",node.pos,node.pos+node.str.length()-1); size_t rhs=construct_tree(++first,last,node.operatorInfo->precedence); node.str=node.operatorInfo->func; node.expressionType=expFunction; node.son=lhs; nodes[lhs].bro=rhs; } } else SyntaxError("Only operator are allowed after such expression",node.pos,node.pos+node.str.length()-1); } return root; } //------------------------------------------------------- // Interpreter::display_expression_tree(ostream&,size_t) //------------------------------------------------------- void Interpreter::display_expression_tree(ostream& os,size_t i) const{ const Node& node=nodes[i]; switch(node.expressionType){ case expLeaf: os<<'['; display_token(os,i); os<<']'; return; case expTuple: os<<"[tuple"; break; case expArray: os<<"[array"; break; case expSet: os<<"[set"; break; case expFunction: os<<"[function '"<=0){//There is at least a son do{ os<<','; display_expression_tree(os,j); j=nodes[j].bro; }while(j>=0); } os<<']'; } //--------------------------------------------- // Interpreter::display_token(ostream&,size_t) //--------------------------------------------- void Interpreter::display_token(ostream& os,size_t i) const{ const Node& node=nodes[i]; switch(node.tokenType){ case tInteger: os<<"(integer,"<eval(); if(value->type!=nullptr and value->type!=type_void){ cout<disp()<pdel(); } } //------------------------------------------------------ // Interpreter::eval_basic(string cmd,Context& context) //------------------------------------------------------ Value* Interpreter::eval_basic(string cmd,Context& context){ size_t root; Node* node; bool error=false; split_to_tokens(cmd); size_t first=0; root=construct_tree(first,nodes_number-1,max_precedence_level); eval_expression(root,context); node=&nodes[root]; return &node->value; } //----------------------------------------------- // Interpreter::eval_expression(size_t,Context&) //----------------------------------------------- void Interpreter::eval_expression(size_t pos,Context& context){ Node &node=nodes[pos]; if(node.expressionType==expLeaf){ if(node.tokenType==tName){ node.value.type=type_symbol; Symbol* symbol=context.get_symbol(node.str); if(symbol!=nullptr){ node.value.ptr=symbol; } else{ node.value.ptr=context.add_symbol(node.str,type_void,nullptr,false); } return; } return; } size_t size=0; slong j=node.son; while(j!=-1){ ++size; eval_expression(j,context); j=nodes[j].bro; } switch(node.expressionType){ case expFunction: context.eval_function(node,nodes); break; case expMemberFunction: context.eval_member_function(node,nodes); break; case expMemberSymbol: context.eval_member_symbol(node,nodes); break; case expArray: context.eval_array(size,node,nodes); break; case expSet: context.eval_set(size,node,nodes); break; case expTuple: context.eval_tuple(size,node,nodes); break; case expArrayGet: Bug("Exp array get not yet implemented"); break; default: Bug("Not yet implemented"); } j=node.son; while(j!=-1){ nodes[j].value.pdel(); j=nodes[j].bro; } } //------------------------------------------------- // Interpreter::get_integer(size_t&,const string&) //------------------------------------------------- fmpz* Interpreter::get_integer(size_t& pos,const string& cmd){ size_t oldPos=pos; size_t end=cmd.length(); char l; do{ l=cmd[++pos]; }while(pos=end){ node.tokenType=tEnd; return; } char l=cmd[pos]; if('0'<=l and l<='9'){ node.tokenType=tInteger; oldPos=pos; node.value.type=type_integer; node.value.ptr=(void*)(get_integer(pos,cmd)); node.str=cmd.substr(oldPos,pos-oldPos+1); return; } if(l=='"'){ node.tokenType=tString; node.str=get_string(pos,cmd); node.value.type=type_string; string* pstr=new string; *pstr=node.str; node.value.ptr=(void*)pstr; return; } if(('a'<=l and l<='z') or ('A'<=l and l<='Z') or l=='_'){ node.tokenType=tName; node.str=get_name(pos,cmd); return; } switch(l){ case ',': node.str=','; node.tokenType=tComma; ++pos; return; case '.': node.str='.'; node.tokenType=tDot; ++pos; return; case '(': node.tokenType=tOpenBracket; node.bracketType=bRound; node.str=l;++pos; return; case ')': node.tokenType=tCloseBracket; node.bracketType=bRound; node.str=l;++pos; return; case '[': node.tokenType=tOpenBracket; node.bracketType=bSquare; node.str=l;++pos; return; case ']': node.tokenType=tCloseBracket; node.bracketType=bSquare; node.str=l;++pos; return; case '{': node.tokenType=tOpenBracket; node.bracketType=bCurly; node.str=l;++pos; return; case '}': node.tokenType=tCloseBracket; node.bracketType=bCurly; node.str=l;++pos; return; } //Try to find operator oldPos=pos; OperatorInfo* operatorInfo=get_operator(pos,cmd); if(operatorInfo!=nullptr){//Operator found node.tokenType=tOperator; node.operatorInfo=operatorInfo; node.str=cmd.substr(oldPos,pos-oldPos); return; } //Operator not found SyntaxError("Token unkown",oldPos,oldPos); return; } //--------------------------------------------- // Interpreter::split_to_tokens(const string&) //--------------------------------------------- void Interpreter::split_to_tokens(const string& cmd){ nodes_number=0; size_t pos=0; while(true){ if(nodes_number>=max_nodes_number) Bug("The command is too huge"); Node& node=nodes[nodes_number++]; set_token(node,pos,cmd); if(node.tokenType==tEnd) break; } //Remove node of token type tEnd --nodes_number; } //*********************** //* Auxiliary functions * //*********************** //-------------------------------------------- // get_delimiter_expression_type(BracketType) //-------------------------------------------- ExpressionType get_delimiter_expression_type(BracketType type){ switch(type){ case bRound: return expTuple; case bSquare: return expArray; case bCurly: return expSet; default: cout<<"BUG from getDelimiterExpressionType"<type->name; for(size_t i=1;itype->name; } return res+")"; } //-------------------------------------------- // function_fullname(string,const Signature&) //-------------------------------------------- string function_fullname(string name,const Signature& signature){ string res=name+"("; if(signature.is_empty()) return res+")"; res+=signature[0]->name; for(size_t i=1;iname; } return res+")"; } ostream& operator<<(ostream& os,const BracketType& bt){ switch(bt){ case bRound: return os<<"round"; break; case bSquare: return os<<"square"; break; case bCurly: return os<<"curly"; break; default: return os<<"?"; break; } } ostream& operator<<(ostream& os,const OperatorInfo& info){ switch(info.type){ case opPreUnitary: return os<<"_ "<