Forráskód Böngészése

MAP's assigning and returning. Bug fixes.

Vladislav Folts 10 éve
szülő
commit
c5377d86cb

BIN
bin/compiled.zip


+ 10 - 8
src/context.js

@@ -630,15 +630,21 @@ exports.ProcDecl = ChainedContext.extend({
             return this.__addArgument(msg.name, msg.arg);
         return ChainedContext.prototype.handleMessage.call(this, msg);
     },
-    handleReturn: function(type){
+    handleReturn: function(e){
+        var type = e.type();
         var result = this.__type.result();
         if (!result)
             throw new Errors.Error("unexpected RETURN in PROCEDURE declared with no result type");
+        
+        var language = this.language();
         var op;
-        if (this.language().types.implicitCast(type, result, false, castOperations, {set: function(v){op = v;}, get:function(){return op;}}))
+        if (language.types.implicitCast(type, result, false, castOperations, {set: function(v){op = v;}, get:function(){return op;}}))
             throw new Errors.Error(
                 "RETURN '" + result.description() + "' expected, got '"
                 + type.description() + "'");
+
+        this.codeGenerator().write("return " + op.clone(language.rtl, e) + ";\n");
+
         this.__returnParsed = true;
     },
     endParse: function(){
@@ -655,14 +661,10 @@ exports.ProcDecl = ChainedContext.extend({
 exports.Return = ChainedContext.extend({
     init: function Context$Return(context){
         ChainedContext.prototype.init.call(this, context);
-        this.__expr = undefined;
     },
     codeGenerator: function(){return nullCodeGenerator;},
-    handleExpression: function(e){this.__expr = e;},
-    endParse: function(){
-        var parent = this.parent();
-        parent.codeGenerator().write("return " + Code.derefExpression(this.__expr).code() + ";\n");
-        parent.handleReturn(this.__expr.type());
+    handleExpression: function(e){
+        this.parent().handleReturn(e);
     }
 });
 

+ 29 - 3
src/eberon/EberonCast.ob

@@ -1,11 +1,15 @@
 MODULE EberonCast;
-IMPORT Cast, Code, EberonString, EberonDynamicArray, OberonRtl, Types;
+IMPORT Cast, Code, EberonMap, EberonRtl, EberonString, EberonDynamicArray, OberonRtl, Types;
 TYPE
-    CastOpToDynamicArray = RECORD (Cast.CastOp)
+    CastOpToDynamicArray = RECORD (Cast.CastOpArray)
+    END;
+
+    CastOpToMap = RECORD (Cast.CastOp)
     END;
 
 VAR
     castOpToDynamicArray: POINTER TO CastOpToDynamicArray;
+    castOpToMap: POINTER TO CastOpToMap;
 
 PROCEDURE CastOpToDynamicArray.make(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExpression;
     RETURN Code.makeSimpleExpression(Cast.cloneArray(e.type()(Types.PArray)^, e.code(), rtl^), NIL)
@@ -27,7 +31,21 @@ END copyArray;
 
 PROCEDURE CastOpToDynamicArray.assign(rtl: OberonRtl.PType; left, right: Code.PExpression): STRING;
     RETURN copyArray(left.type()(Types.PArray)^, left.code(), right.code(), rtl^)
-END CastOpToDynamicArray.assign;
+END;
+
+PROCEDURE CastOpToMap.make(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExpression;
+    RETURN e;
+END;
+
+PROCEDURE CastOpToMap.assign(rtl: OberonRtl.PType; left, right: Code.PExpression): STRING;
+    (* TODO: support non-scalar MAPs *)
+    RETURN rtl(EberonRtl.PType).copyMapOfScalars(right.code(), left.code());
+END;
+
+PROCEDURE CastOpToMap.clone(rtl: OberonRtl.PType; e: Code.PExpression): STRING;
+    (* TODO: support non-scalar MAPs *)
+    RETURN rtl(EberonRtl.PType).cloneMapOfScalars(e.code());
+END;
 
 PROCEDURE isOpenCharArray(type: Types.PType): BOOLEAN;
     RETURN (type IS Types.POpenArray) 
@@ -73,6 +91,13 @@ BEGIN
             op := castOpToDynamicArray;
             result := Cast.errNo;
         END;
+    ELSIF (from IS EberonMap.PType) & (to IS EberonMap.PType) THEN
+        IF Cast.areTypesExactlyMatch(from.valueType, to.valueType) THEN
+            op := castOpToMap;
+            result := Cast.errNo;
+        ELSE
+            result := Cast.err;
+        END;
     ELSE
         result := Cast.implicit(from, to, toVar, ops, op);
     END;
@@ -81,4 +106,5 @@ END implicit;
 
 BEGIN
     NEW(castOpToDynamicArray);
+    NEW(castOpToMap);
 END EberonCast.

+ 2 - 1
src/eberon/EberonMap.ob

@@ -7,8 +7,9 @@ TYPE
     Type* = RECORD(Types.StorageType)
         PROCEDURE Type*(type: Types.PType);
 
-        valueType: Types.PType;
+        valueType*: Types.PType;
     END;
+    PType* = POINTER TO Type;
 
     Method = RECORD(Procedure.Std)
     END;

+ 2 - 0
src/eberon/EberonRtl.ob

@@ -3,6 +3,8 @@ IMPORT OberonRtl;
 TYPE
     Type* = RECORD(OberonRtl.Type)
         clearMap*: PROCEDURE(s: STRING): STRING;
+        cloneMapOfScalars*: PROCEDURE(s: STRING): STRING;
+        copyMapOfScalars*: PROCEDURE(from, to: STRING): STRING;
     END;
     PType* = POINTER TO Type;
 

+ 9 - 24
src/eberon/eberon_context.js

@@ -361,13 +361,15 @@ var InPlaceVariableInit = Context.Chained.extend({
             else // do not clone if it is temporary, e.g. constructor call
                 this._code += e.code();
         }
-        else if (type instanceof Type.Array){
+        else {
             if (type instanceof Type.OpenArray)
                 throw new Errors.Error("cannot initialize variable '" + this.__id + "' with open array");
-            this._code += Cast.cloneArray(type, e.code(), this.language().rtl);
+          
+            var language = this.language();
+            var cloneOp;
+            language.types.implicitCast(type, type, false, op.castOperations(), {set: function(v){cloneOp = v;}, get:function(){return cloneOp;}});
+            this._code += cloneOp.clone(language.rtl, e);
         }
-        else
-            this._code += Code.derefExpression(e).code();
     },
     _onParsed: function(){
         this.parent().codeGenerator().write(this._code);
@@ -425,15 +427,8 @@ var AssignmentOrProcedureCall = Context.Chained.extend({
         var type = d.type();
         var code;
         if (this.__right){
-        /*    if (type instanceof EberonDynamicArray.DynamicArray){
-                if (!(this.__right.type() instanceof Type.Array))
-                    throw new Errors.Error("type mismatch");
-                code = d.code() + " = " + this.language().rtl.clone(this.__right.code());
-            }
-            else */{
-                var left = Code.makeExpression(d.code(), type, d);
-                code = op.assign(left, this.__right, this.language());
-            } 
+            var left = Code.makeExpression(d.code(), type, d);
+            code = op.assign(left, this.__right, this.language());
         }
         else if (!(d.info() instanceof ResultVariable)){
             var procCall = Context.makeProcCall(this, type, d.info());
@@ -1140,17 +1135,7 @@ var Repeat = Context.Repeat.extend({
     }
 });
 
-var Return = Context.Return.extend({
-    init: function EberonContext$Return(context){
-        Context.Return.prototype.init.call(this, context);
-    },
-    handleExpression: function(e){
-        var type = e.type();
-        if (type instanceof Type.Array)
-            e = Code.makeSimpleExpression(Cast.cloneArray(type, e.code(), this.language().rtl), type);
-        Context.Return.prototype.handleExpression.call(this, e);
-    }
-});
+var Return = Context.Return;
 
 var For = Context.For.extend({
     init: function EberonContext$Repeat(context){

+ 19 - 3
src/eberon/eberon_rtl.js

@@ -11,13 +11,29 @@ var methods = {
     clearMap: function(map){
         for(var p in map)
             delete map[p];
+    },
+    cloneMapOfScalars: function(from){
+        var result = {};
+        this.copyMapOfScalars(from, result);
+        return result;
+    },
+    copyMapOfScalars: function(from, to){
+        this.clearMap(to);
+        for(var k in from)
+            to[k] = from[k];
     }
 };
-oberon_rtl.copyMap(oberon_rtl.rtl.methods, methods);
-oberon_rtl.copyMap(methods, exports);
+oberon_rtl.extendMap(oberon_rtl.rtl.methods, methods);
+oberon_rtl.extendMap(methods, exports);
+
+var dependencies = { 
+        "copyMapOfScalars": ["clearMap"],
+        "cloneMapOfScalars": ["copyMapOfScalars"]
+    };
+oberon_rtl.extendMap(oberon_rtl.rtl.dependencies, dependencies);
 
 exports.rtl = {
-    dependencies: oberon_rtl.rtl.dependencies,
+    dependencies: dependencies,
     methods: methods,
     nodejsModule: "eberon/eberon_rtl.js"
 };

+ 15 - 6
src/ob/Cast.ob

@@ -7,7 +7,8 @@ CONST
 TYPE
     CastOp* = RECORD
         PROCEDURE make*(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExpression;
-        PROCEDURE assign*(rtl: OberonRtl.PType; left, right: Code.PExpression): STRING
+        PROCEDURE assign*(rtl: OberonRtl.PType; left, right: Code.PExpression): STRING;
+        PROCEDURE clone*(rtl: OberonRtl.PType; e: Code.PExpression): STRING;
     END;
 
     PCastOp* = POINTER TO CastOp;
@@ -15,7 +16,7 @@ TYPE
     CastOpDoNothing* = RECORD (CastOp)
     END;
 
-    CastOpArray = RECORD (CastOpDoNothing)
+    CastOpArray* = RECORD (CastOpDoNothing)
     END;
 
     CastOpRecord = RECORD (CastOpDoNothing)
@@ -119,7 +120,7 @@ END areTypesExactlyMatchImpl;
 
 PROCEDURE CastOpDoNothing.make(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExpression;
     RETURN e
-END CastOpDoNothing.make;
+END;
 
 PROCEDURE passedByReference*(e: Code.PExpression): BOOLEAN;
 BEGIN
@@ -144,6 +145,10 @@ BEGIN
     RETURN result;
 END;
 
+PROCEDURE CastOpDoNothing.clone(rtl: OberonRtl.PType; e: Code.PExpression): STRING;
+    RETURN Code.derefExpression(e).code();
+END;
+
 PROCEDURE cloneArray*(t: Types.Array; code: STRING; rtl: OberonRtl.Type): STRING;
 VAR
     result: STRING;
@@ -156,15 +161,19 @@ BEGIN
         result := rtl.cloneArrayOfRecords(code);
     END;
     RETURN result
-END cloneArray;
+END;
 
 PROCEDURE CastOpArray.assign(rtl: OberonRtl.PType; left, right: Code.PExpression): STRING;
     RETURN left.code() + " = " + cloneArray(right.type()(Types.PArray)^, right.code(), rtl^)
-END CastOpArray.assign;
+END;
+
+PROCEDURE CastOpArray.clone(rtl: OberonRtl.PType; e: Code.PExpression): STRING;
+    RETURN cloneArray(e.type()(Types.PArray)^, e.code(), rtl^);
+END;
 
 PROCEDURE CastOpRecord.assign(rtl: OberonRtl.PType; left, right: Code.PExpression): STRING;
     RETURN rtl.copyRecord(right.code(), left.code())
-END CastOpRecord.assign;
+END;
 
 PROCEDURE CastOpStrToChar.make(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExpression;
 BEGIN

+ 5 - 1
src/ob/Operator.ob

@@ -763,7 +763,11 @@ PROCEDURE CastToUint8.make(rtl: OberonRtl.PType; e: Code.PExpression): Code.PExp
         opCastToUint8, 
         " & ", 
         Precedence.bitAnd)
-END CastToUint8.make;
+END;
+
+PROCEDURE CastToUint8.clone(rtl: OberonRtl.PType; e: Code.PExpression): STRING;
+    RETURN SELF.make(rtl, e).code();
+END;
 
 BEGIN
     openArrayChar := NEW Types.OpenArray(Types.basic.ch);

+ 4 - 4
src/rtl.js

@@ -8,7 +8,7 @@ if (typeof Uint16Array == "undefined"){
     };
 }
 
-function copyMap(from, to){
+function extendMap(from, to){
     for(var p in from)
         to[p] = from[p];
 }
@@ -16,7 +16,7 @@ function copyMap(from, to){
 function Class(){}
 Class.extend = function extend(methods){
         function Type(){
-            copyMap(methods, this);
+            extendMap(methods, this);
         }
         Type.prototype = this.prototype;
 
@@ -249,5 +249,5 @@ exports.rtl = {
     methods: methods,
     nodejsModule: "rtl.js"
 };
-exports.copyMap = copyMap;
-copyMap(methods, exports);
+exports.extendMap = extendMap;
+extendMap(methods, exports);

+ 33 - 5
test/expected/eberon/map.js

@@ -3,6 +3,20 @@ var RTL$ = {
         if (!condition)
             throw new Error("assertion failed");
     },
+    cloneMapOfScalars: function (from){
+        var result = {};
+        this.copyMapOfScalars(from, result);
+        return result;
+    },
+    copyMapOfScalars: function (from, to){
+        this.clearMap(to);
+        for(var k in from)
+            to[k] = from[k];
+    },
+    clearMap: function (map){
+        for(var p in map)
+            delete map[p];
+    },
     makeCharArray: function (/*dimensions*/){
         var forward = Array.prototype.slice.call(arguments);
         var length = forward.pop();
@@ -62,10 +76,6 @@ var RTL$ = {
                                                   : this.cloneRecord(v);
             }
         }
-    },
-    clearMap: function (map){
-        for(var p in map)
-            delete map[p];
     }
 };
 var test = function (){
@@ -83,7 +93,7 @@ function ForEach(){
 
 function makeMap(){
 	var m = {};
-	return m;
+	return RTL$.cloneMapOfScalars(m);
 }
 
 function ForEachWithExpression(){
@@ -168,6 +178,24 @@ function clear(){
 	RTL$.clearMap(m);
 	RTL$.clearMap(m);
 }
+
+function returnLocalMap(){
+	var result = {};
+	return RTL$.cloneMapOfScalars(result);
+}
+
+function returnNonLocalMap(m/*MAP OF INTEGER*/){
+	return RTL$.cloneMapOfScalars(m);
+}
+
+function assign(a/*MAP OF INTEGER*/){
+	var v = {};
+	RTL$.copyMapOfScalars(a, v);
+	var v2 = RTL$.cloneMapOfScalars(a);
+	var v3 = RTL$.cloneMapOfScalars(v2);
+	var v4 = RTL$.cloneMapOfScalars(returnLocalMap());
+	var v5 = RTL$.cloneMapOfScalars(returnNonLocalMap(v));
+}
 var $map1 = m;
 for(var k in $map1){
 	var v = $map1[k];

+ 1 - 1
test/expected/proc.js

@@ -60,7 +60,7 @@ function withByteArgument(b/*BYTE*/){
 }
 
 function withByteResult(){
-	return 0;
+	return 0 & 0xFF;
 }
 
 function withByteResult2(b/*BYTE*/){

+ 6 - 0
test/expected/return.js

@@ -0,0 +1,6 @@
+var m = function (){
+
+function castIntegerWhenReturnByte(i/*INTEGER*/){
+	return i & 0xFF;
+}
+}();

+ 22 - 0
test/input/eberon/map.ob

@@ -105,6 +105,28 @@ BEGIN
     m.clear;
 END;
 
+PROCEDURE returnLocalMap(): MapOfInteger;
+VAR
+    result: MapOfInteger;
+BEGIN
+    RETURN result;
+END;
+
+PROCEDURE returnNonLocalMap(m: MapOfInteger): MapOfInteger;
+    RETURN m;
+END;
+
+PROCEDURE assign(a: MapOfInteger);
+VAR
+    v: MapOfInteger;
+BEGIN
+    v := a;
+    v2 <- a;
+    v3 <- v2;
+    v4 <- returnLocalMap();
+    v5 <- returnNonLocalMap(v);
+END;
+
 BEGIN
     FOREACH v, k IN m DO
         FOREACH v2, k2 IN m DO

+ 7 - 0
test/input/return.ob

@@ -0,0 +1,7 @@
+MODULE m;
+
+PROCEDURE castIntegerWhenReturnByte(i: INTEGER): BYTE;
+    RETURN i
+END castIntegerWhenReturnByte;
+
+END m.

+ 8 - 0
test/test_unit_eberon.js

@@ -1355,6 +1355,14 @@ exports.suite = {
              ["VAR MAP: INTEGER;", "not parsed"]
             )
         ),
+    "assign": testWithContext(
+        context(grammar.statement, 
+                "TYPE MapOfInteger = MAP OF INTEGER;"
+                + "VAR mapOfInteger1: MapOfInteger; mapOfInteger2: MAP OF INTEGER;"
+                + "mapOfString: MAP OF STRING;"),
+        pass("mapOfInteger1 := mapOfInteger2"),
+        fail(["mapOfInteger1 := mapOfString", "type mismatch: 'mapOfInteger1' is 'MAP OF INTEGER' and cannot be assigned to 'MAP OF STRING' expression"])
+    ),
     "put": testWithContext(
         context(grammar.statement,
                 "VAR m: MAP OF INTEGER;"