Index: dtype.c
===================================================================
RCS file: /home/danw/nawm/repository/nawm/dtype.c,v
retrieving revision 1.3
diff -c -r1.3 dtype.c
*** dtype.c	1999/11/26 20:32:54	1.3
--- dtype.c	1999/11/27 15:53:04
***************
*** 24,36 ****
  
  void inittypes(void)
  {
!   nexttag = 5;
    typenames = xmalloc(nexttag * sizeof(char *));
    typenames[0] = "void";
    typenames[T_INT] = "int";
    typenames[T_STR] = "string";
    typenames[T_WIN] = "window";
-   typenames[T_ARRAY] = NULL;
  }
  
  int newtype(char *name)
--- 24,36 ----
  
  void inittypes(void)
  {
!   nexttag = T_NEXT;
    typenames = xmalloc(nexttag * sizeof(char *));
+   memset(typenames, 0, nexttag * sizeof(char *));
    typenames[0] = "void";
    typenames[T_INT] = "int";
    typenames[T_STR] = "string";
    typenames[T_WIN] = "window";
  }
  
  int newtype(char *name)
***************
*** 66,71 ****
--- 66,73 ----
  }
  
  
+ /* Typecasts */
+ 
  static int ncasts, castssize;
  struct cast {
    dtype from, to;
***************
*** 94,97 ****
--- 96,128 ----
  	return casts[i].func;
      }
    return NULL;
+ }
+ 
+ 
+ /* Class/struct types */
+ 
+ int scopessize;
+ lexscope **scopes; 
+ 
+ void define_dtype_scope(dtype type, lexscope *scope)
+ {
+   if (type >= scopessize)
+     {
+       int oldsize = scopessize;
+ 
+       while (type >= scopessize)
+ 	scopessize = 2 * (scopessize + 1);
+       scopes = xrealloc(scopes, scopessize * sizeof(lexscope *));
+       memset(scopes + oldsize, 0, (scopessize - oldsize) * sizeof(lexscope *));
+     }
+ 
+   scopes[type] = scope;
+ }
+ 
+ lexscope *lookup_dtype_scope(dtype type)
+ {
+   if (type < scopessize)
+     return scopes[type];
+   else
+     return NULL;
  }
Index: lang.h
===================================================================
RCS file: /home/danw/nawm/repository/nawm/lang.h,v
retrieving revision 1.25
diff -c -r1.25 lang.h
*** lang.h	1999/11/26 22:03:52	1.25
--- lang.h	1999/11/27 15:48:32
***************
*** 22,27 ****
--- 22,29 ----
  #define T_WIN 2
  #define T_STR 3
  #define T_ARRAY 4
+ #define T_CLASS 5
+ #define T_NEXT 6
  
  #define is_simple_type(t) (t < 4)
  #define is_atomic_type(t) (t < 3)
***************
*** 71,76 ****
--- 73,85 ----
    void *data;
    struct _varbinding *next;
  } varbinding;
+ 
+ typedef struct _lexscope {
+   struct _lexscope *parent;
+   int numvars;
+   varbinding *vars;
+   dtype *vtypes;
+ } lexscope;
  
  typedef struct _arrayiter {
    int ind;
Index: lexer.l
===================================================================
RCS file: /home/danw/nawm/repository/nawm/lexer.l,v
retrieving revision 1.31
diff -c -r1.31 lexer.l
*** lexer.l	1999/11/26 22:03:53	1.31
--- lexer.l	1999/11/28 02:23:22
***************
*** 43,54 ****
  
  int kind, lineno;
  
- typedef struct _lexscope {
-   struct _lexscope *parent;
-   int numvars;
-   varbinding *vars;
-   dtype *vtypes;
- } lexscope;
  static lexscope *scopestack;
  
  %}
--- 43,48 ----
***************
*** 65,70 ****
--- 59,67 ----
  
  mode			{ return MODE; }
  
+ class			{ return CLASS; }
+ new			{ return NEW; }
+ 
  int			{ yylval.i = T_INT; return DTYPE; }
  string			{ yylval.i = T_STR; return DTYPE; }
  window			{ yylval.i = T_WIN; return DTYPE; }
***************
*** 90,104 ****
  return			{ return RETURN; }
  del			{ return DEL; }
  
