2
0
Vladislav Folts 11 жил өмнө
parent
commit
1144440c93

+ 3 - 2
src/context.js

@@ -98,6 +98,7 @@ function checkTypeCast(from, to, msg){
 var ChainedContext = Class.extend({
     init: function ChainedContext(parent){this.__parent = parent;},
     parent: function(){return this.__parent;},
+    handleMessage: function(msg){return this.__parent.handleMessage(msg);},
     codeGenerator: function(){return this.__parent.codeGenerator();},
     findSymbol: function(id){return this.__parent.findSymbol(id);},
     currentScope: function(s){return this.__parent.currentScope();},
@@ -1673,8 +1674,8 @@ exports.RecordDecl = ChainedContext.extend({
         var gen = this.codeGenerator();
         var qualifiedBase = baseType ? this.qualifyScope(baseType.scope()) + baseType.name() : undefined; 
         gen.write((baseType ? qualifiedBase + ".extend" 
-						    : this.rtl().extendId())
-			   + "(");
+                            : this.rtl().extendId())
+                + "(");
         gen.openScope();
         gen.write("init: function " + this.__type.cons() + "()");
         gen.openScope();

+ 27 - 8
src/eberon/eberon_context.js

@@ -3,6 +3,7 @@
 var Cast = require("cast.js");
 var Context = require("context.js");
 var Errors = require("js/Errors.js");
+var Symbol = require("symbol.js");
 var Type = require("type.js");
 
 var MethodType = Type.Procedure.extend({
@@ -35,18 +36,33 @@ var ProcOrMethodId = Context.Chained.extend({
     }
 });
 
+function getMethodSelf(){}
+
+var Designator = Context.Designator.extend({
+    init: function EberonContext$Designator(parent){
+        Context.Designator.prototype.init.call(this, parent);
+    },
+    handleLiteral: function(s){
+        if (s == "SELF")
+            this.handleSymbol(new Symbol.Found(this.handleMessage(getMethodSelf)), "this");
+        else
+            Context.Designator.prototype.handleLiteral.call(this, s);
+    }
+});
+
 var ProcOrMethodDecl = Context.ProcDecl.extend({
     init: function EberonContext$ProcOrMethodDecl(parent){
         Context.ProcDecl.prototype.init.call(this, parent);
-        this.__boundType = undefined;
+        this.__selfSymbol = undefined;
         this.__methodId = undefined;
         this.__methodType = undefined;
         this.__isNew = undefined;
         this.__endingId = undefined;
     },
+    handleMessage: function(msg){return this.__selfSymbol;},
     handleMethodOrProc: function(id, type){
         if (type){
-            this.__boundType = type;
+            this.__selfSymbol = new Symbol.Symbol("SELF", type);
             this.__methodId = id;
         }
 
@@ -64,7 +80,8 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
     handleLiteral: function(s){
         if (s == "NEW"){
             var id = this.__methodId.id();
-            var existingField = this.__boundType.findSymbol(id);
+            var boundType = this.__selfSymbol.info();
+            var existingField = boundType.findSymbol(id);
             if (existingField)
                 throw new Errors.Error(
                       existingField instanceof MethodType
@@ -72,12 +89,12 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
                       + "' (unwanted NEW attribute?)"
                     : "cannot declare method, record already has field '" + id + "'");
 
-            this.__boundType.addField(this.__methodId, this.__methodType);
+            boundType.addField(this.__methodId, this.__methodType);
             this.__isNew = true;
         }
     },
     handleIdent: function(id){
-        if (this.__boundType){
+        if (this.__selfSymbol){
             if (!this.__endingId)
                 this.__endingId = id + ".";
             else {
@@ -89,20 +106,21 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
             Context.ProcDecl.prototype.handleIdent.call(this, id);
     },
     endParse: function(){
-        if (this.__boundType){
+        if (this.__selfSymbol){
             if (this.__endingId)
                 // should throw
                 Context.ProcDecl.prototype.handleIdent.call(this, this.__endingId);
 
             if (!this.__isNew){
-                var base = this.__boundType.baseType();
+                var boundType = this.__selfSymbol.info();
+                var base = boundType.baseType();
                 var id = this.__methodId.id();
                 var existing = base ? base.findSymbol(id) : undefined;
                 if (!existing){
                     throw new Errors.Error(
                           "there is no method '" + id 
                         + "' to override in base type(s) of '" 
-                        + this.__boundType.name() + "' (NEW attribute is missed?)");
+                        + boundType.name() + "' (NEW attribute is missed?)");
                 }
                 if (!Cast.areProceduresMatch(existing, this.__methodType))
                     throw new Errors.Error(
@@ -115,5 +133,6 @@ var ProcOrMethodDecl = Context.ProcDecl.extend({
     }
 });
 
+exports.Designator = Designator;
 exports.ProcOrMethodId = ProcOrMethodId;
 exports.ProcOrMethodDecl = ProcOrMethodDecl;

+ 17 - 7
src/eberon/eberon_grammar.js

@@ -8,21 +8,31 @@ var Parser = require("parser.js");
 var and = Parser.and;
 var context = Parser.context;
 var optional = Parser.optional;
+var or = Parser.or;
+var repeat = Parser.repeat;
 
 var ident = Grammar.ident;
 
 var methAttributes = optional(and(",", "NEW"));
-var procedureHeading = and("PROCEDURE",
-                           context(and(optional(and(ident, ".")), Grammar.identdef), EbContext.ProcOrMethodId),
-                           context(optional(Grammar.formalParameters), Context.FormalParametersProcDecl),
-                           methAttributes);
 
-function makeProcedureDeclaration(procedureBody){
+function makeProcedureHeading(formalParameters){
+    return and("PROCEDURE",
+               context(and(optional(and(ident, ".")), Grammar.identdef), EbContext.ProcOrMethodId),
+               context(optional(formalParameters), Context.FormalParametersProcDecl),
+               methAttributes);
+}
+
+function makeDesignator(selector){
+    return context(
+        and(or("SELF", Grammar.qualident), repeat(selector)), EbContext.Designator);
+}
+
+function makeProcedureDeclaration(formalParameters, procedureBody){
+    var procedureHeading = makeProcedureHeading(formalParameters);
     return context(and(procedureHeading, ";",
                        procedureBody,
                        and(ident, optional(and(".", ident)))),
                    EbContext.ProcOrMethodDecl);
 }
 
-exports.grammar = Grammar.make(makeProcedureDeclaration);
-exports.grammar.procedureHeading = procedureHeading;
+exports.grammar = Grammar.make(makeDesignator, makeProcedureDeclaration);

+ 37 - 33
src/grammar.js

@@ -25,13 +25,16 @@ var qualident = context(and(optional(and(ident, ".")), ident),
                         Context.QualifiedIdentificator);
 var identdef = context(and(ident, optional("*")),
                        Context.Identdef);
+
+function make(makeDesignator, makeProcedureDeclaration){
+
 var selector = or(and(point, ident)
                 // break recursive declaration of expList
                 , and("[", function(stream, context){return expList(stream, context);}, "]")
                 , "^"
                 , context(and("(", qualident, ")"), Context.TypeCast)
                 );
-var designator = context(and(qualident, repeat(selector)), Context.Designator);
+var designator = makeDesignator(selector);
 var type = or(context(qualident, Context.Type),
               function(stream, context){return strucType(stream, context);} // break recursive declaration of strucType
              );
@@ -64,6 +67,7 @@ var factor = context(
                     return factor(stream, context);}) // break recursive declaration of factor
      )
     , Context.Factor);
+
 var addOperator = context(or("+", "-", "OR"), Context.AddOperator);
 var mulOperator = context(or("*", "/", "DIV", "MOD", "&"), Context.MulOperator);
 var term = context(and(factor, repeat(and(mulOperator, factor))), Context.Term);
@@ -161,39 +165,39 @@ var constantDeclaration = context(and(identdef, "=", constExpression), Context.C
 var imprt = and(ident, optional(and(":=", ident)));
 var importList = and("IMPORT", imprt, repeat(and(",", imprt)));
 
-function make(makeProcedureDeclaration){
-    var result = {};
-    result.procedureDeclaration
-        // break recursive declaration of procedureBody
-        = makeProcedureDeclaration(
-            function(stream, context){
-                return result.procedureBody(stream, context);}
-        );
-    result.declarationSequence
-        = and(optional(and("CONST", repeat(and(constantDeclaration, required(";"))))),
-              optional(and("TYPE", context(repeat(and(typeDeclaration, required(";"))), Context.TypeSection))),
-              optional(and("VAR", repeat(and(variableDeclaration, required(";"))))),
-              repeat(and(result.procedureDeclaration, ";")));
-    result.procedureBody
-        = and(result.declarationSequence,
-              optional(and("BEGIN", statementSequence)),
-              optional(context(and("RETURN", expression), Context.Return)),
-              required("END", "END expected (PROCEDURE)"));
-    result.module
-        = context(and("MODULE", ident, ";",
-                      context(optional(and(importList, ";")), Context.ModuleImport),
-                      result.declarationSequence,
-                      optional(and("BEGIN", statementSequence)),
-                      required("END", "END expected (MODULE)"), ident, point),
-                  Context.ModuleDeclaration);
-    return result;
-    }
+var result = {};
+result.expression = expression;
+result.statement = statement;
+result.typeDeclaration = typeDeclaration;
+result.variableDeclaration = variableDeclaration;
+result.procedureDeclaration
+    // break recursive declaration of procedureBody
+    = makeProcedureDeclaration(
+        formalParameters,
+        function(stream, context){
+            return result.procedureBody(stream, context);}
+    );
+result.declarationSequence
+    = and(optional(and("CONST", repeat(and(constantDeclaration, required(";"))))),
+          optional(and("TYPE", context(repeat(and(typeDeclaration, required(";"))), Context.TypeSection))),
+          optional(and("VAR", repeat(and(variableDeclaration, required(";"))))),
+          repeat(and(result.procedureDeclaration, ";")));
+result.procedureBody
+    = and(result.declarationSequence,
+          optional(and("BEGIN", statementSequence)),
+          optional(context(and("RETURN", expression), Context.Return)),
+          required("END", "END expected (PROCEDURE)"));
+result.module
+    = context(and("MODULE", ident, ";",
+                  context(optional(and(importList, ";")), Context.ModuleImport),
+                  result.declarationSequence,
+                  optional(and("BEGIN", statementSequence)),
+                  required("END", "END expected (MODULE)"), ident, point),
+              Context.ModuleDeclaration);
+return result;
+}
 
 exports.make = make;
-exports.expression = expression;
-exports.formalParameters = formalParameters;
 exports.ident = ident;
 exports.identdef = identdef;
-exports.statement = statement;
-exports.typeDeclaration = typeDeclaration;
-exports.variableDeclaration = variableDeclaration;
+exports.qualident = qualident;

+ 14 - 6
src/oberon/oberon_grammar.js

@@ -7,18 +7,26 @@ var Parser = require("parser.js");
 var and = Parser.and;
 var context = Parser.context;
 var optional = Parser.optional;
+var repeat = Parser.repeat;
 
-var procedureHeading = and("PROCEDURE"
-                         , Grammar.identdef
-                         , context(optional(Grammar.formalParameters), Context.FormalParametersProcDecl));
+function makeProcedureHeading(formalParameters){
+    return and("PROCEDURE"
+             , Grammar.identdef
+             , context(optional(formalParameters), Context.FormalParametersProcDecl));
+}
+
+function makeDesignator(selector){
+    return context(and(Grammar.qualident, repeat(selector)), Context.Designator);
+}
 
-function makeProcedureDeclaration(procedureBody){
+function makeProcedureDeclaration(formalParameters, procedureBody){
+    var procedureHeading = makeProcedureHeading(formalParameters);
     return context(and(procedureHeading, ";",
                        procedureBody,
                        Grammar.ident),
                    Context.ProcDecl);
 }
 
-exports.grammar = Grammar.make(makeProcedureDeclaration);
-exports.grammar.procedureHeading = procedureHeading;
+exports.grammar = Grammar.make(makeDesignator, makeProcedureDeclaration);
+//exports.grammar.procedureHeading = procedureHeading;
 

+ 62 - 66
test/test_unit.js

@@ -26,9 +26,10 @@ function testWithModule(src, pass, fail){
     return TestUnitCommon.testWithModule(src, oberonGrammar, pass, fail);
 }
 
-var testSuite = {
+function makeSuiteForGrammar(grammar){
+return {
 "comment": testWithGrammar(
-    Grammar.expression,
+    grammar.expression,
     pass("(**)123",
          "(*abc*)123",
          "(*abc*)(*def*)123",
@@ -36,7 +37,7 @@ var testSuite = {
     fail(["(*123", "comment was not closed"])
     ),
 "spaces are required to separate keywords and integers": testWithGrammar(
-    Grammar.typeDeclaration,
+    grammar.typeDeclaration,
     pass(),
     fail(["T = ARRAY10OFARRAY5OFINTEGER", "not parsed"],
          ["T = ARRAY10 OF ARRAY 5 OF INTEGER", "not parsed"],
@@ -47,7 +48,7 @@ var testSuite = {
          ["T = ARRAY 10 OF ARRAY 5 OFINTEGER", "not parsed"])
     ),
 "expression": testWithContext(
-    context(Grammar.expression,
+    context(grammar.expression,
             "TYPE ProcType = PROCEDURE(): INTEGER;"
             + "PROCEDURE p1(): INTEGER; RETURN 1 END p1;"
             + "PROCEDURE p2(): ProcType; RETURN p1 END p2;"
@@ -67,7 +68,7 @@ var testSuite = {
          )
     ),
 "string expression": testWithGrammar(
-    Grammar.expression,
+    grammar.expression,
     pass("\"\"",
          "\"a\"",
          "\"abc\"",
@@ -81,7 +82,7 @@ var testSuite = {
         )
     ),
 "parentheses": testWithGrammar(
-    Grammar.expression,
+    grammar.expression,
     pass("(1)",
          "(1 + 2)",
          "(1 + 2) * 3",
@@ -106,13 +107,13 @@ var testSuite = {
          )
     ),
 "variable declaration": testWithGrammar(
-    Grammar.variableDeclaration,
+    grammar.variableDeclaration,
     pass("i: INTEGER",
          "i, j: INTEGER"),
     fail(["i: T", "undeclared identifier: 'T'"])
     ),
 "record declaration": testWithGrammar(
-    Grammar.typeDeclaration,
+    grammar.typeDeclaration,
     pass("T = RECORD END",
          "T = RECORD i: INTEGER END",
          "T = RECORD i, j: INTEGER END",
@@ -130,7 +131,7 @@ var testSuite = {
          )
     ),
 "record extension": testWithContext(
-    context(Grammar.typeDeclaration,
+    context(grammar.typeDeclaration,
             "TYPE B = RECORD END;"),
     pass("T = RECORD(B) END"
          ),
@@ -139,7 +140,7 @@ var testSuite = {
          )
     ),
 "array declaration": testWithContext(
-    context(Grammar.typeDeclaration,
+    context(grammar.typeDeclaration,
             "CONST c1 = 5; VAR v1: INTEGER; p: POINTER TO RECORD END;"),
     pass("T = ARRAY 10 OF INTEGER",
          "T = ARRAY 10 OF BOOLEAN",
@@ -163,12 +164,12 @@ var testSuite = {
          )
     ),
 "multi-dimensional array declaration": testWithGrammar(
-    Grammar.typeDeclaration,
+    grammar.typeDeclaration,
     pass("T = ARRAY 10 OF ARRAY 5 OF INTEGER",
          "T = ARRAY 10, 5 OF INTEGER")
     ),
 "PROCEDURE type declaration": testWithGrammar(
-    Grammar.typeDeclaration,
+    grammar.typeDeclaration,
     pass("T = PROCEDURE",
          "T = PROCEDURE()",
          "T = PROCEDURE(a: INTEGER)",
@@ -176,7 +177,7 @@ var testSuite = {
          "T = PROCEDURE(): T")
     ),
 "POINTER declaration": testWithGrammar(
-    Grammar.typeDeclaration,
+    grammar.typeDeclaration,
     pass("T = POINTER TO RECORD END",
          "T = RECORD p: POINTER TO T END",
          "T = POINTER TO RECORD p: T END"),
@@ -189,7 +190,7 @@ var testSuite = {
         )
     ),
 "POINTER dereference": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "TYPE PT = POINTER TO RECORD END;"
             + "VAR pt: PT; p: POINTER TO RECORD field: INTEGER END; i: INTEGER; r: RECORD END;"),
     pass("p^.field := 1",
@@ -200,7 +201,7 @@ var testSuite = {
          ["pt.unknown := 0", "type 'PT' has no 'unknown' field"])
     ),
 "POINTER assignment": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "TYPE Base = RECORD END;"
                 + "Derived = RECORD (Base) END;"
                 + "PDerivedAnonymous = POINTER TO RECORD(Base) END;"
@@ -222,7 +223,7 @@ var testSuite = {
           ["NIL := p1", "not parsed"])
     ),
 "typeguard": testWithContext(
-    context(Grammar.expression,
+    context(grammar.expression,
             "TYPE Base = RECORD END; PBase = POINTER TO Base; Derived = RECORD (Base) END; PDerived = POINTER TO Derived;"
             + "VAR p1, p2: POINTER TO RECORD END; pBase: POINTER TO Base; pDerived: POINTER TO Derived;"
             + "vb: Base; i: INTEGER;"),
@@ -242,7 +243,7 @@ var testSuite = {
           "invalid type cast: a value variable and cannot be used in typeguard"])
     ),
 "POINTER relations": testWithContext(
-    context(Grammar.expression,
+    context(grammar.expression,
             "TYPE B = RECORD END; D = RECORD(B) END;"
           + "VAR p1, p2: POINTER TO RECORD END; pb: POINTER TO B; pd: POINTER TO D;"),
     pass("p1 = p2",
@@ -258,7 +259,7 @@ var testSuite = {
          )
     ),
 "IS expression": testWithContext(
-    context(Grammar.expression,
+    context(grammar.expression,
             "TYPE Base = RECORD END; Derived = RECORD (Base) END; PDerived = POINTER TO Derived;"
             + "VAR p: POINTER TO RECORD END; pBase: POINTER TO Base; pDerived: POINTER TO Derived; vDerived: Derived; i: INTEGER;"),
     pass("pBase IS Derived"),
@@ -276,7 +277,7 @@ var testSuite = {
          ["pDerived IS INTEGER", "RECORD type expected after 'IS'"])
     ),
 "BYTE": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
               "VAR b1, b2: BYTE; i: INTEGER; set: SET; a: ARRAY 3 OF BYTE;"
             + "PROCEDURE varIntParam(VAR i: INTEGER); END varIntParam;"
             + "PROCEDURE varByteParam(VAR b: BYTE); END varByteParam;"
@@ -306,7 +307,7 @@ var testSuite = {
         )
     ),
 "NEW": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "TYPE P = POINTER TO RECORD END;"
             + "VAR p: P; i: INTEGER;"
             + "PROCEDURE proc(): P; RETURN NIL END proc;"
@@ -319,7 +320,7 @@ var testSuite = {
          ["NEW(proc())", "expression cannot be used as VAR parameter"])
     ),
 "ABS": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "VAR i: INTEGER; r: REAL; c: CHAR;"),
     pass("i := ABS(i)",
          "r := ABS(r)"),
@@ -329,21 +330,21 @@ var testSuite = {
          )
     ),
 "FLOOR": testWithContext(
-    context(Grammar.statement, "VAR i: INTEGER; r: REAL;"),
+    context(grammar.statement, "VAR i: INTEGER; r: REAL;"),
     pass("i := FLOOR(r)"),
     fail(["i := FLOOR(i)", "type mismatch for argument 1: 'INTEGER' cannot be converted to 'REAL'"],
          ["i := FLOOR(r, r)", "1 argument(s) expected, got 2"]
          )
     ),
 "FLT": testWithContext(
-    context(Grammar.statement, "VAR i: INTEGER; r: REAL;"),
+    context(grammar.statement, "VAR i: INTEGER; r: REAL;"),
     pass("r := FLT(i)"),
     fail(["r := FLT(r)", "type mismatch for argument 1: 'REAL' cannot be converted to 'INTEGER'"],
          ["i := FLT(i, i)", "1 argument(s) expected, got 2"]
          )
     ),
 "LSL": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "VAR i: INTEGER; r: REAL; c: CHAR;"),
     pass("i := LSL(i, i)"),
     fail(["i := LSL(i, r)", "type mismatch for argument 2: 'REAL' cannot be converted to 'INTEGER'"],
@@ -353,7 +354,7 @@ var testSuite = {
          )
     ),
 "ASR": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "VAR i: INTEGER; r: REAL; c: CHAR;"),
     pass("i := ASR(i, i)"),
     fail(["i := ASR(i, r)", "type mismatch for argument 2: 'REAL' cannot be converted to 'INTEGER'"],
@@ -363,7 +364,7 @@ var testSuite = {
          )
     ),
 "ROR": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "VAR i: INTEGER; r: REAL; c: CHAR;"),
     pass("i := ROR(i, i)"),
     fail(["i := ROR(i, r)", "type mismatch for argument 2: 'REAL' cannot be converted to 'INTEGER'"],
@@ -373,7 +374,7 @@ var testSuite = {
          )
     ),
 "ODD": testWithContext(
-    context(Grammar.statement, "VAR b: BOOLEAN;"),
+    context(grammar.statement, "VAR b: BOOLEAN;"),
     pass("b := ODD(1)",
          "b := ODD(123)"
          ),
@@ -382,7 +383,7 @@ var testSuite = {
          )
 ),
 "ORD": testWithContext(
-    context(Grammar.statement, "VAR ch: CHAR; i: INTEGER; b: BOOLEAN;"),
+    context(grammar.statement, "VAR ch: CHAR; i: INTEGER; b: BOOLEAN;"),
     pass("i := ORD(ch)",
          "i := ORD(TRUE)",
          "i := ORD({1})",
@@ -393,12 +394,12 @@ var testSuite = {
          )
 ),
 "CHR": testWithContext(
-    context(Grammar.statement, "VAR i: INTEGER; ch: CHAR;"),
+    context(grammar.statement, "VAR i: INTEGER; ch: CHAR;"),
     pass("ch := CHR(i)"),
     fail(["ch := CHR(ch)", "type mismatch for argument 1: 'CHAR' cannot be converted to 'INTEGER'"])
 ),
 "INC": testWithContext(
-    context(Grammar.statement, "VAR i: INTEGER;"),
+    context(grammar.statement, "VAR i: INTEGER;"),
     pass("INC(i)",
          "INC(i, 3)",
          "INC(i, i)"),
@@ -408,7 +409,7 @@ var testSuite = {
          )
 ),
 "DEC": testWithContext(
-    context(Grammar.statement, "VAR i: INTEGER;"),
+    context(grammar.statement, "VAR i: INTEGER;"),
     pass("DEC(i)",
          "DEC(i, 3)",
          "DEC(i, i)"),
@@ -418,13 +419,13 @@ var testSuite = {
          )
 ),
 "PACK": testWithContext(
-    context(Grammar.statement, "VAR r: REAL; i: INTEGER;"),
+    context(grammar.statement, "VAR r: REAL; i: INTEGER;"),
     pass("PACK(r, i)",
          "PACK(r, 3)"),
     fail(["PACK(r, r)", "type mismatch for argument 2: 'REAL' cannot be converted to 'INTEGER'"])
 ),
 "UNPACK": testWithContext(
-    context(Grammar.statement, "VAR r: REAL; i: INTEGER;"),
+    context(grammar.statement, "VAR r: REAL; i: INTEGER;"),
     pass("UNPACK(r, i)"),
     fail(["UNPACK(r, r)", "type mismatch for argument 2: 'REAL' cannot be converted to 'INTEGER'"],
          ["UNPACK(r, 3)", "expression cannot be used as VAR parameter"],
@@ -432,12 +433,12 @@ var testSuite = {
          )
 ),
 "standard procedure cannot be referenced" : testWithContext(
-    context(Grammar.expression, "VAR chr: PROCEDURE(c: CHAR): INTEGER;"),
+    context(grammar.expression, "VAR chr: PROCEDURE(c: CHAR): INTEGER;"),
     pass(),
     fail(["CHR", "standard procedure CHR cannot be referenced"])
     ),
 "assignment statement": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "CONST c = 15;"
             + "VAR ch: CHAR; i, n: INTEGER; b: BOOLEAN;"
                 + "proc1: PROCEDURE; proc2: PROCEDURE(): INTEGER;"
@@ -466,7 +467,7 @@ var testSuite = {
          ["i := noResult()", "procedure returning no result cannot be used in an expression"])
     ),
 "INTEGER number": testWithGrammar(
-    Grammar.expression,
+    grammar.expression,
     pass("0",
          "123",
          "1H",
@@ -481,7 +482,7 @@ var testSuite = {
          ["1F FH", "not parsed"])
     ),
 "SET statement": testWithContext(
-    context(Grammar.statement, "VAR s: SET;"),
+    context(grammar.statement, "VAR s: SET;"),
     pass("s := {}",
          "s := {0}",
          "s := {0, 1}",
@@ -489,7 +490,7 @@ var testSuite = {
     //fail("s := {32}", "0..31")
     ),
 "REAL number": testWithGrammar(
-    Grammar.expression,
+    grammar.expression,
     pass("1.2345",
          "1.",
          "1.2345E6",
@@ -501,13 +502,13 @@ var testSuite = {
          ["1.2345E-1 2", "not parsed"])
     ),
 "LONGREAL number": testWithGrammar(
-    Grammar.expression,
+    grammar.expression,
     pass("1.2345D6",
          "1.2345D+6",
          "1.2345D-6")
     ),
 "IF statement": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "VAR b1: BOOLEAN; i1: INTEGER; p: POINTER TO RECORD END;"),
     pass("IF b1 THEN i1 := 0 END",
          "IF FALSE THEN i1 := 0 ELSE i1 := 1 END",
@@ -521,7 +522,7 @@ var testSuite = {
          ["IF b1 THEN i1 := 0 ELSIF ~b1 (*THEN*) i1 := 0 END", "THEN expected"])
     ),
 "CASE statement": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
               "CONST ci = 15; cc = \"A\";"
             + "VAR c1: CHAR; b1: BOOLEAN; i1, i2: INTEGER; byte: BYTE; p: POINTER TO RECORD END;"),
     pass("CASE i1 OF END",
@@ -553,7 +554,7 @@ var testSuite = {
           "label must be 'CHAR' (the same as case expression), got 'INTEGER'"])
     ),
 "WHILE statement": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "VAR b1: BOOLEAN; i1: INTEGER;"),
     pass("WHILE TRUE DO i1 := 0 END",
          "WHILE b1 DO i1 := 0 ELSIF FALSE DO i1 := 1 END"),
@@ -561,14 +562,14 @@ var testSuite = {
          ["WHILE b1 DO i1 := 0 ELSIF i1 DO i1 := 1 END", "'BOOLEAN' expression expected, got 'INTEGER'"])
     ),
 "REPEAT statement": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "VAR b1: BOOLEAN; i1: INTEGER;"),
     pass("REPEAT i1 := 0 UNTIL TRUE",
          "REPEAT i1 := 0 UNTIL b1"),
     fail(["REPEAT i1 := 0 UNTIL i1", "'BOOLEAN' expression expected, got 'INTEGER'"])
     ),
 "FOR statement": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
               "CONST c = 15;"
             + "VAR b: BOOLEAN; i, n: INTEGER; ch: CHAR; p: POINTER TO RECORD END;"),
     pass("FOR i := 0 TO 10 DO n := 1 END",
@@ -600,7 +601,7 @@ var testSuite = {
           "END expected (FOR)"])
     ),
 "logical operators": testWithContext(
-    context(Grammar.statement, "VAR b1, b2: BOOLEAN; i1: INTEGER; p: POINTER TO RECORD END;"),
+    context(grammar.statement, "VAR b1, b2: BOOLEAN; i1: INTEGER; p: POINTER TO RECORD END;"),
     pass("b1 := b1 OR b2",
          "b1 := b1 & b2",
          "b1 := ~b2"),
@@ -612,7 +613,7 @@ var testSuite = {
          ["b1 := ~i1", "type mismatch: expected 'BOOLEAN', got 'INTEGER'"])
     ),
 "arithmetic operators": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "VAR b1: BOOLEAN; i1, i2: INTEGER; r1, r2: REAL; c1: CHAR; s1: SET;"
             + "p1: PROCEDURE; ptr1: POINTER TO RECORD END;"),
     pass("i1 := i1 + i2",
@@ -635,7 +636,7 @@ var testSuite = {
          ["s1 := +b1", "operator '+' type mismatch: numeric type expected, got 'BOOLEAN'"])
     ),
 "relations are BOOLEAN": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "TYPE Base = RECORD END; Derived = RECORD (Base) END;"
             + "VAR pBase: POINTER TO Base; proc1, proc2: PROCEDURE;"
                 + "set1, set2: SET;"
@@ -652,7 +653,7 @@ var testSuite = {
          "b := r1 >= r2")
     ),
 "SET relations": testWithContext(
-    context(Grammar.expression,
+    context(grammar.expression,
             "VAR set1, set2: SET; b: BOOLEAN; i: INTEGER;"),
     pass("set1 <= set2",
          "set1 >= set2",
@@ -664,7 +665,7 @@ var testSuite = {
          ["i IN b", "type mismatch: expected 'SET', got 'BOOLEAN'"])
     ),
 "SET operators": testWithContext(
-    context(Grammar.expression,
+    context(grammar.expression,
             "VAR set1, set2: SET; b: BOOLEAN; i: INTEGER;"),
     pass("set1 + set2",
          "set1 - set2",
@@ -677,7 +678,7 @@ var testSuite = {
          ["set1 / b", "type mismatch: expected 'SET', got 'BOOLEAN'"])
     ),
 "SET functions": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "VAR set1, set2: SET; b: BOOLEAN; i: INTEGER;"),
     pass("INCL(set1, 0)",
          "EXCL(set1, 3)",
@@ -689,7 +690,7 @@ var testSuite = {
         )
     ),
 "PROCEDURE relations": testWithContext(
-    context(Grammar.expression,
+    context(grammar.expression,
             "VAR p1: PROCEDURE; p2: PROCEDURE;"),
     pass("p1 = p2",
          "p1 # p2",
@@ -698,7 +699,7 @@ var testSuite = {
          )
     ),
 "VAR parameter": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "CONST c = 123;"
             + "VAR i1: INTEGER; b1: BOOLEAN; a1: ARRAY 5 OF INTEGER;"
                 + "r1: RECORD f1: INTEGER END;"
@@ -718,7 +719,7 @@ var testSuite = {
          ["p2(~b1)", "expression cannot be used as VAR parameter"])
     ),
 "procedure call": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "TYPE ProcType = PROCEDURE;" +
             "VAR notProcedure: INTEGER; ptr: POINTER TO RECORD END;" +
             "PROCEDURE p; END p;" +
@@ -740,7 +741,7 @@ var testSuite = {
          )
 ),
 "procedure assignment": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "TYPE ProcType1 = PROCEDURE(): ProcType1;"
               + "ProcType2 = PROCEDURE(): ProcType2;"
               + "ProcType3 = PROCEDURE(p: ProcType3): ProcType3;"
@@ -787,7 +788,7 @@ var testSuite = {
          )
     ),
 "string assignment": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "VAR a1: ARRAY 3 OF CHAR;"
             + "ch1: CHAR;"
             + "intArray: ARRAY 10 OF INTEGER;"
@@ -803,7 +804,7 @@ var testSuite = {
           "type mismatch: 'intArray' is 'ARRAY 10 OF INTEGER' and cannot be assigned to 'multi-character string' expression"])
     ),
 "string relations": testWithContext(
-    context(Grammar.expression,
+    context(grammar.expression,
             "VAR ch: CHAR;"),
     pass("ch = \"a\"",
          "\"a\" = ch",
@@ -813,7 +814,7 @@ var testSuite = {
     fail(["ch = \"ab\"", "type mismatch: expected 'CHAR', got 'multi-character string'"])
     ),
 "array assignment": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "VAR charArray: ARRAY 3 OF CHAR;"
             + "intArray: ARRAY 10 OF INTEGER;"
             + "intArray2: ARRAY 10 OF INTEGER;"
@@ -839,7 +840,7 @@ var testSuite = {
           )
     ),
 "record assignment": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "TYPE Base1 = RECORD END;"
                 + "T1 = RECORD (Base1) END;"
                 + "T2 = RECORD END;"
@@ -851,7 +852,7 @@ var testSuite = {
          ["r1 := b1", "type mismatch: 'r1' is 'T1' and cannot be assigned to 'Base1' expression"])
     ),
 "string argument": testWithContext(
-    context(Grammar.statement,
+    context(grammar.statement,
             "PROCEDURE p1(s: ARRAY OF CHAR); END p1;"
             + "PROCEDURE p2(VAR s: ARRAY OF CHAR); END p2;"
             + "PROCEDURE p3(i: INTEGER); END p3;"
@@ -863,7 +864,7 @@ var testSuite = {
          ["p4(\"abc\")", "type mismatch for argument 1: 'multi-character string' cannot be converted to 'ARRAY OF INTEGER'"])
     ),
 "assert": testWithGrammar(
-    Grammar.statement,
+    grammar.statement,
     pass("ASSERT(TRUE)"),
     fail(["ASSERT()", "1 argument(s) expected, got 0"],
          ["ASSERT(TRUE, 123)", "1 argument(s) expected, got 2"],
@@ -935,11 +936,7 @@ var testSuite = {
     pass(),
     fail(["MODULE m; IMPORT test; BEGIN ASSERT(test.p.i = 0) END m.",
           "POINTER TO non-exported RECORD type cannot be dereferenced"])
-    )
-};
-
-function makeSuiteForGrammar(grammar){
-    return {
+    ),
 "procedure VAR section": testWithGrammar(
     grammar.declarationSequence,
     pass("VAR",
@@ -1316,7 +1313,6 @@ function makeSuiteForGrammar(grammar){
 }
 
 Test.run({
-    "basic": testSuite,
     "common": {
         "oberon": makeSuiteForGrammar(oberonGrammar),
         "eberon": makeSuiteForGrammar(eberonGrammar)

+ 6 - 0
test/test_unit_eberon.js

@@ -48,5 +48,11 @@ exports.suite = {
          ["PROCEDURE T.p(a: INTEGER); END T.p;",
           "overridden method 'p' signature mismatch: should be 'PROCEDURE', got 'PROCEDURE(INTEGER)'"]
         )
+    ),
+"SELF": testWithContext(
+    context(grammar.declarationSequence,
+            "TYPE T = RECORD i: INTEGER END;"),
+    pass("PROCEDURE T.p(), NEW; BEGIN SELF.i := 0; END T.p;"),
+    fail()
     )
 };