From 528fe1c11f9a75d6172f9027cc9866db7bad3730 Mon Sep 17 00:00:00 2001
From: Martin Nilsson <mani@lysator.liu.se>
Date: Sat, 23 Oct 2004 01:26:13 +0200
Subject: [PATCH] Facets

Rev: src/.cvsignore:1.37
Rev: src/Makefile.in:1.387
Rev: src/errors.h:1.27
Rev: src/facetgroup.cmod:1.1
Rev: src/interpret.c:1.357
Rev: src/interpret.h:1.155
Rev: src/language.yacc:1.344
Rev: src/lexer.h:1.50
Rev: src/main.c:1.215
Rev: src/program.c:1.572
Rev: src/program.h:1.212
---
 .gitattributes      |   1 +
 src/.cvsignore      |   1 +
 src/.gitignore      |   1 +
 src/Makefile.in     |   6 +-
 src/errors.h        |   4 +-
 src/facetgroup.cmod | 291 ++++++++++++++++++++++++++++++++++++++++++++
 src/interpret.c     |  16 ++-
 src/interpret.h     |   3 +-
 src/language.yacc   |  65 +++++++++-
 src/lexer.h         |   5 +-
 src/main.c          |   6 +-
 src/program.c       |  58 ++++++++-
 src/program.h       |  11 +-
 13 files changed, 459 insertions(+), 9 deletions(-)
 create mode 100644 src/facetgroup.cmod

diff --git a/.gitattributes b/.gitattributes
index f2cb39efdd..516c273635 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -338,6 +338,7 @@ testfont binary
 /src/error.c foreign_ident
 /src/errors.h foreign_ident
 /src/export_list foreign_ident
+/src/facetgroup.cmod foreign_ident
 /src/fd_control.c foreign_ident
 /src/fd_control.h foreign_ident
 /src/fdlib.c foreign_ident
diff --git a/src/.cvsignore b/src/.cvsignore
index 25fc710fc7..7113a7e3c9 100644
--- a/src/.cvsignore
+++ b/src/.cvsignore
@@ -15,6 +15,7 @@ conftest.c
 conftest.h
 dependencies
 dumpmodule.log
+facetgroup.c
 hilfe
 hsort_template.h
 interpret_functions_fixed.h
diff --git a/src/.gitignore b/src/.gitignore
index d150510c6c..4e12d8b27d 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -15,6 +15,7 @@
 /conftest.h
 /dependencies
 /dumpmodule.log
+/facetgroup.c
 /hilfe
 /hsort_template.h
 /interpret_functions_fixed.h
diff --git a/src/Makefile.in b/src/Makefile.in
index ece4172688..c48496624f 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,5 +1,5 @@
 #
-# $Id: Makefile.in,v 1.386 2004/10/20 18:59:38 grubba Exp $
+# $Id: Makefile.in,v 1.387 2004/10/22 23:22:57 nilsson Exp $
 #
 
 # This line is needed on some machines.
@@ -169,6 +169,7 @@ OBJ= \
  queue.o \
  builtin.o \
  iterators.o \
+ facetgroup.o \
  svalue.o \
  las.o \
  builtin_functions.o \
@@ -983,6 +984,8 @@ builtin.o: $(SRCDIR)/builtin.c
 
 iterators.o: $(SRCDIR)/iterators.c
 
+facetgroup.o: $(SRCDIR)/facetgroup.c
+
 backend.o: $(SRCDIR)/backend.c
 
 # Internal testing target
@@ -1142,6 +1145,7 @@ HFILES=						\
   version.protos                                    \
   builtin.protos					\
   iterators.protos				\
+  facetgroup.protos				\
   rbtree.protos
 
 $(HFILES): precompile.sh-stamp
diff --git a/src/errors.h b/src/errors.h
index c2467b2752..f898d08bda 100644
--- a/src/errors.h
+++ b/src/errors.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: errors.h,v 1.26 2004/04/18 02:19:38 mast Exp $
+|| $Id: errors.h,v 1.27 2004/10/22 23:22:24 nilsson Exp $
 */
 
 #ifdef ERR_DECLARE
