浏览代码

make 'indexOf' available for static arrays too

Vladislav Folts 10 年之前
父节点
当前提交
97b2ddad44

二进制
bin/compiled.zip


+ 1 - 1
src/context.js

@@ -768,7 +768,7 @@ exports.ArrayDecl = HandleSymbolAsType.extend({
         return rtl.makeArray(dimensions + ", " + initializer);
     },
     _makeType: function(elementsType, init, length){
-        return Type.makeStaticArray(init, elementsType, length);
+        return this.language().types.makeStaticArray(init, elementsType, length);
     }
 });
 

+ 120 - 0
src/eberon/EberonArray.ob

@@ -0,0 +1,120 @@
+MODULE EberonArray;
+IMPORT Code, EberonTypes, Errors, LanguageContext, Procedure, Types;
+CONST
+    methodNameIndexOf = "indexOf";
+TYPE
+    Method* = RECORD(Procedure.Std)
+    END;
+    PMethod* = POINTER TO Method;
+
+    MethodField* = RECORD(Types.Field)
+        method*: PMethod
+    END;
+
+    MethodIndexOf = RECORD(Method)
+        elementsType: Types.PType
+    END;
+
+    MethodCallIndexOf = RECORD(Procedure.StdCall)
+    END;
+
+    StaticArray = RECORD(Types.StaticArray)
+    END;
+
+PROCEDURE Method.description(): STRING;
+    RETURN "array method '" + SELF.name + "'"
+END Method.description;
+
+PROCEDURE MethodField.id(): STRING;
+    RETURN "add"
+END MethodField.id;
+
+PROCEDURE MethodField.exported(): BOOLEAN;
+    RETURN FALSE
+END MethodField.exported;
+
+PROCEDURE MethodField.type(): Types.PType;
+    RETURN SELF.method
+END MethodField.type;
+
+PROCEDURE MethodField.asVar(): Types.PId;
+    RETURN EberonTypes.makeMethod(SELF.method)
+END MethodField.asVar;
+
+PROCEDURE makeIndexOfMethod(elementsType: Types.PType): PMethod;
+VAR
+    result: POINTER TO MethodIndexOf;
+BEGIN
+    NEW(result);
+    result.name := methodNameIndexOf;
+    result.elementsType := elementsType;
+    RETURN result
+END makeIndexOfMethod;
+
+PROCEDURE MethodIndexOf.designatorCode(id: STRING): STRING;
+    RETURN "indexOf"
+END MethodIndexOf.designatorCode;
+
+PROCEDURE MethodIndexOf.callGenerator(cx: LanguageContext.PType): Procedure.PCallGenerator;
+VAR
+    a: Types.PProcedureArgument;
+    call: POINTER TO MethodCallIndexOf;
+BEGIN
+    NEW(call);
+    Procedure.initStdCall(call);
+
+    NEW(a);
+    a.type := SELF.elementsType;
+    call.args.add(a);
+    RETURN Procedure.makeCallGenerator(call, cx)
+END MethodIndexOf.callGenerator;
+
+PROCEDURE MethodCallIndexOf.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
+BEGIN
+    argCode <- Procedure.makeArgumentsCode(cx);
+    argType <- Procedure.checkSingleArgument(args, SELF, cx.types, argCode).type();
+    RETURN Code.makeSimpleExpression("(" + argCode.result() + ")", Types.basic.integer)
+END MethodCallIndexOf.make;
+
+PROCEDURE denoteMethod*(id: STRING; elementsType: Types.PType): PMethod;
+VAR
+    result: PMethod;
+BEGIN
+    IF id = methodNameIndexOf THEN
+        result := makeIndexOfMethod(elementsType);
+    END;
+    RETURN result
+END denoteMethod;
+
+PROCEDURE StaticArray.denote(id: STRING): Types.PField;
+VAR
+    field: POINTER TO MethodField;
+    result: Types.PField;
+BEGIN
+    IF id = methodNameIndexOf THEN
+        IF (SELF.elementsType IS Types.PRecord) OR (SELF.elementsType IS Types.PArray) THEN
+            Errors.raise("'" + methodNameIndexOf + "' is not defined for array of '" + SELF.elementsType.description() + "'");
+        END;
+        NEW(field);
+        field.method := makeIndexOfMethod(SELF.elementsType);
+        result := field;
+    ELSE
+        result := SUPER(id);
+    END;
+    RETURN result
+END StaticArray.denote;
+
+PROCEDURE makeStaticArray*(
+    initializer: STRING;
+    elementsType: Types.PType;
+    len: INTEGER
+    ): Types.PArray;
+VAR
+    result: POINTER TO StaticArray;
+BEGIN
+    NEW(result);
+    Types.initStaticArray(initializer, elementsType, len, result^);
+    RETURN result
+END makeStaticArray;
+
+END EberonArray.

