From 41c915e4dc7ecdba99474a7d129859558e4e3ba0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?=
 <grubba@grubba.org>
Date: Fri, 18 Apr 2008 21:57:13 +0200
Subject: [PATCH] Pike compiler mega patch mk II.

Rev: src/builtin_functions.c:1.653
Rev: src/language.yacc:1.414
Rev: src/pike_compiler.h:1.4
Rev: src/program.c:1.667
Rev: src/program.h:1.239
---
 src/builtin_functions.c |  13 +-
 src/language.yacc       |   4 +-
 src/pike_compiler.h     |  20 +-
 src/program.c           | 588 +++++++++++++++++++++++++++++++---------
 src/program.h           |   4 +-
 5 files changed, 483 insertions(+), 146 deletions(-)

diff --git a/src/builtin_functions.c b/src/builtin_functions.c
index 3a258a5716..d7b67bfcee 100644
--- a/src/builtin_functions.c
+++ b/src/builtin_functions.c
@@ -2,7 +2,7 @@
 || 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.
-|| $Id: builtin_functions.c,v 1.652 2008/04/14 10:14:35 grubba Exp $
+|| $Id: builtin_functions.c,v 1.653 2008/04/18 19:56:01 grubba Exp $
 */
 
 #include "global.h"
@@ -4107,18 +4107,11 @@ node *optimize_replace(node *n)
  *!
  *! @seealso
  *!   @[compile_string()], @[compile_file()], @[cpp()], @[master()],
- *!   @[CompilationHandler]
+ *!   @[CompilationHandler], @[DefaultCompilationEnvironment]
  */
 PMOD_EXPORT void f_compile(INT32 args)
 {
-  struct object *ce = clone_object(compilation_program, 0);
-  ONERROR err;
-
-  SET_ONERROR(err, do_free_object, ce);
-
-  apply_low(ce, CE_COMPILE_FUN_NUM, args);
-
-  CALL_AND_UNSET_ONERROR(err);
+  apply_low(compilation_environment, CE_COMPILE_FUN_NUM, args);
 }
 
 
diff --git a/src/language.yacc b/src/language.yacc
index 03a3cad38b..56debf764f 100644
--- a/src/language.yacc
+++ b/src/language.yacc
@@ -2,7 +2,7 @@
 || 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.
-|| $Id: language.yacc,v 1.413 2008/04/14 13:20:20 grubba Exp $
+|| $Id: language.yacc,v 1.414 2008/04/18 19:57:13 grubba Exp $
 */
 
 %pure_parser
@@ -4339,7 +4339,7 @@ void low_yyerror(struct pike_string *str)
   push_int(c->lex.current_line);
   push_constant_text("parse");
   ref_push_string(str);
-  safe_apply_current(CE_REPORT_FUN_NUM, 5);
+  safe_apply_current(PC_REPORT_FUN_NUM, 5);
   pop_stack();
   STACK_LEVEL_DONE(0);
 }
diff --git a/src/pike_compiler.h b/src/pike_compiler.h
index 84a7130301..cdb33bf9f4 100644
--- a/src/pike_compiler.h
+++ b/src/pike_compiler.h
@@ -2,7 +2,7 @@
 || 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.
-|| $Id: pike_compiler.h,v 1.3 2008/04/14 16:34:54 grubba Exp $
+|| $Id: pike_compiler.h,v 1.4 2008/04/18 19:56:01 grubba Exp $
 */
 
 #ifndef PIKE_COMPILER_H
@@ -20,6 +20,7 @@ struct compilation
   int major, minor;			/* compat version */
   struct program *target;		/* Program being compiled. */
   struct object *placeholder;
+  int flags;
   
   struct program *p;			/* Compiled program or NULL. */
   struct lex lex;
@@ -47,16 +48,25 @@ struct compilation
 #define THIS_COMPILATION  ((struct compilation *)(Pike_fp->current_storage))
 #define MAYBE_THIS_COMPILATION  ((Pike_fp && compilation_program && (Pike_fp->context->prog == compilation_program))?THIS_COMPILATION:NULL)
 
