Commits

Stephen McKamey committed 16fe6c0

adding support for JS 'in' infix operator

  • Participants
  • Parent commits 3dbde9f

Comments (0)

Files changed (4)

duel-compiler/src/main/java/org/duelengine/duel/codedom/CodeThisReferenceExpression.java

 	public Class<?> getResultType() {
 		return Object.class;
 	}
+
+	@Override
+	public boolean equals(Object arg) {
+		if (!(arg instanceof CodeThisReferenceExpression)) {
+			// includes null
+			return false;
+		}
+		return super.equals(arg);
+	}
 }

duel-compiler/src/main/java/org/duelengine/duel/codegen/ScriptTranslator.java

 				}
 				// unwrap expression node
 				return this.visit(voidExpr.getExpression());
+		    case Token.IN:
+		    	return this.visitIn((InfixExpression)node);
 			case Token.THIS:
 			case Token.THISFN:
 				// TODO: evaluate if should allow custom extensions via 'this'
 		return new CodePropertyReferenceExpression(target, property);
 	}
 
+	private CodeExpression visitIn(InfixExpression node) {
+		CodeExpression key = this.visitExpression(node.getLeft());
+		CodeExpression map = this.visitExpression(node.getRight());
+
+		return new CodeMethodInvokeExpression(
+			Boolean.class,
+			new CodeTypeReferenceExpression(DuelData.class),
+			"containsKey",
+			map,
+			key);	
+	}
+
 	private CodeExpression visitBinaryOp(InfixExpression node, CodeBinaryOperatorType operator) {
 		CodeExpression left = this.visitExpression(node.getLeft());
 		CodeExpression right = this.visitExpression(node.getRight());

duel-compiler/src/test/java/org/duelengine/duel/codegen/ScriptTranslatorTests.java

 	}
 
 	@Test
+	public void translateMapContainsKeyTest() {
+		String input = "function(data) { return 'foo' in data; }";
+
+		CodeMethod expected =
+			new CodeMethod(
+				AccessModifierType.PRIVATE,
+				Object.class,
+				"code_1",
+				new CodeParameterDeclarationExpression[] {
+					new CodeParameterDeclarationExpression(DuelContext.class, "context"),
+					new CodeParameterDeclarationExpression(Object.class, "data"),
+					new CodeParameterDeclarationExpression(int.class, "index"),
+					new CodeParameterDeclarationExpression(int.class, "count"),
+					new CodeParameterDeclarationExpression(String.class, "key")
+				},
+				new CodeMethodReturnStatement(
+					new CodeMethodInvokeExpression(
+						Boolean.class,
+						new CodeTypeReferenceExpression(DuelData.class),
+						"containsKey",
+						new CodeVariableReferenceExpression(Object.class, "data"),
+						new CodePrimitiveExpression("foo"))));
+
+		List<CodeMember> actual = new ScriptTranslator().translate(input);
+		assertNotNull(actual);
+		assertEquals(1, actual.size());
+		assertEquals(expected, actual.get(0));
+	}
+
+	@Test
 	public void translateArrayAccessTest() {
 		String input = "function(data) { return data[3]; }";
 
 				new CodeMethodReturnStatement(
 					new CodeMethodInvokeExpression(
 						Map.class,
-						new CodeThisReferenceExpression(),
+						new CodeTypeReferenceExpression(DuelData.class),
 						"asMap")));
 
 		List<CodeMember> actual = new ScriptTranslator().translate(input);
 				new CodeMethodReturnStatement(
 					new CodeMethodInvokeExpression(
 						Map.class,
-						new CodeThisReferenceExpression(),
+						new CodeTypeReferenceExpression(DuelData.class),
 						"asMap",
 						new CodePrimitiveExpression("a"), new CodeUnaryOperatorExpression(CodeUnaryOperatorType.NEGATION, new CodePrimitiveExpression(2)),
 						new CodePrimitiveExpression("count"), new CodeVariableReferenceExpression(Object.class, "data"),

duel-runtime/src/main/java/org/duelengine/duel/DuelData.java

 	}
 
 	/**
+	 * Treats the object as a Map and calls containsKey
+	 * @param data
+	 * @param key
+	 * @return true if data contains property or key
+	 */
+	public static boolean containsKey(Object data, Object key) {
+		if (data == null) {
+			return false;
+		}
+
+		Class<?> dataType = data.getClass();
+		data = Map.class.isAssignableFrom(dataType) ? data : asProxy(data, true);
+		if (!Map.class.isAssignableFrom(dataType)) {
+			return false;
+		}
+		
+		return ((Map<?,?>)data).containsKey(key);
+	}
+	
+	/**
 	 * Ensures a data object is easily walked
 	 * @param data
 	 * @return