Browse Source

simple methos declaration is parsed

Vladislav Folts 11 năm trước cách đây
mục cha
commit
172ed5fdd6

+ 5 - 3
src/context.js

@@ -248,8 +248,8 @@ exports.QualifiedIdentificator = ChainedContext.extend({
     }
 });
 
-var Identdef = Class.extend({
-    init: function Identdef(id, exported){
+var IdentdefInfo = Class.extend({
+    init: function Context$Identdef(id, exported){
         this.__id = id;
         this.__exported = exported;
     },
@@ -266,7 +266,7 @@ exports.Identdef = ChainedContext.extend({
     handleIdent: function(id){this.__id = id;},
     handleLiteral: function(){this.__export = true;},
     endParse: function(){
-        this.parent().handleIdentdef(new Identdef(this.__id, this.__export));
+        this.parent().handleIdentdef(new IdentdefInfo(this.__id, this.__export));
     }
 });
 
@@ -1898,3 +1898,5 @@ exports.Context = Class.extend({
 });
 
 exports.Chained = ChainedContext;
+exports.getTypeSymbol = getTypeSymbol;
+exports.IdentdefInfo = IdentdefInfo;

+ 49 - 8
src/eberon/eberon_context.js

@@ -1,20 +1,61 @@
 "use strict";
 
 var Context = require("context.js");
+var Errors = require("js/Errors.js");
+var Type = require("type.js");
 
-var MethodId = Context.Chained.extend({
-    init: function EberonContext$MethodId(parent){
+var ProcOrMethodId = Context.Chained.extend({
+    init: function EberonContext$ProcOrMethodId(parent){
         Context.Chained.prototype.init.call(this, parent);
+        this.__maybeTypeId = undefined;
+        this.__type = undefined;
     },
-    handleIdent: function(id){
-
-    },
+    handleIdent: function(id){this.__maybeTypeId = id;},
     handleLiteral: function(){
-
+        var type = Context.getTypeSymbol(this, this.__maybeTypeId);
+        if (!(type instanceof Type.Record))
+            throw new Errors.Error(
+                  "RECORD type expected in method declaration, got '"
+                + type.description() + "'");
+        this.__type = type;
     },
     handleIdentdef: function(id){
-        this.parent().handleIdentdef(id);
+        this.parent().handleMethodOrProc(id, this.__type);
+    }
+});
+
+var ProcOrMethodDecl = Context.ProcDecl.extend({
+    init: function EberonContext$ProcOrMethodDecl(parent){
+        Context.ProcDecl.prototype.init.call(this, parent);
+        this.__boundType = undefined;
+        this.__endingId = undefined;
+    },
+    handleMethodOrProc: function(id, type){
+        this.__boundType = type;
+        Context.ProcDecl.prototype.handleIdentdef.call(
+            this,
+            type ? new Context.IdentdefInfo(type.name() + "." + id.id(), id.exported()) : id
+            );
+    },
+    handleIdent: function(id){
+        if (this.__boundType){
+            if (!this.__endingId)
+                this.__endingId = id + ".";
+            else {
+                Context.ProcDecl.prototype.handleIdent.call(this, this.__endingId + id);
+                this.__endingId = undefined;
+            }
+        }
+        else
+            Context.ProcDecl.prototype.handleIdent.call(this, id);
+    },
+    endParse: function(){
+        if (this.__boundType && this.__endingId)
+            // shoulf throw
+            Context.ProcDecl.prototype.handleIdent.call(this, this.__endingId);
+        Context.ProcDecl.prototype.endParse.call(this);
     }
 });
 
-exports.MethodId = MethodId;
+exports.ProcOrMethodId = ProcOrMethodId;
+exports.ProcOrMethodDecl = ProcOrMethodDecl;

+ 10 - 3
src/eberon/eberon_grammar.js

@@ -9,12 +9,19 @@ var and = Parser.and;
 var context = Parser.context;
 var optional = Parser.optional;
 
+var ident = Grammar.ident;
+
+var methAttributes = optional(and(",", "NEW"));
 var procedureHeading = and("PROCEDURE",
-                           context(and(optional(and(Grammar.ident, ".")), Grammar.identdef), EbContext.MethodId),
-                           context(optional(Grammar.formalParameters), Context.FormalParametersProcDecl));
+                           context(and(optional(and(ident, ".")), Grammar.identdef), EbContext.ProcOrMethodId),
+                           context(optional(Grammar.formalParameters), Context.FormalParametersProcDecl),
+                           methAttributes);
 
 function makeProcedureDeclaration(procedureBody){
-    return Grammar.makeProcedureDeclaration(procedureHeading, procedureBody);
+    return context(and(procedureHeading, ";",
+                       procedureBody,
+                       and(ident, optional(and(".", ident)))),
+                   EbContext.ProcOrMethodDecl);
 }
 
 exports.grammar = Grammar.make(makeProcedureDeclaration);

+ 0 - 7
src/grammar.js

@@ -156,13 +156,6 @@ var procedureType = and("PROCEDURE"
 var strucType = or(arrayType, recordType, pointerType, procedureType);
 var typeDeclaration = context(and(identdef, "=", strucType), Context.TypeDeclaration);
 
-exports.makeProcedureDeclaration = function(procedureHeading, procedureBody){
-    return context(and(procedureHeading, ";",
-                       procedureBody,
-                       ident),
-                   Context.ProcDecl);
-    };
-
 var constantDeclaration = context(and(identdef, "=", constExpression), Context.ConstDecl);
 
 var imprt = and(ident, optional(and(":=", ident)));

+ 4 - 1
src/oberon/oberon_grammar.js

@@ -13,7 +13,10 @@ var procedureHeading = and("PROCEDURE"
                          , context(optional(Grammar.formalParameters), Context.FormalParametersProcDecl));
 
 function makeProcedureDeclaration(procedureBody){
-    return Grammar.makeProcedureDeclaration(procedureHeading, procedureBody);
+    return context(and(procedureHeading, ";",
+                       procedureBody,
+                       Grammar.ident),
+                   Context.ProcDecl);
 }
 
 exports.grammar = Grammar.make(makeProcedureDeclaration);

+ 5 - 13
test/test_unit.js

@@ -1045,18 +1045,6 @@ function makeSuiteForGrammar(grammar){
          "VAR a: ARRAY 10, 5 OF BOOLEAN; BEGIN a[0][0] := TRUE END",
          "VAR a: ARRAY 10, 5 OF BOOLEAN; BEGIN a[0, 0] := TRUE END")
     ),
-"procedure heading": testWithSetup(
-    function(){
-        function innerMakeContext(cx){
-            return new Context.ProcDecl(TestUnitCommon.makeContext());}
-        return setupParser(grammar.procedureHeading, innerMakeContext);
-    },
-    pass("PROCEDURE p",
-         "PROCEDURE p(a1: INTEGER)",
-         "PROCEDURE p(a1, a2: INTEGER; b1: BOOLEAN)"),
-    fail(["PROCEDURE p(a1: INTEGER; a1: BOOLEAN)", "'a1' already declared"],
-         ["PROCEDURE p(p: INTEGER)", "argument 'p' has the same name as procedure"])
-    ),
 "procedure body": testWithGrammar(
     grammar.procedureBody,
     pass("END",
@@ -1088,6 +1076,7 @@ function makeSuiteForGrammar(grammar){
     pass("PROCEDURE p; END p",
          "PROCEDURE p; VAR i: INTEGER; BEGIN i := i + 1 END p",
          "PROCEDURE p(a: INTEGER); BEGIN a := a + 1 END p",
+         "PROCEDURE p(a1, a2: INTEGER); END p",
          "PROCEDURE p; BEGIN p() END p",
          "PROCEDURE p(a: INTEGER); BEGIN p(a) END p",
          "PROCEDURE p(a: INTEGER; b: BOOLEAN); BEGIN p(a, b) END p",
@@ -1100,7 +1089,10 @@ function makeSuiteForGrammar(grammar){
          ["PROCEDURE p(a: INTEGER); BEGIN p(1, 2) END p", "1 argument(s) expected, got 2"],
          ["PROCEDURE p(a: INTEGER; b: BOOLEAN); BEGIN p(b, a) END p",
           "type mismatch for argument 1: 'BOOLEAN' cannot be converted to 'INTEGER'"],
-         ["PROCEDURE p; BEGIN p1() END p", "undeclared identifier: 'p1'"])
+         ["PROCEDURE p; BEGIN p1() END p", "undeclared identifier: 'p1'"],
+         ["PROCEDURE p(a1: INTEGER; a1: BOOLEAN)", "'a1' already declared"],
+         ["PROCEDURE p(p: INTEGER)", "argument 'p' has the same name as procedure"]         
+         )
     ),
 "procedure RETURN": testWithContext(
     context(

+ 12 - 2
test/test_unit_eberon.js

@@ -13,8 +13,18 @@ function testWithContext(context, pass, fail){
 
 exports.suite = {
 "new method declaration": testWithContext(
-    context(grammar.declarationSequence, "TYPE T = RECORD END;"),
+    context(grammar.declarationSequence, "TYPE T = RECORD END; A = ARRAY 1 OF INTEGER;"),
     pass("PROCEDURE T.p(), NEW; END T.p;"),
-    fail()
+    fail(["PROCEDURE TUnk.p(), NEW; END TUnk.p;", "undeclared identifier: 'TUnk'"],
+         ["PROCEDURE A.p(), NEW; END A.p;",
+          "RECORD type expected in method declaration, got 'ARRAY 1 OF INTEGER'"],
+         ["PROCEDURE T.p(), NEW; END;", "not parsed"],
+         ["PROCEDURE T.p(), NEW; END p;",
+          "mismatched procedure names: 'T.p' at the begining and 'p.' at the end"],
+         ["PROCEDURE T.p(), NEW; END T2.p;",
+          "mismatched procedure names: 'T.p' at the begining and 'T2.p' at the end"],
+         ["PROCEDURE T.p(), NEW; END T.p2;",
+          "mismatched procedure names: 'T.p' at the begining and 'T.p2' at the end"]
+         )
     )
 };