+/* Flags. */
+#define COMPILER_BUSY	1	/* The compiler is busy compiling. */
+#define COMPILER_DONE	2	/* The is finished compiling. */
+
 /* Report levels */
 #define REPORT_INFO	0	/* FYI. */
 #define REPORT_WARNING	1	/* Compiler warning. */
 #define REPORT_ERROR	2	/* Compilation error. */
 #define REPORT_FATAL	3	/* Unrecoverable error. */
 
-/* Function numbers. */
+/* CompilerEnvironment function numbers. */
 #define CE_REPORT_FUN_NUM		0
-#define CE_PIKE_COMPILER_FUN_NUM	1
-#define CE_COMPILE_FUN_NUM		2
-#define CE_RESOLV_FUN_NUM		3
+#define CE_COMPILE_FUN_NUM		1
+#define CE_RESOLV_FUN_NUM		2
+#define CE_PIKE_COMPILER_FUN_NUM	3
+
+/* PikeCompiler function numbers. */
+#define PC_REPORT_FUN_NUM		0
+#define PC_COMPILE_FUN_NUM		1
+#define PC_RESOLV_FUN_NUM		2
 
 #endif	/* !PIKE_COMPILER_H */
diff --git a/src/program.c b/src/program.c
index 229f0be890..0bbbabd56a 100644
--- a/src/program.c
+++ b/src/program.c
@@ -2,7 +2,7 @@
 || 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.
-|| $Id: program.c,v 1.666 2008/04/15 19:16:41 grubba Exp $
+|| $Id: program.c,v 1.667 2008/04/18 19:56:01 grubba Exp $
 */
 
 #include "global.h"
@@ -1220,6 +1220,8 @@ static int current_program_id = PROG_DYNAMIC_ID_START;
 struct program *null_program=0;
 
 struct program *compilation_program = 0;
+struct program *compilation_env_program = 0;
+struct object *compilation_environment = NULL;
 
 struct program *gc_internal_program = 0;
 static struct program *gc_mark_program_pos = 0;
@@ -1626,7 +1628,7 @@ struct node_s *resolve_identifier(struct pike_string *ident)
   } else {
     push_int(0);
   }
