Răsfoiți Sursa

IN operator for MAP

Vladislav Folts 10 ani în urmă
părinte
comite
aad3e58b03

BIN
bin/compiled.zip


+ 4 - 1
src/context.js

@@ -1258,9 +1258,12 @@ exports.Expression = ChainedContext.extend({
         leftExpression = promoteTypeInExpression(leftExpression, rightExpression.type());
         leftExpression = promoteTypeInExpression(leftExpression, rightExpression.type());
         rightExpression = promoteTypeInExpression(rightExpression, leftExpression.type());
         rightExpression = promoteTypeInExpression(rightExpression, leftExpression.type());
 
 
-        var o = relationOp(leftExpression.type(), rightExpression.type(), this.__relation, this.__relOps, this);
+        var o = this._relationOperation(leftExpression.type(), rightExpression.type(), this.__relation);
         this.__expression = o(leftExpression, rightExpression, this.language().rtl);
         this.__expression = o(leftExpression, rightExpression, this.language().rtl);
     },
     },
+    _relationOperation: function(left, right, relation){
+        return relationOp(left, right, relation, this.__relOps, this);
+    },
     handleLiteral: function(relation){
     handleLiteral: function(relation){
         this.__relation = relation;
         this.__relation = relation;
     },
     },

+ 6 - 1
src/eberon/EberonOperator.ob

@@ -1,5 +1,5 @@
 MODULE EberonOperator;
 MODULE EberonOperator;
