ソースを参照

dynamic array 'remove' method

Vladislav Folts 10 年 前
コミット
f637e8348c

BIN
bin/compiled.zip


+ 1 - 2
src/context.js

@@ -366,8 +366,7 @@ exports.Designator = ChainedContext.extend({
         var pValue = e.constValue();
         if (pValue){
             var value = pValue.value;
-            if (value < 0)
-                throw new Errors.Error("index is negative: " + value);
+            Code.checkIndex(value);
             
             var length = index.length;
             if ((this.__currentType instanceof Type.StaticArray || this.__currentType instanceof Type.String)

+ 3 - 3
src/eberon/EberonCast.ob

@@ -1,5 +1,5 @@
 MODULE EberonCast;
-IMPORT Cast, EberonString, EberonTypes, Types;
+IMPORT Cast, EberonString, EberonDynamicArray, Types;
 
 PROCEDURE isOpenCharArray(type: Types.PType): BOOLEAN;
     RETURN (type IS Types.POpenArray) 
@@ -17,10 +17,10 @@ BEGIN
         ELSE
             result := Cast.errNo;
         END;
-    ELSIF (from IS Types.PArray) & (to IS EberonTypes.PDynamicArray)
+    ELSIF (from IS Types.PArray) & (to IS EberonDynamicArray.PDynamicArray)
         & Cast.areTypesExactlyMatch(Types.arrayElementsType(from^), 
                                     Types.arrayElementsType(to^)) THEN
-        IF toVar & ~(from IS EberonTypes.PDynamicArray) THEN
+        IF toVar & ~(from IS EberonDynamicArray.PDynamicArray) THEN
             result := Cast.errVarParameter;
         ELSE
             result := Cast.errNo;

+ 194 - 0
src/eberon/EberonDynamicArray.ob

@@ -0,0 +1,194 @@
+MODULE EberonDynamicArray;
+IMPORT Code, Context, EberonTypes, Errors, JsArray, LanguageContext, Procedure, Types;
+TYPE
+    DynamicArray* = RECORD(Types.Array)
+    END;
+    PDynamicArray* = POINTER TO DynamicArray;
+
+    DynamicArrayMethod = RECORD(Procedure.Std)
+    END;
+    PDynamicArrayMethod = POINTER TO DynamicArrayMethod;
+
+    DynamicArrayMethodField = RECORD(Types.Field)
+        method: PDynamicArrayMethod
+    END;
+
+    DynamicArrayAddCallGenerator = RECORD(Procedure.CallGenerator)
+        cx: LanguageContext.PType;
+        elementsType: Types.PType;
+        code: STRING
+    END;
+
+    DynamicArrayMethodAdd = RECORD(DynamicArrayMethod)
+        elementsType: Types.PType
+    END;
+
+    DynamicArrayMethodRemove = RECORD(DynamicArrayMethod)
+    END;
+
+    RemoveMethodCall = RECORD(Procedure.StdCall)
+    END;
+
+PROCEDURE arrayDimensionDescription(VAR a: Types.Array): STRING;
+VAR
+    result: STRING;
+BEGIN
+    IF a IS DynamicArray THEN
+        result := "*";
+    ELSE
+        result := Types.arrayDimensionDescription(a);
+    END;
+    RETURN result
+END arrayDimensionDescription;
+
+PROCEDURE DynamicArray.initializer(cx: Context.Type; forNew: BOOLEAN): STRING;
+    RETURN "[]"
+END DynamicArray.initializer;
+
+PROCEDURE DynamicArray.description(): STRING;
+    RETURN Types.arrayDescription(SELF, arrayDimensionDescription)
+END DynamicArray.description;
+
+PROCEDURE makeAddField(elementsType: Types.PType): PDynamicArrayMethod;
+VAR
+    result: POINTER TO DynamicArrayMethodAdd;
+BEGIN
+    NEW(result);
+    result.name := "add";
+    result.elementsType := elementsType;
+    RETURN result
+END makeAddField;
+
+PROCEDURE makeRemoveField(): PDynamicArrayMethod;
+VAR
+    result: POINTER TO DynamicArrayMethodRemove;
+BEGIN
+    NEW(result);
+    result.name := "remove";
+    RETURN result
+END makeRemoveField;
+
+PROCEDURE DynamicArray.denote(id: STRING): Types.PField;
+VAR
+    field: POINTER TO DynamicArrayMethodField;
+    method: PDynamicArrayMethod;
+    result: Types.PField;
+BEGIN
+    IF      id = "add" THEN
+        method := makeAddField(SELF.elementsType);
+    ELSIF   id = "remove" THEN
+        method := makeRemoveField();
+    END;
+    IF method # NIL THEN
+        NEW(field);
+        field.method := method;
+        result := field;
+    ELSE
+        result := SUPER(id);
+    END;
+    RETURN result
+END DynamicArray.denote;
+
+PROCEDURE makeDynamicArray*(elementsType: Types.PType): PDynamicArray;
+VAR
+    result: PDynamicArray;
+BEGIN
+    NEW(result);
+    Types.initArray(elementsType, result^);
+    RETURN result
+END makeDynamicArray;
+
+PROCEDURE DynamicArrayMethodField.id(): STRING;
+    RETURN "add"
+END DynamicArrayMethodField.id;
+
+PROCEDURE DynamicArrayMethodField.exported(): BOOLEAN;
+    RETURN FALSE
+END DynamicArrayMethodField.exported;
+
+PROCEDURE DynamicArrayMethodField.type(): Types.PType;
+    RETURN SELF.method
+END DynamicArrayMethodField.type;
+
+PROCEDURE DynamicArrayMethodField.asVar(): Types.PId;
+    RETURN EberonTypes.makeMethod(SELF.method)
+END DynamicArrayMethodField.asVar;
+
+PROCEDURE DynamicArrayAddCallGenerator.handleArgument(e: Code.PExpression);
+BEGIN
+    IF SELF.code # "" THEN
+        Errors.raise("method 'add' expects one argument, got many");
+    END;
+
+    argCode <- Procedure.makeArgumentsCode(SELF.cx);
+    Procedure.checkArgument(
+        e, 
+        Types.makeProcedureArgument(SELF.elementsType, FALSE), 
+        0, 
+        argCode, 
+        SELF.cx.types);
+    SELF.code := argCode.result();
+    
+    t <- e.type();
+    IF (t IS Types.PRecord) OR (t IS Types.PArray) THEN
+        SELF.code := SELF.cx.rtl.clone(SELF.code);
+    END;
+END DynamicArrayAddCallGenerator.handleArgument;
+
+PROCEDURE DynamicArrayAddCallGenerator.end(): Code.PExpression;
+BEGIN
+    IF SELF.code = "" THEN
+        Errors.raise("method 'add' expects one argument, got nothing");
+    END;
+    RETURN Code.makeSimpleExpression(
+            "(" + SELF.code + ")",
+            NIL)
+END DynamicArrayAddCallGenerator.end;
+
+PROCEDURE DynamicArrayMethod.description(): STRING;
+    RETURN "dynamic array method '" + SELF.name + "'"
+END DynamicArrayMethod.description;
+
+PROCEDURE DynamicArrayMethodAdd.designatorCode(id: STRING): STRING;
+    RETURN "push"
+END DynamicArrayMethodAdd.designatorCode;
+
+PROCEDURE DynamicArrayMethodAdd.callGenerator(cx: LanguageContext.PType): Procedure.PCallGenerator;
+VAR
+    result: POINTER TO DynamicArrayAddCallGenerator;
+BEGIN
+    NEW(result);
+    result.cx := cx;
+    result.elementsType := SELF.elementsType;
+    RETURN result
+END DynamicArrayMethodAdd.callGenerator;
+
+PROCEDURE RemoveMethodCall.make(args: JsArray.Type; cx: LanguageContext.Type): Code.PExpression;
+BEGIN
+    arg <- Procedure.checkSingleArgument(args, SELF, cx.types);
+    value <- arg.constValue();
+    IF (value # NIL) & (value^ IS Code.IntConst) THEN
+        Code.checkIndex(value.value);
+    END;
+    RETURN Code.makeSimpleExpression("(" + arg.code() + ")", NIL)
+END RemoveMethodCall.make;
+
+PROCEDURE DynamicArrayMethodRemove.designatorCode(id: STRING): STRING;
+    RETURN "splice"
+END DynamicArrayMethodRemove.designatorCode;
+
+PROCEDURE DynamicArrayMethodRemove.callGenerator(cx: LanguageContext.PType): Procedure.PCallGenerator;
+VAR
+    a: Types.PProcedureArgument;
+    call: POINTER TO RemoveMethodCall;
+BEGIN
+    NEW(call);
+    Procedure.initStdCall(call);
+
+    NEW(a);
+    a.type := Types.basic.integer;
+    JsArray.add(call.args, a);
+    RETURN Procedure.makeCallGenerator(call, cx)
+END DynamicArrayMethodRemove.callGenerator;
+
+END EberonDynamicArray.

+ 1 - 129
src/eberon/EberonTypes.ob

@@ -1,5 +1,5 @@
 MODULE EberonTypes;
-IMPORT Code, Context, Errors, JsArray, Language, LanguageContext, Procedure, Types;
+IMPORT JsArray, LanguageContext, Procedure, Types;
 
 TYPE
     CallGenerator = PROCEDURE(cx: LanguageContext.PType; type: Types.DefinedProcedure): Procedure.PCallGenerator;
@@ -18,59 +18,6 @@ TYPE
     MethodVariable* = RECORD(Types.ProcedureId)
     END;
 
-    DynamicArray* = RECORD(Types.Array)
-    END;
-    PDynamicArray* = POINTER TO DynamicArray;
-
-    DynamicArrayMethodField = RECORD(Types.Field)
-        method: POINTER TO DynamicArrayMethod
-    END;
-
-    (*
-    DynamicArrayAddCall = RECORD(Procedure.StdCall)
-    END;
-    *)
-    DynamicArrayAddCallGenerator = RECORD(Procedure.CallGenerator)
-        cx: LanguageContext.PType;
-        elementsType: Types.PType;
-        code: STRING
-    END;
-
-    DynamicArrayMethod = RECORD(Procedure.Std)
-        elementsType: Types.PType
-    END;
-
-PROCEDURE arrayDimensionDescription*(VAR a: Types.Array): STRING;
-VAR
-    result: STRING;
-BEGIN
-    IF a IS DynamicArray THEN
-        result := "*";
-    ELSE
-        result := Types.arrayDimensionDescription(a);
-    END;
-    RETURN result
-END arrayDimensionDescription;
-
-PROCEDURE DynamicArray.initializer(cx: Context.Type; forNew: BOOLEAN): STRING;
-    RETURN "[]"
-END DynamicArray.initializer;
-
-PROCEDURE DynamicArray.description(): STRING;
-    RETURN Types.arrayDescription(SELF, arrayDimensionDescription)
-END DynamicArray.description;
-
-PROCEDURE DynamicArray.denote(id: STRING): Types.PField;
-VAR
-    result: POINTER TO DynamicArrayMethodField;
-BEGIN
-    NEW(result);
-    NEW(result.method);
-    result.method.name := "add";
-    result.method.elementsType := SELF.elementsType;
-    RETURN result
-END DynamicArray.denote;
-
 PROCEDURE MethodType.designatorCode(id: STRING): STRING;
     RETURN id
 END MethodType.designatorCode;
@@ -123,79 +70,4 @@ BEGIN
     RETURN result
 END makeMethod;
 
-PROCEDURE makeDynamicArray*(elementsType: Types.PType): PDynamicArray;
-VAR
-    result: PDynamicArray;
-BEGIN
-    NEW(result);
-    Types.initArray(elementsType, result^);
-    RETURN result
-END makeDynamicArray;
-
-PROCEDURE DynamicArrayMethodField.id(): STRING;
-    RETURN "add"
-END DynamicArrayMethodField.id;
-
-PROCEDURE DynamicArrayMethodField.exported(): BOOLEAN;
-    RETURN FALSE
-END DynamicArrayMethodField.exported;
-
-PROCEDURE DynamicArrayMethodField.type(): Types.PType;
-    RETURN SELF.method
-END DynamicArrayMethodField.type;
-
-PROCEDURE DynamicArrayMethodField.asVar(): Types.PId;
-    RETURN makeMethod(SELF.method)
-END DynamicArrayMethodField.asVar;
-
-PROCEDURE DynamicArrayAddCallGenerator.handleArgument(e: Code.PExpression);
-BEGIN
-    IF SELF.code # "" THEN
-        Errors.raise("method 'add' expects one argument, got many");
-    END;
-
-    argCode <- Procedure.makeArgumentsCode(SELF.cx);
-    Procedure.checkArgument(
-        e, 
-        Types.makeProcedureArgument(SELF.elementsType, FALSE), 
-        0, 
-        argCode, 
-        SELF.cx.types);
-    SELF.code := argCode.result();
-    
-    t <- e.type();
-    IF (t IS Types.PRecord) OR (t IS Types.PArray) THEN
-        SELF.code := SELF.cx.rtl.clone(SELF.code);
-    END;
-END DynamicArrayAddCallGenerator.handleArgument;
-
-PROCEDURE DynamicArrayAddCallGenerator.end(): Code.PExpression;
-BEGIN
-    IF SELF.code = "" THEN
-        Errors.raise("method 'add' expects one argument, got nothing");
-    END;
-    RETURN Code.makeSimpleExpression(
-            "(" + SELF.code + ")",
-            NIL)
-END DynamicArrayAddCallGenerator.end;
-
-PROCEDURE DynamicArrayMethod.description(): STRING;
-    RETURN "dynamic array method '" + SELF.name + "'"
-END DynamicArrayMethod.description;
-
-PROCEDURE DynamicArrayMethod.designatorCode(id: STRING): STRING;
-    RETURN "push"
-END DynamicArrayMethod.designatorCode;
-
-PROCEDURE DynamicArrayMethod.callGenerator(cx: LanguageContext.PType): Procedure.PCallGenerator;
-VAR
-    result: POINTER TO DynamicArrayAddCallGenerator;
-BEGIN
-    NEW(result);
-    result.cx := cx;
-    result.elementsType := SELF.elementsType;
-    RETURN result
-END DynamicArrayMethod.callGenerator;
-
-BEGIN
 END EberonTypes.

+ 6 - 5
src/eberon/eberon_context.js

@@ -4,6 +4,7 @@ var Cast = require("js/Cast.js");
 var Class = require("rtl.js").Class;
 var Code = require("js/Code.js");
 var Context = require("context.js");
+var EberonDynamicArray= require("js/EberonDynamicArray.js");
 var EberonScope = require("js/EberonScope.js");
 var EberonString = require("js/EberonString.js");
 var EberonTypes = require("js/EberonTypes.js");
@@ -1121,7 +1122,7 @@ var ArrayDecl = Context.ArrayDecl.extend({
     },
     _makeType: function(elementsType, init, length){
         return length == dynamicArrayLength
-            ? EberonTypes.makeDynamicArray(elementsType)
+            ? EberonDynamicArray.makeDynamicArray(elementsType)
             : Type.makeStaticArray(init, elementsType, length);
     }
 });
@@ -1132,7 +1133,7 @@ function assertArgumentIsNotNonVarDynamicArray(msg){
         if (!arg.isVar){
             var type = arg.type;
             while (type instanceof Type.Array){
-                if (type instanceof EberonTypes.DynamicArray)
+                if (type instanceof EberonDynamicArray.DynamicArray)
                     throw new Errors.Error("dynamic array has no use as non-VAR argument '" + msg.name + "'");
                 type = Type.arrayElementsType(type);
             }
@@ -1149,7 +1150,7 @@ var FormalParameters = Context.FormalParameters.extend({
         return Context.FormalParameters.prototype.handleMessage.call(this, msg);
     },
     _checkResultType: function(type){
-        if (type instanceof EberonTypes.DynamicArray)
+        if (type instanceof EberonDynamicArray.DynamicArray)
             return;
         Context.FormalParameters.prototype._checkResultType.call(this, type);
     }
@@ -1164,7 +1165,7 @@ var FormalType = Context.HandleSymbolAsType.extend({
     setType: function(type){           
         for(var i = this.__arrayDimensions.length; i--;){
             type = this.__arrayDimensions[i] 
-                ? EberonTypes.makeDynamicArray(type)
+                ? EberonDynamicArray.makeDynamicArray(type)
                 : Type.makeOpenArray(type);
         }
         this.parent().setType(type);
@@ -1188,7 +1189,7 @@ var FormalParametersProcDecl = Context.FormalParametersProcDecl.extend({
         return Context.FormalParametersProcDecl.prototype.handleMessage.call(this, msg);
     },
     _checkResultType: function(type){
-        if (type instanceof EberonTypes.DynamicArray)
+        if (type instanceof EberonDynamicArray.DynamicArray)
             return;
         Context.FormalParametersProcDecl.prototype._checkResultType.call(this, type);
     }

+ 9 - 0
src/ob/Code.ob

@@ -1,6 +1,7 @@
 MODULE Code;
 IMPORT 
     JsMap, 
+    Errors,
     Object, 
     Stream, 
     ScopeBase, 
@@ -485,4 +486,12 @@ BEGIN
     result.imports := imports;
     RETURN result
 END makeModuleGenerator;
+
+PROCEDURE checkIndex*(i: INTEGER);
+BEGIN
+    IF i < 0 THEN
+        Errors.raise("index is negative: " + String.fromInt(i));
+    END;
+END checkIndex;
+
 END Code.

+ 1 - 1
src/ob/Procedure.ob

@@ -21,7 +21,7 @@ TYPE
     PCall = POINTER TO Call;
 
     StdCall* = RECORD(Call)
-        args: JsArray.Type
+        args*: JsArray.Type
     END;
     PStdCall = POINTER TO StdCall;
 

+ 12 - 1
test/test_unit_eberon.js

@@ -954,6 +954,17 @@ exports.suite = {
             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'"]
+                )
+        ),
     }
 };