-  if (!safe_apply_current(CE_RESOLV_FUN_NUM, 3)) {
+  if (!safe_apply_current(PC_RESOLV_FUN_NUM, 3)) {
     if(Pike_compiler->compiler_pass==2) {
       if (throw_value.type == T_STRING) {
 	my_yyerror("%S", throw_value.u.string);
@@ -7107,16 +7109,164 @@ int report_compiler_dependency(struct program *p)
  *!   The compiler environment.
  */
 
+/*! @decl void report(SeverityLevel severity, @
+ *!                   string filename, int linenumber, @
+ *!                   string subsystem, @
+ *!                   string message, mixed ... extra_args)
+ *!
+ *!   Report a diagnostic from the compiler.
+ */
+static void f_compilation_env_report(INT32 args)
+{
+  int level;
+  struct pike_string *filename;
+  INT_TYPE linenumber;
+  struct pike_string *subsystem;
+  struct pike_string *message;
+  if (args > 5) {
+    f_sprintf(args - 4);
+    args = 5;
+  }
+  get_all_args("report", args, "%d%W%i%W%W",
+	       &level, &filename, &linenumber, &subsystem, &message);
+
+  /* Ignore informational level messages */
+  if (level >= REPORT_WARNING) {
+    if (get_master()) {
+      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, linenumber, message->str);
+      } else {
+	fprintf(stderr, "%s:%ld: Warning: %s\n",
+		filename->str, linenumber, message->str);
+      }
+      fflush(stderr);
+    }
+  }
+  pop_n_elems(args);
+  push_int(0);
+}
+
+/*! @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
+ *!   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 (Pike_sp[-1].type != 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, @
+ *!		       object|void handler)
+ */
+static void f_compilation_env_resolv(INT32 args)
+{
+  struct pike_string *ident;
+  struct pike_string *filename;
+  struct object *handler = NULL;
+
+  get_all_args("resolv", args, "%W%W.%O",
+	       &ident, &filename, &handler);
+
+  if(get_master())
+  {
+    struct compilation *c = THIS_COMPILATION;
+    DECLARE_CYCLIC();
+    if(BEGIN_CYCLIC(ident, filename))
+    {
+      my_yyerror("Recursive module dependency in %S.", ident);
+    }else{
+      SET_CYCLIC_RET(1);
+
+      APPLY_MASTER("resolv", args);
+    }
+    END_CYCLIC();
+  } else {
+    pop_n_elems(args);
+    push_undefined();
+  }
+}
+
+/*! @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);
-  if(c->handler) free_object(c->handler);
-  if(c->compat_handler) free_object(c->compat_handler);
-  if(c->target) free_program(c->target);
-  if(c->placeholder) free_object(c->placeholder);
-  if(c->lex.current_file) free_string(c->lex.current_file);
+  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->placeholder) {
+    free_object(c->placeholder);
+    c->placeholder = NULL;
+  }
+  if(c->lex.current_file) {
+    free_string(c->lex.current_file);
+    c->lex.current_file = NULL;
+  }
   free_svalue(& c->default_module);
+  c->default_module.type = T_INT;
   free_supporter(&c->supporter);
   verify_supporters();
 }
@@ -7334,6 +7484,12 @@ 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);
   low_start_new_program(c->p,2,0,0,0);
   free_program(c->p);
@@ -7456,6 +7612,8 @@ static void run_cleanup(struct compilation *c, int delayed)
     }
   }
   verify_supporters();
+  c->flags &= ~(COMPILER_BUSY);
+  c->flags |= COMPILER_DONE;
 }
 
 static int call_delayed_pass2(struct compilation *cc, int finish)
@@ -7496,6 +7654,11 @@ static int call_delayed_pass2(struct compilation *cc, int finish)
   return ok;
 }
 
+/*! @class PikeCompiler
+ *!
+ *!   The Pike compiler.
+ */
+
 static void compilation_event_handler(int e)
 {
   struct compilation *c = THIS_COMPILATION;
@@ -7527,6 +7690,10 @@ static void compilation_event_handler(int e)
  *!                   string message, mixed ... extra_args)
  *!
  *!   Report a diagnostic from the compiler.
+ *!
+ *!   The default implementation calls the corresponding function
+ *!   in the active handlers, and otherwise falls back to
+ *!   @[CompilationEnvironment::report()] in the parent object.
  */
 static void f_compilation_report(INT32 args)
 {
@@ -7536,57 +7703,68 @@ static void f_compilation_report(INT32 args)
   INT_TYPE linenumber;
   struct pike_string *subsystem;
   struct pike_string *message;
-  if (args > 5) {
-    f_sprintf(args - 4);
-    args = 5;
-  }
-  get_all_args("report", args, "%d%W%i%W%W",
-	       &level, &filename, &linenumber, &subsystem, &message);
+  struct object *handler = NULL;
+  int fun = -1;
 
-  /* Ignore informational level messages */
-  if (level) {
-    if ((c->handler && c->handler->prog) ||
-	(c->compat_handler && c->compat_handler->prog) ||
-	get_master()) {
-      ref_push_string(filename);
-      push_int(linenumber);
-      ref_push_string(message);
-      if (level >= 2) {
-	low_safe_apply_handler("compile_error",
-			       c->handler, c->compat_handler, 3);
-	args++;
-      } else {
-	low_safe_apply_handler("compile_warning",
-			       c->handler, c->compat_handler, 3);
-	args++;
+  /* FIXME: get_all_args() ought to have a marker
+   *        indicating that accept more arguments...
+   */
+  get_all_args("report", args, "%d", &level);
+
+  if ((c->handler || c->compat_handler) &&
+      (level >= REPORT_WARNING)) {
+    /* Ignore informational level messages */
+    const char *fun_name = "compile_warning";
+
+    if (level >= REPORT_ERROR) fun_name = "compile_error";
+
+    if((handler = c->handler) && handler->prog) {
+      if ((fun = find_identifier(fun_name, handler->prog)) !=
+	  -1) {
+	goto apply_handler;
       }
-    } else {
-      if (level >= 2) {
-	fprintf(stderr, "%s:%ld: %s\n",
-		filename->str, linenumber, message->str);
-      } else {
-	fprintf(stderr, "%s:%ld: Warning: %s\n",
-		filename->str, linenumber, message->str);
+    }
+    if ((handler = c->compat_handler) && handler->prog) {
+      if ((fun = find_identifier(fun_name, handler->prog)) !=
+	  -1) {
+	goto apply_handler;
       }
-      fflush(stderr);
     }
   }
-  pop_n_elems(args);
-  push_int(0);
+  /* Nothing apropriate in any handlers.
+   * Call the report() in our parent.
+   */
+  apply_external(1, CE_REPORT_FUN_NUM, args);
+  return;
+
+ apply_handler:
+  if (args > 5) {
+    f_sprintf(args - 4);
+    args = 5;
+  }
+  get_all_args("report", args, "%d%W%i%W%W",
+	       &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 program compile(string source, CompilationHandler|void handler, @
- *!                       int|void major, int|void minor,@
- *!                       program|void target, object|void placeholder)
+/*! @decl void create(string|void source, @
+ *!                   CompilationHandler|void handler, @
+ *!                   int|void major, int|void minor,@
+ *!                   program|void target, object|void placeholder)
  *!
- *!   Compile a string to a program.
+ *!   Create a Pike compiler object for a source string.
  *!
  *!   This function takes a piece of Pike code as a string and
- *!   compiles it into a clonable program.
+ *!   initializes a compiler object accordingly.
  *!
  *!   The optional argument @[handler] is used to specify an alternative
- *!   error handler. If it is not specified the current master object will
- *!   be used.
+ *!   error handler. If it is not specified the current master object
+ *!   at compile time will be used.
  *!
  *!   The optional arguments @[major] and @[minor] are used to tell the
  *!   compiler to attempt to be compatible with Pike @[major].@[minor].
@@ -7595,7 +7773,7 @@ static void f_compilation_report(INT32 args)
  *!   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.
+ *!   Also note that no preprocessing is performed.
  *!   To preprocess the program you can use @[compile_string()] or
  *!   call the preprocessor manually by calling @[cpp()].
  *!
@@ -7603,9 +7781,9 @@ static void f_compilation_report(INT32 args)
  *!   @[compile_string()], @[compile_file()], @[cpp()], @[master()],
  *!   @[CompilationHandler]
  */
-static void f_compilation_compile(INT32 args)
+static void f_compilation_create(INT32 args)
 {
-  struct pike_string *aprog;
+  struct pike_string *aprog = NULL;
   struct object *ahandler = NULL;/* error handler */
   int amajor = -1;
   int aminor = -1;
@@ -7618,43 +7796,46 @@ static void f_compilation_compile(INT32 args)
 #endif
   struct compilation *c = THIS_COMPILATION;
 
-  if (c->target) {
-    Pike_error("CompilationEnvironment in use.\n");
+  if (c->flags & COMPILER_BUSY) {
+    Pike_error("PikeCompiler object is in use.\n");
   }
 
   STACK_LEVEL_START(args);
 
-  get_all_args("compile", args, "%W.%O%d%d%P%O",
+  get_all_args("create", args, ".%W%O%d%d%P%O",
 	       &aprog, &ahandler,
 	       &amajor, &aminor,
 	       &atarget, &aplaceholder);
 
   if (args == 3) {
-    SIMPLE_BAD_ARG_ERROR("compile", 4, "int");
+    SIMPLE_BAD_ARG_ERROR("create", 4, "int");
   }
 
   check_c_stack(65536);
 
-  CDFPRINTF((stderr, "th(%ld) %p compile() enter, placeholder=%p\n",
+  CDFPRINTF((stderr, "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);
-  add_ref(c->prog=aprog);
-  if (ahandler) {
-    if (c->handler) free_object(c->handler);
-    add_ref(c->handler = ahandler);
-  }
+  if ((c->prog=aprog)) add_ref(aprog);
+
+  if (c->handler) free_object(c->handler);
+  if ((c->handler=ahandler)) add_ref(ahandler);
+
   c->major=amajor;
   c->minor=aminor;
 
-  if((c->target=atarget)) add_ref(atarget);
-  else c->target = low_allocate_program();
+  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);
@@ -7678,11 +7859,76 @@ static void f_compilation_compile(INT32 args)
   c->default_module=Pike_sp[-1];
   dmalloc_touch_svalue(Pike_sp-1);
   Pike_sp--;
+  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)
+{
+  struct pike_string *aprog;
+  struct object *ahandler = NULL;/* error handler */
+  int amajor = -1;
+  int aminor = -1;
+  struct program *atarget = NULL;
+  struct object *aplaceholder = NULL;
+  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("CompilationEnvironment in use.\n");
+  }
+
+  get_all_args("compile", args, "");
+
+  check_c_stack(65536);
+
+  CDFPRINTF((stderr, "th(%ld) %p 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. */
+    low_start_new_program(c->target, 1, NULL, 0, NULL);
+    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;
+
   low_init_threads_disable();
   c->saved_threads_disabled = threads_disabled;
 
@@ -7702,18 +7948,16 @@ static void f_compilation_compile(INT32 args)
     CDFPRINTF((stderr, "th(%ld) %p compile() finish later, placeholder=%p.\n",
 	       (long) th_self(), c->target, c->placeholder));
     /* finish later */
-    add_ref(c->p);
     verify_supporters();
     /* We're hanging in the supporter. */
     ret = c->p;
   }else{
     /* finish now */
-    if(c->p) run_pass2(c);
+    run_pass2(c);
     debug_malloc_touch(c);
     run_cleanup(c,0);
     
-    ret=c->p;
-    c->p = NULL;
+    ret = c->p;
 
     debug_malloc_touch(c);
 
@@ -7739,42 +7983,39 @@ static void f_compilation_compile(INT32 args)
 #endif /* PIKE_DEBUG */
     verify_supporters();
   }
-  STACK_LEVEL_DONE(args);
   pop_n_elems(args);
   if (ret)
-    push_program(ret);
+    ref_push_program(ret);
   else
     push_int(0);
 }
 
+/*! @decl mixed resolv(string identifier, string filename, @
+ *!                    object handler)
+ *!
+ *!   Resolve the symbol @[identifier].
+ *!
+ *!   The default implementation calls the corresponding function
+ *!   in any active handler, and otherwise falls back to
+ *!   @[CompilationEnvironment::resolv()] in the parent object.
+ */
 static void f_compilation_resolv(INT32 args)
 {
-  struct pike_string *ident;
-  struct pike_string *filename;
+  struct compilation *c = THIS_COMPILATION;
   struct object *handler;
+  int fun = -1;
 
-  get_all_args("resolv", args, "%W%W%O", &ident, &filename, &handler);
-
-  if(get_master())
-  {
-    struct compilation *c = THIS_COMPILATION;
-    DECLARE_CYCLIC();
-    if(BEGIN_CYCLIC(ident, filename))
-    {
-      my_yyerror("Recursive module dependency in %S.", ident);
-    }else{
-      SET_CYCLIC_RET(1);
-
-      low_unsafe_apply_handler("resolv", handler, c->compat_handler, args);
-    }
-    END_CYCLIC();
+  if (((handler = c->handler) && handler->prog &&
+       ((fun = find_identifier("resolv", handler->prog)) != -1)) ||
+      ((handler = c->compat_handler) && handler->prog &&
+       ((fun = find_identifier("resolv", handler->prog)) != -1))) {
+    apply_low(handler, fun, args);
   } else {
-    pop_n_elems(args);
-    push_undefined();
+    apply_external(1, CE_RESOLV_FUN_NUM, args);
   }
 }
 
-/* Fake being called via CompilationEnvironment()->compile()
+/* Fake being called via PikeCompiler()->compile()
  *
  * This function is used to set up the environment for
  * compiling C efuns and modules.
@@ -7790,7 +8031,7 @@ static void low_enter_compiler(struct object *ce, int inherit)
 #ifdef PROFILING
   new_frame->children_base = Pike_interpreter.accounted_time;
   new_frame->start_time = get_cpu_time() - Pike_interpreter.unlocked_time;
-  new_frame->ident = CE_COMPILE_FUN_NUM;	/* Fake call of compile(). */
+  new_frame->ident = PC_COMPILE_FUN_NUM;	/* Fake call of compile(). */
 #endif /* PROFILING */
   new_frame->next = Pike_fp;
   new_frame->current_object = ce;
@@ -7807,7 +8048,7 @@ static void low_enter_compiler(struct object *ce, int inherit)
 	       new_frame->context->prog, compilation_program);
   }
 #endif /* PIKE_DEBUG */
-  new_frame->fun = new_frame->context->identifier_level + CE_COMPILE_FUN_NUM;
+  new_frame->fun = new_frame->context->identifier_level + PC_COMPILE_FUN_NUM;
   new_frame->expendible = Pike_sp;
   new_frame->locals = Pike_sp;
   new_frame->save_sp = Pike_sp;
@@ -7824,7 +8065,9 @@ static void low_enter_compiler(struct object *ce, int inherit)
 
 PMOD_EXPORT void enter_compiler(struct pike_string *filename, int linenumber)
 {
-  struct object *ce = clone_object(compilation_program, 0);
+  struct object *ce = parent_clone_object(compilation_program,
+					  compilation_environment,
+					  CE_PIKE_COMPILER_FUN_NUM, 0);
   struct compilation *c;
 
   low_enter_compiler(ce, 0);
@@ -7845,27 +8088,17 @@ PMOD_EXPORT void exit_compiler(void)
 {
 #ifdef PIKE_DEBUG
   if ((Pike_fp->current_program != compilation_program) ||
-      (Pike_fp->fun != 2)) {
+      (Pike_fp->fun != PC_COMPILE_FUN_NUM)) {
     Pike_fatal("exit_compiler(): Frame stack out of whack!\n");
   }
 #endif /* PIKE_DEBUG */
   POP_PIKE_FRAME();
 }
 
-/*! @class PikeCompiler
+/*! @class CompilerState
  *!
- *!   The Pike compiler.
- */
-
-/*! @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 calls @[CompilerEnvironment::report()]
- *!   with the same arguments.
+ *! @note
+ *!   Not in use yet!
  */
 
 #define THIS_PROGRAM_STATE  ((struct program_state *)(Pike_fp->current_storage))
@@ -7896,20 +8129,27 @@ static void program_state_event_handler(int event)
 /*! @endclass
  */
 
+/*! @endclass
+ */
+
 /* Strap the compiler by creating the compilation program by hand. */
 static void compile_compiler(void)
 {
-  struct program *p = compilation_program = low_allocate_program();
-  struct object *ce;
+  struct program *p = low_allocate_program();
+  struct program *p2 = compilation_program = low_allocate_program();
+  struct object *co;
   struct inherit *inh;
+  struct pike_string *pike_compiler_string;
 
   p->parent_info_storage = -1;
-  p->event_handler = compilation_event_handler;
+  /* p->event_handler = compilation_env_event_handler; */
   p->flags |= PROGRAM_HAS_C_METHODS;
 
-  /* ADD_STORAGE(struct compilation); */
-  p->alignment_needed = ALIGNOF(struct compilation);
-  p->storage_needed = sizeof(struct compilation);
+#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()
@@ -7921,25 +8161,70 @@ static void compile_compiler(void)
   inh->parent_identifier = -1;
   inh->parent_offset = OBJECT_PARENT;
   inh->identifier_ref_offset = 0;
-  inh->storage_offset = 0;
+  inh->storage_offset = p->xstorage;
   inh->parent = NULL;
   inh->name = NULL;
   p->num_inherits = 1;
 
-  /* Force clone_object() to accept the program... */
+  /* Force clone_object() to accept the program...
+   */
   p->flags |= PROGRAM_PASS_1_DONE;
-  ce = clone_object(p, 0);
+  compilation_environment = clone_object(p, 0);
   p->flags &= ~PROGRAM_PASS_1_DONE;
 
-  low_enter_compiler(ce, 0);
+  /* Once more, this time for p2...
+   */
+
+  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);
+
+  p2->inherits = inh = xalloc(sizeof(struct inherit));
+  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);
 
   low_start_new_program(p, 1, NULL, 0, NULL);
   free_program(p);	/* Remove the extra ref we just got... */
 
-  /* low_start_new_program() has zapped the inherit we
-   * created above, so we need to repair the frame pointer.
+  ADD_FUNCTION("report", f_compilation_env_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);
+
+  low_start_new_program(p2, 1, NULL, 0, NULL);
+
+  /* low_start_new_program() has zapped the inherit we created
+   * for p2 above, so we need to repair the frame pointer.
    */
-  Pike_fp->context = p->inherits;
+  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
@@ -7950,6 +8235,17 @@ static void compile_compiler(void)
 	       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), 0);
+
   start_new_program();
 
   ADD_STORAGE(struct program_state);
@@ -7958,18 +8254,46 @@ static void compile_compiler(void)
     PROGRAM_NEEDS_PARENT|PROGRAM_USES_PARENT|PROGRAM_HAS_C_METHODS;
 
   /* Alias for report above. */
-  low_define_alias(NULL, NULL, 0, 1, CE_REPORT_FUN_NUM);
-
+  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_PROGRAM, 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),
+		    tStr, PIKE_T_STRING, ID_HIDDEN);
+
+  /* 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("compile", f_compilation_compile, tFunc(tStr, tPrg(tObj)), 0);
-
-  ADD_FUNCTION("resolv", f_compilation_resolv, tFunc(tStr tStr tObj, tMix), 0);
+  compilation_env_program = end_program();
 
-  add_global_program("CompilerEnvironment",
-		     compilation_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();
 }
 
 struct program *compile(struct pike_string *aprog,
@@ -8467,6 +8791,14 @@ void cleanup_program(void)
     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;
+  }
 }
 
 void gc_mark_program_as_referenced(struct program *p)
@@ -8780,7 +9112,7 @@ void low_pop_local_variables(int level)
       push_constant_text("parse");
       push_constant_text("Unused local variable %s.");
       ref_push_string(Pike_compiler->compiler_frame->variable[e].name);
-      safe_apply_current(CE_REPORT_FUN_NUM, 6);
+      safe_apply_current(PC_REPORT_FUN_NUM, 6);
       pop_stack();
     }
     free_string(Pike_compiler->compiler_frame->variable[e].name);
@@ -8812,7 +9144,7 @@ void pop_local_variables(int level)
 	push_constant_text("parse");
 	push_constant_text("Unused local variable %s.");
 	ref_push_string(Pike_compiler->compiler_frame->variable[level].name);
-	safe_apply_current(CE_REPORT_FUN_NUM, 6);
+	safe_apply_current(PC_REPORT_FUN_NUM, 6);
 	pop_stack();
 	/* Make sure we only warn once... */
 	Pike_compiler->compiler_frame->variable[level].flags |=
@@ -9047,7 +9379,7 @@ void yywarning(char *fmt, ...)
   push_int(c->lex.current_line);
   push_constant_text("parse");
   push_string(msg);
-  safe_apply_current(CE_REPORT_FUN_NUM, 5);
+  safe_apply_current(PC_REPORT_FUN_NUM, 5);
   pop_stack();
 }
 
diff --git a/src/program.h b/src/program.h
index eb64d9009b..7f600d1d45 100644
--- a/src/program.h
+++ b/src/program.h
@@ -2,7 +2,7 @@
 || 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.
-|| $Id: program.h,v 1.238 2008/04/15 13:07:52 grubba Exp $
+|| $Id: program.h,v 1.239 2008/04/18 19:56:01 grubba Exp $
 */
 
 #ifndef PROGRAM_H
@@ -661,7 +661,9 @@ BLOCK_ALLOC_FILL_PAGES(program, n/a);
 
 extern struct program *first_program;
 extern struct program *null_program;
+extern struct program *compilation_env_program;
 extern struct program *compilation_program;
+extern struct object *compilation_environment;
 extern struct program *pike_trampoline_program;
 extern struct program *gc_internal_program;
 extern struct program *placeholder_program;
-- 
GitLab