@@ -125,6 +125,8 @@ DECLARE_ERROR(cpp, Cpp, ERR_INHERIT(generic), EMPTY)
 
 DECLARE_ERROR(compilation, Compilation, ERR_INHERIT(generic), EMPTY)
 
+DECLARE_ERROR(compile_callback, CompileCallback, ERR_INHERIT(generic), EMPTY)
+
 DECLARE_ERROR(master_load, MasterLoad, ERR_INHERIT (generic), EMPTY)
 
 DECLARE_ERROR (module_load, ModuleLoad,
diff --git a/src/facetgroup.cmod b/src/facetgroup.cmod
new file mode 100644
index 0000000000..1290ae8377
--- /dev/null
+++ b/src/facetgroup.cmod
@@ -0,0 +1,291 @@
+/* -*- c -*- 
+|| 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: facetgroup.cmod,v 1.1 2004/10/22 23:20:35 nilsson Exp $
+*/
+
+#include "global.h"
+#include "fdlib.h"
+#include "main.h"
+#include "object.h"
+#include "mapping.h"
+#include "multiset.h"
+#include "svalue.h"
+#include "stralloc.h"
+#include "array.h"
+#include "pike_macros.h"
+#include "pike_error.h"
+#include "pike_memory.h"
+#include "dynamic_buffer.h"
+#include "interpret.h"
+#include "las.h"
+#include "gc.h"
+#include "stralloc.h"
+#include "opcodes.h"
+#include "pike_error.h"
+#include "program.h"
+#include "operators.h"
+#include "builtin_functions.h"
+#include "constants.h"
+#include "program.h"
+#include "block_alloc.h"
+
+DECLARATIONS
+
+/*! @class facetgroup
+ *! 
+ *! This class is used to handle facets in the system. All facets 
+ *! in the system have to belong to a facet group. The facet 
+ *! group is a pike module that inherits from this class. For 
+ *! example you can create a file MyFacetgroup.pmod with the following
+ *! content:
+ *!
+ *! @tt{inherit facetgroup;
+ *! int main() { ; } @}
+ *!
+ *! You can then use the facet group MyFacetGroup in a facet-class 
+ *! like this:
+ *!
+ *! @tt{class A
+ *! {
+ *!   facet NameOfMyFacet : .MyFacetGroup; 
+ *!   // Rest of class A 
+ *! } @}
+ *!
+ */
+
+/* Linked list of facet-classes */
+struct facet_class_struct { 
+  int id;
+  struct facet_class_struct *next;
+};
+
+/* Linked list of facets with their facet-classes */
+struct facet_node_struct {
+  struct pike_string *name;
+  struct facet_class_struct *classes;
+  struct facet_node_struct *next;
+};
+
+/* Linked list of facets a product class is inheriting from */
+struct facet_list_struct {
+  int facet_index;
+  int facet_class;
+  struct facet_list_struct *next;
+};
+
+/* Linked list of product classes with lists of what facets they use */
+struct product_class_struct {
+  int id;
+  struct facet_list_struct *facets;
+  int num_used_facets;
+  struct product_class_struct *next;
+};
+
+BLOCK_ALLOC_FILL_PAGES(facet_class_struct, 2)
+BLOCK_ALLOC_FILL_PAGES(facet_node_struct, 2)
+BLOCK_ALLOC_FILL_PAGES(product_class_struct, 2)
+BLOCK_ALLOC_FILL_PAGES(facet_list_struct, 2)
+
+
+/* The actual facet_group class */
+PIKECLASS facet_group
+{
+  CVAR struct facet_node_struct *facets;
+  CVAR struct product_class_struct *pclasses;
+  CVAR int num_facets;
+  CVAR int checked_product_classes;
+
+  /* Retruns 1 if product classes in this facet group have been checked,
+   * 0 otherwise */
+  PIKEFUN int product_classes_checked() {
+    RETURN THIS->checked_product_classes; 
+  }
+
+  /* Function to check that all product-classes inherits from all facet */
+  PIKEFUN void check_product_classes() {
+    struct facet_list_struct *fl;
+    struct product_class_struct *pc;
+    int error = 0;
+    for(pc=THIS->pclasses; pc; pc = pc->next) {
+      if (pc->num_used_facets < THIS->num_facets) {
+	throw_error_object(low_clone(compile_callback_error_program),0,0,0,
+			   "Product class does not inherit from all facets.\n");
+      }
+      else if (pc->num_used_facets > THIS->num_facets) {
+	/* It should be impossible to get here */
+	throw_error_object(low_clone(compile_callback_error_program),0,0,0,
+			   "Product class inherits more than once from some facet.\n");
+      }
+    }
+    THIS->checked_product_classes = 1;
+    pop_n_elems(args);
+  }
+
+  /* Add info that the class "class" inherits from the facet "facet_index" */
+  PIKEFUN void add_product_class(int class, int facet_index, int facet_class) {
+    struct facet_list_struct *fl, *fltmp;
+    struct product_class_struct *pc, *pctmp;
+    /* Set checked_product_classes to 0 to indicate that not all
+     * product classes have been checked */
+    THIS->checked_product_classes = 0;
+    /* Check whether the product class is allready in our list of
+     * product classes */
+    for (pc=THIS->pclasses; pc; pc = pc->next) {
+      if (class == pc->id)
+	break;
+    }
+
+    if (!pc) { /* New product class */
+      pctmp = alloc_product_class_struct();
+      pctmp->id = class;
+      pctmp->facets = NULL;
+      pctmp->num_used_facets = 0;
+      pctmp->next = THIS->pclasses;
+      THIS->pclasses = pctmp;
+      pc = pctmp;
+    }
+
+    /* pc now points to the product class to modify */
+    for(fl=pc->facets; fl; fl = fl->next) {
+      if (fl->facet_index == facet_index)
+	break;
+    }
+    if (!fl) {
+      //Add facet "facet_index" to product class "class"'s inherits
+      fltmp = alloc_facet_list_struct();
+      fltmp->facet_index = facet_index;
+      fltmp->facet_class = facet_class;
+      pc->num_used_facets++;
+      fltmp->next = pc->facets;
+      pc->facets = fltmp;
+    }
+    else  /* The product class already inherits from this facet */
+      if (fl->facet_class != facet_class)
+	throw_error_object(low_clone(compile_callback_error_program),0,0,0,
+			   "Product class can only inherit from one class in every facet.\n");
+    pop_n_elems(args);
+  }
+  
+  /* Add a facet class in the facet group */
+  PIKEFUN int add_facet_class(string facet, int class, int product_class) {
+    struct facet_class_struct *c, *ctmp;
+    struct facet_node_struct *f, *prevf, *ftmp;
+    struct product_class_struct *pc, *prevpc;
+    struct object *o;
+    int facet_index = 0;
+    if (facet == NULL)
+      throw_error_object(low_clone(compile_callback_error_program),0,0,0,
+			 "Invalid facet name.\n");
+
+    // Check if it is a new facet or not.
+    prevf = NULL;
+    for(f=THIS->facets; f; f=f->next, facet_index++) {
+      if (f->name == facet)
+	break;
+      prevf=f;
+    }
+    if (product_class) {
+      // This occurs if the inherit statement comes before the facet
+      // statement in the class
+      for (prevpc=pc=THIS->pclasses; pc; pc = pc->next) {
+	if (pc->id == class)
+	  break;
+	prevpc = pc;
+      }
+      if (!pc)
+	throw_error_object(low_clone(compile_callback_error_program),0,0,0,
+			   "Program marked as product class but not found in list of product classes.\n");
+      else {
+	if (pc->num_used_facets > 1 ||
+	    facet_index != pc->facets->facet_index)
+	  throw_error_object(low_clone(compile_callback_error_program),0,0,0,
+			     "Facet class can not inherit from a class in another facet.");
+	else {
+	  if (prevpc->id == pc->id)
+	    THIS->pclasses = pc->next;
+	  else
+	    prevpc->next = pc->next;
+	  really_free_product_class_struct(pc);
+	}
+      }
+    }
+    if (!f) { /* A new facet */
+      THIS->num_facets++;
+      f = alloc_facet_node_struct();
+      add_ref(f->name = facet);
+      f->next = NULL;
+      if (!prevf)
+	THIS->facets = f;
+      else
+	prevf->next = f;
+      f->classes = NULL;
+    }
+    // f now points to the facet 'facet' in 'facets'
+    // Check whether the class 'class' is already in the facet
+    for (c=f->classes; c; c = c->next) {
+      if (class == c->id)
+	break;
+    }
+    if (c) {
+      throw_error_object(low_clone(compile_callback_error_program),0,0,0,
+			 "Redundant facet statement.\n");
+    }
+    else {
+      ctmp = alloc_facet_class_struct();
+      ctmp->id = class;
+      ctmp->next = f->classes;
+      f->classes = ctmp;
+    }
+    RETURN facet_index;
+  }
+
+  INIT {
+    THIS->facets = NULL;
+    THIS->pclasses = NULL;
+    THIS->num_facets = 0;
+    THIS->checked_product_classes = 0;
+  }
+
+  EXIT {
+    struct facet_node_struct *f, *fnext;
+    struct facet_class_struct *fc, *fcnext;
+    struct product_class_struct *p, *pnext;
+    struct facet_list_struct *fl, *flnext;
+    for (fnext=f=THIS->facets; fnext; f=fnext) {
+      fnext = f->next;
+      for (fcnext=fc=f->classes; fcnext; fc=fcnext) {
+	fcnext = fc->next;
+	really_free_facet_class_struct(fc);
+      }
+      really_free_string(f->name);
+      really_free_facet_node_struct(f);
+    }
+    for (pnext=p=THIS->pclasses; pnext; p=pnext) {
+      pnext = p->next;
+      for (flnext=fl=p->facets; flnext; fl=flnext) {
+	flnext = fl->next;
+	really_free_facet_list_struct(fl);
+      }
+      really_free_product_class_struct(p);
+    }
+  }
+};
+
+void init_facetgroup(void)
+{
+  init_facet_class_struct_blocks();
+  init_facet_node_struct_blocks();
+  init_facet_list_struct_blocks();
+  init_product_class_struct_blocks();
+  INIT;
+  add_global_program("FacetGroup", facet_group_program);
+}
+
+void exit_facetgroup(void)
+{
+  EXIT
+}
+/*! @endclass 
+ */
diff --git a/src/interpret.c b/src/interpret.c
index 3194c32f91..da837c5b56 100644
--- a/src/interpret.c
+++ b/src/interpret.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: interpret.c,v 1.356 2004/10/16 07:27:29 agehall Exp $
+|| $Id: interpret.c,v 1.357 2004/10/22 23:23:51 nilsson Exp $
 */
 
 #include "global.h"
@@ -2216,6 +2216,20 @@ PMOD_EXPORT int apply_low_safe_and_stupid(struct object *o, INT32 offset)
   return ret;
 }
 