+ 11 - 78
src/eberon/EberonDynamicArray.ob

@@ -1,29 +1,23 @@
 MODULE EberonDynamicArray;
-IMPORT Cast, Code, Context, EberonTypes, Errors, LanguageContext, Procedure, Types;
+IMPORT Cast, Code, Context, EberonArray, Errors, LanguageContext, Procedure, Types;
 CONST
     methodNameAdd = "add";
     methodNameClear = "clear";
-    methodNameIndexOf = "indexOf";
     methodNameRemove = "remove";
 TYPE
     DynamicArray* = RECORD(Types.Array)
     END;
     PDynamicArray* = POINTER TO DynamicArray;
 
-    Method = RECORD(Procedure.Std)
-    END;
-    PMethod = POINTER TO Method;
-
-    MethodField = RECORD(Types.Field)
-        method: PMethod
-    END;
-
     AddCallGenerator = RECORD(Procedure.CallGenerator)
         cx: LanguageContext.PType;
         elementsType: Types.PType;
         code: STRING
     END;
 
+    Method = RECORD(EberonArray.Method)
+    END;
+
     MethodAdd = RECORD(Method)
         elementsType: Types.PType
     END;
@@ -31,10 +25,6 @@ TYPE
     MethodClear = RECORD(Method)
     END;
 
-    MethodIndexOf = RECORD(Method)
-        elementsType: Types.PType
-    END;
-
     MethodRemove = RECORD(Method)
     END;
 
@@ -44,9 +34,6 @@ TYPE
     MethodCallRemove = RECORD(Procedure.StdCall)
     END;
 
-    MethodCallIndexOf = RECORD(Procedure.StdCall)
-    END;
-
 PROCEDURE arrayDimensionDescription(VAR a: Types.Array): STRING;
 VAR
     result: STRING;
@@ -67,7 +54,7 @@ PROCEDURE DynamicArray.description(): STRING;
     RETURN Types.arrayDescription(SELF, arrayDimensionDescription)
 END DynamicArray.description;
 
-PROCEDURE makeAddField(elementsType: Types.PType): PMethod;
+PROCEDURE makeAddField(elementsType: Types.PType): EberonArray.PMethod;
 VAR
     result: POINTER TO MethodAdd;
 BEGIN
@@ -77,7 +64,7 @@ BEGIN
     RETURN result
 END makeAddField;
 
-PROCEDURE makeClearMethod(): PMethod;
+PROCEDURE makeClearMethod(): EberonArray.PMethod;
 VAR
     result: POINTER TO MethodClear;
 BEGIN
@@ -86,17 +73,7 @@ BEGIN
     RETURN result
 END makeClearMethod;
 
-PROCEDURE makeIndexOfMethod(elementsType: Types.PType): PMethod;
-VAR
-    result: POINTER TO MethodIndexOf;
-BEGIN
-    NEW(result);
-    result.name := methodNameIndexOf;
-    result.elementsType := elementsType;
-    RETURN result
-END makeIndexOfMethod;
-
-PROCEDURE makeRemoveMethod(): PMethod;
+PROCEDURE makeRemoveMethod(): EberonArray.PMethod;
 VAR
     result: POINTER TO MethodRemove;
 BEGIN
@@ -107,18 +84,18 @@ END makeRemoveMethod;
 
 PROCEDURE DynamicArray.denote(id: STRING): Types.PField;
 VAR
