--- parser3/src/main/compile.C 2001/09/26 10:32:25 1.50 +++ parser3/src/main/compile.C 2026/10/05 17:50:18 1.91 @@ -1,80 +1,102 @@ /** @file Parser: compiler part of request class. - Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) - Author: Alexander Petrosyan (http://design.ru/paf) - - $Id: compile.C,v 1.50 2001/09/26 10:32:25 parser Exp $ + Copyright (c) 2001-2026 Art. Lebedev Studio (https://www.artlebedev.com) + Authors: Konstantin Morshnev , Alexandr Petrosian */ -#include "pa_opcode.h" +volatile const char * IDENT_COMPILE_C="$Id: compile.C,v 1.91 2026/10/05 17:50:18 moko Exp $"; + #include "pa_request.h" -#include "pa_string.h" -#include "pa_array.h" #include "compile_tools.h" -#include "pa_exception.h" - -#include +#include "pa_vclass.h" extern int yydebug; -extern int yyparse (void *); +extern int yyparse (Parse_control *); -VStateless_class& Request::real_compile(COMPILE_PARAMS) { +ArrayClass& Request::compile(VStateless_class* aclass, const char* source, const String* main_alias, uint file_no, int line_no_offset, Code_cache* code) { // prepare to parse - struct parse_control pc; - - // input - pc.pool=&pool(); - pc.request=this; - VStateless_class *cclass; - if(aclass) // we were told the class to compile to? - cclass=aclass; // yes, remember it [used in ^process] - else if(name) { // we were told the name of compiled class? - // yes. create it - cclass=NEW VClass(pool()); - // defaulting base. may change with @BASE - // dont use ?: for there would be getting & of temp object - if(base_class) - cclass->set_base(*base_class); - classes().put(*name, cclass); - cclass->set_name(*name); - } else - cclass=&OP; // until changed with @CLASS would consider operators loading - pc.cclass=cclass; - - pc.source=source; -#ifndef NO_STRING_ORIGIN - pc.file=file; - pc.line=pc.col=0; + Parse_control pc(*this, aclass, source, main_alias, file_no, line_no_offset); +#ifdef CODE_CACHE + if(code) + code->file_no=file_no; + pc.code_cache=code; #endif - // initialise state - pc.trim_bof=true; - pc.pending_state=0; - pc.string=NEW String(pool()); - pc.ls=LS_USER; - pc.sp=0; - pc.object_constructor_allowed=false; - + // parse=compile! //yydebug=1; if(yyparse(&pc)) { // error? - if(pc.col==0) { // expecting something after EOL means they've expected it BEFORE - // step back. -1 col means EOL - pc.line--; - pc.col=-1; - } - THROW(0,0, - 0, -#ifndef NO_STRING_ORIGIN - "%s(%d:%d): " -#endif - "%s", -#ifndef NO_STRING_ORIGIN - file, 1+pc.line, pc.col, -#endif - pc.error); + pc.pos_prev_c(); + if(!pc.explicit_result) + if(pc.pos.col==0) // expecting something after EOL means they've expected it BEFORE + pc.pos_prev_c(); + + exception_trace.push(Trace(0, Operation::Origin::create(file_no, pc.pos.line, pc.pos.col))); + throw Exception("parser.compile", 0, "%s", pc.error); } +#ifdef CODE_CACHE + if(code) + Code_cache_manager::put(*code); +#endif + // result - return *pc.cclass; + return *pc.cclasses; +} + +#ifdef CODE_CACHE + +#define CLASS_ADD if(!pc.class_add()) \ + throw Exception("parser.compile", 0, "%s - class is already defined", pc.cclass->type()); + +/// replays the compilation using the cached methods, mirrors control_method and code_method in compile.y +ArrayClass& Code_cache::replay(Request& r, VStateless_class& aclass) { + Parse_control pc(r, &aclass, "", 0 /*main_alias: only ^process has one*/, file_no, 0); + const String* filespec=r.get_used_filespec(file_no); + + for(Array::Iterator i(actions); i; ) { + Action action=i.next(); + switch(action.kind) { + case CLASS: + CLASS_ADD; + pc.cclass_new=new VClass(action.name->cstr(), filespec); + pc.append=false; + break; + case USE: + CLASS_ADD; + r.use_file(*action.name, filespec, action.origin); + break; + case BASE: + CLASS_ADD; + if(VStateless_class* base_class=r.get_class(*action.name)) + pc.cclass->get_class()->set_base(base_class); + else + throw Exception("parser.compile", 0, "'%s': undefined class in @BASE", action.name->cstr()); + break; + case OPTION: + if(*action.name==Symbols::LOCALS_SYMBOL) + pc.set_all_vars_local(); + else if(*action.name==Symbols::PARTIAL_SYMBOL) { + if(VStateless_class* existed=pc.get_existed_class(pc.cclass_new)) { + if(!pc.reuse_existed_class(existed)) + throw Exception("parser.compile", 0, "can't append methods to '%s' - the class wasn't marked as partial", pc.cclass_new->type()); + } else + pc.cclass_new->set_partial(); + } else if(*action.name==Symbols::STATIC_SYMBOL) + pc.set_methods_call_type(Method::CT_STATIC); + else if(*action.name==Symbols::DYNAMIC_SYMBOL) + pc.set_methods_call_type(Method::CT_DYNAMIC); + break; + case METHOD: + CLASS_ADD; + pc.cclass->set_method(*action.name, action.method); + break; + case MAIN: + pc.cclass->set_method(*action.name, action.method); + break; + } + } + + return *pc.cclasses; } +#endif