diff src/lex.l @ 9476:d9b25c5b8ee5

handle classdef syntax in lexer and parser
author Ryan Rusaw
date Thu, 30 Jul 2009 16:26:39 -0400
parents 25ed2d6aacf6
children
line wrap: on
line diff
--- a/src/lex.l	Thu Jul 30 21:14:04 2009 +0200
+++ b/src/lex.l	Thu Jul 30 16:26:39 2009 -0400
@@ -289,6 +289,8 @@
 static void handle_number (void);
 static int handle_string (char delim);
 static int handle_close_bracket (bool spc_gobbled, int bracket_type);
+static int handle_superclass_identifier (void);
+static int handle_meta_identifier (void);
 static int handle_identifier (void);
 static bool have_continuation (bool trailing_comments_ok = true);
 static bool have_ellipsis_continuation (bool trailing_comments_ok = true);
@@ -690,7 +692,7 @@
       {
 	warning ("block comment open at end of input");
 
-	if ((reading_fcn_file || reading_script_file)
+	if ((reading_fcn_file || reading_script_file || reading_classdef_file)
 	    && ! curr_fcn_file_name.empty ())
 	  warning ("near line %d of file `%s.m'",
 		   input_line_number, curr_fcn_file_name.c_str ());
@@ -714,7 +716,43 @@
   }
 
 %{
-// Function handles.
+// Superclass method identifiers. 
+%}
+
+{IDENT}@{IDENT}{S}* |
+{IDENT}@{IDENT}.{IDENT}{S}* {
+    LEXER_DEBUG ("{IDENT}@{IDENT}{S}*|{IDENT}@{IDENT}.{IDENT}{S}*");
+
+    int id_tok = handle_superclass_identifier ();
+
+    if (id_tok >= 0)
+      {
+        lexer_flags.looking_for_object_index = true;
+
+        COUNT_TOK_AND_RETURN (SUPERCLASSREF);
+      }
+  }
+  
+%{
+// Metaclass query
+%}  
+  
+\?{IDENT}{S}* | 
+\?{IDENT}.{IDENT}{S}* {
+    LEXER_DEBUG ("\?{IDENT}{S}* | \?{IDENT}.{IDENT}{S}*");
+    
+    int id_tok = handle_meta_identifier ();
+
+    if (id_tok >= 0)
+      {
+        lexer_flags.looking_for_object_index = true;
+
+        COUNT_TOK_AND_RETURN (METAQUERY);
+      }
+  }  
+
+%{
+// Function handles and superclass references
 %}
 
 "@" {
@@ -729,6 +767,7 @@
     lexer_flags.at_beginning_of_statement = false;
 
     COUNT_TOK_AND_RETURN ('@');
+      
   }
 
 %{
@@ -874,7 +913,6 @@
 "<<"	{ LEXER_DEBUG ("<<"); XBIN_OP_RETURN (LSHIFT, false, false); }
 ">>"	{ LEXER_DEBUG (">>"); XBIN_OP_RETURN (RSHIFT, false, false); }
 
-
 {NOT} {
     LEXER_DEBUG ("{NOT}");
 
@@ -1065,7 +1103,7 @@
     }
 
   // Can be reset by defining a function.
-  if (! (reading_script_file || reading_fcn_file))
+  if (! (reading_script_file || reading_fcn_file || reading_classdef_file))
     {
       current_input_column = 1;
       input_line_number = command_editor::current_command_number ();
@@ -1075,6 +1113,7 @@
   // input.
   if ((interactive || forced_interactive)
       && ! (reading_fcn_file
+        || reading_classdef_file
 	    || reading_script_file
 	    || get_input_from_eval_string
 	    || input_from_startup_file))
@@ -1417,10 +1456,11 @@
 	  break;
 
 	case end_kw:
-	  if (inside_any_object_index ()
-	      || (lexer_flags.defining_func
-		  && ! (lexer_flags.looking_at_return_list
-			|| lexer_flags.parsed_function_name)))
+	  if (! reading_classdef_file
+	      && (inside_any_object_index ()
+		  || (lexer_flags.defining_func
+		      && ! (lexer_flags.looking_at_return_list
+			    || lexer_flags.parsed_function_name))))
 	    return 0;
 
 	  yylval.tok_val = new token (token::simple_end, l, c);
@@ -1461,6 +1501,26 @@
 	  yylval.tok_val = new token (token::while_end, l, c);
 	  lexer_flags.at_beginning_of_statement = true;
 	  break;
+	  
+	case endclassdef_kw:
+	  yylval.tok_val = new token (token::classdef_end, l, c);
+	  lexer_flags.at_beginning_of_statement = true;
+	  break;
+	  
+	case endevents_kw:
+	  yylval.tok_val = new token (token::events_end, l, c);
+	  lexer_flags.at_beginning_of_statement = true;
+	  break;
+	  
+	case endmethods_kw:
+	  yylval.tok_val = new token (token::methods_end, l, c);
+	  lexer_flags.at_beginning_of_statement = true;
+	  break;
+	  
+	case endproperties_kw:
+	  yylval.tok_val = new token (token::properties_end, l, c);
+	  lexer_flags.at_beginning_of_statement = true;
+	  break;
 
 	case for_kw:
 	case while_kw:
@@ -1485,19 +1545,43 @@
 	  promptflag--;
 	  break;
 
+	case get_kw:
+	case set_kw:  
+	  // 'get' and 'set' are keywords in classdef method
+	  // declarations.
+	  if (! lexer_flags.maybe_classdef_get_set_method)
+	    return 0;
+	  break;
+
+	case properties_kw:
+	case methods_kw:
+	case events_kw:
+	  // 'properties', 'methods' and 'events' are keywords for
+	  // classdef blocks.
+	  if (! lexer_flags.parsing_classdef)
+	    return 0;
+	  // fall through ...
+
+	case classdef_kw:
+	  // 'classdef' is always a keyword.
+	  promptflag--;
+	  break;	  
+
 	case function_kw:
 	  promptflag--;
 
 	  lexer_flags.defining_func = true;
 	  lexer_flags.parsed_function_name = false;
 
-	  if (! (reading_fcn_file || reading_script_file))
+	  if (! (reading_fcn_file || reading_script_file
+		 || reading_classdef_file))
 	    input_line_number = 1;
 	  break;
 
         case magic_file_kw:
 	  {
-	    if ((reading_fcn_file || reading_script_file)
+	    if ((reading_fcn_file || reading_script_file
+		 || reading_classdef_file)
 		&& ! curr_fcn_file_full_name.empty ())
 	      yylval.tok_val = new token (curr_fcn_file_full_name, l, c);
 	    else
@@ -2963,6 +3047,80 @@
   return retval;
 }
 
+static int
+handle_superclass_identifier (void)
+{
+  eat_continuation ();
+
+  std::string pkg;  
+  std::string meth = strip_trailing_whitespace (yytext); 
+  size_t pos = meth.find ("@");
+  std::string cls = meth.substr (pos).substr (1);
+  meth = meth.substr (0, pos - 1);  
+  
+  pos = cls.find (".");
+  if (pos != std::string::npos)
+    {	 
+      pkg = cls.substr (pos).substr (1);
+      cls = cls.substr (0, pos - 1);
+    }
+    
+  int kw_token = (is_keyword_token (meth) || is_keyword_token (cls)
+		  || is_keyword_token (pkg));
+  if (kw_token)
+    {
+      error ("method, class and package names may not be keywords");
+      return LEXICAL_ERROR;
+    }
+ 
+  yylval.tok_val
+    = new token (meth.empty () ? 0 : &(symbol_table::insert (meth)),
+                 cls.empty () ? 0 : &(symbol_table::insert (cls)),
+                 pkg.empty () ? 0 : &(symbol_table::insert (pkg)),
+		 input_line_number, current_input_column);				   
+  token_stack.push (yylval.tok_val);
+  
+  lexer_flags.convert_spaces_to_comma = true;
+  current_input_column += yyleng;
+  
+  return SUPERCLASSREF;
+}
+
+static int
+handle_meta_identifier (void)
+{
+  eat_continuation ();
+
+  std::string pkg;
+  std::string cls = strip_trailing_whitespace (yytext).substr (1);
+  size_t pos = cls.find (".");
+  
+  if (pos != std::string::npos)
+    {	 
+      pkg = cls.substr (pos).substr (1);
+      cls = cls.substr (0, pos - 1);
+    }
+  
+  int kw_token = is_keyword_token (cls) || is_keyword_token (pkg);
+  if (kw_token)
+    {
+       error ("class and package names may not be keywords");
+      return LEXICAL_ERROR;
+    }
+  
+  yylval.tok_val
+    = new token (cls.empty () ? 0 : &(symbol_table::insert (cls)),
+		 pkg.empty () ? 0 : &(symbol_table::insert (pkg)),
+		 input_line_number, current_input_column);
+
+  token_stack.push (yylval.tok_val);
+                   
+  lexer_flags.convert_spaces_to_comma = true;
+  current_input_column += yyleng;
+  
+  return METAQUERY;
+}
+
 // Figure out exactly what kind of token to return when we have seen
 // an identifier.  Handles keywords.  Return -1 if the identifier
 // should be ignored.
@@ -3153,6 +3311,10 @@
   defining_func = false;
   parsed_function_name = false;
   parsing_class_method = false;
+  
+  // Not initially defining a class with classdef.
+  maybe_classdef_get_set_method = false;
+  parsing_classdef = false;
 
   // Not initiallly looking at a function handle.
   looking_at_function_handle = 0;
@@ -3400,6 +3562,14 @@
     case CLOSE_BRACE: std::cerr << "CLOSE_BRACE\n"; break;
     case SCRIPT_FILE: std::cerr << "SCRIPT_FILE\n"; break;
     case FUNCTION_FILE: std::cerr << "FUNCTION_FILE\n"; break;
+    case SUPERCLASSREF: std::cerr << "SUPERCLASSREF\n"; break;
+    case METAQUERY: std::cerr << "METAQUERY\n"; break;
+    case GET: std::cerr << "GET\n"; break;
+    case SET: std::cerr << "SET\n"; break;
+    case PROPERTIES: std::cerr << "PROPERTIES\n"; break;
+    case METHODS: std::cerr << "METHODS\n"; break;
+    case EVENTS: std::cerr << "EVENTS\n"; break;
+    case CLASSDEF: std::cerr << "CLASSDEF\n"; break;
     case '\n': std::cerr << "\\n\n"; break;
     case '\r': std::cerr << "\\r\n"; break;
     case '\t': std::cerr << "TAB\n"; break;