-    field: POINTER TO MethodField;
-    method: PMethod;
+    field: POINTER TO EberonArray.MethodField;
+    method: EberonArray.PMethod;
     result: Types.PField;
 BEGIN
     IF      id = methodNameAdd THEN
         method := makeAddField(SELF.elementsType);
     ELSIF   id = methodNameClear THEN
         method := makeClearMethod();
-    ELSIF   id = methodNameIndexOf THEN
-        method := makeIndexOfMethod(SELF.elementsType);
     ELSIF   id = methodNameRemove THEN
         method := makeRemoveMethod();
+    ELSE
+        method := EberonArray.denoteMethod(id, SELF.elementsType);
     END;
     IF method # NIL THEN
         NEW(field);
@@ -139,22 +116,6 @@ BEGIN
     RETURN result
 END makeDynamicArray;
 
-PROCEDURE MethodField.id(): STRING;
-    RETURN "add"
-END MethodField.id;
-
-PROCEDURE MethodField.exported(): BOOLEAN;
-    RETURN FALSE
-END MethodField.exported;
-
-PROCEDURE MethodField.type(): Types.PType;
-    RETURN SELF.method
-END MethodField.type;
-
-PROCEDURE MethodField.asVar(): Types.PId;
-    RETURN EberonTypes.makeMethod(SELF.method)
-END MethodField.asVar;
-
 PROCEDURE AddCallGenerator.handleArgument(e: Code.PExpression);
 BEGIN
     IF SELF.code # "" THEN
@@ -227,24 +188,10 @@ BEGIN
     RETURN Code.makeSimpleExpression("(" + argCode.result() + ", 1)", NIL)
 END MethodCallRemove.make;
 
-PROCEDURE MethodCallIndexOf.make(args: ARRAY OF Code.PExpression; cx: LanguageContext.PType): Code.PExpression;
-BEGIN
-    argCode <- Procedure.makeArgumentsCode(cx);
-    argType <- Procedure.checkSingleArgument(args, SELF, cx.types, argCode).type();
-    IF (argType IS Types.PRecord) OR (argType IS Types.PArray) THEN
-        Errors.raise("cannot search for element of type '" + argType.description() + "'");
-    END;
-    RETURN Code.makeSimpleExpression("(" + argCode.result() + ")", Types.basic.integer)
-END MethodCallIndexOf.make;
-
 PROCEDURE MethodRemove.designatorCode(id: STRING): STRING;
     RETURN "splice"
 END MethodRemove.designatorCode;
 
-PROCEDURE MethodIndexOf.designatorCode(id: STRING): STRING;
-    RETURN "indexOf"
-END MethodIndexOf.designatorCode;
-
 PROCEDURE MethodClear.callGenerator(cx: LanguageContext.PType): Procedure.PCallGenerator;
 VAR
     call: POINTER TO MethodCallClear;
@@ -268,18 +215,4 @@ BEGIN
     RETURN Procedure.makeCallGenerator(call, cx)
 END MethodRemove.callGenerator;
 
-PROCEDURE MethodIndexOf.callGenerator(cx: LanguageContext.PType): Procedure.PCallGenerator;
-VAR
-    a: Types.PProcedureArgument;
-    call: POINTER TO MethodCallIndexOf;
-BEGIN
-    NEW(call);
-    Procedure.initStdCall(call);
-
-    NEW(a);
-    a.type := SELF.elementsType;
-    call.args.add(a);
-    RETURN Procedure.makeCallGenerator(call, cx)
-END MethodIndexOf.callGenerator;
-
 END EberonDynamicArray.

+ 1 - 1
src/eberon/eberon_context.js

@@ -1143,7 +1143,7 @@ var ArrayDecl = Context.ArrayDecl.extend({
     _makeType: function(elementsType, init, length){
         return length == dynamicArrayLength
             ? EberonDynamicArray.makeDynamicArray(elementsType)
-            : Type.makeStaticArray(init, elementsType, length);
+            : Context.ArrayDecl.prototype._makeType.call(this, elementsType, init, length);
     }
 });
 

+ 3 - 1
src/eberon/eberon_grammar.js

