Prechádzať zdrojové kódy

Allow non-scalar variables to be exported (in Eberon only).

Vladislav Folts 11 rokov pred
rodič
commit
7e10187458

+ 3 - 1
doc/wiki/eberon.md

@@ -2,4 +2,6 @@
 
 Eberon extends original Oberon so any valid oberon program is also a valid eberon program. A new syntax was introduced for extensions but I tried to maintain the original syntax flavor (e.g. CAPS).
 
-* [Methods](/vladfolts/oberonjs/wiki/eberon-methods)
+### Extensions
+* [Methods](/vladfolts/oberonjs/wiki/eberon-methods)
+* Non-scalar variables (arrays and records) can be exported (forbidden in oberon for some unknown reason).

+ 4 - 4
src/context.js

@@ -1521,19 +1521,19 @@ exports.VariableDeclaration = HandleSymbolAsType.extend({
         checkIfFieldCanBeExported(name, this.__idents, "variable");
     },
     setType: function(type){this.__type = type;},
+    type: function(){return this.__type;},
     typeName: function(){return undefined;},
     isAnonymousDeclaration: function(){return true;},
+    checkExport: function(){},
     endParse: function(){
         var v = Type.makeVariable(this.__type, false);
         var idents = this.__idents;
         var gen = this.codeGenerator();
         for(var i = 0; i < idents.length; ++i){
             var id = idents[i];
-            if (id.exported()
-                && (this.__type instanceof Type.Record
-                    || this.__type instanceof Type.Array))
-                throw new Errors.Error("only scalar type variables can be exported");
             var varName = id.id();
+            if (id.exported())
+                this.checkExport(varName);
             this.currentScope().addSymbol(new Symbol.Symbol(varName, v), id.exported());
             var t = Type.variableType(v);
             gen.write("var " + varName + " = " + t.initializer(this) + ";");

+ 2 - 2
src/eberon/eberon_context.js

@@ -109,7 +109,7 @@ var Designator = Context.Designator.extend({
 var RecordType = Type.Record.extend({
     init: function EberonContext$RecordType(name, cons, scope){
         Type.Record.prototype.init.call(this);
-        Type.initRecord(this, name, cons, scope)
+        Type.initRecord(this, name, cons, scope);
         this.__finalized = false;
         this.__declaredMethods = {};
         this.__definedMethods = [];
@@ -361,4 +361,4 @@ exports.Designator = Designator;
 exports.MethodHeading = MethodHeading;
 exports.ProcOrMethodId = ProcOrMethodId;
 exports.ProcOrMethodDecl = ProcOrMethodDecl;
-exports.RecordDecl = RecordDecl;
+exports.RecordDecl = RecordDecl;

+ 1 - 0
src/eberon/eberon_grammar.js

@@ -51,5 +51,6 @@ exports.grammar = Grammar.make(
     makeProcedureDeclaration,
     makeFieldList,
     EbContext.RecordDecl,
+    Context.VariableDeclaration,
     Grammar.reservedWords + " SELF SUPER"
     );

+ 2 - 1
src/grammar.js

@@ -27,6 +27,7 @@ function make(makeDesignator,
               makeProcedureDeclaration,
               makeFieldList,
               recordDeclContext,
+              varDeclContext,
               reservedWords
               ){
 var result = {};
@@ -51,7 +52,7 @@ var type = or(context(qualident, Context.Type),
               function(stream, context){return strucType(stream, context);} // break recursive declaration of strucType
              );
 var identList = and(identdef, repeat(and(",", identdef)));
-var variableDeclaration = context(and(identList, ":", type), Context.VariableDeclaration);
+var variableDeclaration = context(and(identList, ":", type), varDeclContext);
 
 var integer = or(context(and(digit, repeat(hexDigit), "H", separator), Context.HexInteger)
                , context(and(digit, repeat(digit), separator), Context.Integer));

+ 13 - 0
src/ob/Code.ob

@@ -0,0 +1,13 @@
+MODULE Code;
+IMPORT Types;
+TYPE
+    Generator = RECORD
+        PROCEDURE write();
+        PROCEDURE getResult();
+        PROCEDURE openScope();
+        PROCEDURE closeScope()
+    END;
+
+    NullGenerator = RECORD(Generator)
+    END;
+END Code.

+ 15 - 2
src/oberon/oberon_context.js

@@ -1,7 +1,8 @@
 "use strict";
 
-var Type = require("js/Types.js");
 var Context = require("context.js");
+var Errors = require("js/Errors.js");
+var Type = require("js/Types.js");
 
 var RecordDecl = Context.RecordDecl.extend({
     init: function OberonContext$RecordDecl(context){
@@ -9,4 +10,16 @@ var RecordDecl = Context.RecordDecl.extend({
     }
 });
 
-exports.RecordDecl = RecordDecl;
+var VariableDeclaration = Context.VariableDeclaration.extend({
+    init: function(context){
+        Context.VariableDeclaration.prototype.init.call(this, context);
+    },
+    checkExport: function(id){
+        var type = this.type();
+        if (type instanceof Type.Record || type instanceof Type.Array)
+            throw new Errors.Error("variable '" + id + "' cannot be exported: only scalar variables can be exported");
+    }
+});
+
+exports.RecordDecl = RecordDecl;
+exports.VariableDeclaration = VariableDeclaration;

+ 1 - 0
src/oberon/oberon_grammar.js

@@ -37,5 +37,6 @@ exports.grammar = Grammar.make(
     makeProcedureDeclaration,
     makeFieldList,
     ObContext.RecordDecl,
+    ObContext.VariableDeclaration,
     Grammar.reservedWords
     );

+ 4 - 6
test/test_unit.js

@@ -7,6 +7,7 @@ var Grammar = require("grammar.js");
 var Test = require("test.js");
 var TestUnitCommon = require("test_unit_common.js");
 var TestUnitEberon = require("test_unit_eberon.js");
+var TestUnitOberon = require("test_unit_oberon.js");
 
 var eberonGrammar = require("eberon/eberon_grammar.js").grammar;
 var oberonGrammar = require("oberon/oberon_grammar.js").grammar;
@@ -1249,11 +1250,7 @@ return {
          "VAR i*: INTEGER;",
          "PROCEDURE p*; END p;"
          ),
-    fail(["VAR r*: RECORD END;",
-          "only scalar type variables can be exported"],
-         ["VAR a*: ARRAY 5 OF INTEGER;",
-          "only scalar type variables can be exported"],
-         ["TYPE T = RECORD f*: INTEGER END;",
+    fail(["TYPE T = RECORD f*: INTEGER END;",
           "field 'f' can be exported only if record 'T' itself is exported too"],
          ["TYPE PT* = POINTER TO RECORD f*: INTEGER END;",
           "cannot export anonymous RECORD field: 'f'"],
@@ -1337,5 +1334,6 @@ Test.run({
         "oberon": makeSuiteForGrammar(oberonGrammar),
         "eberon": makeSuiteForGrammar(eberonGrammar)
     },
-    "eberon": TestUnitEberon.suite
+    "eberon": TestUnitEberon.suite,
+    "oberon": TestUnitOberon.suite
 });

+ 9 - 1
test/test_unit_eberon.js

@@ -144,5 +144,13 @@ exports.suite = {
           "type 'T' has no 'mNotExported' field"],
          ["MODULE m; IMPORT test; TYPE T = RECORD(test.T) END; PROCEDURE T.mNotExported(); END T.mNotExported; END m.",
           "'T' has no declaration for method 'mNotExported'"])
-    )
+    ),
+"non-scalar variables can be exported": testWithContext(
+    context(grammar.declarationSequence, 
+            "TYPE T = RECORD END; A = ARRAY 3 OF INTEGER;"
+            ),
+    pass("VAR r*: T;",
+         "VAR a*: A;"),
+    fail()
+    ),
 };

+ 20 - 0
test/test_unit_oberon.js

@@ -0,0 +1,20 @@
+"use strict";
+
+var grammar = require("oberon/oberon_grammar.js").grammar;
+var TestUnitCommon = require("test_unit_common.js");
+
+var pass = TestUnitCommon.pass;
+var fail = TestUnitCommon.fail;
+var testWithGrammar = TestUnitCommon.testWithGrammar;
+
+exports.suite = {
+"scalar variables cannot be exported": testWithGrammar(
+    grammar.declarationSequence,
+    pass(),
+    fail(["VAR r*: RECORD END;",
+          "variable 'r' cannot be exported: only scalar variables can be exported"],
+         ["VAR a*: ARRAY 5 OF INTEGER;",
+          "variable 'a' cannot be exported: only scalar variables can be exported"]
+        )
+    )
+};