-IMPORT Code, CodePrecedence, OberonRtl, Operator;
+IMPORT Code, CodePrecedence, OberonRtl, Operator, Types;
 
 
 PROCEDURE opAddStr(left, right: Code.PConst): Code.PConst;
 PROCEDURE opAddStr(left, right: Code.PConst): Code.PConst;
     RETURN Code.makeStringConst(left^(Code.StringConst).value
     RETURN Code.makeStringConst(left^(Code.StringConst).value
@@ -64,4 +64,9 @@ PROCEDURE greaterEqualStr*(left, right: Code.PExpression; rtl: OberonRtl.PType):
     RETURN Operator.relational(left, right, rtl, opGraterEqualStr, " >= ")
     RETURN Operator.relational(left, right, rtl, opGraterEqualStr, " >= ")
 END greaterEqualStr;
 END greaterEqualStr;
 
 
+PROCEDURE inMap*(left, right: Code.PExpression; rtl: OberonRtl.PType): Code.PExpression;
+    RETURN Code.makeSimpleExpression("Object.prototype.hasOwnProperty.call(" + right.code() + ", " + left.code() + ")",
+                                     Types.basic.bool);
+END;
+
 END EberonOperator.
 END EberonOperator.

+ 13 - 2
src/eberon/eberon_context.js

@@ -188,6 +188,11 @@ function OperatorNewMsg(e){
     this.expression = e;
     this.expression = e;
 }
 }
 
 
+function checkMapKeyType(type){
+    if (type != EberonString.string() && !Type.isString(type))
+        throw new Errors.Error("invalid MAP key type: STRING or string literal or ARRAY OF CHAR expected, got '" + type.description() + "'");            
+}
+
 var Designator = Context.Designator.extend({
 var Designator = Context.Designator.extend({
     init: function EberonContext$Designator(parent){
     init: function EberonContext$Designator(parent){
         Context.Designator.prototype.init.call(this, parent);
         Context.Designator.prototype.init.call(this, parent);
@@ -195,8 +200,7 @@ var Designator = Context.Designator.extend({
     },
     },
     _checkIndexType: function(type){
     _checkIndexType: function(type){
         if (this._currentType() instanceof EberonMap.Type){
         if (this._currentType() instanceof EberonMap.Type){
-            if (type != EberonString.string() && !Type.isString(type))
-                throw new Errors.Error("invalid MAP index: STRING or string literal or ARRAY OF CHAR expected, got '" + type.description() + "'");            
+            checkMapKeyType(type);
             return;
             return;
         }
         }
         return Context.Designator.prototype._checkIndexType.call(this, type);
         return Context.Designator.prototype._checkIndexType.call(this, type);
@@ -990,6 +994,13 @@ var Expression = Context.Expression.extend({
         if (this.__currentTypePromotion)
         if (this.__currentTypePromotion)
             this.parent().handleMessage(new TransferPromotedTypesMsg(this.__currentTypePromotion));
             this.parent().handleMessage(new TransferPromotedTypesMsg(this.__currentTypePromotion));
         return Context.Expression.prototype.endParse.call(this);
         return Context.Expression.prototype.endParse.call(this);
+    },
+    _relationOperation: function(left, right, relation){
+        if (relation == "IN" && right instanceof EberonMap.Type){
+            checkMapKeyType(left);
+            return eOp.inMap;            
+        }
+        return Context.Expression.prototype._relationOperation.call(this, left, right, relation);
     }
     }
 });
 });
 
 

+ 1 - 1
src/ob/Lexer.ob

@@ -12,7 +12,7 @@ CONST
         + "var void while with false true null class enum export extends "
         + "var void while with false true null class enum export extends "
         + "import super implements interface let package private protected "
         + "import super implements interface let package private protected "
         + "public static yield "
         + "public static yield "
-        + "Math Number" (* Math and Number are used in generated code for some functions so it is 
+        + "Object Math Number" (* Object, Math and Number are used in generated code for some functions so it is 
                     reserved word from code generator standpoint *)
                     reserved word from code generator standpoint *)
         ;
         ;
 
 

+ 0 - 0
src/ob/Object.ob → src/ob/Object$.ob


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

@@ -94,6 +94,11 @@ function put(){
 	RTL$.copyRecord(new T(), RTL$.getMappedValue(mapOfPointer, "abc"));
 	RTL$.copyRecord(new T(), RTL$.getMappedValue(mapOfPointer, "abc"));
 }
 }
 
 
+function in$(){
+	var m = {};
+	RTL$.assert(!Object.prototype.hasOwnProperty.call(m, "abc"));
+}
+
 function get(){
 function get(){
 	var m = {};
 	var m = {};
 	var s = '';
 	var s = '';

+ 1 - 1
test/expected/js_keyword.js

@@ -1,5 +1,5 @@
 var do$ = function (){
 var do$ = function (){
-var break$ = 0;var case$ = 0;var catch$ = 0;var continue$ = 0;var debugger$ = 0;var default$ = 0;var delete$ = 0;var else$ = 0;var class$ = 0;var const$ = 0;var enum$ = 0;var export$ = 0;var extends$ = 0;var import$ = 0;var super$ = 0;var true$ = 0;var false$ = 0;var null$ = 0;var implements$ = 0;var interface$ = 0;var let$ = 0;var package$ = 0;var private$ = 0;var protected$ = 0;var public$ = 0;var static$ = 0;var yield$ = 0;var finally$ = 0;var for$ = 0;var if$ = 0;var in$ = 0;var instanceof$ = 0;var new$ = 0;var return$ = 0;var switch$ = 0;var this$ = 0;var try$ = 0;var typeof$ = 0;var var$ = 0;var void$ = 0;var while$ = 0;var with$ = 0;var Math$ = 0;var Number$ = 0;
+var break$ = 0;var case$ = 0;var catch$ = 0;var continue$ = 0;var debugger$ = 0;var default$ = 0;var delete$ = 0;var else$ = 0;var class$ = 0;var const$ = 0;var enum$ = 0;var export$ = 0;var extends$ = 0;var import$ = 0;var super$ = 0;var true$ = 0;var false$ = 0;var null$ = 0;var implements$ = 0;var interface$ = 0;var let$ = 0;var package$ = 0;var private$ = 0;var protected$ = 0;var public$ = 0;var static$ = 0;var yield$ = 0;var finally$ = 0;var for$ = 0;var if$ = 0;var in$ = 0;var instanceof$ = 0;var new$ = 0;var return$ = 0;var switch$ = 0;var this$ = 0;var try$ = 0;var typeof$ = 0;var var$ = 0;var void$ = 0;var while$ = 0;var with$ = 0;var Object$ = 0;var Math$ = 0;var Number$ = 0;
 
 
 function function$(){
 function function$(){
 	var i = null;
 	var i = null;

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

@@ -34,6 +34,13 @@ BEGIN
     mapOfPointer["abc"]^ := T();
     mapOfPointer["abc"]^ := T();
 END;
 END;
 
 
+PROCEDURE in();
+VAR
+    m: MAP OF INTEGER;
+BEGIN
+    ASSERT(~("abc" IN m));
+END;
+
 PROCEDURE get();
 PROCEDURE get();
 VAR
 VAR
     m: MapOfInteger;
     m: MapOfInteger;

+ 28 - 0
test/input/eberon/run/map.ob

@@ -9,6 +9,20 @@ BEGIN
     END;
     END;
 END;
 END;
 
 
+PROCEDURE testForEach();
+VAR
+    m: MAP OF INTEGER;
+BEGIN
+    m["abc"] := 1;
+    count <- 0;
+    FOREACH v, k IN m DO
+        ASSERT(v = 1);
+        ASSERT(k = "abc");
+        INC(count);
+    END;
+    ASSERT(count = 1);
+END;
+
 PROCEDURE testPutGet();
 PROCEDURE testPutGet();
 VAR
 VAR
     m: MAP OF INTEGER;
     m: MAP OF INTEGER;
@@ -22,7 +36,21 @@ BEGIN
     ASSERT(m[a] = 1);
     ASSERT(m[a] = 1);
 END;
 END;
 
 
+PROCEDURE testIn();
+VAR
+    m: MAP OF INTEGER;
+    a: ARRAY 3 OF CHAR;
+BEGIN
+    m["abc"] := 1;
+    ASSERT("abc" IN m);
+    ASSERT(~("cde" IN m));
+    a := "abc";
+    ASSERT(a IN m);
+END;
+
 BEGIN
 BEGIN
     testEmptyForEach();
     testEmptyForEach();
+    testForEach();
     testPutGet();
     testPutGet();
+    testIn();
 END test.
 END test.

+ 1 - 1
test/input/js_keyword.ob

@@ -6,7 +6,7 @@ VAR
     true, false, null,
     true, false, null,
     implements, interface, let, package, private, protected, public, static, yield,
     implements, interface, let, package, private, protected, public, static, yield,
     finally, for, if, in, instanceof, new, return, switch, this, 
     finally, for, if, in, instanceof, new, return, switch, this, 
-    try, typeof, var, void, while, with, Math, Number
+    try, typeof, var, void, while, with, Object, Math, Number
     : INTEGER;
     : INTEGER;
 PROCEDURE function();
 PROCEDURE function();
 VAR i: throw;
 VAR i: throw;

+ 13 - 2
test/test_unit_eberon.js

@@ -1351,7 +1351,7 @@ exports.suite = {
              "m[sIndex] := 123",
              "m[sIndex] := 123",
              "m[aIndex] := 123"
              "m[aIndex] := 123"
             ),
             ),
-        fail(["m[123] := 123", "invalid MAP index: STRING or string literal or ARRAY OF CHAR expected, got 'INTEGER'"])
+        fail(["m[123] := 123", "invalid MAP key type: STRING or string literal or ARRAY OF CHAR expected, got 'INTEGER'"])
         ),
         ),
     "get": testWithContext(
     "get": testWithContext(
         context(grammar.expression,
         context(grammar.expression,
@@ -1361,7 +1361,18 @@ exports.suite = {
              "m[sIndex]",
              "m[sIndex]",
              "m[aIndex]"
              "m[aIndex]"
             ),
             ),
-        fail(["m[123]", "invalid MAP index: STRING or string literal or ARRAY OF CHAR expected, got 'INTEGER'"])
+        fail(["m[123]", "invalid MAP key type: STRING or string literal or ARRAY OF CHAR expected, got 'INTEGER'"])
+        ),
+    "IN": testWithContext(
+        context(grammar.expression,
+                "VAR m: MAP OF INTEGER;"
+                + "sIndex: STRING; aIndex: ARRAY 3 OF CHAR;"),
+        pass("\"abc\" IN m",
+             "(\"abc\" IN m) = FALSE",
+             "sIndex IN m",
+             "aIndex IN m"
+            ),
+        fail(["123 IN m", "invalid MAP key type: STRING or string literal or ARRAY OF CHAR expected, got 'INTEGER'"])
         ),
         ),
     "non-VAR parameter": testWithContext(
     "non-VAR parameter": testWithContext(
         context(grammar.declarationSequence,
         context(grammar.declarationSequence,