@@ -2,6 +2,7 @@
 
 var Cast = require("js/EberonCast.js");
 var Context = require("context.js");
+var EbArray = require("js/EberonArray.js");
 var EbContext = require("eberon/eberon_context.js");
 var Grammar = require("grammar.js");
 var Parser = require("parser.js");
@@ -121,6 +122,7 @@ exports.language = {
         ),
     stdSymbols: Symbols.makeStd(),
     types: {
-        implicitCast: Cast.implicit
+        implicitCast: Cast.implicit,
+        makeStaticArray: EbArray.makeStaticArray
     }
 };

+ 13 - 3
src/ob/Types.ob

@@ -657,6 +657,18 @@ BEGIN
     RETURN result
 END makeOpenArray;
 
+PROCEDURE initStaticArray*(
+    initializer: STRING;
+    elementsType: PType;
+    len: INTEGER;
+    VAR result: StaticArray
+    );
+BEGIN
+    initArray(elementsType, result);
+    result.mInitializer := initializer;
+    result.len := len;
+END initStaticArray;
+
 PROCEDURE makeStaticArray*(
     initializer: STRING;
     elementsType: PType;
@@ -666,9 +678,7 @@ VAR
     result: PStaticArray;
 BEGIN
     NEW(result);
-    initArray(elementsType, result^);
-    result.mInitializer := initializer;
-    result.len := len;
+    initStaticArray(initializer, elementsType, len, result^);
     RETURN result
 END makeStaticArray;
 

+ 3 - 1
src/oberon/oberon_grammar.js

@@ -6,6 +6,7 @@ var Grammar = require("grammar.js");
 var ObContext = require("oberon/oberon_context.js");
 var Parser = require("parser.js");
 var Symbols = require("js/OberonSymbols.js");
+var Types = require("js/Types.js");
 
 var and = Parser.and;
 var context = Parser.context;
@@ -101,7 +102,8 @@ exports.language = {
         ),
     stdSymbols: Symbols.makeStd(),
     types: {
-        implicitCast: Cast.implicit
+        implicitCast: Cast.implicit,
+        makeStaticArray: Types.makeStaticArray
     }
 };
 

+ 147 - 144
test/test_unit_eberon.js

@@ -870,150 +870,153 @@ exports.suite = {
               "cannot assign to non-VAR formal parameter"]
             )
     ),
