256 lines
9.1 KiB
Plaintext
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;
|
||
|
}
|
||
|
}
|