1. Stephen McKamey
  2. duel

Commits

Stephen McKamey  committed eae43e4

- fixing property and global var assignment expressions

  • Participants
  • Parent commits b3d56bd
  • Branches default

Comments (0)

Files changed (4)

File src/org/duelengine/duel/DuelView.java

View file
 		return context.getGlobal(ident);
 	}
 
+	protected void putGlobal(DuelContext context, String ident, Object value) {
+		context.putGlobal(ident, value);
+	}
+
 	protected boolean hasGlobals(DuelContext context, String... idents) {
 		return context.hasGlobals(idents);
 	}

File src/org/duelengine/duel/codegen/CodeDOMBuilder.java

View file
 						boolean.class,
 						new CodeThisReferenceExpression(),
 						"hasGlobals",
-						args),
-					new CodeMethodReturnStatement(expression));
+						args));
+
+				if (firstIsMethod && expression instanceof CodeMethodInvokeExpression) {
+					CodeMethod method = (CodeMethod)members.get(0);
+					runtimeCheck.getTrueStatements().addAll(method.getStatements());
+					this.viewType.getMembers().remove(method);
+				} else {
+					runtimeCheck.getTrueStatements().add(new CodeMethodReturnStatement(expression));
+				}
 
 				CodeMethod runtimeCheckMethod = new CodeMethod(
 					AccessModifierType.PRIVATE,
 
 				// ensure a break in the write stream
 				this.flushBuffer();
-				this.scopeStack.push(runtimeCheckMethod.getStatements());
+				this.scopeStack.push(runtimeCheck.getFalseStatements());
 				try {
 					// defer blocks that cannot be fully processed server-side
 					this.buildDeferredWrite(node.getClientCode(), node.getArgSize());
 					this.scopeStack.pop();
 				}
 
-				// if was immediately writen, return null
-				runtimeCheckMethod.getStatements().add(new CodeMethodReturnStatement(CodePrimitiveExpression.NULL));
+				// return null if immediately writen
+				runtimeCheck.getFalseStatements().add(new CodeMethodReturnStatement(CodePrimitiveExpression.NULL));
 
 				// have the expression be a method invocation
 				expression = new CodeMethodInvokeExpression(

File src/org/duelengine/duel/codegen/ServerCodeGen.java

View file
 		SUPPRESS
 	}
 
-	private static class GlobalRefVisitor implements CodeVisitor {
-		private boolean hasGlobalRef = false;
-
-		public boolean hasGlobalRef() {
-			return this.hasGlobalRef;
-		}
-
-		@Override
-		public boolean visit(CodeObject node) {
-			if (node instanceof ScriptVariableReferenceExpression) {
-				this.hasGlobalRef = true;
-				return false;
-			}
-			return true;
-		}
-	}
-
 	private static final String DUEL_PACKAGE = DuelView.class.getPackage().getName();
 	private final CodeGenSettings settings;
 	private int depth;
 		CodeExpression left = expression.getLeft();
 		CodeExpression right = expression.getRight();
 
-		// check if LHS modifies global scope
-		GlobalRefVisitor visitor = new GlobalRefVisitor();
-		left.visit(visitor);
-		boolean leftHasGlobalRef = visitor.hasGlobalRef();
+		boolean leftIsPropertyRef = (left instanceof CodePropertyReferenceExpression);
+		boolean leftIsGlobalRef = (left instanceof ScriptVariableReferenceExpression);
 
 		String operator;
 		switch (expression.getOperator()) {
 				operator = " - ";
 				break;
 			case SUBTRACT_ASSIGN:
-				if (leftHasGlobalRef || !CodeDOMUtility.isNumber(left)) {
+				if (leftIsPropertyRef || leftIsGlobalRef || !CodeDOMUtility.isNumber(left)) {
 					this.writeExpression(output, CodeDOMUtility.asAssignment(CodeBinaryOperatorType.SUBTRACT,
 						left, CodeDOMUtility.ensureNumber(left), CodeDOMUtility.ensureNumber(right)));
 					return;
 				operator = " * ";
 				break;
 			case MULTIPLY_ASSIGN:
-				if (leftHasGlobalRef || !CodeDOMUtility.isNumber(left)) {
+				if (leftIsPropertyRef || leftIsGlobalRef || !CodeDOMUtility.isNumber(left)) {
 					this.writeExpression(output, CodeDOMUtility.asAssignment(CodeBinaryOperatorType.MULTIPLY,
 						left, CodeDOMUtility.ensureNumber(left), CodeDOMUtility.ensureNumber(right)));
 					return;
 				operator = " / ";
 				break;
 			case DIVIDE_ASSIGN:
-				if (leftHasGlobalRef || !CodeDOMUtility.isNumber(left)) {
+				if (leftIsPropertyRef || leftIsGlobalRef || !CodeDOMUtility.isNumber(left)) {
 					this.writeExpression(output, CodeDOMUtility.asAssignment(CodeBinaryOperatorType.DIVIDE,
 						left, CodeDOMUtility.ensureNumber(left), CodeDOMUtility.ensureNumber(right)));
 					return;
 				operator = " % ";
 				break;
 			case MODULUS_ASSIGN:
-				if (leftHasGlobalRef || !CodeDOMUtility.isNumber(left)) {
+				if (leftIsPropertyRef || leftIsGlobalRef || !CodeDOMUtility.isNumber(left)) {
 					this.writeExpression(output, CodeDOMUtility.asAssignment(CodeBinaryOperatorType.MODULUS,
 						left, CodeDOMUtility.ensureNumber(left), CodeDOMUtility.ensureNumber(right)));
 					return;
 				operator = " & ";
 				break;
 			case BITWISE_AND_ASSIGN:
-				if (leftHasGlobalRef || !CodeDOMUtility.isNumber(left)) {
+				if (leftIsPropertyRef || leftIsGlobalRef || !CodeDOMUtility.isNumber(left)) {
 					this.writeExpression(output, CodeDOMUtility.asAssignment(CodeBinaryOperatorType.BITWISE_AND,
 						left, CodeDOMUtility.ensureNumber(left), CodeDOMUtility.ensureNumber(right)));
 					return;
 				operator = " | ";
 				break;
 			case BITWISE_OR_ASSIGN:
-				if (leftHasGlobalRef || !CodeDOMUtility.isNumber(left)) {
+				if (leftIsPropertyRef || leftIsGlobalRef || !CodeDOMUtility.isNumber(left)) {
 					this.writeExpression(output, CodeDOMUtility.asAssignment(CodeBinaryOperatorType.BITWISE_OR,
 						left, CodeDOMUtility.ensureNumber(left), CodeDOMUtility.ensureNumber(right)));
 					return;
 				operator = " ^ ";
 				break;
 			case BITWISE_XOR_ASSIGN:
-				if (leftHasGlobalRef || !CodeDOMUtility.isNumber(left)) {
+				if (leftIsPropertyRef || leftIsGlobalRef || !CodeDOMUtility.isNumber(left)) {
 					this.writeExpression(output, CodeDOMUtility.asAssignment(CodeBinaryOperatorType.BITWISE_XOR,
 						left, CodeDOMUtility.ensureNumber(left), CodeDOMUtility.ensureNumber(right)));
 					return;
 				operator = " << ";
 				break;
 			case SHIFT_LEFT_ASSIGN:
-				if (leftHasGlobalRef || !CodeDOMUtility.isNumber(left)) {
+				if (leftIsPropertyRef || leftIsGlobalRef || !CodeDOMUtility.isNumber(left)) {
 					this.writeExpression(output, CodeDOMUtility.asAssignment(CodeBinaryOperatorType.SHIFT_LEFT,
 						left, CodeDOMUtility.ensureNumber(left), CodeDOMUtility.ensureNumber(right)));
 					return;
 				operator = " >> ";
 				break;
 			case SHIFT_RIGHT_ASSIGN:
-				if (leftHasGlobalRef || !CodeDOMUtility.isNumber(left)) {
+				if (leftIsPropertyRef || leftIsGlobalRef || !CodeDOMUtility.isNumber(left)) {
 					this.writeExpression(output, CodeDOMUtility.asAssignment(CodeBinaryOperatorType.SHIFT_RIGHT,
 						left, CodeDOMUtility.ensureNumber(left), CodeDOMUtility.ensureNumber(right)));
 					return;
 				operator = " >>> ";
 				break;
 			case USHIFT_RIGHT_ASSIGN:
-				if (leftHasGlobalRef || !CodeDOMUtility.isNumber(left)) {
+				if (leftIsPropertyRef || leftIsGlobalRef || !CodeDOMUtility.isNumber(left)) {
 					this.writeExpression(output, CodeDOMUtility.asAssignment(CodeBinaryOperatorType.USHIFT_RIGHT,
 						left, CodeDOMUtility.ensureNumber(left), CodeDOMUtility.ensureNumber(right)));
 					return;
 		}
 
 		if (isAssign) {
-			if (leftHasGlobalRef) {
-				System.err.println("TODO: Assignment LHS contains global ref: "+left);
+			if (leftIsPropertyRef) {
+				// translate into dynamic helper method call
+				CodePropertyReferenceExpression leftPropRef = (CodePropertyReferenceExpression)left; 
+				this.writeExpression(
+					output,
+					new CodeMethodInvokeExpression(
+						expression.getResultType(),
+						new CodeThisReferenceExpression(),
+						"setProperty",
+						leftPropRef.getTarget(),
+						leftPropRef.getPropertyName(),
+						right));
+				return;
+			} else if (leftIsGlobalRef) {
+				// translate into dynamic helper method call
+				ScriptVariableReferenceExpression leftVarRef = (ScriptVariableReferenceExpression)left; 
+				this.writeExpression(
+					output,
+					new CodeMethodInvokeExpression(
+						expression.getResultType(),
+						new CodeThisReferenceExpression(),
+						"putGlobal",
+						new CodeVariableReferenceExpression(DuelContext.class, "context"),
+						new CodePrimitiveExpression(leftVarRef.getIdent()),
+						right));
+				return;
 			}
 
 			this.writeExpression(output, left);

File test/org/duelengine/duel/codegen/CodeDOMBuilderTests.java

View file
 						"hasGlobals",
 						new CodeVariableReferenceExpression(DuelContext.class, "context"),
 						new CodePrimitiveExpression("foo")),
-					new CodeMethodReturnStatement(
-						new CodePropertyReferenceExpression(
-							new ScriptVariableReferenceExpression("foo"),
-							new CodePrimitiveExpression("bar")).withParens())
-				),
-				new CodeExpressionStatement(new CodeMethodInvokeExpression(
-					Void.class,
-					new CodeThisReferenceExpression(),
-					"write",
-					new CodeVariableReferenceExpression(DuelContext.class, "context"),
-					new CodePrimitiveExpression("<script type=\"text/javascript\">"))),
-				new CodeExpressionStatement(new CodeMethodInvokeExpression(
-					Void.class,
-					new CodeThisReferenceExpression(),
-					"writeGlobals",
-					new CodeVariableReferenceExpression(DuelContext.class, "context"),
-					new CodePrimitiveExpression(false))),
-				new CodeExpressionStatement(new CodeMethodInvokeExpression(
-					Void.class,
-					new CodeThisReferenceExpression(),
-					"write",
-					new CodeVariableReferenceExpression(DuelContext.class, "context"),
-					new CodePrimitiveExpression("duel.write(function() { return (foo.bar); });</script>"))),
-				new CodeMethodReturnStatement(CodePrimitiveExpression.NULL)
+					new CodeStatement[] {
+						new CodeMethodReturnStatement(
+							new CodePropertyReferenceExpression(
+								new ScriptVariableReferenceExpression("foo"),
+								new CodePrimitiveExpression("bar")).withParens())
+					},
+					new CodeStatement[] {
+						new CodeExpressionStatement(new CodeMethodInvokeExpression(
+							Void.class,
+							new CodeThisReferenceExpression(),
+							"write",
+							new CodeVariableReferenceExpression(DuelContext.class, "context"),
+							new CodePrimitiveExpression("<script type=\"text/javascript\">"))),
+						new CodeExpressionStatement(new CodeMethodInvokeExpression(
+							Void.class,
+							new CodeThisReferenceExpression(),
+							"writeGlobals",
+							new CodeVariableReferenceExpression(DuelContext.class, "context"),
+							new CodePrimitiveExpression(false))),
+						new CodeExpressionStatement(new CodeMethodInvokeExpression(
+							Void.class,
+							new CodeThisReferenceExpression(),
+							"write",
+							new CodeVariableReferenceExpression(DuelContext.class, "context"),
+							new CodePrimitiveExpression("duel.write(function() { return (foo.bar); });</script>"))),
+						new CodeMethodReturnStatement(CodePrimitiveExpression.NULL)
+					}
+				)
 			).withThrows(IOException.class)
 		);
 
 			new CodeMethod(
 				AccessModifierType.PRIVATE,
 				Object.class,
-				"code_2",
-				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 CodeExpressionStatement(
-					new CodeBinaryOperatorExpression(
-						CodeBinaryOperatorType.ASSIGN,
-						new CodePropertyReferenceExpression(
-							new ScriptVariableReferenceExpression("foo"),
-							new CodePrimitiveExpression("bar")),
-						new CodeBinaryOperatorExpression(
-							CodeBinaryOperatorType.ADD,
-							new ScriptVariableReferenceExpression("baz"),
-							new CodeVariableReferenceExpression(Object.class, "data")).withParens())),
-				new CodeMethodReturnStatement(CodePrimitiveExpression.NULL)
-			),
-			new CodeMethod(
-				AccessModifierType.PRIVATE,
-				Object.class,
 				"hybrid_3",
 				new CodeParameterDeclarationExpression[] {
 					new CodeParameterDeclarationExpression(DuelContext.class, "context"),
 						new CodeVariableReferenceExpression(DuelContext.class, "context"),
 						new CodePrimitiveExpression("foo"),
 						new CodePrimitiveExpression("baz")),
-					new CodeMethodReturnStatement(
-						new CodeMethodInvokeExpression(
-							Object.class,
+					new CodeStatement[] {
+						new CodeExpressionStatement(
+							new CodeBinaryOperatorExpression(
+								CodeBinaryOperatorType.ASSIGN,
+								new CodePropertyReferenceExpression(
+									new ScriptVariableReferenceExpression("foo"),
+									new CodePrimitiveExpression("bar")),
+								new CodeBinaryOperatorExpression(
+									CodeBinaryOperatorType.ADD,
+									new ScriptVariableReferenceExpression("baz"),
+									new CodeVariableReferenceExpression(Object.class, "data")).withParens())),
+						new CodeMethodReturnStatement(CodePrimitiveExpression.NULL)
+					},
+					new CodeStatement[] {
+						new CodeExpressionStatement(new CodeMethodInvokeExpression(
+							Void.class,
 							new CodeThisReferenceExpression(),
-							"code_2",
+							"write",
+							new CodeVariableReferenceExpression(DuelContext.class, "context"),
+							new CodePrimitiveExpression("<script type=\"text/javascript\">"))),
+						new CodeExpressionStatement(new CodeMethodInvokeExpression(
+							Void.class,
+							new CodeThisReferenceExpression(),
+							"writeGlobals",
+							new CodeVariableReferenceExpression(DuelContext.class, "context"),
+							new CodePrimitiveExpression(false))),
+						new CodeExpressionStatement(new CodeMethodInvokeExpression(
+							Void.class,
+							new CodeThisReferenceExpression(),
+							"write",
+							new CodeVariableReferenceExpression(DuelContext.class, "context"),
+							new CodePrimitiveExpression("duel.write(function(data) { foo.bar = (baz+data); }, "))),
+						new CodeExpressionStatement(new CodeMethodInvokeExpression(
+							Void.class,
+							new CodeThisReferenceExpression(),
+							"dataEncode",
 							new CodeVariableReferenceExpression(DuelContext.class, "context"),
 							new CodeVariableReferenceExpression(Object.class, "data"),
-							new CodeVariableReferenceExpression(int.class, "index"),
-							new CodeVariableReferenceExpression(int.class, "count"),
-							new CodeVariableReferenceExpression(String.class, "key")))
-				),
-				new CodeExpressionStatement(new CodeMethodInvokeExpression(
-					Void.class,
-					new CodeThisReferenceExpression(),
-					"write",
-					new CodeVariableReferenceExpression(DuelContext.class, "context"),
-					new CodePrimitiveExpression("<script type=\"text/javascript\">"))),
-				new CodeExpressionStatement(new CodeMethodInvokeExpression(
-					Void.class,
-					new CodeThisReferenceExpression(),
-					"writeGlobals",
-					new CodeVariableReferenceExpression(DuelContext.class, "context"),
-					new CodePrimitiveExpression(false))),
-				new CodeExpressionStatement(new CodeMethodInvokeExpression(
-					Void.class,
-					new CodeThisReferenceExpression(),
-					"write",
-					new CodeVariableReferenceExpression(DuelContext.class, "context"),
-					new CodePrimitiveExpression("duel.write(function(data) { foo.bar = (baz+data); }, "))),
-				new CodeExpressionStatement(new CodeMethodInvokeExpression(
-					Void.class,
-					new CodeThisReferenceExpression(),
-					"dataEncode",
-					new CodeVariableReferenceExpression(DuelContext.class, "context"),
-					new CodeVariableReferenceExpression(Object.class, "data"),
-					CodePrimitiveExpression.ONE)),
-				new CodeExpressionStatement(new CodeMethodInvokeExpression(
-					Void.class,
-					new CodeThisReferenceExpression(),
-					"write",
-					new CodeVariableReferenceExpression(DuelContext.class, "context"),
-					new CodePrimitiveExpression(");</script>"))),
-				new CodeMethodReturnStatement(CodePrimitiveExpression.NULL)
+							CodePrimitiveExpression.ONE)),
+						new CodeExpressionStatement(new CodeMethodInvokeExpression(
+							Void.class,
+							new CodeThisReferenceExpression(),
+							"write",
+							new CodeVariableReferenceExpression(DuelContext.class, "context"),
+							new CodePrimitiveExpression(");</script>"))),
+						new CodeMethodReturnStatement(CodePrimitiveExpression.NULL)
+					}
+				)
 			).withThrows(IOException.class)
 		);