-    "dynamic ARRAY": {
-        "declaration": testWithContext(
-            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 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(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, 
-                    "TYPE A = ARRAY * OF INTEGER; B = ARRAY * OF BOOLEAN;"
-                    + "VAR a: A; b: B;"),
-            pass("PROCEDURE p(): A; RETURN a END p;",
-                 "PROCEDURE p(): A; VAR static: ARRAY 3 OF INTEGER; RETURN static END p;"),
-            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 Int3 = ARRAY 3 OF INTEGER;"
-                    + "VAR dInt: ARRAY * OF INTEGER;"
-                    + "dIntInt: ARRAY *,* OF INTEGER;"
-                    + "PROCEDURE pOpenInt(a: ARRAY OF INTEGER); END pOpenInt;"
-                    + "PROCEDURE pOpenIntOfInt(a: ARRAY OF ARRAY OF INTEGER); END pOpenIntOfInt;"
-                    + "PROCEDURE pInt3(a: Int3); END pInt3;"),
-            pass("pOpenInt(dInt)",
-                 "pOpenIntOfInt(dIntInt)"),
-            fail(["pInt3(dInt)", "type mismatch for argument 1: 'ARRAY * OF INTEGER' cannot be converted to 'ARRAY 3 OF INTEGER'"])
-        ),
-        "pass as 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;"
-                    + "aIntInt: ARRAY * OF ARRAY * OF INTEGER;"
-                    + "aInt3Int: ARRAY * OF ARRAY 3 OF INTEGER;"
-                    + "PROCEDURE paVar(VAR a: A); END paVar;"
-                    + "PROCEDURE paVarOpen(VAR a: ARRAY OF INTEGER); END paVarOpen;"
-                    + "PROCEDURE pDynamicIntOfInt(VAR a: ARRAY * OF ARRAY * OF INTEGER); END pDynamicIntOfInt;"
-                    + "PROCEDURE pDynamicIntOfOpenInt(VAR a: ARRAY * OF ARRAY OF INTEGER); END pDynamicIntOfOpenInt;"
-                    ),
-            pass("paVar(a)",
-                 "paVarOpen(a)",
-                 "pDynamicIntOfInt(aIntInt)",
-                 "pDynamicIntOfOpenInt(aIntInt)",
-                 "pDynamicIntOfOpenInt(aInt3Int)"
-                 ),
-            fail(["paVar(aStatic)", "type mismatch for argument 1: cannot pass 'ARRAY 3 OF INTEGER' as VAR parameter of type 'ARRAY * OF INTEGER'"],
-                 ["pDynamicIntOfInt(aInt3Int)", "type mismatch for argument 1: 'ARRAY *, 3 OF INTEGER' cannot be converted to 'ARRAY *, * OF INTEGER'"]
-                 )
-        ),
-        "assign": testWithContext(
-            context(grammar.statement, 
-                    "VAR stat: ARRAY 3 OF INTEGER; dynamic: ARRAY * OF INTEGER;"),
-            pass("dynamic := stat"),
-            fail(["stat := dynamic", "type mismatch: 'stat' is 'ARRAY 3 OF INTEGER' and cannot be assigned to 'ARRAY * OF INTEGER' expression"],
-                 ["dynamic := NIL", "type mismatch: 'dynamic' is 'ARRAY * OF INTEGER' and cannot be assigned to 'NIL' expression"])
-        ),
-        "indexing": testWithContext(
-            context(grammar.expression, 
-                    "VAR a: ARRAY * OF INTEGER;"),
-            pass("a[0]", "a[1]"),
-            fail(["a[-1]", "index is negative: -1"], 
-                 ["a[-2]", "index is negative: -2"])
-        ),
-        "add": testWithContext(
-            context(grammar.statement, 
-                    "VAR a: ARRAY * OF INTEGER;"
-                     + "a2: ARRAY * OF ARRAY * OF INTEGER;"
-                     + "aStatic: ARRAY 3 OF INTEGER;"
-                     + "byte: BYTE;"),
-            pass("a.add(123)",
-                 "a.add(byte)",
-                 "a2.add(a)",
-                 "a2.add(aStatic)"
-                 ),
-            fail(["a.add := NIL", "cannot assign to method"],
-                 ["v <- a.add", "dynamic array method 'add' cannot be referenced"],                
-                 ["a.add()", "method 'add' expects one argument, got nothing"],
-                 ["a.add(1, 2)", "method 'add' expects one argument, got many"],                
-                 ["a.add(TRUE)", "type mismatch for argument 1: 'BOOLEAN' cannot be converted to 'INTEGER'"]                
-                )
-        ),
-        "add open array to dynamic array of static arrays": testWithContext(
-            context(grammar.declarationSequence, 
-                    "VAR a: ARRAY * OF ARRAY 3 OF INTEGER;"),
-            pass(),
-            fail(["PROCEDURE p(paramA: ARRAY OF INTEGER); BEGIN a.add(paramA); END p", 
-                  "type mismatch for argument 1: 'ARRAY OF INTEGER' cannot be converted to 'ARRAY 3 OF INTEGER'"]                
-                )
-        ),
-        "remove": testWithContext(
-            context(grammar.statement, 
-                    "VAR a: ARRAY * OF INTEGER;"),
-            pass("a.remove(0)"),
-            fail(["a.remove(-1)", "index is negative: -1"],
-                 ["a.remove()", "1 argument(s) expected, got 0"],
-                 ["a.remove(0, 1)", "1 argument(s) expected, got 2"],
-                 ["a.remove(TRUE)", "type mismatch for argument 1: 'BOOLEAN' cannot be converted to 'INTEGER'"],
-                 ["a.Remove(0)", "selector '.Remove' cannot be applied to 'ARRAY * OF INTEGER'"]
-                )
-        ),
-        "indexOf": testWithContext(
-            context(grammar.expression, 
-                    "TYPE "
-                    + "T = RECORD END;"
-                    + "VAR "
-                    + "r: T;"
-                    + "intArray: ARRAY * OF INTEGER;"
-                    + "boolArray: ARRAY * OF BOOLEAN;"
-                    + "recordArray: ARRAY * OF T;"
-                    + "arrayOfArray: ARRAY *,* OF INTEGER;"
+    "array": {
+            "indexOf": testWithContext(
+                context(grammar.expression, 
+                        "TYPE "
+                        + "T = RECORD END;"
+                        + "VAR "
+                        + "r: T;"
+                        + "intArray: ARRAY 3 OF INTEGER;"
+                        + "boolDynArray: ARRAY * OF BOOLEAN;"
+                        + "recordArray: ARRAY 3 OF T;"
+                        + "arrayOfArray: ARRAY 3, 4 OF INTEGER;"
+                        ),
+                pass("intArray.indexOf(0)",
+                     "boolDynArray.indexOf(FALSE) = -1"
                     ),
-            pass("intArray.indexOf(0)",
-                 "boolArray.indexOf(FALSE) = -1"
-                ),
-            fail(["intArray.indexOf(TRUE)", "type mismatch for argument 1: 'BOOLEAN' cannot be converted to 'INTEGER'"],
-                 ["recordArray.indexOf(r)", "cannot search for element of type 'T'"],
-                 ["arrayOfArray.indexOf(intArray)", "cannot search for element of type 'ARRAY * OF INTEGER'"]
-                )
-        ),
-        "clear": testWithContext(
-            context(grammar.statement, 
-                    "VAR a: ARRAY * OF INTEGER;"),
-            pass("a.clear()"),
-            fail(["a.clear(0)", "0 argument(s) expected, got 1"])
-        )
+                fail(["intArray.indexOf(TRUE)", "type mismatch for argument 1: 'BOOLEAN' cannot be converted to 'INTEGER'"],
+                     ["recordArray.indexOf(r)", "'indexOf' is not defined for array of 'T'"],
+                     ["arrayOfArray.indexOf(intArray)", "'indexOf' is not defined for array of 'ARRAY 4 OF INTEGER'"],
+                     ["intArray.indexOf", "array method 'indexOf' cannot be referenced"]                
+                    )
+            ),
+        "dynamic": {
+            "declaration": testWithContext(
+                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 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(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, 
+                        "TYPE A = ARRAY * OF INTEGER; B = ARRAY * OF BOOLEAN;"
+                        + "VAR a: A; b: B;"),
+                pass("PROCEDURE p(): A; RETURN a END p;",
+                     "PROCEDURE p(): A; VAR static: ARRAY 3 OF INTEGER; RETURN static END p;"),
+                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 Int3 = ARRAY 3 OF INTEGER;"
+                        + "VAR dInt: ARRAY * OF INTEGER;"
+                        + "dIntInt: ARRAY *,* OF INTEGER;"
+                        + "PROCEDURE pOpenInt(a: ARRAY OF INTEGER); END pOpenInt;"
+                        + "PROCEDURE pOpenIntOfInt(a: ARRAY OF ARRAY OF INTEGER); END pOpenIntOfInt;"
+                        + "PROCEDURE pInt3(a: Int3); END pInt3;"),
+                pass("pOpenInt(dInt)",
+                     "pOpenIntOfInt(dIntInt)"),
+                fail(["pInt3(dInt)", "type mismatch for argument 1: 'ARRAY * OF INTEGER' cannot be converted to 'ARRAY 3 OF INTEGER'"])
+            ),
+            "pass as 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;"
+                        + "aIntInt: ARRAY * OF ARRAY * OF INTEGER;"
+                        + "aInt3Int: ARRAY * OF ARRAY 3 OF INTEGER;"
+                        + "PROCEDURE paVar(VAR a: A); END paVar;"
+                        + "PROCEDURE paVarOpen(VAR a: ARRAY OF INTEGER); END paVarOpen;"
+                        + "PROCEDURE pDynamicIntOfInt(VAR a: ARRAY * OF ARRAY * OF INTEGER); END pDynamicIntOfInt;"
+                        + "PROCEDURE pDynamicIntOfOpenInt(VAR a: ARRAY * OF ARRAY OF INTEGER); END pDynamicIntOfOpenInt;"
+                        ),
+                pass("paVar(a)",
+                     "paVarOpen(a)",
+                     "pDynamicIntOfInt(aIntInt)",
+                     "pDynamicIntOfOpenInt(aIntInt)",
+                     "pDynamicIntOfOpenInt(aInt3Int)"
+                     ),
+                fail(["paVar(aStatic)", "type mismatch for argument 1: cannot pass 'ARRAY 3 OF INTEGER' as VAR parameter of type 'ARRAY * OF INTEGER'"],
+                     ["pDynamicIntOfInt(aInt3Int)", "type mismatch for argument 1: 'ARRAY *, 3 OF INTEGER' cannot be converted to 'ARRAY *, * OF INTEGER'"]
+                     )
+            ),
+            "assign": testWithContext(
+                context(grammar.statement, 
+                        "VAR stat: ARRAY 3 OF INTEGER; dynamic: ARRAY * OF INTEGER;"),
+                pass("dynamic := stat"),
+                fail(["stat := dynamic", "type mismatch: 'stat' is 'ARRAY 3 OF INTEGER' and cannot be assigned to 'ARRAY * OF INTEGER' expression"],
+                     ["dynamic := NIL", "type mismatch: 'dynamic' is 'ARRAY * OF INTEGER' and cannot be assigned to 'NIL' expression"])
+            ),
+            "indexing": testWithContext(
+                context(grammar.expression, 
+                        "VAR a: ARRAY * OF INTEGER;"),
+                pass("a[0]", "a[1]"),
+                fail(["a[-1]", "index is negative: -1"], 
+                     ["a[-2]", "index is negative: -2"])
+            ),
+            "add": testWithContext(
+                context(grammar.statement, 
+                        "VAR a: ARRAY * OF INTEGER;"
+                         + "a2: ARRAY * OF ARRAY * OF INTEGER;"
+                         + "aStatic: ARRAY 3 OF INTEGER;"
+                         + "byte: BYTE;"),
+                pass("a.add(123)",
+                     "a.add(byte)",
+                     "a2.add(a)",
+                     "a2.add(aStatic)"
+                     ),
+                fail(["a.add := NIL", "cannot assign to method"],
+                     ["v <- a.add", "dynamic array method 'add' cannot be referenced"],                
+                     ["a.add()", "method 'add' expects one argument, got nothing"],
+                     ["a.add(1, 2)", "method 'add' expects one argument, got many"],                
+                     ["a.add(TRUE)", "type mismatch for argument 1: 'BOOLEAN' cannot be converted to 'INTEGER'"]                
+                    )
+            ),
+            "add open array to dynamic array of static arrays": testWithContext(
+                context(grammar.declarationSequence, 
+                        "VAR a: ARRAY * OF ARRAY 3 OF INTEGER;"),
+                pass(),
+                fail(["PROCEDURE p(paramA: ARRAY OF INTEGER); BEGIN a.add(paramA); END p", 
+                      "type mismatch for argument 1: 'ARRAY OF INTEGER' cannot be converted to 'ARRAY 3 OF INTEGER'"]                
+                    )
+            ),
+            "remove": testWithContext(
+                context(grammar.statement, 
+                        "VAR a: ARRAY * OF INTEGER;"),
+                pass("a.remove(0)"),
+                fail(["a.remove(-1)", "index is negative: -1"],
+                     ["a.remove()", "1 argument(s) expected, got 0"],
+                     ["a.remove(0, 1)", "1 argument(s) expected, got 2"],
+                     ["a.remove(TRUE)", "type mismatch for argument 1: 'BOOLEAN' cannot be converted to 'INTEGER'"],
+                     ["a.Remove(0)", "selector '.Remove' cannot be applied to 'ARRAY * OF INTEGER'"]
+                    )
+            ),
+            "clear": testWithContext(
+                context(grammar.statement, 
+                        "VAR a: ARRAY * OF INTEGER;"),
+                pass("a.clear()"),
+                fail(["a.clear(0)", "0 argument(s) expected, got 1"])
+            )
+        }
     }
 };