8d87312018-02-04Martin Nilsson /* -*- mode: c; encoding: utf-8; -*-
dd40072017-02-02Henrik Grubbström (Grubba) || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */ #include "global.h" #include "program.h" #include "object.h" #include "buffer.h" #include "pike_types.h" #include "stralloc.h" #include "las.h" #include "lex.h" #include "pike_macros.h" #include "fsort.h" #include "pike_error.h" #include "docode.h" #include "interpret.h" #include "main.h" #include "pike_memory.h" #include "gc.h" #include "threads.h" #include "constants.h" #include "operators.h" #include "builtin_functions.h" #include "mapping.h" #include "cyclic.h" #include "opcodes.h" #include "version.h" #include "block_allocator.h" #include "block_alloc.h" #include "pikecode.h" #include "pike_compiler.h" #include "module_support.h" #include "bitvector.h" #include "sprintf.h"
7a50022018-08-05Martin Nilsson #include "cpp.h"
dd40072017-02-02Henrik Grubbström (Grubba)  #include <errno.h> #include <fcntl.h> #ifdef PIKE_THREADS static COND_T Pike_compiler_cond; static THREAD_T Pike_compiler_thread; static int lock_depth = 0; PMOD_EXPORT void lock_pike_compiler(void) { if (lock_depth && (Pike_compiler_thread != th_self())) { SWAP_OUT_CURRENT_THREAD(); while (lock_depth && (Pike_compiler_thread != th_self())) { co_wait_interpreter(&Pike_compiler_cond); } SWAP_IN_CURRENT_THREAD(); } lock_depth++; Pike_compiler_thread = th_self(); } PMOD_EXPORT void unlock_pike_compiler(void) { #ifdef PIKE_DEBUG if (lock_depth < 1) { Pike_fatal("Pike compiler running unlocked!\n"); } #endif lock_depth--; co_broadcast(&Pike_compiler_cond); } #else PMOD_EXPORT void lock_pike_compiler(void) { } PMOD_EXPORT void unlock_pike_compiler(void) { } #endif static void low_enter_compiler(struct object *ce, int inherit); /* #define COMPILER_DEBUG */ /* #define PROGRAM_BUILD_DEBUG */ #ifdef COMPILER_DEBUG #define CDFPRINTF(...) fprintf(stderr, __VA_ARGS__) #ifndef PIKE_THREADS /* The CDFPRINTF lines wants to print lock_depth, so fake one of those */ static const int lock_depth = 1; #endif #else /* !COMPILER_DEBUG */ #define CDFPRINTF(...) #endif /* COMPILER_DEBUG */
89124a2018-06-26Henrik Grubbström (Grubba) struct program *reporter_program = NULL;
dd40072017-02-02Henrik Grubbström (Grubba) struct program *compilation_program = 0; struct program *compilation_env_program = 0; struct object *compilation_environment = NULL; /* * Supporters. * * Supporters are used to register that a program being compiled depends on * another program that also is being compiled. * * Every program being compiled has a supporter (in the compilation * struct). */ struct Supporter *current_supporter=0; #ifdef PIKE_DEBUG struct supporter_marker { struct supporter_marker *next; void *data; int level, verified; }; #undef INIT_BLOCK #define INIT_BLOCK(X) do { (X)->level = (X)->verified = 0; }while(0) PTR_HASH_ALLOC(supporter_marker, 128); static int supnum; #define SNUM(X) (get_supporter_marker((X))->level) static void mark_supporters(struct Supporter *s) { struct supporter_marker *m; if(!s) return; debug_malloc_touch(s); m=get_supporter_marker(s); if(m->level) return; m->level = -1; if(s->magic != 0x500b0127) { #ifdef DEBUG_MALLOC describe(s); #endif Pike_fatal("This is not a supporter (addr=%p, magic=%x)!\n",s,s->magic); } mark_supporters(s->dependants); mark_supporters(s->next_dependant); m->level=supnum++; mark_supporters(s->previous); mark_supporters(s->depends_on); } static void low_verify_supporters(struct Supporter *s) { struct Supporter *ss; struct supporter_marker *m; if(!s) return; debug_malloc_touch(s); m=get_supporter_marker(s); if(m->verified) return; m->verified = 1; low_verify_supporters(s->dependants); low_verify_supporters(s->next_dependant); #if 0 fprintf(stderr, "low_verify_supporters %p%s, level %d: " "previous %p, depends_on %p, dependants %p, next_dependant %p\n", s, s == current_supporter ? " == current_supporter" : "", m->level, s->previous, s->depends_on, s->dependants, s->next_dependant); #endif if(s->previous && SNUM(s->previous) <= m->level) Pike_fatal("Que, numbers out of whack1\n"); if(s->depends_on && SNUM(s->depends_on) <= m->level) Pike_fatal("Que, numbers out of whack2\n"); for(ss=s->dependants;ss;ss=ss->next_dependant) { if (ss->depends_on != s) Pike_fatal("Dependant hasn't got depends_on set properly.\n"); if(SNUM(ss) >= m->level) Pike_fatal("Que, numbers out of whack3\n"); } low_verify_supporters(s->previous); low_verify_supporters(s->depends_on); } void verify_supporters() { if(d_flag) { supnum=1; init_supporter_marker_hash(); #if 0 fprintf(stderr, "verify_supporters start\n"); #endif mark_supporters(current_supporter); low_verify_supporters(current_supporter); #ifdef DO_PIKE_CLEANUP { size_t e=0; for(e=0;e<supporter_marker_hash_table_size;e++) while(supporter_marker_hash_table[e]) remove_supporter_marker(supporter_marker_hash_table[e]->data); } #endif exit_supporter_marker_hash(); #if 0 fprintf(stderr, "verify_supporters end\n"); #endif } } #else #define verify_supporters(); #endif void init_supporter(struct Supporter *s, supporter_callback *fun, void *data) { CDFPRINTF("th(%ld) init_supporter() supporter=%p data=%p.\n", (long) th_self(), s, data); verify_supporters(); #ifdef PIKE_DEBUG s->magic = 0x500b0127; #endif s->previous=current_supporter; current_supporter=s; s->depends_on=0; s->dependants=0; s->next_dependant=0; s->fun=fun; s->data=data; s->prog=0; verify_supporters(); } int unlink_current_supporter(struct Supporter *c) { int ret=0; #ifdef PIKE_DEBUG if(c != current_supporter) Pike_fatal("Previous unlink failed.\n"); #endif debug_malloc_touch(c); verify_supporters(); if(c->depends_on) { #ifdef PIKE_DEBUG struct Supporter *s; for (s = c->depends_on->dependants; s; s = s->next_dependant) if (s == c) Pike_fatal("Dependant already linked in.\n"); #endif ret++; c->next_dependant = c->depends_on->dependants; c->depends_on->dependants=c; add_ref(c->self); CDFPRINTF("th(%ld) unlink_current_supporter() " "supporter=%p (prog %p) depends on %p (prog %p).\n", (long) th_self(), c, c->prog, c->depends_on, c->depends_on->prog); } current_supporter=c->previous; verify_supporters(); return ret; } void free_supporter(struct Supporter *c) { verify_supporters(); if (c->depends_on) { struct Supporter **s; for (s = &c->depends_on->dependants; *s; s = &(*s)->next_dependant) if (*s == c) {*s = c->next_dependant; break;} c->depends_on = 0; } verify_supporters(); } int call_dependants(struct Supporter *s, int finish) { int ok = 1; struct Supporter *tmp; CDFPRINTF("th(%ld) call_dependants() supporter=%p (prog %p) " "finish=%d.\n", (long) th_self(), s, s->prog, finish); verify_supporters(); while((tmp=s->dependants)) { CDFPRINTF("th(%ld) dependant: %p (prog %p) (data:%p).\n", (long) th_self(), tmp, tmp->prog, tmp->data); s->dependants=tmp->next_dependant; #ifdef PIKE_DEBUG tmp->next_dependant=0; #endif verify_supporters(); if (!tmp->fun(tmp->data, finish)) ok = 0; verify_supporters(); free_object(tmp->self); } return ok; } int report_compiler_dependency(struct program *p) { int ret=0; struct Supporter *c,*cc; if (p == Pike_compiler->new_program) { /* Depends on self... */ return 0; } CDFPRINTF("th(%ld) compiler dependency on %p from %p\n", (long)th_self(), p, Pike_compiler->new_program); verify_supporters(); if (Pike_compiler->flags & COMPILATION_FORCE_RESOLVE) return 0; for(cc=current_supporter;cc;cc=cc->previous) { if(cc->prog && !(cc->prog->flags & PROGRAM_PASS_1_DONE)) { c=cc->depends_on; if(!c) c=cc->previous; for(;c;c=c->previous) { if(c->prog == p) { cc->depends_on=c; CDFPRINTF("th(%ld) supporter %p (prog %p) " "now depends on %p (prog %p)\n", (long) th_self(), cc, cc->prog, c, c->prog); verify_supporters(); ret++; /* dependency registred */ } } } } verify_supporters(); return ret; } extern int yyparse(void); static void do_yyparse(void) { struct svalue *save_sp = Pike_sp; yyparse(); /* Parse da program */ if (save_sp != Pike_sp) { #ifdef PIKE_DEBUG if (!Pike_compiler->num_parse_error) { Pike_fatal("yyparse() left %"PRINTPTRDIFFT"d droppings on the stack!\n", Pike_sp - save_sp); } #endif pop_n_elems(Pike_sp - save_sp); } } /*! @class Reporter *! *! API for reporting parse errors and similar. */ /*! @decl enum SeverityLevel *! Message severity level. *! { NOTICE, WARNING, ERROR, FATAL } *! *! @constant NOTICE *! @constant WARNING *! @constant ERROR *! @constant FATAL *! *! @seealso *! @[report()] */ /*! @decl void report(SeverityLevel severity, @ *! string filename, int(1..) linenumber, @ *! string subsystem, @ *! string message, mixed ... extra_args) *! *! Report a diagnostic from the compiler. *! *! @param severity *! The severity of the diagnostic. *! *! @param filename *! @param linenumber *! Location which triggered the diagnostic. *! *! @param subsystem *! Compiler subsystem that generated the diagnostic. *! *! @param message *! @[sprintf()]-style formatting string with the diagnostic message. *! *! @param extra_args *! Extra arguments to @[sprintf()]. *! *! The default implementation does the following: *! *! @ul *! @item *! If there's a @[MasterObject()->report()], call it *! with the same arguments as ourselves. *! @item *! Otherwise depending on @[severity]: *! @int *! @value NOTICE *! Ignored. *! @value WARNING *! Calls @[MasterObject()->compile_warning()]. *! @value ERROR *! @value FATAL *! Calls @[MasterObject()->compile_error()]. *! @endint *! @endul *! *! If there's no master object yet, the diagnostic is output to *! @[Stdio.stderr]. *! *! @note *! In Pike 7.8 and earlier @[MasterObject()->report()] was not called. *! *! @seealso *! @[PikeCompiler()->report()] */ /* NOTE: This function MUST NOT use any storage in the Reporter program! */ static void f_reporter_report(INT32 args) { int level; struct pike_string *filename; INT_TYPE linenumber; struct pike_string *subsystem; struct pike_string *message; struct object *master_ob; if ((master_ob = get_master()) && master_ob->prog) { int fun = find_identifier("report", master_ob->prog); if (fun >= 0) { apply_low(master_ob, fun, args); return; } } if (args > 5) { f_sprintf(args - 4); args = 5; }
c91b1d2018-08-05Martin Nilsson  get_all_args(NULL, args, "%d%W%+%W%W",
dd40072017-02-02Henrik Grubbström (Grubba)  &level, &filename, &linenumber, &subsystem, &message); /* Ignore informational level messages */ if (level >= REPORT_WARNING) { if (master_ob && master_ob->prog) { ref_push_string(filename); push_int(linenumber); ref_push_string(message); if (level >= REPORT_ERROR) { APPLY_MASTER("compile_error", 3); args++; } else { APPLY_MASTER("compile_warning", 3); args++; } } else { /* We hope that errors from compiling the master * won't contain wide-strings... */ if (level >= REPORT_ERROR) { fprintf(stderr, "%s:%ld: %s\n", filename->str, (long)linenumber, message->str); } else { fprintf(stderr, "%s:%ld: Warning: %s\n", filename->str, (long)linenumber, message->str); } fflush(stderr); } } pop_n_elems(args); push_int(0); } /*! @endclass */ /*! @module DefaultCompilerEnvironment *! *! The @[CompilerEnvironment] object that is used *! for loading C-modules and by @[predef::compile()]. *! *! @note *! @[predef::compile()] is essentially an alias for the *! @[CompilerEnvironment()->compile()] in this object. *! *! @seealso *! @[CompilerEnvironment], @[predef::compile()] */ /*! @decl inherit CompilerEnvironment */ /*! @endmodule */ /*! @class CompilerEnvironment *! *! The compiler environment. *! *! By inheriting this class and overloading the functions, *! it is possible to make a custom Pike compiler. *! *! @note *! Prior to Pike 7.8 this sort of customization has to be done *! either via custom master objects, or via @[CompilationHandler]s. *! *! @seealso *! @[CompilationHandler], @[MasterObject], @[master()], @[replace_master()] */ /*! @decl inherit Reporter *! *! Implements the @[Reporter] API. *! *! @seealso *! @[Reporter()->report()], @[Reporter()->SeverityLevel] */ /*! @class lock *! *! This class acts as a lock against other threads accessing the compiler. *! *! The lock is released when the object is destructed. */ static void compiler_environment_lock_event_handler(int e) { switch(e) { case PROG_EVENT_INIT: lock_pike_compiler(); break; case PROG_EVENT_EXIT: unlock_pike_compiler(); break; } } /*! @endclass */ /*! @decl program compile(string source, CompilationHandler|void handler, @ *! int|void major, int|void minor,@ *! program|void target, object|void placeholder) *! *! Compile a string to a program. *! *! This function takes a piece of Pike code as a string and *! compiles it into a clonable program. *! *! The optional argument @[handler] is used to specify an alternative *! error handler. If it is not specified the current master object will *! be used. *! *! The optional arguments @[major] and @[minor] are used to tell the *! compiler to attempt to be compatible with Pike @[major].@[minor]. *! *! @note *! This function essentially performs *! @code *! program compile(mixed ... args) *! { *! return PikeCompiler(@@args)->compile(); *! } *! @endcode *! *! @note *! Note that @[source] must contain the complete source for a program. *! It is not possible to compile a single expression or statement. *! *! Also note that @[compile()] does not preprocess the program. *! To preprocess the program you can use @[compile_string()] or *! call the preprocessor manually by calling @[cpp()]. *! *! @seealso *! @[compile_string()], @[compile_file()], @[cpp()], @[master()], *! @[CompilationHandler] */ static void f_compilation_env_compile(INT32 args) { apply_current(CE_PIKE_COMPILER_FUN_NUM, args); args = 1; if (TYPEOF(Pike_sp[-1]) != T_OBJECT) { Pike_error("Bad return value from PikeCompiler().\n"); } apply(Pike_sp[-1].u.object, "compile", 0); stack_pop_n_elems_keep_top(args); } /*! @decl mixed resolv(string identifier, string filename, @
2a2b5c2018-07-07Henrik Grubbström (Grubba)  *! object|void handler, object|void compat_handler)
dd40072017-02-02Henrik Grubbström (Grubba)  *! *! Look up @[identifier] in the current context. *! *! The default implementation calls the corresponding
2a2b5c2018-07-07Henrik Grubbström (Grubba)  *! function in the handlers (if any), falling back to *! the master object. *! *! @returns *! Returns the value of the @[identifier] if found, and *! @[UNDEFINED] if not.
dd40072017-02-02Henrik Grubbström (Grubba)  */ static void f_compilation_env_resolv(INT32 args) { struct pike_string *ident; struct pike_string *filename; struct object *handler = NULL;
2a2b5c2018-07-07Henrik Grubbström (Grubba)  struct object *compat_handler = NULL;
dd40072017-02-02Henrik Grubbström (Grubba) 
c91b1d2018-08-05Martin Nilsson  get_all_args(NULL, args, "%W%W.%O%O",
2a2b5c2018-07-07Henrik Grubbström (Grubba)  &ident, &filename, &handler, &compat_handler);
dd40072017-02-02Henrik Grubbström (Grubba)  if(get_master()) { DECLARE_CYCLIC(); if(BEGIN_CYCLIC(ident, filename)) { my_yyerror("Recursive module dependency in %S.", ident); }else{ SET_CYCLIC_RET(1);
2a2b5c2018-07-07Henrik Grubbström (Grubba)  low_unsafe_apply_handler("resolv", handler, compat_handler, args);
dd40072017-02-02Henrik Grubbström (Grubba)  } END_CYCLIC(); } else { pop_n_elems(args); push_undefined(); } } /*! @decl object get_compilation_handler(int major, int minor) *! *! Get compatibility handler for Pike @[major].@[minor]. *! *! The default implementation calls the corresponding *! function in the master object. *! *! @note *! This function is typically called by *! @[PikeCompiler()->get_compilation_handler()]. *! *! @seealso *! @[MasterObject()->get_compilation_handler()]. */ static void f_compilation_env_get_compilation_handler(INT32 args) { if(get_master()) { APPLY_MASTER("get_compilation_handler", args); } else { pop_n_elems(args); push_undefined(); } } /*! @decl mapping(string:mixed)|object get_default_module() *! *! Get the default module for the current compatibility level *! (ie typically the value returned by @[predef::all_constants()]). *! *! The default implementation calls the corresponding function *! in the master object. *! *! @returns *! @mixed *! @type mapping(string:mixed)|object *! Constant table to use. *! *! @type int(0..0) *! Use the builtin constant table. *! @endmixed *! *! @note *! This function is typically called by *! @[Pike_compiler()->get_default_module()]. *! *! @seealso *! @[MasterObject()->get_default_module()]. */ static void f_compilation_env_get_default_module(INT32 args) { if(get_master()) { APPLY_MASTER("get_default_module", args); } else { pop_n_elems(args); push_undefined(); } } /*! @decl program handle_inherit(string inh, string current_file, @ *! object|void handler) *! *! Look up an inherit @[inh]. *! *! The default implementation calls the corresponding function *! in the master object. *! *! @seealso *! @[MasterObject()->handle_inherit()]. */ static void f_compilation_env_handle_inherit(INT32 args) { if(get_master()) { APPLY_MASTER("handle_inherit", args); } else { pop_n_elems(args); push_undefined(); } }
b066222018-07-10Henrik Grubbström (Grubba) /*! @decl program handle_import(string module, string current_file, @ *! object|void handler) *! *! Look up an import @[module]. *! *! The default implementation calls the corresponding function *! in the master object. *! *! @seealso *! @[MasterObject()->handle_import()]. */ static void f_compilation_env_handle_import(INT32 args) { if(get_master()) { APPLY_MASTER("handle_import", args); } else { pop_n_elems(args); push_undefined(); } }
dd40072017-02-02Henrik Grubbström (Grubba) #if 0 /* @decl int filter_exception(SeverityLevel level, mixed err) * * The default implementation calls * @[MasterObject()->compile_exception()] for @[level] @[ERROR] * and @[FATAL]. * * @note * This function is not implemented in Pike 7.8. * * @seealso * @[MasterObject()->compile_exception()]. */ static void f_compilation_env_filter_exception(INT32 args) { int level; struct svalue *err;
c91b1d2018-08-05Martin Nilsson  get_all_args(NULL, args, "%d%*", &level, &err);
dd40072017-02-02Henrik Grubbström (Grubba)  if (args > 2) { pop_n_elems(args-2); args = 2; } #if 0 if (level >= REPORT_WARNING) { if (level >= REPORT_ERROR) { APPLY_MASTER("compile_exception", 1); /* FIXME! */ } else { push_int(level); push_string(format_exception_for_error_msg(err)); /* FIXME! */ } } #endif pop_n_elems(args); push_undefined(); return; } #endif /*! @class PikeCompiler *! *! The Pike compiler. *! *! An object of this class compiles a single string *! of Pike code. */ static void free_compilation(struct compilation *c) { debug_malloc_touch(c); if (c->prog) { free_string(c->prog); c->prog = NULL; } if(c->handler) { free_object(c->handler); c->handler = NULL; } if(c->compat_handler) { free_object(c->compat_handler); c->compat_handler = NULL; } if(c->target) { free_program(c->target); c->target = NULL; } if(c->p) { free_program(c->p); c->p = NULL; } if(c->placeholder) { free_object(c->placeholder); c->placeholder = NULL; } if(c->lex.current_file) { free_string(c->lex.current_file); c->lex.current_file = NULL; } if(c->lex.attributes) { free_node(c->lex.attributes); c->lex.attributes = NULL; } if (c->resolve_cache) { free_mapping(c->resolve_cache); c->resolve_cache = NULL; } free_svalue(& c->default_module); SET_SVAL(c->default_module, T_INT, NUMBER_NUMBER, integer, 0); free_supporter(&c->supporter); verify_supporters(); } static void run_init(struct compilation *c) { debug_malloc_touch(c); if (c->compat_handler) free_object(c->compat_handler); c->compat_handler=0; if (c->resolve_cache) { free_mapping(c->resolve_cache); c->resolve_cache = 0; } c->lex.current_line=1; free_string(c->lex.current_file); c->lex.current_file=make_shared_string("-"); c->lex.attributes = NULL; if (runtime_options & RUNTIME_STRICT_TYPES) { c->lex.pragmas = ID_STRICT_TYPES; } else { c->lex.pragmas = 0; } c->lex.end = c->prog->str + (c->prog->len << c->prog->size_shift); switch(c->prog->size_shift) { case 0: c->lex.current_lexer = yylex0; break; case 1: c->lex.current_lexer = yylex1; break; case 2: c->lex.current_lexer = yylex2; break; } c->lex.pos=c->prog->str; } static void run_init2(struct compilation *c) { #if 0 int i; struct program *p; struct reference *refs; #endif /* 0 */ debug_malloc_touch(c); Pike_compiler->compiler = c; /* Get the proper default module. */ safe_apply_current2(PC_GET_DEFAULT_MODULE_FUN_NUM, 0, NULL); if(TYPEOF(Pike_sp[-1]) == T_INT) { pop_stack(); ref_push_mapping(get_builtin_constants()); } assign_svalue(&c->default_module, Pike_sp-1); pop_stack(); use_module(& c->default_module); Pike_compiler->compat_major=PIKE_MAJOR_VERSION; Pike_compiler->compat_minor=PIKE_MINOR_VERSION; if(c->major>=0) change_compiler_compatibility(c->major, c->minor); #if 0 /* Make all inherited private symbols that weren't overloaded * in the first pass local. */ p = c->new_program; i = p->num_identifier_references; refs = p->identifier_references; while (i--) { if (refs[i].id_flags & ID_PRIVATE) refs[i].id_flags |= ID_INLINE; } #endif /* 0 */ } static void run_exit(struct compilation *c) { debug_malloc_touch(c); #ifdef PIKE_DEBUG if(c->num_used_modules) Pike_fatal("Failed to pop modules properly.\n"); #endif #ifdef PIKE_DEBUG if (c->compilation_depth != -1) { fprintf(stderr, "compile(): compilation_depth is %d\n", c->compilation_depth); } #endif /* PIKE_DEBUG */ if (c->resolve_cache) { free_mapping(c->resolve_cache); c->resolve_cache = NULL; } verify_supporters(); } static void zap_placeholder(struct compilation *c) { /* fprintf(stderr, "Destructing placeholder.\n"); */ if (c->placeholder->storage) { yyerror("Placeholder already has storage!"); #if 0 fprintf(stderr, "Placeholder already has storage!\n" "placeholder: %p, storage: %p, prog: %p\n", c->placeholder, c->placeholder->storage, c->placeholder->prog); #endif debug_malloc_touch(c->placeholder); destruct(c->placeholder); } else { /* FIXME: Is this correct? */ /* It would probably be nicer if it was possible to just call * destruct on the object, but this works too. -Hubbe */ free_program(c->placeholder->prog); c->placeholder->prog = NULL; debug_malloc_touch(c->placeholder); } free_object(c->placeholder); c->placeholder=0; verify_supporters(); } /* NOTE: Must not throw errors! */ static int run_pass1(struct compilation *c) { int ret=0; debug_malloc_touch(c); run_init(c); #if 0 CDFPRINTF("th(%ld) compile() starting compilation_depth=%d\n", (long)th_self(), c->compilation_depth); #endif if(c->placeholder && c->placeholder->prog != null_program) { yyerror("Placeholder object is not a null_program clone!"); return 0; } debug_malloc_touch(c->placeholder); if(c->target && !(c->target->flags & PROGRAM_VIRGIN)) { yyerror("Placeholder program is not virgin!"); return 0; }
d38e6a2017-12-14Henrik Grubbström (Grubba)  low_start_new_program(c->target, COMPILER_PASS_FIRST, 0, 0, 0);
dd40072017-02-02Henrik Grubbström (Grubba)  c->supporter.prog = Pike_compiler->new_program; CDFPRINTF("th(%ld) %p run_pass1() start: " "lock_depth:%d, compilation_depth:%d\n", (long)th_self(), Pike_compiler->new_program, lock_depth, c->compilation_depth); run_init2(c); if(c->placeholder) { if(c->placeholder->prog != null_program) { yyerror("Placeholder argument is not a null_program clone!"); c->placeholder=0; debug_malloc_touch(c->placeholder); }else{ free_program(c->placeholder->prog); add_ref(c->placeholder->prog=Pike_compiler->new_program); debug_malloc_touch(c->placeholder); } } #if 0 CDFPRINTF("th(%ld) %p compile(): First pass\n", (long)th_self(), Pike_compiler->new_program); #endif do_yyparse(); /* Parse da program */ if (!Pike_compiler->new_program->num_linenumbers) { /* The lexer didn't write an initial entry. */ store_linenumber(0, c->lex.current_file); #ifdef DEBUG_MALLOC if(strcmp(c->lex.current_file->str,"-")) debug_malloc_name(Pike_compiler->new_program, c->lex.current_file->str, 0); #endif } CDFPRINTF("th(%ld) %p run_pass1() done for %s\n", (long)th_self(), Pike_compiler->new_program, c->lex.current_file->str); ret=unlink_current_supporter(& c->supporter); c->p=debug_malloc_pass(end_first_pass(0)); run_exit(c); if(c->placeholder) { if(!c->p || (c->placeholder->storage)) { debug_malloc_touch(c->placeholder); zap_placeholder(c); } else { #ifdef PIKE_DEBUG if (c->placeholder->prog != c->p) Pike_fatal("Placeholder object got wrong program after first pass.\n"); #endif debug_malloc_touch(c->placeholder); c->placeholder->storage=c->p->storage_needed ? (char *)xcalloc(c->p->storage_needed, 1) : (char *)NULL; call_c_initializers(c->placeholder); } } verify_supporters(); return ret; }
99ca3e2017-12-17Henrik Grubbström (Grubba) void run_pass_extra(struct compilation *c) { debug_malloc_touch(c); debug_malloc_touch(c->placeholder); if (!c->p) { c->flags &= ~(COMPILER_BUSY); c->flags |= COMPILER_DONE; return; } run_init(c); low_start_new_program(c->p, COMPILER_PASS_EXTRA, 0, 0, 0); free_program(c->p); c->p=0; run_init2(c); CDFPRINTF("th(%ld) %p run_pass_extra() start: " "lock_depth:%d, compilation_depth:%d\n", (long)th_self(), Pike_compiler->new_program, lock_depth, c->compilation_depth); verify_supporters(); do_yyparse(); /* Parse da program */ CDFPRINTF("th(%ld) %p run_pass2() done for %s\n", (long)th_self(), Pike_compiler->new_program, c->lex.current_file->str); verify_supporters(); c->p=debug_malloc_pass(end_first_pass(0)); run_exit(c); }
dd40072017-02-02Henrik Grubbström (Grubba) void run_pass2(struct compilation *c) { debug_malloc_touch(c); debug_malloc_touch(c->placeholder); if (!c->p) { c->flags &= ~(COMPILER_BUSY); c->flags |= COMPILER_DONE; return; } run_init(c);
6fbcdd2017-12-12Henrik Grubbström (Grubba)  low_start_new_program(c->p, COMPILER_PASS_LAST, 0, 0, 0);
dd40072017-02-02Henrik Grubbström (Grubba)  free_program(c->p); c->p=0; run_init2(c); CDFPRINTF("th(%ld) %p run_pass2() start: " "lock_depth:%d, compilation_depth:%d\n", (long)th_self(), Pike_compiler->new_program, lock_depth, c->compilation_depth); verify_supporters(); do_yyparse(); /* Parse da program */ CDFPRINTF("th(%ld) %p run_pass2() done for %s\n", (long)th_self(), Pike_compiler->new_program, c->lex.current_file->str); verify_supporters(); c->p=debug_malloc_pass(end_program()); run_exit(c); } static void run_cleanup(struct compilation *c, int delayed) { debug_malloc_touch(c); debug_malloc_touch(c->placeholder); #if 0 /* FIXME */ #ifdef PIKE_THREADS if (lock_depth != c->saved_lock_depth) { Pike_fatal("compile(): lock_depth:%d saved_lock_depth:%d\n", lock_depth, c->saved_lock_depth); } #endif #endif /* PIKE_DEBUG */ unlock_pike_compiler(); CDFPRINTF("th(%ld) %p run_cleanup(): " "lock_depth:%d, compilation_depth:%d\n", (long)th_self(), c->target, lock_depth, c->compilation_depth); if (!c->p) { /* fprintf(stderr, "Destructing placeholder.\n"); */ if(c->placeholder) { debug_malloc_touch(c->placeholder); zap_placeholder(c); } if(delayed && c->target) { struct program *p = c->target; /* Free the constants in the failed program, to untangle the * cyclic references we might have to this program, typically * in parent pointers in nested classes. */ if (p->constants) { int i; for (i = 0; i < p->num_constants; i++) { free_svalue(&p->constants[i].sval); SET_SVAL(p->constants[i].sval, T_INT, NUMBER_NUMBER, integer, 0); } } /* We have to notify the master object that * a previous compile() actually failed, even * if we did not know it at the time */ CDFPRINTF("th(%ld) %p unregistering failed delayed compile.\n", (long) th_self(), p); ref_push_program(p); /* FIXME: Shouldn't the compilation handler be used here? */ SAFE_APPLY_MASTER("unregister",1); pop_stack(); { #ifdef PIKE_DEBUG int refs = p->refs; #endif /* Free the target here to avoid false alarms in the debug * check below. */ free_program (c->target); c->target = NULL; #ifdef PIKE_DEBUG if (refs > 1) { /* Other programs can have indexed out constants from p, which * might be broken themselves and/or keep references to p * through the parent pointer. We should find all those other * programs and invalidate them too, but how can that be done? * The whole delayed compilation thingie is icky icky icky... :P * /mast */ fprintf(stderr, "Warning: Program %p still got %d " "external refs after unregister:\n", p, p->refs); locate_references(p); fprintf (stderr, "Describing program:\n"); describe_something (p, T_PROGRAM, 0, 0, 0, NULL); } #endif } } } else { if (c->placeholder) { if (c->target->flags & PROGRAM_FINISHED) { JMP_BUF rec; /* Initialize the placeholder. */ #ifdef PIKE_DEBUG if (c->placeholder->prog != c->p) Pike_fatal("Placeholder object got wrong program after second pass.\n"); #endif if(SETJMP(rec)) { handle_compile_exception (NULL); debug_malloc_touch(c->placeholder); zap_placeholder(c); }else{ debug_malloc_touch(c->placeholder); call_pike_initializers(c->placeholder,0); } UNSETJMP(rec); } else { debug_malloc_touch(c->placeholder); zap_placeholder(c); } } } verify_supporters(); c->flags &= ~(COMPILER_BUSY); c->flags |= COMPILER_DONE; } static int call_delayed_pass2(struct compilation *cc, int finish) { int ok = 0; debug_malloc_touch(cc); debug_malloc_touch(cc->p); CDFPRINTF("th(%ld) %p %s delayed compile.\n", (long) th_self(), cc->p, finish ? "continuing" : "cleaning up"); /* Reenter the delayed compilation. */ add_ref(cc->supporter.self); low_enter_compiler(cc->supporter.self, cc->compilation_inherit);
4dab7a2017-12-19Henrik Grubbström (Grubba)  if (finish && cc->p) { if (cc->flags & COMPILER_NEED_EXTRA_PASS) { CDFPRINTF("Running delayed EXTRA PASS\n"); run_pass_extra(cc); } run_pass2(cc); }
dd40072017-02-02Henrik Grubbström (Grubba)  run_cleanup(cc,1); exit_compiler(); debug_malloc_touch(cc); #ifdef PIKE_DEBUG if(cc->supporter.dependants) Pike_fatal("Que???\n"); #endif if(cc->p) { ok = finish; free_program(cc->p); /* later */ cc->p = NULL; } CDFPRINTF("th(%ld) %p delayed compile %s.\n", (long) th_self(), cc->target, ok ? "done" : "failed"); verify_supporters(); return ok; } static void compilation_event_handler(int e) { struct compilation *c = THIS_COMPILATION; switch (e) { case PROG_EVENT_INIT: CDFPRINTF("th(%ld) compilation: INIT(%p).\n", (long) th_self(), c); memset(c, 0, sizeof(*c)); c->supporter.self = Pike_fp->current_object; /* NOTE: Not ref-counted! */ c->compilation_inherit = Pike_fp->context - Pike_fp->current_object->prog->inherits; buffer_init(&c->used_modules); SET_SVAL(c->default_module, T_MAPPING, 0, mapping, get_builtin_constants()); add_ref(c->default_module.u.mapping); c->major = -1; c->minor = -1; c->lex.current_line = 1; c->lex.current_file = make_shared_string("-"); c->compilation_depth = -1; break; case PROG_EVENT_EXIT: CDFPRINTF("th(%ld) compilation: EXIT(%p).\n", (long) th_self(), c); buffer_free(&c->used_modules); free_compilation(c); break; } } /*! @decl void report(SeverityLevel severity, @ *! string filename, int linenumber, @ *! string subsystem, @ *! string message, mixed ... extra_args) *! *! Report a diagnostic from the compiler. *! *! The default implementation attempts to call the first *! corresponding function in the active handlers in priority order: *! *! @ol *! @item *! Call handler->report(). *! @item *! Call handler->compile_warning() or handler->compile_error() *! depending on @[severity]. *! @item *! Call compat->report(). *! @item *! Call compat->compile_warning() or compat->compile_error() *! depending on @[severity]. *! @item *! Fallback: Call @[CompilerEnvironment()->report()] *! in the parent object. *! @endol *! *! The arguments will be as follows: *! @dl *! @item report() *! The report() function will be called with the same arguments *! as this function. *! @item compile_warning()/compile_error() *! Depending on the @[severity] either compile_warning() *! or compile_error() will be called. *! *! They will be called with the @[filename], @[linenumber] *! and formatted @[message] as arguments. *! *! Note that these will not be called for the @[NOTICE] severity, *! and that compile_error() will be used for both @[ERROR] and *! @[FATAL]. *! @enddl *! *! @note *! In Pike 7.8 and earlier the report() function was not called *! in the handlers. *! *! @seealso *! @[CompilerEnvironment()->report()] */ static void f_compilation_report(INT32 args) { struct compilation *c = THIS_COMPILATION; int level; struct pike_string *filename; INT_TYPE linenumber; struct pike_string *subsystem; struct pike_string *message; struct object *handler = NULL; int fun = -1; /* FIXME: get_all_args() ought to have a marker * indicating that we accept more arguments... */
c91b1d2018-08-05Martin Nilsson  get_all_args(NULL, args, "%d", &level);
dd40072017-02-02Henrik Grubbström (Grubba)  if ((c->handler || c->compat_handler)) { const char *fun_name = "compile_warning"; if (level >= REPORT_ERROR) fun_name = "compile_error"; if((handler = c->handler) && handler->prog) { if ((fun = find_identifier("report", handler->prog)) != -1) { apply_low(handler, fun, args); return; } if ((fun = find_identifier(fun_name, handler->prog)) != -1) { goto apply_handler; } } if ((handler = c->compat_handler) && handler->prog) { if ((fun = find_identifier("report", handler->prog)) != -1) { apply_low(handler, fun, args); return; } if ((fun = find_identifier(fun_name, handler->prog)) != -1) { goto apply_handler; } } } /* Nothing apropriate in any handlers. * Call the report() in our parent. */ apply_external(1, CE_REPORT_FUN_NUM, args); return; apply_handler: /* Ignore informational level messages */ if (level < REPORT_WARNING) return; if (args > 5) { f_sprintf(args - 4); args = 5; }
c91b1d2018-08-05Martin Nilsson  get_all_args(NULL, args, "%d%W%+%W%W",
dd40072017-02-02Henrik Grubbström (Grubba)  &level, &filename, &linenumber, &subsystem, &message); ref_push_string(filename); push_int(linenumber); ref_push_string(message); apply_low(handler, fun, 3); stack_pop_n_elems_keep_top(args); } /*! @decl void create(string|void source, @ *! CompilationHandler|void handler, @ *! int|void major, int|void minor,@ *! program|void target, object|void placeholder) *! *! Create a PikeCompiler object for a source string. *! *! This function takes a piece of Pike code as a string and *! initializes a compiler object accordingly. *! *! @param source *! Source code to compile. *! *! @param handler *! The optional argument @[handler] is used to specify an alternative *! error handler. If it is not specified the current master object *! at compile time will be used. *! *! @param major *! @param minor *! The optional arguments @[major] and @[minor] are used to tell the *! compiler to attempt to be compatible with Pike @[major].@[minor]. *! *! @param target *! @[__empty_program()] program to fill in. The virgin program *! returned by @[__empty_program()] will be modified and returned *! by @[compile()] on success. *! *! @param placeholder *! @[__null_program()] placeholder object to fill in. The object *! will be modified into an instance of the resulting program *! on successfull compile. Note that @[lfun::create()] in the *! program will be called without any arguments. *! *! @note *! Note that @[source] must contain the complete source for a program. *! It is not possible to compile a single expression or statement. *! *! Also note that no preprocessing is performed. *! To preprocess the program you can use @[compile_string()] or *! call the preprocessor manually by calling @[cpp()]. *! *! @note *! Note that all references to @[target] and @[placeholder] should *! removed if @[compile()] failes. On failure the @[placeholder] *! object will be destructed. *! *! @seealso *! @[compile_string()], @[compile_file()], @[cpp()], @[master()], *! @[CompilationHandler] */ static void f_compilation_create(INT32 args) { struct pike_string *aprog = NULL; struct object *ahandler = NULL;/* error handler */ int amajor = -1; int aminor = -1; struct program *atarget = NULL; struct object *aplaceholder = NULL; int dependants_ok = 1; struct compilation *c = THIS_COMPILATION; if (c->flags & COMPILER_BUSY) { Pike_error("PikeCompiler object is in use.\n"); } STACK_LEVEL_START(args);
c91b1d2018-08-05Martin Nilsson  get_all_args(NULL, args, ".%W%O%d%d%P%O",
dd40072017-02-02Henrik Grubbström (Grubba)  &aprog, &ahandler, &amajor, &aminor, &atarget, &aplaceholder); if (args == 3) { SIMPLE_ARG_TYPE_ERROR("create", 4, "int"); } check_c_stack(65536); CDFPRINTF("th(%ld) %p compilation create() enter, placeholder=%p\n", (long) th_self(), atarget, aplaceholder); debug_malloc_touch(c); verify_supporters(); c->flags &= ~COMPILER_DONE; if (c->p) free_program(c->p); c->p = NULL; if (c->prog) free_string(c->prog); if ((c->prog=aprog)) add_ref(aprog); if (c->handler) free_object(c->handler); if ((c->handler=ahandler)) add_ref(ahandler); if (c->target) free_program(c->target); if ((c->target=atarget)) add_ref(atarget); if (c->placeholder) free_object(c->placeholder); if ((c->placeholder=aplaceholder)) add_ref(aplaceholder); c->major = amajor?amajor:-1; c->minor = aminor?aminor:-1; STACK_LEVEL_DONE(args); pop_n_elems(args); push_int(0); } /*! @decl program compile() *! *! Compile the current source into a program. *! *! This function compiles the current Pike source code *! into a clonable program. *! *! @seealso *! @[compile_string()], @[compile_file()], @[cpp()], @[master()], *! @[CompilationHandler], @[create()] */ static void f_compilation_compile(INT32 args) { int delay, dependants_ok = 1; struct program *ret; #ifdef PIKE_DEBUG ONERROR tmp; #endif struct compilation *c = THIS_COMPILATION; if (c->flags & COMPILER_BUSY) { Pike_error("PikeCompiler in use.\n"); }
c91b1d2018-08-05Martin Nilsson  get_all_args(NULL, args, "");
dd40072017-02-02Henrik Grubbström (Grubba)  check_c_stack(65536); CDFPRINTF("th(%ld) %p f_compilation_compile() enter, " "placeholder=%p\n", (long) th_self(), c->target, c->placeholder); debug_malloc_touch(c); verify_supporters(); if (c->flags & COMPILER_DONE) { /* Already compiled. */ pop_n_elems(args); if (c->p) ref_push_program(c->p); else push_int(0); return; } if (!c->prog) { /* No program text. */
d38e6a2017-12-14Henrik Grubbström (Grubba)  low_start_new_program(c->target, COMPILER_PASS_FIRST, NULL, 0, NULL);
dd40072017-02-02Henrik Grubbström (Grubba)  c->p = end_program(); c->flags |= COMPILER_DONE; pop_n_elems(args); ref_push_program(c->p); return; } #ifdef PIKE_DEBUG SET_ONERROR(tmp, fatal_on_error,"Compiler exited with longjump!\n"); #endif c->flags |= COMPILER_BUSY; lock_pike_compiler(); #ifdef PIKE_THREADS c->saved_lock_depth = lock_depth; #endif init_supporter(& c->supporter, (supporter_callback *) call_delayed_pass2, (void *)c); delay=run_pass1(c); dependants_ok = call_dependants(& c->supporter, !!c->p ); #ifdef PIKE_DEBUG /* FIXME */ UNSET_ONERROR(tmp); #endif if(delay) { CDFPRINTF("th(%ld) %p f_compilation_compile() finish later, " "placeholder=%p.\n", (long) th_self(), c->target, c->placeholder); /* finish later */ verify_supporters(); /* We're hanging in the supporter. */ ret = debug_malloc_pass(c->p); }else{ CDFPRINTF("th(%ld) %p f_compilation_compile() finish now.\n", (long) th_self(), c->target);
4dab7a2017-12-19Henrik Grubbström (Grubba)  if (c->flags & COMPILER_NEED_EXTRA_PASS) { CDFPRINTF("Running EXTRA PASS\n"); run_pass_extra(c); }
dd40072017-02-02Henrik Grubbström (Grubba)  /* finish now */ run_pass2(c); debug_malloc_touch(c); run_cleanup(c,0); ret = debug_malloc_pass(c->p); debug_malloc_touch(c); if (!dependants_ok) { CDFPRINTF("th(%ld) %p f_compilation_compile() reporting failure " "since a dependant failed.\n", (long) th_self(), c->target);
ab53cf2018-02-24Martin Nilsson  throw_error_object(fast_clone_object(compilation_error_program), 0, 0,
dd40072017-02-02Henrik Grubbström (Grubba)  "Compilation failed.\n"); } if(!ret) { CDFPRINTF("th(%ld) %p f_compilation_compile() failed.\n", (long) th_self(), c->target);
ab53cf2018-02-24Martin Nilsson  throw_error_object(fast_clone_object(compilation_error_program), 0, 0,
dd40072017-02-02Henrik Grubbström (Grubba)  "Compilation failed.\n"); } debug_malloc_touch(ret); #ifdef PIKE_DEBUG if (a_flag > 2) { dump_program_tables(ret, 0); } #endif /* PIKE_DEBUG */ verify_supporters(); } pop_n_elems(args); if (ret) ref_push_program(ret); else push_int(0); }
2a2b5c2018-07-07Henrik Grubbström (Grubba) /*! @decl mixed resolv(string identifier)
dd40072017-02-02Henrik Grubbström (Grubba)  *! *! Resolve the symbol @[identifier]. *!
2a2b5c2018-07-07Henrik Grubbström (Grubba)  *! The default implementation calls @[CompilerEnvironment()->resolv()] *! in the parent object, with the remaining arguments taken from the *! current @[PikeCompiler] context. *! *! @returns *! Returns the value of @[sym] if found, and @[UNDEFINED] if not.
dd40072017-02-02Henrik Grubbström (Grubba)  */ static void f_compilation_resolv(INT32 args) {
2a2b5c2018-07-07Henrik Grubbström (Grubba)  struct pike_string *sym;
dd40072017-02-02Henrik Grubbström (Grubba)  struct compilation *c = THIS_COMPILATION; struct object *handler; int fun = -1;
c91b1d2018-08-05Martin Nilsson  get_all_args(NULL, args, "%W", &sym);
2a2b5c2018-07-07Henrik Grubbström (Grubba)  ref_push_string(sym); ref_push_string(c->lex.current_file); if (c->handler) { ref_push_object(c->handler); } else { push_undefined(); } if (c->compat_handler) { ref_push_object(c->compat_handler);
dd40072017-02-02Henrik Grubbström (Grubba)  } else {
2a2b5c2018-07-07Henrik Grubbström (Grubba)  push_undefined();
dd40072017-02-02Henrik Grubbström (Grubba)  }
2a2b5c2018-07-07Henrik Grubbström (Grubba)  apply_external(1, CE_RESOLV_FUN_NUM, 4);
dd40072017-02-02Henrik Grubbström (Grubba) } /*! @decl object get_compilation_handler(int major, int minor) *! *! Get compatibility handler for Pike @[major].@[minor]. *! *! @note *! This function is called by @[change_compiler_compatibility()]. */ static void f_compilation_get_compilation_handler(INT32 args) { struct compilation *c = THIS_COMPILATION; struct object *handler; int fun = -1; if (((handler = c->handler) && handler->prog && ((fun = find_identifier("get_compilation_handler", handler->prog)) != -1)) || ((handler = c->compat_handler) && handler->prog && ((fun = find_identifier("get_compilation_handler", handler->prog)) != -1))) { apply_low(handler, fun, args); } else { apply_external(1, CE_GET_COMPILATION_HANDLER_FUN_NUM, args); } } /*! @decl mapping(string:mixed)|object get_default_module() *! *! Get the default module for the current compatibility level *! (ie typically the value returned by @[predef::all_constants()]). *! *! The default implementation calls the corresponding function *! in the current handler, the current compatibility handler *! or in the parent @[CompilerEnvironment] in that order. *! *! @returns *! @mixed *! @type mapping(string:mixed)|object *! Constant table to use. *! *! @type int(0..0) *! Use the builtin constant table. *! @endmixed *! *! @note *! This function is called by @[change_compiler_compatibility()]. */ static void f_compilation_get_default_module(INT32 args) { struct compilation *c = THIS_COMPILATION; struct object *handler; int fun = -1; if (((handler = c->handler) && handler->prog && ((fun = find_identifier("get_default_module", handler->prog)) != -1)) || ((handler = c->compat_handler) && handler->prog && ((fun = find_identifier("get_default_module", handler->prog)) != -1))) { apply_low(handler, fun, args); } else { apply_external(1, CE_GET_DEFAULT_MODULE_FUN_NUM, args); } } /*! @decl void change_compiler_compatibility(int major, int minor) *! *! Change compiler to attempt to be compatible with Pike @[major].@[minor]. */ static void f_compilation_change_compiler_compatibility(INT32 args) { struct compilation *c = THIS_COMPILATION; int major = -1; int minor = -1; STACK_LEVEL_START(args);
c91b1d2018-08-05Martin Nilsson  get_all_args(NULL, args, "%d%d", &major, &minor);
dd40072017-02-02Henrik Grubbström (Grubba)  if ((major == -1) && (minor == -1)) { major = PIKE_MAJOR_VERSION; minor = PIKE_MINOR_VERSION; } if ((major == Pike_compiler->compat_major) && (minor == Pike_compiler->compat_minor)) { /* Optimization: Already at this compat level. */ pop_n_elems(args); push_int(0); return; } Pike_compiler->compat_major=major; Pike_compiler->compat_minor=minor; /* Optimization: The up to date compiler shouldn't need a compat handler. */ if((major != PIKE_MAJOR_VERSION) || (minor != PIKE_MINOR_VERSION)) { apply_current(PC_GET_COMPILATION_HANDLER_FUN_NUM, args); if((TYPEOF(Pike_sp[-1]) == T_OBJECT) && (Pike_sp[-1].u.object->prog)) { if (SUBTYPEOF(Pike_sp[-1])) { /* FIXME: */ Pike_error("Subtyped compat handlers are not supported yet.\n"); } if (c->compat_handler == Pike_sp[-1].u.object) { /* Still at the same compat level. */ pop_stack(); push_int(0); return; } else { if(c->compat_handler) free_object(c->compat_handler); c->compat_handler = Pike_sp[-1].u.object; dmalloc_touch_svalue(Pike_sp-1); Pike_sp--; } } else { pop_stack(); if(c->compat_handler) { free_object(c->compat_handler); c->compat_handler = NULL; } else { /* No change in compat handler. */ push_int(0); return; } } } else { pop_n_elems(args); if (c->compat_handler) { free_object(c->compat_handler); c->compat_handler = NULL; } else { /* No change in compat handler. */ push_int(0); return; } } STACK_LEVEL_CHECK(0); Pike_fp->args = 0; /* Clean up the stack frame. */ apply_current(PC_GET_DEFAULT_MODULE_FUN_NUM, 0); if(TYPEOF(Pike_sp[-1]) == T_INT) { pop_stack(); ref_push_mapping(get_builtin_constants()); } STACK_LEVEL_CHECK(1); assign_svalue(&c->default_module, Pike_sp-1); /* Replace the implicit import of all_constants() with * the new value. */ if(c->num_used_modules) { struct svalue *dst = buffer_ptr(&c->used_modules); free_svalue( dst ); dst[0] = Pike_sp[-1]; Pike_sp--; dmalloc_touch_svalue(Pike_sp); if(Pike_compiler->module_index_cache) { free_mapping(Pike_compiler->module_index_cache); Pike_compiler->module_index_cache=0; } }else{ use_module(Pike_sp-1); pop_stack(); } STACK_LEVEL_DONE(0); push_int(0); } /*! @decl program handle_inherit(string inh) *! *! Look up an inherit @[inh] in the current program. */ static void f_compilation_handle_inherit(INT32 args) { struct compilation *c = THIS_COMPILATION; struct object *handler; int fun = -1; if (args > 1) pop_n_elems(args-1); ref_push_string(c->lex.current_file); if (c->handler && c->handler->prog) { ref_push_object(c->handler); args = 3; } else args = 2; if (((handler = c->handler) && handler->prog && ((fun = find_identifier("handle_inherit", handler->prog)) != -1)) || ((handler = c->compat_handler) && handler->prog && ((fun = find_identifier("handle_inherit", handler->prog)) != -1))) { apply_low(handler, fun, args); } else { apply_external(1, CE_HANDLE_INHERIT_FUN_NUM, args); } }
b066222018-07-10Henrik Grubbström (Grubba) /*! @decl program handle_import(string module) *! *! Look up an import @[module]. */ static void f_compilation_handle_import(INT32 args) { struct compilation *c = THIS_COMPILATION; struct object *handler; int fun = -1; if (args > 1) pop_n_elems(args-1); ref_push_string(c->lex.current_file); if (c->handler && c->handler->prog) { ref_push_object(c->handler); args = 3; } else args = 2; if (((handler = c->handler) && handler->prog && ((fun = find_identifier("handle_import", handler->prog)) != -1)) || ((handler = c->compat_handler) && handler->prog && ((fun = find_identifier("handle_import", handler->prog)) != -1))) { apply_low(handler, fun, args); } else { apply_external(1, CE_HANDLE_IMPORT_FUN_NUM, args); } }
dd40072017-02-02Henrik Grubbström (Grubba) /*! @decl int(0..1) pop_type_attribute(string attribute, type a, type b) *! *! Type attribute handler. *! *! Called during type checking when @expr{a <= b@} and *! @[a] had the type attribute @[attribute] before the *! comparison. *! *! The default implementation implements the "deprecated" *! attribute. *! *! @returns *! Returns @expr{1@} if the type check should be allowed *! (ie @expr{__attribute__(attribute, a) <= b@}), and *! @expr{0@} (zero) otherwise. *! *! @seealso *! @[push_type_attribute()] */ static void f_compilation_pop_type_attribute(INT32 args) { struct pike_string *attr; struct svalue *a, *b; struct compilation *c = THIS_COMPILATION; struct pike_string *deprecated_string;
c91b1d2018-08-05Martin Nilsson  get_all_args(NULL, args, "%W%*%*", &attr, &a, &b);
dd40072017-02-02Henrik Grubbström (Grubba) 
bdfe4e2017-12-11Henrik Grubbström (Grubba)  if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST) {
dd40072017-02-02Henrik Grubbström (Grubba)  MAKE_CONST_STRING(deprecated_string, "deprecated"); if ((attr == deprecated_string) && !(c->lex.pragmas & ID_NO_DEPRECATION_WARNINGS)) { push_svalue(a); yytype_report(REPORT_WARNING, NULL, 0, NULL, NULL, 0, NULL, 1, "Using deprecated %O value."); } } pop_n_elems(args); push_int(1); } /*! @decl int(0..1) push_type_attribute(string attribute, type a, type b) *! *! Type attribute handler. *! *! Called during type checking when @expr{a <= b@} and *! @[b] had the type attribute @[attribute] before the *! comparison. *! *! The default implementation implements the "deprecated" *! attribute. *! *! @returns *! Returns @expr{1@} if the type check should be allowed *! (ie @expr{a <= __attribute__(attribute, b)@}), and *! @expr{0@} (zero) otherwise. *! *! @seealso *! @[pop_type_attribute()] */ static void f_compilation_push_type_attribute(INT32 args) { struct pike_string *attr; struct svalue *a, *b; struct compilation *c = THIS_COMPILATION; struct pike_string *deprecated_string;
c91b1d2018-08-05Martin Nilsson  get_all_args(NULL, args, "%W%*%*", &attr, &a, &b);
dd40072017-02-02Henrik Grubbström (Grubba) 
bdfe4e2017-12-11Henrik Grubbström (Grubba)  if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST) {
dd40072017-02-02Henrik Grubbström (Grubba)  MAKE_CONST_STRING(deprecated_string, "deprecated"); if ((attr == deprecated_string) && !(c->lex.pragmas & ID_NO_DEPRECATION_WARNINGS) && !((TYPEOF(*a) == PIKE_T_TYPE) && (a->u.type == zero_type_string))) { /* Don't warn about setting deprecated values to zero. */ push_svalue(b); yytype_report(REPORT_WARNING, NULL, 0, NULL, NULL, 0, NULL, 1, "Using deprecated %O value."); } } pop_n_elems(args); push_int(1); } /*! @decl int(0..1) apply_type_attribute(string attribute, @ *! type a, type|void b) *! *! Type attribute handler. *! *! @param attribute *! Attribute that @[a] had. *! *! @param a *! Type of the value being called. *! *! @param b *! Type of the first argument in the call, or *! @[UNDEFINED] if no more arguments. *! *! Called during type checking when @[a] has been successfully *! had a partial evaluation with the argument @[b] and *! @[a] had the type attribute @[attribute] before the *! evaluation. *! *! The default implementation implements the "deprecated" *! attribute. *! *! @returns *! Returns @expr{1@} if the type check should be allowed *! (ie @expr{__attribute__(attribute, a)(b)@}) is valid, *! and @expr{0@} (zero) otherwise. *! *! @seealso *! @[pop_type_attribute()], @[push_type_attribute()] */ static void f_compilation_apply_type_attribute(INT32 args) { struct pike_string *attr; struct svalue *a, *b = NULL; struct compilation *c = THIS_COMPILATION; struct pike_string *deprecated_string;
c91b1d2018-08-05Martin Nilsson  get_all_args(NULL, args, "%W%*.%*", &attr, &a, &b);
dd40072017-02-02Henrik Grubbström (Grubba) 
bdfe4e2017-12-11Henrik Grubbström (Grubba)  if (Pike_compiler->compiler_pass == COMPILER_PASS_LAST) {
dd40072017-02-02Henrik Grubbström (Grubba)  MAKE_CONST_STRING(deprecated_string, "deprecated"); if ((attr == deprecated_string) && !(c->lex.pragmas & ID_NO_DEPRECATION_WARNINGS) && (!b || ((TYPEOF(*b) == T_INT) && (SUBTYPEOF(*b) == NUMBER_UNDEFINED) && (!b->u.integer)))) { /* push_svalue(a); */ yytype_report(REPORT_WARNING, NULL, 0, NULL, NULL, 0, NULL, 0, "Calling a deprecated value."); } } pop_n_elems(args); push_int(1); } /*! @decl type(mixed) apply_attribute_constant(string attr, @ *! mixed value, @ *! type arg_type, @ *! void cont_type) *! *! Handle constant arguments to attributed function argument types. *! *! @param attr *! Attribute that @[arg_type] had. *! *! @param value *! Constant value sent as parameter. *! *! @param arg_type *! Declared type of the function argument. *! *! @param cont_type *! Continuation function type after the current argument. *! *! This function is called when a function is called *! with the constant value @[value] and it has been *! successfully matched against @[arg_type], *! and @[arg_type] had the type attribute @[attr]. *! *! This function is typically used to perform specialized *! argument checking and to allow for a strengthening *! of the function type based on @[value]. *! *! The default implementation implements the @expr{"sprintf_format"@}, *! @expr{"sscanf_format"@} and @expr{"sscanf_76_format"@} attributes. *! *! @returns *! Returns a continuation type if it succeeded in strengthening the type. *! *! Returns @tt{UNDEFINED@} otherwise (this is not an error indication). *! *! @seealso *! @[pop_type_attribute()], @[push_type_attribute()] */ static void f_compilation_apply_attribute_constant(INT32 args) { struct compilation *c = THIS_COMPILATION; struct pike_string *attribute; struct pike_string *test; struct svalue *sval;
c91b1d2018-08-05Martin Nilsson  get_all_args(NULL, args, "%S%*", &attribute, &sval);
dd40072017-02-02Henrik Grubbström (Grubba)  if ((TYPEOF(*sval) == T_INT) && !sval->u.integer) { pop_n_elems(args); push_undefined(); return; } MAKE_CONST_STRING(test, "sprintf_format"); if (attribute == test) { f___handle_sprintf_format(args); return; } MAKE_CONST_STRING(test, "strict_sprintf_format"); if (attribute == test) { f___handle_sprintf_format(args); return; } MAKE_CONST_STRING(test, "sscanf_format"); if (attribute == test) { f___handle_sscanf_format(args); return; } MAKE_CONST_STRING(test, "sscanf_76_format"); if (attribute == test) { f___handle_sscanf_format(args); return; } pop_n_elems(args); push_undefined(); } static void f_compilation__sprintf(INT32 args) { struct compilation *c = THIS_COMPILATION; struct string_builder buf; init_string_builder_alloc(&buf, 50, 0); string_builder_strcat(&buf, "PikeCompiler("); if (c->prog) { string_builder_strcat(&buf, "\"\", "); } else { string_builder_strcat(&buf, "UNDEFINED, "); } if (c->handler) { ref_push_object(c->handler); string_builder_sprintf(&buf, "%O, ", Pike_sp-1); pop_stack(); } else { string_builder_strcat(&buf, "UNDEFINED, "); } string_builder_sprintf(&buf, "%d, %d, %s, %s)", c->major, c->minor, c->target?"target":"UNDEFINED", c->placeholder?"placeholder":"UNDEFINED"); pop_n_elems(args); push_string(finish_string_builder(&buf)); } /** * Fake being called via PikeCompiler()->compile() * * This function is used to set up the environment for * compiling C efuns and modules. * * Note: Since this is a stack frame, it will be cleaned up * automatically on error, so no need to use ONERROR(). * * Note: Steals a reference from ce. */ static void low_enter_compiler(struct object *ce, int inherit) { struct pike_frame *new_frame = alloc_pike_frame(); #ifdef PROFILING new_frame->children_base = Pike_interpreter.accounted_time; new_frame->start_time = get_cpu_time() - Pike_interpreter.unlocked_time; new_frame->ident = PC_COMPILE_FUN_NUM; /* Fake call of compile(). */ #endif /* PROFILING */ new_frame->next = Pike_fp; new_frame->current_object = ce; /* Note: The compilation environment object hangs on this frame, * so that it will be freed when the frame dies. */ new_frame->current_program = ce->prog; add_ref(new_frame->current_program);
ad82802018-07-16Henrik Grubbström (Grubba)  new_frame->context = ce->prog->inherits + inherit;
dd40072017-02-02Henrik Grubbström (Grubba)  new_frame->current_storage = ce->storage + new_frame->context->storage_offset; #ifdef PIKE_DEBUG if (new_frame->context->prog != compilation_program) { Pike_fatal("Invalid inherit for compilation context (%p != %p).\n", new_frame->context->prog, compilation_program); } #endif /* PIKE_DEBUG */ new_frame->fun = new_frame->context->identifier_level + PC_COMPILE_FUN_NUM; new_frame->locals = Pike_sp; new_frame->save_sp_offset = 0; new_frame->save_mark_sp = Pike_mark_sp; new_frame->args = 0; new_frame->num_args = 0; new_frame->num_locals = 0; new_frame->pc = 0; new_frame->return_addr = 0; new_frame->scope = 0; Pike_fp = new_frame; } PMOD_EXPORT void enter_compiler(struct pike_string *filename, INT_TYPE linenumber) { struct object *ce = parent_clone_object(compilation_program, compilation_environment, CE_PIKE_COMPILER_FUN_NUM, 0); struct compilation *c; low_enter_compiler(ce, 0); c = THIS_COMPILATION; if (filename) { free_string(c->lex.current_file); copy_shared_string(c->lex.current_file, filename); } if (linenumber) { c->lex.current_line = linenumber; } } /** * Reverse the effect of enter_compiler(). */ PMOD_EXPORT void exit_compiler(void) { #ifdef PIKE_DEBUG
ad82802018-07-16Henrik Grubbström (Grubba)  if ((Pike_fp->context->prog != compilation_program) || (Pike_fp->fun != Pike_fp->context->identifier_level + PC_COMPILE_FUN_NUM)) {
dd40072017-02-02Henrik Grubbström (Grubba)  Pike_fatal("exit_compiler(): Frame stack out of whack!\n"); } #endif /* PIKE_DEBUG */ POP_PIKE_FRAME(); }
f36a622017-02-09Henrik Grubbström (Grubba) /** * Main entry point for compiler messages originating from C-code. * * Sends the message along to PikeCompiler()->report(). * * NOTE: The format string fmt (and vargs) is only formatted with * string_builder_vsprintf() if the number of extra * Pike stack arguments (args) is zero. * * NOTE: This function may be called from functions that sometimes * execute outside of the compilation context, eg by * __handle_sprintf_format(), which can be called directly * by Pike-code, in which case it is a NO-OP. */ PMOD_EXPORT void va_yyreport(int severity_level, struct pike_string *file, INT_TYPE line, struct pike_string *system, INT32 args, const char *fmt, va_list vargs) { struct compilation *c = MAYBE_THIS_COMPILATION; struct string_builder s; if (!c) { /* No compiler context. */ pop_n_elems(args); return; } STACK_LEVEL_START(args); #ifdef PIKE_DEBUG if(Pike_interpreter.recoveries && Pike_sp-Pike_interpreter.evaluator_stack < Pike_interpreter.recoveries->stack_pointer) Pike_fatal("Stack error (underflow)\n"); #endif /* Convert type errors to warnings in non-strict compat mode. */ if ((system == type_check_system_string) && (severity_level == REPORT_ERROR) && (Pike_compiler->compat_major != -1) && !(c->lex.pragmas & ID_STRICT_TYPES) && ((Pike_compiler->compat_major < PIKE_MAJOR_VERSION) || ((Pike_compiler->compat_major == PIKE_MAJOR_VERSION) && (Pike_compiler->compat_minor < PIKE_MINOR_VERSION)))) { severity_level = REPORT_WARNING; } /* If we have parse errors we might get erroneous warnings, * so don't print them. * This has the additional benefit of making it easier to * visually locate the actual error message. */ if ((severity_level <= REPORT_WARNING) && Pike_compiler->num_parse_error) { pop_n_elems(args); return; } if (severity_level >= REPORT_ERROR) { if (Pike_compiler->num_parse_error > 20) { pop_n_elems(args); return; } Pike_compiler->num_parse_error++; cumulative_parse_error++; } push_int(severity_level); ref_push_string(file?file:c->lex.current_file); push_int(line?line:c->lex.current_line); ref_push_string(system); if (args) { int i = args; push_text(fmt); /* Copy the arguments. */ while (i--) { push_svalue(Pike_sp-(args+5)); } } else { init_string_builder(&s, 0); string_builder_vsprintf(&s, fmt, vargs); push_string(finish_string_builder(&s)); } safe_apply_current(PC_REPORT_FUN_NUM, args + 5); pop_stack(); if (args) pop_n_elems(args); STACK_LEVEL_DONE(0); } PMOD_EXPORT void low_yyreport(int severity_level, struct pike_string *file, INT_TYPE line, struct pike_string *system, INT32 args, const char *fmt, ...) { va_list vargs; va_start(vargs,fmt); va_yyreport(severity_level, file, line, system, args, fmt, vargs); va_end(vargs); } PMOD_EXPORT void yyreport(int severity_level, struct pike_string *system, INT32 args, const char *fmt, ...) { va_list vargs; va_start(vargs,fmt); va_yyreport(severity_level, NULL, 0, system, args, fmt, vargs); va_end(vargs); } PMOD_EXPORT void yywarning(char *fmt, ...) { va_list vargs; va_start(vargs,fmt); va_yyreport(REPORT_WARNING, NULL, 0, parser_system_string, 0, fmt, vargs); va_end(vargs); } PMOD_EXPORT void my_yyerror(const char *fmt,...) { va_list vargs; va_start(vargs,fmt); va_yyreport(REPORT_ERROR, NULL, 0, parser_system_string, 0, fmt, vargs); va_end(vargs); } PMOD_EXPORT void yyerror(const char *str) { my_yyerror("%s", str); } /** * Main entry point for errors from the type-checking subsystems. * * The message (if any) will be formatted for the same source * position as the got_t. * * The expect_t will be formatted for the same position as the got_t * if there's no expected_file/expected_line. * * The got_t will be formatted for the current lex position if there's * no got_file/got_line. */ void yytype_report(int severity_level, struct pike_string *expected_file, INT_TYPE expected_line, struct pike_type *expected_t, struct pike_string *got_file, INT_TYPE got_line, struct pike_type *got_t, INT32 args, const char *fmt, ...) { if (fmt) { va_list vargs; va_start(vargs, fmt); va_yyreport(severity_level, got_file, got_line, type_check_system_string, args, fmt, vargs); va_end(vargs); } if (expected_t && got_t) { yyexplain_nonmatching_types(severity_level, expected_file?expected_file:got_file, expected_line?expected_line:got_line, expected_t, got_file, got_line, got_t); } else if (expected_t) { ref_push_type_value(expected_t); low_yyreport(severity_level, expected_file?expected_file:got_file, expected_line?expected_line:got_line, type_check_system_string, 1, "Expected: %O."); } else if (got_t) { ref_push_type_value(got_t); low_yyreport(severity_level, got_file, got_line, type_check_system_string, 1, "Got : %O."); } } void yytype_error(const char *msg, struct pike_type *expected_t, struct pike_type *got_t, unsigned int flags) { yytype_report((flags & YYTE_IS_WARNING)?REPORT_WARNING:REPORT_ERROR, NULL, 0, expected_t, NULL, 0, got_t, 0, "%s", msg); } struct pike_string *format_exception_for_error_msg (struct svalue *thrown) { struct pike_string *s = NULL; push_svalue (thrown); SAFE_APPLY_MASTER ("describe_error", 1); if (TYPEOF(Pike_sp[-1]) == T_STRING) { f_string_trim(1); push_constant_text("\n"); push_constant_text(" "); f_replace(3); return (--Pike_sp)->u.string; } else { pop_stack(); return NULL; } } void handle_compile_exception (const char *yyerror_fmt, ...) { struct svalue thrown; struct compilation *c = THIS_COMPILATION; CHECK_COMPILER(); move_svalue (&thrown, &throw_value); mark_free_svalue (&throw_value); if (yyerror_fmt) { va_list args; va_start (args, yyerror_fmt); va_yyreport(REPORT_ERROR, NULL, 0, parser_system_string, 0, yyerror_fmt, args); va_end (args); } push_svalue(&thrown); /* safe_apply_current(PC_FILTER_EXCEPTION_FUN_NUM, 1); */ low_safe_apply_handler("compile_exception", c->handler, c->compat_handler, 1); if (SAFE_IS_ZERO(Pike_sp-1)) { struct pike_string *s = format_exception_for_error_msg (&thrown); if (s) { push_string(s); yyreport(REPORT_ERROR, parser_system_string, 1, "%s"); } } pop_stack(); free_svalue(&thrown); }
dd40072017-02-02Henrik Grubbström (Grubba) /*! @class CompilerState *! *! Keeps the state of a single program/class during compilation. *! *! @note *! Not in use yet! */ #define THIS_PROGRAM_STATE ((struct program_state *)(Pike_fp->current_storage)) static void program_state_event_handler(int UNUSED(event)) { #if 0 struct program_state *c = THIS_PROGRAM_STATE; switch (event) { case PROG_EVENT_INIT: #define INIT #include "compilation.h" break; case PROG_EVENT_EXIT: #define EXIT #include "compilation.h" break; } #endif /* 0 */ } /*! @endclass */ /*! @endclass */ /*! @endclass */ /** * Strap the compiler by creating the compilation program by hand. */ static void compile_compiler(void) { struct program *p = low_allocate_program(); struct program *p2 = compilation_program = low_allocate_program(); struct object *co; struct inherit *inh;
f5a16a2018-11-08Henrik Grubbström (Grubba)  p->id = PROG_COMPILERENVIRONMENT_ID;
dd40072017-02-02Henrik Grubbström (Grubba)  p->parent_info_storage = -1; /* p->event_handler = compilation_env_event_handler; */ p->flags |= PROGRAM_HAS_C_METHODS; #if 0 /* ADD_STORAGE(struct compilation_env); */ p->alignment_needed = ALIGNOF(struct compilation_env); p->storage_needed = p->xstorage + sizeof(struct compilation_env); #endif /* 0 */ /* Add the initial inherit, this is needed for clone_object() * to actually call the event handler, and for low_enter_compiler() * to find the storage and context. */
2d21052018-01-19Martin Nilsson  p->inherits = inh = ALLOC_STRUCT(inherit);
dd40072017-02-02Henrik Grubbström (Grubba)  inh->prog = p; inh->inherit_level = 0; inh->identifier_level = 0; inh->parent_identifier = -1; inh->parent_offset = OBJECT_PARENT; inh->identifier_ref_offset = 0; inh->storage_offset = p->xstorage; inh->parent = NULL; inh->name = NULL; p->num_inherits = 1; /* Force clone_object() to accept the program... */ p->flags |= PROGRAM_PASS_1_DONE; compilation_environment = clone_object(p, 0); p->flags &= ~PROGRAM_PASS_1_DONE; /* Once more, this time for p2... */
f5a16a2018-11-08Henrik Grubbström (Grubba)  p2->id = PROG_COMPILERENVIRONMENT_PIKECOMPILER_ID;
dd40072017-02-02Henrik Grubbström (Grubba)  p2->parent_info_storage = 0; p2->xstorage = sizeof(struct parent_info); p2->event_handler = compilation_event_handler; p2->flags |= PROGRAM_NEEDS_PARENT|PROGRAM_USES_PARENT|PROGRAM_HAS_C_METHODS; /* ADD_STORAGE(struct compilation); */ p2->alignment_needed = ALIGNOF(struct compilation); p2->storage_needed = p2->xstorage + sizeof(struct compilation);
2d21052018-01-19Martin Nilsson  p2->inherits = inh = ALLOC_STRUCT(inherit);
dd40072017-02-02Henrik Grubbström (Grubba)  inh->prog = p2; inh->inherit_level = 0; inh->identifier_level = 0; inh->parent_identifier = CE_PIKE_COMPILER_FUN_NUM; inh->parent_offset = OBJECT_PARENT; inh->identifier_ref_offset = 0; inh->storage_offset = p2->xstorage; inh->parent = NULL; inh->name = NULL; p2->num_inherits = 1; p2->flags |= PROGRAM_PASS_1_DONE; co = parent_clone_object(p2, compilation_environment, CE_PIKE_COMPILER_FUN_NUM, 0); p2->flags &= ~PROGRAM_PASS_1_DONE; low_enter_compiler(co, 0);
d38e6a2017-12-14Henrik Grubbström (Grubba)  low_start_new_program(p, COMPILER_PASS_FIRST, NULL, 0, NULL);
dd40072017-02-02Henrik Grubbström (Grubba)  free_program(p); /* Remove the extra ref we just got... */ /* NOTE: The order of these identifiers is hard-coded in * the CE_*_FUN_NUM definitions in "pike_compiler.h". */ /* NB: Overloaded properly by inherit of Reporter later on. */ ADD_FUNCTION("report", f_reporter_report, tFuncV(tName("SeverityLevel", tInt03) tStr tIntPos tStr tStr, tMix, tVoid),0); ADD_FUNCTION("compile", f_compilation_env_compile, tFunc(tOr(tStr, tVoid) tOr(tObj, tVoid) tOr(tInt, tVoid) tOr(tInt, tVoid) tOr(tPrg(tObj), tVoid) tOr(tObj, tVoid), tPrg(tObj)), 0); ADD_FUNCTION("resolv", f_compilation_env_resolv, tFunc(tStr tStr tObj, tMix), 0);
d38e6a2017-12-14Henrik Grubbström (Grubba)  low_start_new_program(p2, COMPILER_PASS_FIRST, NULL, 0, NULL);
dd40072017-02-02Henrik Grubbström (Grubba)  /* low_start_new_program() has zapped the inherit we created * for p2 above, so we need to repair the frame pointer. */ Pike_fp->context = p2->inherits; /* MAGIC! We're now executing inside the object being compiled, * and have done sufficient stuff to be able to call and use * the normal program building functions. */ /* NOTE: The order of these identifiers is hard-coded in * the PC_*_FUN_NUM definitions in "pike_compiler.h". */ ADD_FUNCTION("report", f_compilation_report, tFuncV(tName("SeverityLevel", tInt03) tStr tIntPos tStr tStr, tMix, tVoid),0); ADD_FUNCTION("compile", f_compilation_compile, tFunc(tNone, tPrg(tObj)), 0); ADD_FUNCTION("resolv", f_compilation_resolv, tFunc(tStr tStr tObj, tMix), 0); ADD_FUNCTION("create", f_compilation_create, tFunc(tOr(tStr, tVoid) tOr(tObj, tVoid) tOr(tInt, tVoid) tOr(tInt, tVoid) tOr(tPrg(tObj), tVoid) tOr(tObj, tVoid), tVoid), ID_PROTECTED); ADD_FUNCTION("get_compilation_handler", f_compilation_get_compilation_handler, tFunc(tInt tInt, tObj), 0); ADD_FUNCTION("get_default_module", f_compilation_get_default_module, tFunc(tNone, tOr(tMap(tStr, tMix), tObj)), 0); ADD_FUNCTION("change_compiler_compatibility", f_compilation_change_compiler_compatibility, tFunc(tInt tInt, tVoid), 0); ADD_FUNCTION("handle_inherit", f_compilation_handle_inherit, tFunc(tStr, tPrg(tObj)), 0);
b066222018-07-10Henrik Grubbström (Grubba)  ADD_FUNCTION("handle_import", f_compilation_handle_import, tFunc(tStr, tPrg(tObj)), 0);
dd40072017-02-02Henrik Grubbström (Grubba)  ADD_FUNCTION("pop_type_attribute", f_compilation_pop_type_attribute, tFunc(tStr tType(tMix) tType(tMix), tInt01), 0); ADD_FUNCTION("push_type_attribute", f_compilation_push_type_attribute, tFunc(tStr tType(tMix) tType(tMix), tInt01), 0); ADD_FUNCTION("apply_type_attribute", f_compilation_apply_type_attribute, tFunc(tStr tType(tMix) tOr(tType(tMix), tVoid), tInt01), 0); ADD_FUNCTION("apply_attribute_constant", f_compilation_apply_attribute_constant, tFunc(tStr tMix tType(tMix) tType(tFunction), tType(tFunction)), 0); ADD_FUNCTION("_sprintf", f_compilation__sprintf, tFunc(tInt tOr(tMap(tStr, tMix), tVoid), tStr), ID_PROTECTED); start_new_program();
f5a16a2018-11-08Henrik Grubbström (Grubba)  Pike_compiler->new_program->id = PROG_COMPILERENVIRONMENT_PIKECOMPILER_COMPILERSTATE_ID;
dd40072017-02-02Henrik Grubbström (Grubba)  ADD_STORAGE(struct program_state); Pike_compiler->new_program->event_handler = program_state_event_handler; Pike_compiler->new_program->flags |= PROGRAM_NEEDS_PARENT|PROGRAM_USES_PARENT|PROGRAM_HAS_C_METHODS; /* Alias for report above. */ low_define_alias(NULL, NULL, 0, 1, PC_REPORT_FUN_NUM); end_class("CompilerState", 0); /* Map some of our variables so that the gc can find them. */ PIKE_MAP_VARIABLE("prog", OFFSETOF(compilation, prog), tStr, PIKE_T_STRING, ID_HIDDEN); PIKE_MAP_VARIABLE("handler", OFFSETOF(compilation, handler), tObj, PIKE_T_OBJECT, 0); PIKE_MAP_VARIABLE("compat_handler", OFFSETOF(compilation, compat_handler), tObj, PIKE_T_OBJECT, 0); PIKE_MAP_VARIABLE("target", OFFSETOF(compilation, target), tPrg(tObj), PIKE_T_PROGRAM, ID_HIDDEN); PIKE_MAP_VARIABLE("placeholder", OFFSETOF(compilation, placeholder), tObj, PIKE_T_OBJECT, ID_HIDDEN); PIKE_MAP_VARIABLE("p", OFFSETOF(compilation, p), tPrg(tObj), PIKE_T_PROGRAM, ID_HIDDEN); PIKE_MAP_VARIABLE("current_file", OFFSETOF(compilation, lex.current_file),
335bf22018-07-17Henrik Grubbström (Grubba)  tStr, PIKE_T_STRING, ID_PROTECTED);
dd40072017-02-02Henrik Grubbström (Grubba)  PIKE_MAP_VARIABLE("default_module", OFFSETOF(compilation, default_module), tOr(tMap(tStr,tMix),tObj), PIKE_T_MIXED, 0); /* end_class()/end_program() adds the parent_info storage once more. * Remove the one we added above, so that we don't get it double. */ p2->xstorage = 0; end_class("PikeCompiler", 0); /* end_class()/end_program() has zapped the inherit once again, * so we need to repair the frame pointer. */ Pike_fp->context = compilation_program->inherits; ADD_FUNCTION("get_compilation_handler", f_compilation_env_get_compilation_handler, tFunc(tInt tInt, tObj), 0); ADD_FUNCTION("get_default_module", f_compilation_env_get_default_module, tFunc(tNone, tOr(tMap(tStr, tMix), tObj)), 0); ADD_FUNCTION("handle_inherit", f_compilation_env_handle_inherit, tFunc(tStr tStr tOr(tObj, tVoid), tPrg(tObj)), 0);
b066222018-07-10Henrik Grubbström (Grubba)  ADD_FUNCTION("handle_import", f_compilation_env_handle_import, tFunc(tStr tStr tOr(tObj, tVoid), tPrg(tObj)), 0);
dd40072017-02-02Henrik Grubbström (Grubba)  /* Reporter */ start_new_program(); { struct svalue type_value;
f5a16a2018-11-08Henrik Grubbström (Grubba)  Pike_compiler->new_program->id = PROG_COMPILERENVIRONMENT_REPORTER_ID;
dd40072017-02-02Henrik Grubbström (Grubba)  ADD_FUNCTION("report", f_reporter_report, tFuncV(tName("SeverityLevel", tInt03) tStr tIntPos tStr tStr, tMix, tVoid),0); /* enum SeverityLevel { NOTICE, WARNING, ERROR, FATAL } */ SET_SVAL(type_value, PIKE_T_TYPE, 0, type, CONSTTYPE(tName("SeverityLevel", tInt03))); simple_add_constant("SeverityLevel", &type_value, 0); free_svalue(&type_value); add_integer_constant("NOTICE", REPORT_NOTICE, 0); add_integer_constant("WARNING", REPORT_WARNING, 0); add_integer_constant("ERROR", REPORT_ERROR, 0); add_integer_constant("FATAL", REPORT_FATAL, 0); reporter_program = end_program(); } add_global_program("Reporter", reporter_program); low_inherit(reporter_program, NULL, -1, 0, 0, 0); start_new_program();
f5a16a2018-11-08Henrik Grubbström (Grubba)  Pike_compiler->new_program->id = PROG_COMPILERENVIRONMENT_LOCK_ID;
dd40072017-02-02Henrik Grubbström (Grubba)  Pike_compiler->new_program->event_handler = compiler_environment_lock_event_handler; Pike_compiler->new_program->flags |= PROGRAM_DESTRUCT_IMMEDIATE; end_class("lock", 0);
2f77c92018-07-04Henrik Grubbström (Grubba)  init_cpp_compilerenv_classes();
dd40072017-02-02Henrik Grubbström (Grubba)  compilation_env_program = end_program(); add_global_program("CompilerEnvironment", compilation_env_program); exit_compiler(); ref_push_object(compilation_environment); low_add_constant("DefaultCompilerEnvironment", Pike_sp-1); pop_stack(); }
2f07ac2017-02-04Henrik Grubbström (Grubba) void push_compiler_frame(int lexical_scope) { struct compiler_frame *f; f=ALLOC_STRUCT(compiler_frame); f->previous=Pike_compiler->compiler_frame; f->lexical_scope=lexical_scope; f->current_type=0; f->current_return_type=0; f->current_number_of_locals=0; f->max_number_of_locals=0; f->min_number_of_locals=0; f->last_block_level=-1; f->current_function_number=-2; /* no function */ f->recur_label=-1; f->is_inline=0; f->num_args=-1; f->opt_flags = OPT_SIDE_EFFECT|OPT_EXTERNAL_DEPEND; /* FIXME: Should be 0. */ Pike_compiler->compiler_frame=f; } node *low_pop_local_variables(int level, node *block) { struct compilation *c = THIS_COMPILATION; while(Pike_compiler->compiler_frame->current_number_of_locals > level) { int e; e=--(Pike_compiler->compiler_frame->current_number_of_locals); if (block) { block = mknode(F_COMMA_EXPR, block, mknode(F_POP_VALUE, mknode(F_ASSIGN,
a1af302017-03-18Henrik Grubbström (Grubba)  mklocalnode(e, 0), mkintnode(0)),
2f07ac2017-02-04Henrik Grubbström (Grubba)  NULL)); }
bdfe4e2017-12-11Henrik Grubbström (Grubba)  if ((Pike_compiler->compiler_pass == COMPILER_PASS_LAST) &&
2f07ac2017-02-04Henrik Grubbström (Grubba)  !(Pike_compiler->compiler_frame->variable[e].flags & LOCAL_VAR_IS_USED)) { ref_push_string(Pike_compiler->compiler_frame->variable[e].name); low_yyreport(REPORT_WARNING, Pike_compiler->compiler_frame->variable[e].file, Pike_compiler->compiler_frame->variable[e].line, parser_system_string, 1, "Unused local variable %s."); } free_string(Pike_compiler->compiler_frame->variable[e].name); free_type(Pike_compiler->compiler_frame->variable[e].type); if(Pike_compiler->compiler_frame->variable[e].def) free_node(Pike_compiler->compiler_frame->variable[e].def); free_string(Pike_compiler->compiler_frame->variable[e].file); } return block; } node *pop_local_variables(int level, node *block) { #if 1 struct compilation *c = THIS_COMPILATION; /* We need to save the variables Kuppo (but not their names) */ if(level < Pike_compiler->compiler_frame->min_number_of_locals) { /* FIXME: Consider using flags to indicate whether a local variable * actually is used from a nested scope. */ for(;level<Pike_compiler->compiler_frame->min_number_of_locals;level++) {
bdfe4e2017-12-11Henrik Grubbström (Grubba)  if ((Pike_compiler->compiler_pass == COMPILER_PASS_LAST) &&
2f07ac2017-02-04Henrik Grubbström (Grubba)  !(Pike_compiler->compiler_frame->variable[level].flags & LOCAL_VAR_IS_USED)) { ref_push_string(Pike_compiler->compiler_frame->variable[level].name); low_yyreport(REPORT_WARNING, Pike_compiler->compiler_frame->variable[level].file, Pike_compiler->compiler_frame->variable[level].line, parser_system_string, 1, "Unused local variable %s."); /* Make sure we only warn once... */ Pike_compiler->compiler_frame->variable[level].flags |= LOCAL_VAR_IS_USED; } free_string(Pike_compiler->compiler_frame->variable[level].name); copy_shared_string(Pike_compiler->compiler_frame->variable[level].name, empty_pike_string); /* FIXME: Do we need to keep the filenames? */ } } #endif return low_pop_local_variables(level, block); } void pop_compiler_frame(void) { struct compiler_frame *f; f=Pike_compiler->compiler_frame; #ifdef PIKE_DEBUG if(!f) Pike_fatal("Popping out of compiler frames\n"); #endif low_pop_local_variables(0, NULL); if(f->current_type) free_type(f->current_type); if(f->current_return_type) free_type(f->current_return_type); Pike_compiler->compiler_frame=f->previous; dmfree((char *)f); } PMOD_EXPORT void change_compiler_compatibility(int major, int minor) { CHECK_COMPILER(); push_int(major); push_int(minor); safe_apply_current2(PC_CHANGE_COMPILER_COMPATIBILITY_FUN_NUM, 2, "change_compiler_compatibility"); pop_stack(); }
1420732017-02-08Henrik Grubbström (Grubba) #define DEFAULT_CMOD_STORAGE static /*! @decl constant __null_program *! *! Program used internally by the compiler to create objects *! that are later modified into instances of the compiled program *! by the compiler. *! *! @seealso *! @[__placeholder_object] */ struct program *null_program = NULL; PIKECLASS null { } /* This placeholder should be used * in the first compiler pass to take the place * of unknown things */ struct program *placeholder_program = NULL; struct object *placeholder_object = NULL; PIKECLASS placeholder { PIKEFUN object `()(mixed ... params) { ref_push_object(Pike_fp->current_object); } PIKEFUN object `[](mixed ... params) { ref_push_object(Pike_fp->current_object); } PIKEFUN string _sprintf(int c, mapping|void opts) { if (c != 'O') { push_int(0); return; } push_text("__placeholder_object"); } }
4878fa2018-11-07Henrik Grubbström (Grubba) void low_init_pike_compiler(void)
dd40072017-02-02Henrik Grubbström (Grubba) { #ifdef PIKE_THREADS co_init(&Pike_compiler_cond); #endif compile_compiler();
4878fa2018-11-07Henrik Grubbström (Grubba) }
5147e62017-02-06Henrik Grubbström (Grubba) 
1420732017-02-08Henrik Grubbström (Grubba) 
4878fa2018-11-07Henrik Grubbström (Grubba) /* * Now that the compiler has been compiled, * we can use the usual cmod stuff. */
5147e62017-02-06Henrik Grubbström (Grubba) 
4878fa2018-11-07Henrik Grubbström (Grubba) void init_pike_compiler(void) {
5147e62017-02-06Henrik Grubbström (Grubba)  INIT;
1420732017-02-08Henrik Grubbström (Grubba)  { struct svalue s; SET_SVAL(s, T_PROGRAM, 0, program, null_program); low_add_constant("__null_program", &s); } /*! @decl constant __placeholder_object *! *! Object used internally by the compiler. *! *! @seealso *! @[__null_program] */ { struct svalue s; placeholder_object = fast_clone_object(placeholder_program); SET_SVAL(s, T_OBJECT, 0, object, placeholder_object); low_add_constant("__placeholder_object", &s); }
1874052018-04-21Henrik Grubbström (Grubba)  { struct pike_string *attr; struct svalue s; MAKE_CONST_STRING(attr, "utf8_string"); SET_SVAL(s, T_TYPE, 0, type, utf8_type_string); low_add_efun(attr, &s); }
dd40072017-02-02Henrik Grubbström (Grubba) } void cleanup_pike_compiler(void) {
5147e62017-02-06Henrik Grubbström (Grubba)  EXIT;
4878fa2018-11-07Henrik Grubbström (Grubba) }
5147e62017-02-06Henrik Grubbström (Grubba) 
4878fa2018-11-07Henrik Grubbström (Grubba) void low_cleanup_pike_compiler(void) {
dd40072017-02-02Henrik Grubbström (Grubba)  if (compilation_program) { free_program(compilation_program); compilation_program = 0; } if (compilation_environment) { free_object(compilation_environment); compilation_environment = 0; } if (compilation_env_program) { free_program(compilation_env_program); compilation_env_program = 0; } if (reporter_program) { free_program(reporter_program); reporter_program = 0; } #ifdef PIKE_THREADS co_destroy(&Pike_compiler_cond); #endif }