+PMOD_EXPORT void safe_apply_low3(struct object *o,int fun,int args, char *error)
+{
+  JMP_BUF recovery;
+  free_svalue(& throw_value);
+  throw_value.type=T_INT;
+  if(SETJMP_SP(recovery, args))
+  {
+    handle_compile_exception(error);
+  }else{
+    apply_low(o,fun,args);
+  }
+  UNSETJMP(recovery);
+}
+
 PMOD_EXPORT void safe_apply_low2(struct object *o,int fun,int args, int handle_errors)
 {
   JMP_BUF recovery;
diff --git a/src/interpret.h b/src/interpret.h
index 39c4dc0c2f..8c6df91739 100644
--- a/src/interpret.h
+++ b/src/interpret.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: interpret.h,v 1.154 2004/09/22 13:10:30 mast Exp $
+|| $Id: interpret.h,v 1.155 2004/10/22 23:23:51 nilsson Exp $
 */
 
 #ifndef INTERPRET_H
@@ -671,6 +671,7 @@ PMOD_EXPORT void call_handle_error(void);
 PMOD_EXPORT int apply_low_safe_and_stupid(struct object *o, INT32 offset);
 PMOD_EXPORT void safe_apply_low(struct object *o,int fun,int args);
 PMOD_EXPORT void safe_apply_low2(struct object *o,int fun,int args, int handle_errors);
+PMOD_EXPORT void safe_apply_low3(struct object *o,int fun,int args, char *error);
 PMOD_EXPORT void safe_apply(struct object *o, const char *fun ,INT32 args);
 PMOD_EXPORT int low_unsafe_apply_handler(const char *fun,
 					 struct object *handler,
diff --git a/src/language.yacc b/src/language.yacc
index 975d15c124..f9157f8841 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.343 2004/10/22 14:42:16 grubba Exp $
+|| $Id: language.yacc,v 1.344 2004/10/22 23:23:20 nilsson Exp $
 */
 
 %pure_parser
@@ -60,6 +60,7 @@
 %token TOK_IF
 %token TOK_IMPORT
 %token TOK_INHERIT
+%token TOK_FACET
 %token TOK_INLINE
 %token TOK_LOCAL_ID
 %token TOK_FINAL_ID
@@ -208,6 +209,7 @@ int yylex(YYSTYPE *yylval);
 %type <number> TOK_DEFAULT
 %type <number> TOK_DO
 %type <number> TOK_ELSE
+%type <number> TOK_FACET
 %type <number> TOK_FLOAT_ID
 %type <number> TOK_FOR
 %type <number> TOK_FOREACH
@@ -429,6 +431,41 @@ program_ref: low_program_ref
   }
   ;
 
+facet: TOK_FACET TOK_IDENTIFIER ':' idents ';'
+  {
+    struct object *o;
+    if (Pike_compiler->compiler_pass == 1) {
+      if (Pike_compiler->new_program->facet_class == PROGRAM_IS_FACET_CLASS) {
+	yyerror("A class can only belong to one facet");
+      }
+      else {
+	resolv_constant($4);
+	if (Pike_sp[-1].type == T_OBJECT) {
+	  o = Pike_sp[-1].u.object;
+	  push_string($2->u.sval.u.string);
+	  push_int(Pike_compiler->new_program->id);
+	  push_int(Pike_compiler->new_program->facet_class);
+	  safe_apply_low3(o, find_identifier("add_facet_class",o->prog), 3,
+			  "Failed to add facet class to system");
+	  if (Pike_sp[-1].type == T_INT &&
+	      Pike_sp[-1].u.integer >= 0) {
+	    Pike_compiler->new_program->facet_class = PROGRAM_IS_FACET_CLASS;
+	    Pike_compiler->new_program->facet_index = Pike_sp[-1].u.integer;
+	    add_ref(Pike_compiler->new_program->facet_group = o);
+	  }
+	  else
+	    yyerror("Could not add facet class to system.");
+	  pop_n_elems(2);
+	}
+	else
+	  yyerror("Illegal facet group specifier.");
+	free_node($4);
+      }
+    }
+  }
+  ;
+
+
 inherit_ref:
   {
     SET_FORCE_RESOLVE($<number>$);
@@ -451,6 +488,28 @@ inheritance: modifiers TOK_INHERIT inherit_ref optional_rename_inherit ';'
       if($4) s=$4->u.sval.u.string;
       compiler_do_inherit($3,$1,s);
     }
+
+    /* If this is a product class, check that all product classes in its
+     * facet-group inherits from all facets */
+    if($3 && Pike_compiler->compiler_pass == 2) {
+      if (Pike_compiler->new_program->facet_class==PROGRAM_IS_PRODUCT_CLASS){
+	if (!Pike_compiler->new_program->facet_group)
+	  yyerror("Invalid facet group.");
+	apply(Pike_compiler->new_program->facet_group,
+	      "product_classes_checked", 0);
+	if (Pike_sp[-1].type == T_INT &&
+	    Pike_sp[-1].u.integer == 0) {
+	  pop_stack();
+	  safe_apply_low3(Pike_compiler->new_program->facet_group,
+			  find_identifier
+			  ("check_product_classes",
+			   Pike_compiler->new_program->facet_group->prog),
+			  0,
+			  "Error in some product classes");
+	}
+      }
+    }
+
     if($4) free_node($4);
     pop_stack();
     if ($3) free_node($3);
@@ -928,6 +987,7 @@ def: modifiers type_or_error optional_stars TOK_IDENTIFIER push_compiler_frame0
   }
   | modifiers type_or_error name_list ';' {}
   | inheritance {}
