package slangc.model.expressions; import slangc.api.BytecodeInstructionWriter; import slangc.api.Reporter; import slangc.api.BytecodeInstructionWriter.Label; import slangc.bytecode.TypeSignature; import slangc.model.BuiltinTypeModel; import slangc.model.ExpressionModel; import slangc.model.ExpressionOwner; import slangc.model.ExpressionResult; import slangc.model.InnerTypeScope; import slangc.model.MemberModel; import slangc.model.TypeModel; import slangc.parser.Branch; import slangc.parser.Node; import slangc.parser.Token; public class BinaryExpression extends ExpressionModel implements ExpressionOwner { ExpressionModel leftHandSide; String operator; ExpressionModel rightHandSide; public BinaryExpression(ExpressionOwner owner, Node source) { super(owner, source); leftHandSide = ExpressionModel.construct(this, ((Branch)source).getSubnode(0)); operator = getOpName(((Branch)source).getSubnode(1)); rightHandSide = ExpressionModel.construct(this, ((Branch)source).getSubnode(2)); } public static String getOpName(Node source) { if (source instanceof Branch) { Branch b = (Branch) source; String r = ""; for (int i = 0; i < b.countSubnodes(); i++) { r += getOpName(b.getSubnode(i)); } return r; } else { // Must be token Token t = (Token) source; return t.getSnippet().getSource(); } } public static TypeModel resultType(TypeModel lhs, String op, TypeModel rhs) { lhs = nearestMathType(lhs); rhs = nearestMathType(rhs); if (op.equals("<") || op.equals(">") || op.equals("<=") || op.equals(">=") || op.equals("==") || op.equals("!=")) { return lhs.getPackage().getSystem().getDefaultBooleanType(); } if (op.equals("+") && (lhs == lhs.getPackage().getSystem().getDefaultStringType() || rhs == rhs.getPackage().getSystem().getDefaultStringType())) { return lhs.getPackage().getSystem().getDefaultStringType(); } if (lhs.isAssignableFrom(rhs)) { return lhs; } else if (rhs.isAssignableFrom(lhs)) { return rhs; } else { return null; } } public static TypeModel nearestMathType(TypeModel t) { if (t == t.getPackage().getSystem().getDefaultFloat32Type()) { return t; } else if (t == t.getPackage().getSystem().getDefaultFloat64Type()) { return t; } else if (t == t.getPackage().getSystem().getDefaultInt64Type()) { return t; } else if (t == t.getPackage().getSystem().getDefaultBooleanType()) { // Not really a math type but treated as one return t; } else if (t == t.getPackage().getSystem().getDefaultDuckType()) { // Not really a math type but treated as one return t; } else if (t instanceof BuiltinTypeModel) { return t.getPackage().getSystem().getDefaultInt32Type(); } else { return t; } } public static TypeModel inputType(TypeModel lhs, String op, TypeModel rhs) { lhs = nearestMathType(lhs); rhs = nearestMathType(rhs); //if (op.equals("<") || op.equals(">") || op.equals("<=") || op.equals(">=") || op.equals("==") || op.equals("!=")) { // return lhs.getPackage().getSystem().getDefaultBooleanType(); //} if (op.equals("+") && (lhs == lhs.getPackage().getSystem().getDefaultStringType() || rhs == rhs.getPackage().getSystem().getDefaultStringType())) { return lhs.getPackage().getSystem().getDefaultStringType(); } if (lhs.isAssignableFrom(rhs)) { return lhs; } else if (rhs.isAssignableFrom(lhs)) { return rhs; } else { return null; } } @Override protected ExpressionResult resolveResult() { if (leftHandSide.getResult().resolvesToValueOrNull() && rightHandSide.getResult().resolvesToValueOrNull()) { TypeModel lhs = leftHandSide.getResult().getValueTypeWithNullType(getSystem().getDefaultBaseType()); TypeModel rhs = rightHandSide.getResult().getValueTypeWithNullType(getSystem().getDefaultBaseType()); TypeModel res = resultType(lhs, getOperator(), rhs); if (res == null) { return ExpressionResult.INVALID; } else { return new ExpressionResult.TypedValue(res); } } return super.resolveResult(); } @Override public void dump(Reporter reporter, String indent, String incr) { reporter.note("DUMP", indent + "> Binary expression '" + getOperator() + "' (" + getSource().getNodeType() + ")"); dumpResolved(reporter, indent + incr, incr); leftHandSide.dump(reporter, indent + incr, incr); rightHandSide.dump(reporter, indent + incr, incr); } @Override public ExpressionModel[] getSubexpressions() { return new ExpressionModel[] {leftHandSide, rightHandSide}; } @Override public TypeModel getExpectedResult(ExpressionModel e) { // TODO not sure if relevant here return null; } @Override public InnerTypeScope getTypeScope() { return getOwner().getTypeScope(); } @Override public TypeModel resolveType(Node subnode) { return getOwner().resolveType(subnode); } @Override public MemberModel getMethodOrField() { return getOwner().getMethodOrField(); } public String getOperator() { return operator; } @Override public TypeSignature innerGenerate(BytecodeInstructionWriter w) { String op = getOperator(); if (op.equals("&&")) { BytecodeInstructionWriter.Label endLabel = w.newLabel("and_end"); getLeftHandSide().generate(w); w.genDup(BytecodeInstructionWriter.StackType.BIT); w.genJump(BytecodeInstructionWriter.JumpOp.IFFALSE, endLabel); w.genDrop(BytecodeInstructionWriter.StackType.BIT); getRightHandSide().generate(w); w.labelHere(endLabel); return getSystem().getDefaultBooleanType().getTypeSignature(); } else if (op.equals("||")) { BytecodeInstructionWriter.Label endLabel = w.newLabel("or_end"); getLeftHandSide().generate(w); w.genDup(BytecodeInstructionWriter.StackType.BIT); w.genJump(BytecodeInstructionWriter.JumpOp.IFTRUE, endLabel); w.genDrop(BytecodeInstructionWriter.StackType.BIT); getRightHandSide().generate(w); w.labelHere(endLabel); return getSystem().getDefaultBooleanType().getTypeSignature(); } else { getLeftHandSide().generate(w); getRightHandSide().generate(w); return generateALUOp(w, getLeftHandSide().getResult().getValueTypeWithNullType(getSystem().getDefaultBaseType()), getOperator(), getRightHandSide().getResult().getValueTypeWithNullType(getSystem().getDefaultBaseType())).getTypeSignature(); } } public static TypeModel generateALUOp(BytecodeInstructionWriter w, TypeModel lhs, String op, TypeModel rhs) { TypeModel r = resultType(lhs, op, rhs); TypeModel i = inputType(lhs, op, rhs); if (r == null) { r = lhs; } if (i == null) { i = lhs; } if (!rhs.getTypeSignature().mappableEquals(i.getTypeSignature())) { w.genConvert(rhs.getTypeSignature(), i.getTypeSignature()); } if (!lhs.getTypeSignature().mappableEquals(i.getTypeSignature())) { w.genSwap(i.getTypeSignature(), lhs.getTypeSignature()); w.genConvert(lhs.getTypeSignature(), i.getTypeSignature()); w.genSwap(i.getTypeSignature(), i.getTypeSignature()); } if (op.equals("+")) { if (i == i.getPackage().getSystem().getDefaultStringType()) { w.genStrcat(2); } else { w.genALU(BytecodeInstructionWriter.ALUOp.ADD, i.getTypeSignature()); } } else if (op.equals("-")) { w.genALU(BytecodeInstructionWriter.ALUOp.SUB, i.getTypeSignature()); } else if (op.equals("*")) { w.genALU(BytecodeInstructionWriter.ALUOp.MUL, i.getTypeSignature()); } else if (op.equals("/")) { w.genALU(BytecodeInstructionWriter.ALUOp.DIV, i.getTypeSignature()); } else if (op.equals("%")) { w.genALU(BytecodeInstructionWriter.ALUOp.MOD, i.getTypeSignature()); } else if (op.equals(">>")) { w.genALU(BytecodeInstructionWriter.ALUOp.SHRS, i.getTypeSignature()); } else if (op.equals(">>>")) { w.genALU(BytecodeInstructionWriter.ALUOp.SHRZ, i.getTypeSignature()); } else if (op.equals("<<")) { w.genALU(BytecodeInstructionWriter.ALUOp.SHLZ, i.getTypeSignature()); } else if (op.equals("&")) { w.genALU(BytecodeInstructionWriter.ALUOp.AND, i.getTypeSignature()); } else if (op.equals("|")) { w.genALU(BytecodeInstructionWriter.ALUOp.OR, i.getTypeSignature()); } else if (op.equals("^")) { w.genALU(BytecodeInstructionWriter.ALUOp.XOR, i.getTypeSignature()); } else if (op.equals("==")) { w.genComp(BytecodeInstructionWriter.CompOp.EQUAL, i.getTypeSignature()); } else if (op.equals("!=")) { w.genComp(BytecodeInstructionWriter.CompOp.NOT_EQUAL, i.getTypeSignature()); } else if (op.equals("<=")) { w.genComp(BytecodeInstructionWriter.CompOp.BELOW_OR_EQUAL, i.getTypeSignature()); } else if (op.equals(">=")) { w.genComp(BytecodeInstructionWriter.CompOp.ABOVE_OR_EQUAL, i.getTypeSignature()); } else if (op.equals("<")) { w.genComp(BytecodeInstructionWriter.CompOp.BELOW, i.getTypeSignature()); } else if (op.equals(">")) { w.genComp(BytecodeInstructionWriter.CompOp.ABOVE, i.getTypeSignature()); } else { w.genError("TODO: generateALUOp for '" + op + "'"); } return r; } public ExpressionModel getLeftHandSide() { return leftHandSide; } public ExpressionModel getRightHandSide() { return rightHandSide; } }