Browse Source

forbid dynamic arrays as non-VAR arguments

Vladislav Folts 11 years ago
parent
commit
2cfb581c3e

+ 1 - 0
src/context.js

@@ -2005,3 +2005,4 @@ exports.unwrapType = unwrapType;
 exports.IdentdefInfo = IdentdefInfo;
 exports.RecordField = RecordField;
 exports.RelationOps = RelationOps;
+exports.HandleSymbolAsType = HandleSymbolAsType;

+ 47 - 0
src/eberon/eberon_context.js

@@ -1118,10 +1118,28 @@ var ArrayDecl = Context.ArrayDecl.extend({
     }
 });
 
+function assertArgumentIsNotNonVarDynamicArray(msg){
+    if (msg instanceof Context.AddArgumentMsg){
+        var arg = msg.arg;
+        if (!arg.isVar){
+            var type = arg.type;
+            while (type instanceof Type.Array){
+                if (EberonTypes.isDynamicArray(type))
+                    throw new Errors.Error("dynamic array has no use as non-VAR argument '" + msg.name + "'");
+                type = Type.arrayElementsType(type);
+            }
+        }
+    }
+}
+
 var FormalParameters = Context.FormalParameters.extend({
     init: function EberonContext$FormalParameters(context){
         Context.FormalParameters.prototype.init.call(this, context);
     },
+    handleMessage: function(msg){
+        assertArgumentIsNotNonVarDynamicArray(msg);
+        return Context.FormalParameters.prototype.handleMessage.call(this, msg);
+    },
     _checkResultType: function(type){
         if (EberonTypes.isDynamicArray(type))
             return;
@@ -1129,10 +1147,38 @@ var FormalParameters = Context.FormalParameters.extend({
     }
 });
 
+var FormalType = Context.HandleSymbolAsType.extend({
+    init: function EberonContext$FormalType(context){
+        Context.HandleSymbolAsType.prototype.init.call(this, context);
+        this.__arrayDimensions = [];
+        this.__dynamicDimension = false;
+    },
+    setType: function(type){           
+        for(var i = this.__arrayDimensions.length; i--;){
+            var length = this.__arrayDimensions[i] ? EberonTypes.dynamicArrayLength 
+                                                  : Type.openArrayLength;
+            type = EberonTypes.makeArray(undefined, type, length);
+        }
+        this.parent().setType(type);
+    },
+    handleLiteral: function(s){
+        if (s == "*")
+            this.__dynamicDimension = true;
+        else if ( s == "OF"){
+            this.__arrayDimensions.push(this.__dynamicDimension);
+            this.__dynamicDimension = false;
+        }
+    }
+});
+
 var FormalParametersProcDecl = Context.FormalParametersProcDecl.extend({
     init: function EberonContext$FormalParametersProcDecl(context){
         Context.FormalParametersProcDecl.prototype.init.call(this, context);
     },
+    handleMessage: function(msg){
+        assertArgumentIsNotNonVarDynamicArray(msg);
+        return Context.FormalParametersProcDecl.prototype.handleMessage.call(this, msg);
+    },
     _checkResultType: function(type){
         if (EberonTypes.isDynamicArray(type))
             return;
@@ -1163,6 +1209,7 @@ exports.ExpressionProcedureCall = ExpressionProcedureCall;
 exports.For = For;
 exports.FormalParameters = FormalParameters;
 exports.FormalParametersProcDecl = FormalParametersProcDecl;
+exports.FormalType = FormalType;
 exports.Identdef = Identdef;
 exports.If = If;
 exports.MethodHeading = MethodHeading;

+ 1 - 0
src/eberon/eberon_grammar.js

@@ -103,6 +103,7 @@ exports.language = {
             ArrayDecl:          EbContext.ArrayDecl,
             Factor:             EbContext.Factor,
             FormalParameters:   EbContext.FormalParameters,
+            FormalType:         EbContext.FormalType,
             Term:               EbContext.Term,
             AddOperator:        EbContext.AddOperator,
             MulOperator:        EbContext.MulOperator,

+ 2 - 2
src/grammar.js

@@ -169,8 +169,8 @@ var recordType = and("RECORD", context(and(optional(and("(", baseType, ")")), op
 
 var pointerType = and("POINTER", "TO", context(type, Context.PointerDecl));
 
-var formalType = context(and(repeat(makeFormalArray()), qualident), Context.FormalType);
-var fpSection = and(optional(literal("VAR")), ident, repeat(and(",", ident)), ":", formalType);
+var formalType = context(and(repeat(makeFormalArray()), qualident), contexts.FormalType);
+var fpSection = and(optional("VAR"), ident, repeat(and(",", ident)), ":", formalType);
 var formalParameters = and(
           "("
         , optional(context(and(fpSection, repeat(and(";", fpSection))), Context.ProcParams))

+ 1 - 0
src/oberon/oberon_grammar.js

@@ -83,6 +83,7 @@ exports.language = {
             ArrayDecl:          Context.ArrayDecl,
             Factor:             Context.Factor,
             FormalParameters:   Context.FormalParameters,
+            FormalType:         Context.FormalType,
             Term:               Context.Term,
             AddOperator:        Context.AddOperator,
             MulOperator:        Context.MulOperator,

+ 13 - 14
test/test_unit_eberon.js

@@ -716,20 +716,30 @@ exports.suite = {
     ),
     "dynamic ARRAY": {
         "declaration": testWithContext(
-            context(grammar.declarationSequence, ""),
+            context(grammar.declarationSequence, 
+                    "TYPE DA = ARRAY * OF INTEGER;"),
             pass("TYPE A = ARRAY * OF INTEGER;",
                  "TYPE A = ARRAY * OF ARRAY * OF INTEGER;",
                  "TYPE A = ARRAY *, * OF INTEGER;",
                  "TYPE A = ARRAY 3, * OF INTEGER;",
                  "TYPE A = ARRAY *, 3 OF INTEGER;",
-                 "TYPE A = ARRAY * OF INTEGER; P = PROCEDURE(): A;",
+                 "TYPE P = PROCEDURE(): DA;",
+                 "TYPE P = PROCEDURE(VAR a: DA): DA;",
+                 "TYPE P = PROCEDURE(VAR a: ARRAY * OF INTEGER): DA;",
                  "VAR a: ARRAY * OF INTEGER;",
                  "PROCEDURE p(VAR a: ARRAY * OF INTEGER);END p;",
                  "PROCEDURE p(VAR a: ARRAY * OF ARRAY * OF INTEGER);END p;",
                  "PROCEDURE p(VAR a: ARRAY OF ARRAY * OF INTEGER);END p;"
                  ),
             fail(["TYPE A = ARRAY OF INTEGER;", "not parsed"],
-                 ["TYPE P = PROCEDURE(): ARRAY OF INTEGER;", "';' expected"])
+                 ["TYPE P = PROCEDURE(): ARRAY OF INTEGER;", "';' expected"],
+                 ["TYPE P = PROCEDURE(a: DA);", "dynamic array has no use as non-VAR argument 'a'"],
+                 ["TYPE P = PROCEDURE(a: ARRAY * OF INTEGER);", "dynamic array has no use as non-VAR argument 'a'"],
+                 ["PROCEDURE p(a: DA);END p;", "dynamic array has no use as non-VAR argument 'a'"],
+                 ["PROCEDURE p(a: ARRAY * OF INTEGER);END p;", "dynamic array has no use as non-VAR argument 'a'"],
+                 ["PROCEDURE p(a: ARRAY OF ARRAY * OF INTEGER);END p;", "dynamic array has no use as non-VAR argument 'a'"],
+                 ["PROCEDURE p(a: ARRAY * OF ARRAY OF INTEGER);END p;", "dynamic array has no use as non-VAR argument 'a'"]
+                 )
         ),
         "return": testWithContext(
             context(grammar.declarationSequence, 
@@ -740,17 +750,6 @@ exports.suite = {
             fail(["PROCEDURE p(): ARRAY OF INTEGER; RETURN a; END p;", "not parsed"],
                  ["PROCEDURE p(): A; RETURN b; END p;", "RETURN 'ARRAY * OF INTEGER' expected, got 'ARRAY * OF BOOLEAN'"])
         ),
-        "pass as non-VAR argument": testWithContext(
-            context(grammar.statement, 
-                    "TYPE A = ARRAY * OF INTEGER; B = ARRAY * OF BOOLEAN;"
-                    + "VAR a: A; b: B; aStatic: ARRAY 3 OF INTEGER;"
-                    + "PROCEDURE pa(a: A); END pa;"
-                    + "PROCEDURE pOpenA(a: ARRAY OF INTEGER); END pOpenA;"),
-            pass("pa(a)",
-                 "pa(aStatic)",
-                 "pOpenA(a)"),
-            fail(["pa(b)", "type mismatch for argument 1: 'ARRAY * OF BOOLEAN' cannot be converted to 'ARRAY * OF INTEGER'"])
-        ),
         "pass as VAR argument": testWithContext(
             context(grammar.statement, 
                     "TYPE A = ARRAY * OF INTEGER; B = ARRAY * OF BOOLEAN;"