+  | facet {}
   | import {}
   | constant {}
   | class { free_node($1); }
@@ -1081,6 +1141,7 @@ magic_identifiers3:
   | TOK_CONSTANT   { $$ = "constant"; }
   | TOK_CONTINUE   { $$ = "continue"; }
   | TOK_DEFAULT    { $$ = "default"; }
+  | TOK_FACET      { $$ = "facet"; }
   | TOK_IMPORT     { $$ = "import"; }
   | TOK_INHERIT    { $$ = "inherit"; }
   | TOK_LAMBDA     { $$ = "lambda"; }
@@ -3860,6 +3921,8 @@ bad_expr_ident:
   { yyerror("return is a reserved word."); }
   | TOK_IMPORT
   { yyerror("import is a reserved word."); }
+  | TOK_FACET
+  { yyerror("facet is a reserved word."); }
   | TOK_INHERIT
   { yyerror("inherit is a reserved word."); }
   | TOK_CATCH
diff --git a/src/lexer.h b/src/lexer.h
index 44fdb6759e..ab69c94991 100644
--- a/src/lexer.h
+++ b/src/lexer.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: lexer.h,v 1.49 2004/06/30 00:17:42 nilsson Exp $
+|| $Id: lexer.h,v 1.50 2004/10/22 23:24:15 nilsson Exp $
 */
 
 /*
@@ -376,6 +376,9 @@ static int low_yylex(YYSTYPE *yylval)
 	case TWO_CHAR('e','x'):
 	  if(ISWORD("extern")) return TOK_EXTERN;
 	  break;
+	case TWO_CHAR('f','a'):
+	  if(ISWORD("facet")) return TOK_FACET;
+	  break;
 	case TWO_CHAR('f','i'):
 	  if(ISWORD("final")) return TOK_FINAL_ID;
 	  break;
diff --git a/src/main.c b/src/main.c
index 3f7ad22846..da488bab0e 100644
--- a/src/main.c
+++ b/src/main.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: main.c,v 1.214 2004/10/14 11:07:44 grubba Exp $
+|| $Id: main.c,v 1.215 2004/10/22 23:24:28 nilsson Exp $
 */
 
 #include "global.h"