! [A-Za-z_][A-Za-z_0-9]*	{ yylval.n = lookup(yytext, &kind, 0);
! 			  if (yylval.n)
! 			    return kind;
! 			  else
! 			    {
! 			      yylval.s = xstrdup(yytext);
! 			      return SYM;
! 			    }
! 			}
  [0-9]+			{ yylval.i = atoi(yytext); return NUM; }
  \"([^"\\]|\\.)*\"	{ yylval.s = process_string(yytext); return STR; }
  
--- 87,93 ----
  return			{ return RETURN; }
  del			{ return DEL; }
  
! [A-Za-z_][A-Za-z_0-9]*	{ yylval.s = xstrdup(yytext); return SYM; }
  [0-9]+			{ yylval.i = atoi(yytext); return NUM; }
  \"([^"\\]|\\.)*\"	{ yylval.s = process_string(yytext); return STR; }
  
***************
*** 127,132 ****
--- 116,122 ----
  "."			{ return '.'; }
  ","			{ return ','; }
  ";"			{ return ';'; }
+ ":"			{ return ':'; }
  
  [ \t]*			{ ; }
  #.*$			{ ; }
***************
*** 365,377 ****
    scopestack->vars = var;
  }
  
! void *lookup(char *name, int *type, int norecurse)
  {
-   lexscope *scope;
    varbinding *b;
    void *ans;
  
!   for (scope = scopestack; scope; scope = scope->parent)
      {
        for (b = scope->vars; b; b = b->next)
  	{
--- 355,366 ----
    scopestack->vars = var;
  }
  
! void *lookup_in_scope(char *name, int *type, lexscope *scope, int norecurse)
  {
    varbinding *b;
    void *ans;
  
!   for (; scope; scope = scope->parent)
      {
        for (b = scope->vars; b; b = b->next)
  	{
***************
*** 385,390 ****
--- 374,384 ----
  	break;
      }
    return NULL;
+ }
+ 
+ void *lookup(char *name, int *type, int norecurse)
+ {
+   return lookup_in_scope(name, type, scopestack, norecurse);
  }
  
  char *nameof(void *data)
Index: parser.y
===================================================================
RCS file: /home/danw/nawm/repository/nawm/parser.y,v
retrieving revision 1.32
diff -c -r1.32 parser.y
*** parser.y	1999/11/26 22:03:54	1.32
--- parser.y	1999/11/28 02:42:46
***************
*** 67,77 ****
    dtype t;
  }
  
! %token <i> MODE INCLUDE OPTION BEGIN_ END COMMAND FUNCTION
  %token <i> KEYPRESS KEYRELEASE BUTTONPRESS BUTTONRELEASE MOTION ENTER LEAVE
  %token <i> IF ELSE FOR IN WHILE DO BREAK CONTINUE RETURN DEL
  %token <i> ASSIGNOP ADDOP MULTOP COMPOP BOOLOP UNOP SUBSCRIPT ELEMENT
! %token <i> '(' ')' '[' ']' '{' '}' ',' ';' '.'
  %token <i> NUM DTYPE
  %token <v> VAR
  %token <f> FUN CMD
--- 67,77 ----
    dtype t;
  }
  
! %token <i> MODE INCLUDE OPTION BEGIN_ END COMMAND FUNCTION CLASS NEW
  %token <i> KEYPRESS KEYRELEASE BUTTONPRESS BUTTONRELEASE MOTION ENTER LEAVE
  %token <i> IF ELSE FOR IN WHILE DO BREAK CONTINUE RETURN DEL
  %token <i> ASSIGNOP ADDOP MULTOP COMPOP BOOLOP UNOP SUBSCRIPT ELEMENT
! %token <i> '(' ')' '[' ']' '{' '}' ',' ';' ':' '.'
  %token <i> NUM DTYPE
  %token <v> VAR
  %token <f> FUN CMD
***************
*** 82,90 ****
  %type <n> bool_expr comp_expr memb_expr add_expr mult_expr unary_expr
  %type <n> primary_expr lvalue subscript_expr
  %type <i> key button
! %type <t> type primitivetype
  %type <b> binddecl modebody
! %type <s> opt_string sym
  
  %%
  nawmrc		: decls
--- 82,90 ----
  %type <n> bool_expr comp_expr memb_expr add_expr mult_expr unary_expr
  %type <n> primary_expr lvalue subscript_expr
  %type <i> key button
! %type <t> type primitivetype parenttype
  %type <b> binddecl modebody
! %type <s> opt_string
  
  %%
  nawmrc		: decls
***************
*** 98,103 ****
--- 98,104 ----
  
  decl		: specdecl
  		| modedecl
+ 		| classdecl
  		| vardecl
  		| fundecl
  		| binddecl									{ add_to_anymode($1); }
***************
*** 130,143 ****
  primitivetype	: DTYPE										{ $$ = (dtype)$1; }
  		;
  
! sym		: SYM
! 		| VAR										{ $$ = xstrdup(yytext); }
! 		| FUN										{ $$ = xstrdup(yytext); }
! 		| CMD										{ $$ = xstrdup(yytext); }
! 		;
! 
! syms1		: sym										{ $$ = mknode(0, 0, 1, $1); }
! 		| syms1 ',' sym									{ tmp = mknode(0, 0, 1, $3); $$ = chain(tmp, $1); }
  		| error										{ die("while looking for a symbol name."); }
  		;
  
--- 131,138 ----
  primitivetype	: DTYPE										{ $$ = (dtype)$1; }
  		;
  
! syms1		: SYM										{ $$ = mknode(0, 0, 1, $1); }
! 		| syms1 ',' SYM									{ tmp = mknode(0, 0, 1, $3); $$ = chain(tmp, $1); }
  		| error										{ die("while looking for a symbol name."); }
  		;
  
***************
*** 145,150 ****
--- 140,157 ----
  		| syms1										{ $$ = $1; }
  		;
  
+ classdecl	: CLASS SYM parenttype '{' classbody '}'					{ defclass($2, $3); }
+ 		;
+ 
+ parenttype	: 										{ $$ = 0; }
+ 		| ':' DTYPE									{ $$ = $2; }
+ 		;
+ 
+ classbody	:
+ 		| classbody vardecl
+ 		| classbody fundecl
+ 		;
+ 
  fundecl		: COMMAND SYM syms { start_fundecl(0, $2); pushlexscope(1); } '{' vardecls commands '}'		 	  							{ finish_fundecl($2, $3, reverse($7)); }
  		| FUNCTION type SYM '(' syms ')' { start_fundecl($2, $3); pushlexscope(1); } '{' vardecls commands '}'								{ finish_fundecl($3, $5, reverse($10)); }
  		;
***************
*** 184,190 ****
  		| commands1 command								{ $$ = chain($2, $1); }
  		;
  
! command		: CMD exprs ';'									{ $$ = apply_check(CMD, $1, $2); }
  		| IF '(' expr ')' command							{ $$ = mknode(IF, 0, 3, typecheck($3, T_INT), $5, NULL); }
  		| IF '(' expr ')' command ELSE command 						{ $$ = mknode(IF, 0, 3, typecheck($3, T_INT), $5, $7); }
  		| FOR '(' forexpr ')' command							{ $$ = mknode(FOR, 0, 2, $3, $5); }
--- 191,197 ----
  		| commands1 command								{ $$ = chain($2, $1); }
  		;
  
! command		: SYM exprs ';'									{ $$ = apply_check(CMD, $1, $2); }
  		| IF '(' expr ')' command							{ $$ = mknode(IF, 0, 3, typecheck($3, T_INT), $5, NULL); }
  		| IF '(' expr ')' command ELSE command 						{ $$ = mknode(IF, 0, 3, typecheck($3, T_INT), $5, $7); }
  		| FOR '(' forexpr ')' command							{ $$ = mknode(FOR, 0, 2, $3, $5); }
***************
*** 199,205 ****
  		| error ';'									{ die("while parsing commands."); }
  		;
  
! forexpr		: VAR IN expr									{ arraycheck($3); $$ = mknode(IN, 0, 2, typecheck(mknode(VAR, $1->type, 1, $1), array_basetype($3->etype)), $3); }
  		| expr ';' expr ';' expr							{ $$ = mknode(FOR, 0, 3, $1, typecheck($3, T_INT), $5); }
  		;
  
--- 206,212 ----
  		| error ';'									{ die("while parsing commands."); }
  		;
  
! forexpr		: SYM IN expr									{ arraycheck($3); $$ = mknode(IN, 0, 2, typecheck(lookup_var($1), array_basetype($3->etype)), $3); }
  		| expr ';' expr ';' expr							{ $$ = mknode(FOR, 0, 3, $1, typecheck($3, T_INT), $5); }
  		;
  
***************
*** 220,227 ****
  		| lvalue ASSIGNOP expr								{ $$ = mknode($2, $1->etype, 2, $1, typecheck($3, $1->etype)); }
  		;
  
! lvalue		: VAR										{ $$ = mknode(VAR, $1->type, 1, $1); }
  		| subscript_expr '[' expr ']'							{ arraycheck($1); $$ = mknode(SUBSCRIPT, array_basetype($1->etype), 2, $1, typecheck($3, array_subtype($1->etype))); }
  		;
  
  bool_expr	: comp_expr
--- 227,235 ----
  		| lvalue ASSIGNOP expr								{ $$ = mknode($2, $1->etype, 2, $1, typecheck($3, $1->etype)); }
  		;
  
! lvalue		: SYM										{ $$ = lookup_var($1); }
  		| subscript_expr '[' expr ']'							{ arraycheck($1); $$ = mknode(SUBSCRIPT, array_basetype($1->etype), 2, $1, typecheck($3, array_subtype($1->etype))); }
+ 		| subscript_expr '.' SYM							{ $$ = lookup_sym($1->etype, $3); }
  		;
  
  bool_expr	: comp_expr
***************
*** 250,262 ****
  
  subscript_expr	: primary_expr
  		| subscript_expr '[' expr ']'							{ arraycheck($1); $$ = mknode(SUBSCRIPT, array_basetype($1->etype), 2, $1, typecheck($3, array_subtype($1->etype))); }
! 		| subscript_expr '.' sym							{ arraycheck($1); $$ = mknode(ELEMENT, T_INT, 2, $1, $3); }
  		;
  
  primary_expr	: NUM										{ $$ = mknode(NUM, T_INT, 1, $1); }
  		| STR										{ $$ = mknode(STR, T_STR, 1, $1); }
! 		| VAR										{ $$ = mknode(VAR, $1->type, 1, $1); }
! 		| FUN opt_args									{ $$ = apply_check(FUN, $1, $2); }
  		| '(' expr ')'									{ $$ = $2; }
  		;
  
--- 258,270 ----
  
  subscript_expr	: primary_expr
  		| subscript_expr '[' expr ']'							{ arraycheck($1); $$ = mknode(SUBSCRIPT, array_basetype($1->etype), 2, $1, typecheck($3, array_subtype($1->etype))); }
! 		| subscript_expr '.' SYM							{ $$ = lookup_sym($1->etype, $3); }
! 		| subscript_expr '(' exprs ')							{ $$ = apply_check(FUN, $1, $3); }
  		;
  
  primary_expr	: NUM										{ $$ = mknode(NUM, T_INT, 1, $1); }
  		| STR										{ $$ = mknode(STR, T_STR, 1, $1); }
! 		| SYM										{ $$ = lookup_sym(0, $1); }
  		| '(' expr ')'									{ $$ = $2; }
  		;
  
***************
*** 509,514 ****
--- 517,553 ----
        die("Type mismatch: expected array type, got %s, at line %d.",
  	  typename(array->etype), lineno);
      }
+ }
+ 
+ static node *lookup_sym(dtype scopetype, char *name)
+ {
+   int type;
+   void *data;
+ 
+   if (scopetype)
+     data = lookup_in_scope(name, &type, lookup_dtype_scope(scopetype), 0);
+   else
+     data = lookup(name, &type, 0);
+ 
+   if (!data)
+     die("Undefined symbol \"%s\" at line %d.", name, lineno);
+   free(name);
+ 
+   if (type == VAR)
+     return mknode(VAR, ((variable *)data)->etype, 1, data);
+   else
+     return mknode(type, type, 1, data);
+ }
+ 
+ static node *lookup_var(char *name)
+ {
+   node *n = lookup_sym(0, name);
+   if (n->type != VAR)
+     {
+       die("Symbol \"%s\" is wrong type: expected variable, "
+ 	  "got function at line %d.", name);
+     }
+   return n;
  }
  
  static void parse_error(char *error)
