slcom/slangc/model/expressions/BinaryExpression.sauce

256 lines
9.1 KiB
Plaintext

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;
}
}