@@ -918,6 +918,7 @@ DECLSPEC(noreturn) void pike_do_exit(int num) ATTRIBUTE((noreturn))
 void low_init_main(void)
 {
   void init_iterators(void);
+  void init_facetgroup(void);
 
   init_cpp();
   init_backend();
@@ -933,6 +934,7 @@ void low_init_main(void)
   init_builtin_efuns();
   init_signals();
   init_dynamic_load();
+  init_facetgroup();
 }
 
 void exit_main(void)
@@ -972,6 +974,7 @@ void low_exit_main(void)
 {
 #ifdef DO_PIKE_CLEANUP
   void exit_iterators(void);
+  void exit_facetgroup(void);
 
   /* Clear various global references. */
 
@@ -988,6 +991,7 @@ void low_exit_main(void)
   cleanup_module_support();
   exit_operators();
   exit_iterators();
+  exit_facetgroup();
   cleanup_program();
   cleanup_compiler();
   cleanup_error();
diff --git a/src/program.c b/src/program.c
index 903332d314..89b97c4493 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.571 2004/10/22 20:18:03 grubba Exp $
+|| $Id: program.c,v 1.572 2004/10/22 23:24:49 nilsson Exp $
 */
 
 #include "global.h"
@@ -2052,6 +2052,12 @@ void low_start_new_program(struct program *p,
   int id=0;
   struct svalue tmp;
 
+  if(Pike_compiler->compiler_pass == 1 && p) {
+    p->facet_class = 0;
+    p->facet_index = -1;
+    p->facet_group = NULL;
+  }
+
 #if 0
 #ifdef SHARED_NODES
   if (!node_hash.table) {
@@ -3587,6 +3593,53 @@ static int find_depth(struct program_state *state,
 }
 #endif
 
+void check_for_facet_inherit(struct program *p)
+{
+  int fid;
+  /* If the inherit statement comes before the facet keyword in the
+   * class declaration the class will be temporarily marked as a
+   * product-class, but this will be taken care of when the facet
+   * keyword is found. */
+  if (p && Pike_compiler->new_program->facet_group &&
+      p->facet_group != Pike_compiler->new_program->facet_group)
+    yyerror("A class can not belong to two facet-groups\n");
+  if (p && p->facet_class == PROGRAM_IS_FACET_CLASS) {
+    if (Pike_compiler->new_program->facet_class == PROGRAM_IS_FACET_CLASS) {
+      if(Pike_compiler->new_program->facet_index != p->facet_index)
+	yyerror("Facet class can't inherit from class in different facet.");
+    }
+    /* Otherwise this is a product class */
+    else {
+      int line = 0;
+      Pike_compiler->new_program->facet_class = PROGRAM_IS_PRODUCT_CLASS;
+      Pike_compiler->new_program->facet_group = p->facet_group;
+      push_int(Pike_compiler->new_program->id);
+      push_int(p->facet_index);
+      push_int(p->id);
+      safe_apply_low3(p->facet_group,
+		      find_identifier("add_product_class",
+				      p->facet_group->prog),
+		      3,
+		      "Unable to add product class");
+    }
+  }
+  /* The inherited class is not a facet class */
+  else if (p && p->facet_class == PROGRAM_IS_PRODUCT_CLASS) {
+    if (Pike_compiler->new_program->facet_class == PROGRAM_IS_FACET_CLASS) {
+      yyerror("Facet class can't inherit from product class.");
+    }
+    else if(Pike_compiler->new_program->facet_class==PROGRAM_IS_PRODUCT_CLASS){
+      yyerror("Product class can't inherit from other prodcut class.");
+    }
+    /* A class that inherits from a product class is also a product class */
+    else if(Pike_compiler->new_program->facet_class!=PROGRAM_IS_FACET_CLASS) {
+      Pike_compiler->new_program->facet_class = PROGRAM_IS_PRODUCT_CLASS;
+      Pike_compiler->new_program->facet_group = p->facet_group;
+    }
+  }
+}
+
+
 /*
  * make this program inherit another program
  */
@@ -3621,6 +3674,9 @@ void low_inherit(struct program *p,
     return;
   }
 
+  /* Check if inherit is a facet inherit. */
+  check_for_facet_inherit(p);
+
   if (p == placeholder_program) {
     yyerror("Trying to inherit placeholder program (resolver problem).");
     return;
diff --git a/src/program.h b/src/program.h
index 664796a3cf..5bbc7299c5 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.211 2004/09/28 23:58:26 mast Exp $
+|| $Id: program.h,v 1.212 2004/10/22 23:24:50 nilsson Exp $
 */
 
 #ifndef PROGRAM_H
@@ -472,6 +472,10 @@ struct pike_trampoline
  * parent object. Only set if PROGRAM_USES_PARENT is. */
 #define PROGRAM_NEEDS_PARENT 0x1000
 
+/* Indicates that the class is a facet or product_class. */
+#define PROGRAM_IS_FACET_CLASS 0x1
+#define PROGRAM_IS_PRODUCT_CLASS 0x2
+
 /* Using define instead of enum allows for ifdefs - Hubbe */
 #define PROG_EVENT_INIT 0
 #define PROG_EVENT_EXIT 1
@@ -539,6 +543,11 @@ struct program
 #include "program_areas.h"
   
   INT16 lfuns[NUM_LFUNS];
+
+  /* Facet related stuff */
+  INT16 facet_class;   /* PROGRAM_IS_X_CLASS (X=FACET/PRODUCT) */
+  INT32 facet_index;   /* Index to the facet this facet class belongs to */
+  struct object *facet_group;
 };
 
 #if 0
-- 
GitLab