Initial commit of main compiler sources (or should I say ... SAUCES!)
This commit is contained in:
87
slangc/model/expressions/ArrayIndexExpression.sauce
Normal file
87
slangc/model/expressions/ArrayIndexExpression.sauce
Normal file
@@ -0,0 +1,87 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ArrayTypeModel;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.ErrorType;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class ArrayIndexExpression extends ExpressionModel implements ExpressionOwner {
|
||||
private ExpressionModel leftHandSide;
|
||||
private ExpressionModel indexExpression;
|
||||
|
||||
public ArrayIndexExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
leftHandSide = ExpressionModel.construct(this, ((Branch)source).getSubnode(0));
|
||||
indexExpression = ExpressionModel.construct(this, ((Branch)source).getSubnode(2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Array index expression:");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
leftHandSide.dump(reporter, indent + incr, incr);
|
||||
indexExpression.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public ExpressionModel getLeftHandSide() {
|
||||
return leftHandSide;
|
||||
}
|
||||
|
||||
public ExpressionModel getIndexExpression() {
|
||||
return indexExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return new ExpressionModel[] {leftHandSide, indexExpression};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
if (leftHandSide.getResult().resolvesToValueOrNull() && leftHandSide.getResult().getKind() != ExpressionResult.Kind.NULL) {
|
||||
TypeModel lhsType = leftHandSide.getResult().getValueType();
|
||||
if (lhsType instanceof ArrayTypeModel) {
|
||||
ArrayTypeModel arrayType = (ArrayTypeModel)lhsType;
|
||||
return new ExpressionResult.PointsToStorageSlot(arrayType);
|
||||
} else {
|
||||
getSource().annotate(ErrorType.INTERNAL_ERROR, "Left hand side of an array index expression should be an array type, got " + lhsType + " instead");
|
||||
return ExpressionResult.INVALID;
|
||||
}
|
||||
} else {
|
||||
getSource().annotate(ErrorType.INTERNAL_ERROR, "Couldn't make sense of left-hand-side of array index expression expecting a typeName but got " + leftHandSide.getResult());
|
||||
return ExpressionResult.INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
getLeftHandSide().generate(w);
|
||||
getIndexExpression().generate(w);
|
||||
w.genArrayLoad(getResult().getValueType().getTypeSignature());
|
||||
return getResult().getValueType().getTypeSignature();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateStore(BytecodeInstructionWriter w, TypeSignature storing) {
|
||||
getLeftHandSide().generate(w);
|
||||
getIndexExpression().generate(w);
|
||||
w.genArrayStore(getResult().getValueType().getTypeSignature());
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
94
slangc/model/expressions/ArrayInitialiserExpression.sauce
Normal file
94
slangc/model/expressions/ArrayInitialiserExpression.sauce
Normal file
@@ -0,0 +1,94 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ArrayTypeModel;
|
||||
import slangc.model.ClauseModel;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.model.clauses.Expressions;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.ErrorType;
|
||||
import slangc.parser.Node;
|
||||
|
||||
/**
|
||||
* An array initialiser is sort of a special edge case, in between an expression and a more specific clause.
|
||||
* The main difference between an array initialiser and a normal expression is that the result type needs
|
||||
* to be known/valid.
|
||||
*
|
||||
* @author Zak
|
||||
*
|
||||
*/
|
||||
public class ArrayInitialiserExpression extends ExpressionModel implements ExpressionOwner {
|
||||
private Expressions valueExpressions;
|
||||
|
||||
public ArrayInitialiserExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
|
||||
if (owner.getExpectedResult(this) == null) {
|
||||
source.annotate(ErrorType.INTERNAL_ERROR, "An array initialiser can only appear as an expression if the expected type is known!");
|
||||
} else if (!(owner.getExpectedResult(this) instanceof ArrayTypeModel)) {
|
||||
source.annotate(ErrorType.INTERNAL_ERROR, "Array initialiser type is invalid");
|
||||
}
|
||||
|
||||
valueExpressions = (Expressions)ClauseModel.construct(this, ((Branch)source).getSubnode(1));
|
||||
//sourceFile.annotate(ErrorType.INTERNAL_ERROR, "Unrecognised expression (Internal error/TODO)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Array initialiser of: (element type " + getExpectedResult(null) + ")");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
valueExpressions.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
TypeModel et = getOwner().getExpectedResult(this);
|
||||
if (et == null) {
|
||||
return ExpressionResult.INVALID;
|
||||
} else {
|
||||
return new ExpressionResult.TypedValue(et);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
if (getOwner().getExpectedResult(this) == null || !(getOwner().getExpectedResult(this) instanceof ArrayTypeModel)) {
|
||||
return null;
|
||||
}
|
||||
return ((ArrayTypeModel)getOwner().getExpectedResult(this)).getElementType();
|
||||
}
|
||||
|
||||
public Expressions getArguments() {
|
||||
return valueExpressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return valueExpressions.getSubexpressions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
w.genConst(w.getTarget().getHeap().getConstInt32("" + valueExpressions.countExpressions()));
|
||||
w.genNewArray(getResult().getValueType().getTypeSignature());
|
||||
for (int i = 0; i < valueExpressions.countExpressions(); i++) {
|
||||
w.genDup(getResult().getValueType().getTypeSignature()); // TODO: Wrong dup type?
|
||||
ExpressionModel e = valueExpressions.getExpression(i);
|
||||
TypeSignature et = e.generate(w);
|
||||
w.genSwap(et, getResult().getValueType().getTypeSignature());
|
||||
w.genConst(w.getTarget().getHeap().getConstInt32("" + i));
|
||||
//w.genSwap(getSystem().getDefaultInt32Type().getTypeSignature(), getResult().getValueType().getTypeSignature());
|
||||
w.genArrayStore(((ArrayTypeModel)getResult().getValueType()).getElementType().getTypeSignature());
|
||||
}
|
||||
return getResult().getValueType().getTypeSignature();
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
123
slangc/model/expressions/AssignmentExpression.sauce
Normal file
123
slangc/model/expressions/AssignmentExpression.sauce
Normal file
@@ -0,0 +1,123 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
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;
|
||||
|
||||
public class AssignmentExpression extends ExpressionModel implements ExpressionOwner {
|
||||
ExpressionModel leftHandSide;
|
||||
String operator;
|
||||
ExpressionModel rightHandSide;
|
||||
|
||||
public AssignmentExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
leftHandSide = ExpressionModel.construct(this, ((Branch)source).getSubnode(0));
|
||||
operator = BinaryExpression.getOpName(((Branch)source).getSubnode(1));
|
||||
operator = operator.sub(0, operator.ints().length-1);
|
||||
rightHandSide = ExpressionModel.construct(this, ((Branch)source).getSubnode(2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Assignment expression (" + getSource().getNodeType() + ")");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
leftHandSide.dump(reporter, indent + incr, incr);
|
||||
rightHandSide.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
if (e == rightHandSide && leftHandSide.isResolved()) {
|
||||
return leftHandSide.getResult().getValueType();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
return new ExpressionResult.TypedValue(leftHandSide.getResult().getValueType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public InnerTypeScope getTypeScope() {
|
||||
return getOwner().getTypeScope();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypeModel resolveType(Node subnode) {
|
||||
return getOwner().resolveType(subnode);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MemberModel getMethodOrField() {
|
||||
return getOwner().getMethodOrField();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return new ExpressionModel[] {leftHandSide, rightHandSide};
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
TypeSignature storing = null;
|
||||
if (usesOperator()) {
|
||||
getLeftHandSide().generate(w);
|
||||
getRightHandSide().generate(w);
|
||||
if (leftHandSide.getResult() == null || rightHandSide.getResult() == null) {
|
||||
w.genError("Bad assignment");
|
||||
return null;
|
||||
} else {
|
||||
storing = BinaryExpression.generateALUOp(w, leftHandSide.getResult().getValueTypeWithNullType(getSystem().getDefaultBaseType()), getOperator(), rightHandSide.getResult().getValueTypeWithNullType(getSystem().getDefaultBaseType())).getTypeSignature();
|
||||
}
|
||||
} else {
|
||||
storing = getRightHandSide().generate(w);
|
||||
}
|
||||
if (!storing.mappableEquals(leftHandSide.getResult().getValueType().getTypeSignature())) {
|
||||
w.genConvert(storing, leftHandSide.getResult().getValueType().getTypeSignature());
|
||||
storing = leftHandSide.getResult().getValueType().getTypeSignature();
|
||||
}
|
||||
getLeftHandSide().generateStore(w, storing);
|
||||
return getLeftHandSide().generate(w);
|
||||
/* TODO: Optimised += and co
|
||||
TypeSignature contextType = leftHandSide.generateAssignContext(w);
|
||||
if (usesOperator()) {
|
||||
w.genDup(contextType);
|
||||
leftHandSide.generateAssignLoad(w);
|
||||
rightHandSide.generate(w);
|
||||
BinaryExpression.generateALUOp(leftHandSide.getResult().getValueType(), getOperator(), rightHandSide.getResult().getValueType());
|
||||
}
|
||||
w.genError("TODO: innerGenerate for " + Type.of(this));
|
||||
return null;
|
||||
*/
|
||||
}
|
||||
|
||||
/** Returns the operator used in this assignment (will be an empty string if no operator used). */
|
||||
public String getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public boolean usesOperator() {
|
||||
return !operator.equals("");
|
||||
}
|
||||
|
||||
public ExpressionModel getLeftHandSide() {
|
||||
return leftHandSide;
|
||||
}
|
||||
|
||||
public ExpressionModel getRightHandSide() {
|
||||
return rightHandSide;
|
||||
}
|
||||
}
|
85
slangc/model/expressions/AutomaticMethodCallExpression.sauce
Normal file
85
slangc/model/expressions/AutomaticMethodCallExpression.sauce
Normal file
@@ -0,0 +1,85 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ClauseModel;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.MethodModel;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.model.UserTypeModel;
|
||||
import slangc.model.clauses.Arguments;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class AutomaticMethodCallExpression extends ExpressionModel /*implements ExpressionOwner*/ {
|
||||
private String name;
|
||||
private Arguments arguments;
|
||||
private MethodModel targetMethod;
|
||||
|
||||
public AutomaticMethodCallExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
name = UserTypeModel.plainName(((Branch)((Branch)source).getSubnode(0)).getSubnode(0));
|
||||
|
||||
arguments = (Arguments)ClauseModel.construct(this, ((Branch)source).getSubnode(1));
|
||||
//sourceFile.annotate(ErrorType.INTERNAL_ERROR, "Unrecognised expression (Internal error/TODO)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Automatic method call expression '" + name + "' of:");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
arguments.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public Arguments getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return arguments.getSubexpressions();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
targetMethod = bestTargetMethod(lookupSimpleMethod(name), arguments);
|
||||
return ExpressionResult.fromMethodResult(targetMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTargetMethod() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodModel getTargetMethod() {
|
||||
return targetMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
arguments.generate(w, getTargetMethod(), true);
|
||||
if (!getTargetMethod().isStatic()) {
|
||||
OuterThisExpression.generatePossibleOuterThis(w, (UserTypeModel)getMethodOrField().getOwner(), getTargetMethod().getOwner());
|
||||
}
|
||||
w.genCall(getTargetMethod().getMethodSignature());
|
||||
return getTargetMethod().getMethodSignature().returnType;
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
255
slangc/model/expressions/BinaryExpression.sauce
Normal file
255
slangc/model/expressions/BinaryExpression.sauce
Normal file
@@ -0,0 +1,255 @@
|
||||
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;
|
||||
}
|
||||
}
|
65
slangc/model/expressions/CastExpression.sauce
Normal file
65
slangc/model/expressions/CastExpression.sauce
Normal file
@@ -0,0 +1,65 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class CastExpression extends ExpressionModel implements ExpressionOwner {
|
||||
TypeModel type;
|
||||
ExpressionModel valueExpression;
|
||||
|
||||
public CastExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
// TODO: This doesn't handle and-ed types from newer "legacy" code properly yet
|
||||
type = owner.resolveType(((Branch)((Branch)source).getSubnode(1)).getSubnode(0));
|
||||
valueExpression = ExpressionModel.construct(this, ((Branch)source).getSubnode(3));
|
||||
}
|
||||
|
||||
public TypeModel getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public ExpressionModel getValueExpression() {
|
||||
return valueExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Cast to '" + type + "'");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
valueExpression.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
// TODO: I'm not sure if there are cases where cast influences decoding of right-hand-side
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return new ExpressionModel[] {valueExpression};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
return new ExpressionResult.TypedValue(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
TypeSignature incoming = valueExpression.generate(w);
|
||||
w.genConvert(incoming, getType().getTypeSignature());
|
||||
return getType().getTypeSignature();
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
103
slangc/model/expressions/ConditionalExpression.sauce
Normal file
103
slangc/model/expressions/ConditionalExpression.sauce
Normal file
@@ -0,0 +1,103 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
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;
|
||||
|
||||
public class ConditionalExpression extends ExpressionModel implements ExpressionOwner {
|
||||
ExpressionModel leftHandSide;
|
||||
ExpressionModel trueBranch;
|
||||
ExpressionModel falseBranch;
|
||||
|
||||
public ConditionalExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
leftHandSide = ExpressionModel.construct(this, ((Branch)source).getSubnode(0));
|
||||
trueBranch = ExpressionModel.construct(this, ((Branch)source).getSubnode(2));
|
||||
falseBranch = ExpressionModel.construct(this, ((Branch)source).getSubnode(4));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Conditional expression");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
leftHandSide.dump(reporter, indent + incr, incr);
|
||||
trueBranch.dump(reporter, indent + incr, incr);
|
||||
falseBranch.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return new ExpressionModel[] {leftHandSide, trueBranch, falseBranch};
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
if (trueBranch.getResult().resolvesToValueOrNull() && falseBranch.getResult().resolvesToValueOrNull()) {
|
||||
TypeModel lhs = trueBranch.getResult().getValueTypeWithNullType(null);
|
||||
TypeModel rhs = falseBranch.getResult().getValueTypeWithNullType(null);
|
||||
TypeModel res = null;
|
||||
if (lhs == null && rhs == null) {
|
||||
res = getSystem().getDefaultBaseType();
|
||||
} else if (lhs == null) {
|
||||
res = rhs;
|
||||
} else if (rhs == null) {
|
||||
res = lhs;
|
||||
} else {
|
||||
res = BinaryExpression.resultType(lhs, ":", rhs);
|
||||
}
|
||||
if (res == null) {
|
||||
return ExpressionResult.INVALID;
|
||||
} else {
|
||||
return new ExpressionResult.TypedValue(res);
|
||||
}
|
||||
}
|
||||
return super.resolveResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
BytecodeInstructionWriter.Label elseLabel = w.newLabel("cond_else");
|
||||
BytecodeInstructionWriter.Label endLabel = w.newLabel("cond_end");
|
||||
|
||||
TypeSignature xt = leftHandSide.generate(w);
|
||||
w.genJump(BytecodeInstructionWriter.JumpOp.IFFALSE, elseLabel);
|
||||
trueBranch.generate(w);
|
||||
w.genJump(BytecodeInstructionWriter.JumpOp.GOTO, endLabel);
|
||||
w.labelHere(elseLabel);
|
||||
falseBranch.generate(w);
|
||||
w.labelHere(endLabel);
|
||||
|
||||
return getResult().getValueType().getTypeSignature();
|
||||
}
|
||||
}
|
93
slangc/model/expressions/CountExpression.sauce
Normal file
93
slangc/model/expressions/CountExpression.sauce
Normal file
@@ -0,0 +1,93 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
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;
|
||||
|
||||
public class CountExpression extends ExpressionModel implements ExpressionOwner {
|
||||
ExpressionModel leftHandSide;
|
||||
String operator;
|
||||
|
||||
public CountExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
leftHandSide = ExpressionModel.construct(this, ((Branch)source).getSubnode(0));
|
||||
operator = BinaryExpression.getOpName(((Branch)source).getSubnode(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Count expression (" + getSource().getNodeType() + ")");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
leftHandSide.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return new ExpressionModel[] {leftHandSide};
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
if (leftHandSide.getResult().resolvesToValue()) {
|
||||
return new ExpressionResult.TypedValue(leftHandSide.getResult().getValueType());
|
||||
} else {
|
||||
return ExpressionResult.INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
TypeSignature lhsType = leftHandSide.generate(w);
|
||||
w.genDup(lhsType);
|
||||
w.genConst(w.getTarget().getHeap().getConstInt32("1"));
|
||||
if (operator.equals("++")) {
|
||||
TypeModel rt = BinaryExpression.generateALUOp(w, leftHandSide.getResult().getValueType(), "+", getSystem().getDefaultInt32Type());
|
||||
if (!rt.getTypeSignature().mappableEquals(leftHandSide.getResult().getValueType().getTypeSignature())) {
|
||||
w.genConvert(rt.getTypeSignature(), leftHandSide.getResult().getValueType().getTypeSignature());
|
||||
}
|
||||
leftHandSide.generateStore(w, leftHandSide.getResult().getValueType().getTypeSignature());
|
||||
return lhsType;
|
||||
} else if (operator.equals("--")) {
|
||||
TypeModel rt = BinaryExpression.generateALUOp(w, leftHandSide.getResult().getValueType(), "-", getSystem().getDefaultInt32Type());
|
||||
if (!rt.getTypeSignature().mappableEquals(leftHandSide.getResult().getValueType().getTypeSignature())) {
|
||||
w.genConvert(rt.getTypeSignature(), leftHandSide.getResult().getValueType().getTypeSignature());
|
||||
}
|
||||
leftHandSide.generateStore(w, leftHandSide.getResult().getValueType().getTypeSignature());
|
||||
return lhsType;
|
||||
} else {
|
||||
w.genError("TODO: innerGenerate for " + Type.of(this) + " with '" + operator + "'");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
56
slangc/model/expressions/GenericReferenceExpression.sauce
Normal file
56
slangc/model/expressions/GenericReferenceExpression.sauce
Normal file
@@ -0,0 +1,56 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.FieldModel;
|
||||
import slangc.model.LocalStorageModel;
|
||||
import slangc.model.Named;
|
||||
import slangc.model.StorageSlot;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.model.UserTypeModel;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.ErrorType;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class GenericReferenceExpression extends ExpressionModel {
|
||||
private TypeModel type;
|
||||
|
||||
public GenericReferenceExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
type = owner.resolveType(((Branch)source).getSubnode(0));
|
||||
//name = UserTypeModel.plainName(((Branch)source).getSubnode(0));
|
||||
// This now waits until expressions are resolved later
|
||||
//resolvedNamedEntity = lookupSimpleName(name);
|
||||
//sourceFile.annotate(ErrorType.INTERNAL_ERROR, "Unrecognised expression (Internal error/TODO)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Generic reference expression -> " + type);
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return NO_SUBEXPRESSIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
return new ExpressionResult.PointsToType((TypeModel) type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
w.genError("INTERNAL ERROR: innerGenerate shouldn't be called for " + Type.of(this));
|
||||
return null;
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
64
slangc/model/expressions/InstanceofExpression.sauce
Normal file
64
slangc/model/expressions/InstanceofExpression.sauce
Normal file
@@ -0,0 +1,64 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class InstanceofExpression extends ExpressionModel implements ExpressionOwner {
|
||||
TypeModel type;
|
||||
ExpressionModel valueExpression;
|
||||
|
||||
public InstanceofExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
valueExpression = ExpressionModel.construct(this, ((Branch)source).getSubnode(0));
|
||||
type = owner.resolveType(((Branch)source).getSubnode(2));
|
||||
}
|
||||
|
||||
public TypeModel getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public ExpressionModel getValueExpression() {
|
||||
return valueExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Instanceof '" + type + "':");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
valueExpression.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return new ExpressionModel[] {valueExpression};
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
// TODO: I'm not sure if there are cases where cast influences decoding of right-hand-side
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
return new ExpressionResult.TypedValue((TypeModel)lookupSimpleName("boolean"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
TypeSignature incoming = valueExpression.generate(w);
|
||||
w.genTypeCheck(incoming, getType().getTypeSignature());
|
||||
return getSystem().getDefaultBooleanType().getTypeSignature();
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
198
slangc/model/expressions/LiteralExpression.sauce
Normal file
198
slangc/model/expressions/LiteralExpression.sauce
Normal file
@@ -0,0 +1,198 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.ErrorType;
|
||||
import slangc.parser.Node;
|
||||
import slangc.parser.NodeType;
|
||||
import slangc.parser.Token;
|
||||
|
||||
public class LiteralExpression extends ExpressionModel {
|
||||
public static enum SimpleType {
|
||||
INT32,
|
||||
INT64,
|
||||
UINT32,
|
||||
UINT64,
|
||||
FLOAT32,
|
||||
FLOAT64,
|
||||
STRING,
|
||||
NULL,
|
||||
BOOLEAN,
|
||||
OTHER
|
||||
}
|
||||
private SimpleType simpleType = null;
|
||||
private boolean negated = false;
|
||||
|
||||
public LiteralExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
//sourceFile.annotate(ErrorType.INTERNAL_ERROR, "Unrecognised expression (Internal error/TODO)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Literal expression (" + getSource().getNodeType() + ")");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
}
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return NO_SUBEXPRESSIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
if (getSource().getNodeType() == NodeType.STRING_LITERAL_EXPRESSION) {
|
||||
simpleType = SimpleType.STRING;
|
||||
return new ExpressionResult.TypedValue(getSystem().getDefaultStringType());//(TypeModel) lookupSimpleName("String")); // TODO: Better lookup
|
||||
} else if (getSource().getNodeType() == NodeType.INTEGER_LITERAL_EXPRESSION || getSource().getNodeType() == NodeType.FLOAT_LITERAL_EXPRESSION) {
|
||||
String lit = ((Token)((Branch)getSource()).getSubnode(0)).getSnippet().getSource();
|
||||
if (getSource().getNodeType() == NodeType.FLOAT_LITERAL_EXPRESSION) {
|
||||
// TODO: Translations for d/D
|
||||
if (lit.search("f") || lit.search("F")) {
|
||||
simpleType = SimpleType.FLOAT32;
|
||||
return new ExpressionResult.TypedValue(getSystem().getDefaultFloat32Type());
|
||||
} else {
|
||||
simpleType = SimpleType.FLOAT64;
|
||||
return new ExpressionResult.TypedValue(getSystem().getDefaultFloat64Type());
|
||||
}
|
||||
} else {
|
||||
// TODO: Translations for l/L
|
||||
if (lit.search("l") || lit.search("L")) {
|
||||
// TODO: Translations for u/U
|
||||
if (lit.search("u") || lit.search("U")) {
|
||||
simpleType = SimpleType.UINT64;
|
||||
} else {
|
||||
simpleType = SimpleType.INT64;
|
||||
}
|
||||
return new ExpressionResult.TypedValue(
|
||||
simpleType == SimpleType.UINT64
|
||||
? getSystem().getDefaultUint64Type()
|
||||
: getSystem().getDefaultInt64Type());
|
||||
} else {
|
||||
// Integer literals need some special handling for when they're assigning a field
|
||||
// or variable with a known type. This applies to all of the types smaller than
|
||||
// ints (otherwise they'd need casts everywhere they're used).
|
||||
// TODO: Translations for u/U
|
||||
if (lit.search("u") || lit.search("U")) {
|
||||
simpleType = SimpleType.UINT32;
|
||||
} else {
|
||||
simpleType = SimpleType.INT32;
|
||||
}
|
||||
TypeModel expected = getOwner().getExpectedResult(this);
|
||||
TypeModel byteType = (TypeModel) lookupSimpleName("byte");
|
||||
TypeModel shortType = (TypeModel) lookupSimpleName("short");
|
||||
TypeModel charType = (TypeModel) lookupSimpleName("char");
|
||||
if (expected != null) {
|
||||
if (expected.simplify() == byteType.simplify()) {
|
||||
// TODO: Check that literal typeName actually fits in the expected type
|
||||
return new ExpressionResult.TypedValue(byteType);
|
||||
} else if (expected.simplify() == shortType.simplify()) {
|
||||
return new ExpressionResult.TypedValue(shortType);
|
||||
} else if (expected.simplify() == charType.simplify()) {
|
||||
return new ExpressionResult.TypedValue(charType);
|
||||
}
|
||||
}
|
||||
return new ExpressionResult.TypedValue(simpleType == SimpleType.UINT32 ?
|
||||
getSystem().getDefaultUint32Type()
|
||||
: getSystem().getDefaultInt32Type());
|
||||
}
|
||||
}
|
||||
} else if (getSource().getNodeType() == NodeType.CHAR_LITERAL_EXPRESSION) {
|
||||
simpleType = SimpleType.INT32;
|
||||
return new ExpressionResult.TypedValue((TypeModel) lookupSimpleName("int"/*"char"*/));
|
||||
} else if (getSource().getNodeType() == NodeType.NULL_LITERAL_EXPRESSION) {
|
||||
simpleType = SimpleType.NULL;
|
||||
return ExpressionResult.NULL;
|
||||
} else if (getSource().getNodeType() == NodeType.BOOLEAN_LITERAL_EXPRESSION) {
|
||||
simpleType = SimpleType.BOOLEAN;
|
||||
return new ExpressionResult.TypedValue(getSystem().getDefaultBooleanType());
|
||||
} else {
|
||||
simpleType = null;
|
||||
getSource().annotate(ErrorType.INTERNAL_ERROR, "Unrecognised expression type " + getSource().getNodeType());
|
||||
return ExpressionResult.INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleType getSimpleType() {
|
||||
return simpleType;
|
||||
}
|
||||
|
||||
public String getRawSource() {
|
||||
return ((Token)((Branch)getSource()).getSubnode(0)).getSnippet().getSource();
|
||||
}
|
||||
|
||||
public String getProcessedString() {
|
||||
String start = getRawSource();
|
||||
return start.sub(1, start.ints().length-1);
|
||||
}
|
||||
|
||||
public boolean canNegate() {
|
||||
switch (getSimpleType()) {
|
||||
case SimpleType.INT32:
|
||||
case SimpleType.INT64:
|
||||
case SimpleType.FLOAT32:
|
||||
case SimpleType.FLOAT64:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void negate() {
|
||||
if (!canNegate()) {
|
||||
throw new Error("Internal error, this literal can't be negated");
|
||||
}
|
||||
negated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
switch (getSimpleType()) {
|
||||
case SimpleType.BOOLEAN:
|
||||
if (getRawSource().equals("true")) {
|
||||
w.genBoolean(true);
|
||||
} else { // false
|
||||
w.genBoolean(false);
|
||||
}
|
||||
break;
|
||||
case SimpleType.INT32:
|
||||
w.genConst(w.getTarget().getHeap().getConstInt32((negated ? "-" : "") + getRawSource()));
|
||||
break;
|
||||
case SimpleType.INT64:
|
||||
w.genConst(w.getTarget().getHeap().getConstInt64((negated ? "-" : "") + getRawSource()));
|
||||
break;
|
||||
case SimpleType.UINT32:
|
||||
w.genConst(w.getTarget().getHeap().getConstUint32(getRawSource()));
|
||||
break;
|
||||
case SimpleType.UINT64:
|
||||
w.genConst(w.getTarget().getHeap().getConstUint64(getRawSource()));
|
||||
break;
|
||||
case SimpleType.FLOAT32:
|
||||
w.genConst(w.getTarget().getHeap().getConstFloat32(getRawSource()));
|
||||
break;
|
||||
case SimpleType.FLOAT64:
|
||||
w.genConst(w.getTarget().getHeap().getConstFloat64(getRawSource()));
|
||||
break;
|
||||
case SimpleType.STRING:
|
||||
w.genConst(w.getTarget().getHeap().getConstStringLiteral(getRawSource()));
|
||||
break;
|
||||
case SimpleType.NULL:
|
||||
w.genConst(w.getTarget().getHeap().getNull());
|
||||
break;
|
||||
default:
|
||||
w.genError("TODO: innerGenerate for " + Type.of(this));
|
||||
return null;
|
||||
}
|
||||
|
||||
return getResult().getValueTypeWithNullType(getSystem().getDefaultBaseType()).getTypeSignature();
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
106
slangc/model/expressions/NewClassExpression.sauce
Normal file
106
slangc/model/expressions/NewClassExpression.sauce
Normal file
@@ -0,0 +1,106 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ClauseModel;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.FieldModel;
|
||||
import slangc.model.MethodModel;
|
||||
import slangc.model.StatementOwner;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.model.UserTypeModel;
|
||||
import slangc.model.clauses.Arguments;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.ErrorType;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class NewClassExpression extends ExpressionModel implements StatementOwner {
|
||||
TypeModel declaredType;
|
||||
Arguments arguments;
|
||||
|
||||
public NewClassExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
//type = owner.resolveType(((Branch)source).getSubnode(1));
|
||||
|
||||
declaredType = getOwner().getTypeScope().getInnerTypeForSource((Branch)source);
|
||||
if (declaredType == null) {
|
||||
source.annotate(ErrorType.INTERNAL_ERROR, "Unable to match expression to type declaration");
|
||||
}
|
||||
|
||||
if (declaredType instanceof UserTypeModel) {
|
||||
((UserTypeModel)declaredType).statementOrExpression = this;
|
||||
}
|
||||
|
||||
arguments = (Arguments)ClauseModel.construct(this, ((Branch)source).getSubnode(2));
|
||||
}
|
||||
|
||||
public TypeModel getType() {
|
||||
return declaredType;
|
||||
}
|
||||
|
||||
public Arguments getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> New class expression of '" + declaredType + "'");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
arguments.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
// NOTE: Only the expressions in the arguments are considered subexpressions
|
||||
// (any expressions within the defined class are handled as portions of that type instead)
|
||||
return arguments.getSubexpressions();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
targetMethod = bestTargetMethod(declaredType.simplify().getInstanceConstructors(), arguments);
|
||||
return new ExpressionResult.TypedValue(declaredType.simplify());
|
||||
}
|
||||
|
||||
private MethodModel targetMethod = null;
|
||||
|
||||
@Override
|
||||
public boolean hasTargetMethod() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodModel getTargetMethod() {
|
||||
// TODO Auto-generated method stub
|
||||
return targetMethod;
|
||||
}
|
||||
|
||||
public static TypeSignature[] generateUpvalueLoads(BytecodeInstructionWriter w, UserTypeModel type) {
|
||||
FieldModel[] upvalues = type.getUpvalues();
|
||||
TypeSignature[] result = new TypeSignature[upvalues.length];
|
||||
for (int i = 0; i < upvalues.length; i++) {
|
||||
w.genLoadLocalOrParam(upvalues[i].getStorageType().getTypeSignature(), upvalues[i].getUpvalueReference().getIndex());
|
||||
result[i] = upvalues[i].getStorageType().getTypeSignature();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
UserTypeModel t = (UserTypeModel) getType().simplify();
|
||||
UserTypeModel outer = (UserTypeModel) t.getOwner().getNearestType();
|
||||
OuterThisExpression.generatePossibleOuterThis(w, (UserTypeModel)getMethodOrField().getOwner(), outer);
|
||||
TypeSignature[] upvs = generateUpvalueLoads(w, t);
|
||||
arguments.generate(w, getTargetMethod(), true);
|
||||
w.genNewInner(getTargetMethod().getMethodSignature(), upvs);
|
||||
return getType().simplify().getTypeSignature();
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
69
slangc/model/expressions/NewClearedArrayExpression.sauce
Normal file
69
slangc/model/expressions/NewClearedArrayExpression.sauce
Normal file
@@ -0,0 +1,69 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class NewClearedArrayExpression extends ExpressionModel implements ExpressionOwner {
|
||||
TypeModel type;
|
||||
ExpressionModel sizeExpression;
|
||||
|
||||
public NewClearedArrayExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
// NOTE: Since the final [...] is given with the sizeExpression instead of with
|
||||
// the rest of the type, we need to manually find the array type for the declared type:
|
||||
TypeModel base = owner.resolveType(((Branch)source).getSubnode(1));
|
||||
if (base != null) {
|
||||
type = base.getOrCreateArrayInstance();
|
||||
}
|
||||
sizeExpression = ExpressionModel.construct(this, ((Branch)source).getSubnode(3));
|
||||
}
|
||||
|
||||
public TypeModel getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public ExpressionModel getSizeExpression() {
|
||||
return sizeExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> New cleared array expression of '" + getType() + "'");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
sizeExpression.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return new ExpressionModel[] {sizeExpression};
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
// TODO maybe should be int?
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
return new ExpressionResult.TypedValue(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
TypeSignature xt = sizeExpression.generate(w);
|
||||
w.genNewArray(type.getTypeSignature());
|
||||
return type.getTypeSignature();
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
61
slangc/model/expressions/NewInitialisedArrayExpression.sauce
Normal file
61
slangc/model/expressions/NewInitialisedArrayExpression.sauce
Normal file
@@ -0,0 +1,61 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class NewInitialisedArrayExpression extends ExpressionModel implements ExpressionOwner {
|
||||
TypeModel type;
|
||||
ArrayInitialiserExpression initialiser;
|
||||
|
||||
public NewInitialisedArrayExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
type = owner.resolveType(((Branch)source).getSubnode(1));
|
||||
initialiser = (ArrayInitialiserExpression)ExpressionModel.construct(this, ((Branch)source).getSubnode(2));
|
||||
}
|
||||
|
||||
public TypeModel getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public ArrayInitialiserExpression getInitialisers() {
|
||||
return initialiser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> New initialised array expression of '" + type + "'");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
initialiser.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return new ExpressionModel[] {initialiser};
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
return new ExpressionResult.TypedValue(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
return initialiser.generate(w);
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
86
slangc/model/expressions/NewObjectExpression.sauce
Normal file
86
slangc/model/expressions/NewObjectExpression.sauce
Normal file
@@ -0,0 +1,86 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ClauseModel;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.MethodModel;
|
||||
import slangc.model.StatementOwner;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.model.UserTypeModel;
|
||||
import slangc.model.clauses.Arguments;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class NewObjectExpression extends ExpressionModel implements StatementOwner {
|
||||
TypeModel type;
|
||||
Arguments arguments;
|
||||
|
||||
public NewObjectExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
type = owner.resolveType(((Branch)source).getSubnode(1));
|
||||
arguments = (Arguments)ClauseModel.construct(this, ((Branch)source).getSubnode(2));
|
||||
}
|
||||
|
||||
public TypeModel getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Arguments getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> New object expression of '" + type + "'");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
arguments.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return arguments.getSubexpressions();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
targetMethod = bestTargetMethod(type.getInstanceConstructors(), arguments);
|
||||
return new ExpressionResult.TypedValue(type);
|
||||
}
|
||||
|
||||
private MethodModel targetMethod = null;
|
||||
|
||||
@Override
|
||||
public boolean hasTargetMethod() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodModel getTargetMethod() {
|
||||
return targetMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
if (getType() instanceof UserTypeModel && ((UserTypeModel) getType()).isNonStaticInnerType()) {
|
||||
UserTypeModel t = (UserTypeModel) getType();
|
||||
UserTypeModel outer = (UserTypeModel) t.getOwner().getNearestType();
|
||||
OuterThisExpression.generatePossibleOuterThis(w, (UserTypeModel)getMethodOrField().getOwner(), outer);
|
||||
TypeSignature[] upvs = NewClassExpression.generateUpvalueLoads(w, t);
|
||||
arguments.generate(w, getTargetMethod(), true);
|
||||
w.genNewInner(getTargetMethod().getMethodSignature(), upvs);
|
||||
return type.getTypeSignature();
|
||||
} else {
|
||||
arguments.generate(w, getTargetMethod(), true);
|
||||
w.genNewObject(getTargetMethod().getMethodSignature());
|
||||
return type.getTypeSignature();
|
||||
}
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
115
slangc/model/expressions/NormalMethodCallExpression.sauce
Normal file
115
slangc/model/expressions/NormalMethodCallExpression.sauce
Normal file
@@ -0,0 +1,115 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ClauseModel;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.MethodModel;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.model.UserTypeModel;
|
||||
import slangc.model.clauses.Arguments;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.ErrorType;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class NormalMethodCallExpression extends ExpressionModel implements ExpressionOwner {
|
||||
private ExpressionModel leftHandSide;
|
||||
private String name;
|
||||
private Arguments arguments;
|
||||
|
||||
public NormalMethodCallExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
leftHandSide = ExpressionModel.construct(this, ((Branch)source).getSubnode(0));
|
||||
name = UserTypeModel.plainName(((Branch)source).getSubnode(2));
|
||||
|
||||
arguments = (Arguments)ClauseModel.construct(this, ((Branch)source).getSubnode(3));
|
||||
//sourceFile.annotate(ErrorType.INTERNAL_ERROR, "Unrecognised expression (Internal error/TODO)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Normal method call expression '" + name + "' of:");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
leftHandSide.dump(reporter, indent + incr, incr);
|
||||
arguments.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
ExpressionModel[] args = arguments.getSubexpressions();
|
||||
ExpressionModel[] result = new ExpressionModel[args.length + 1];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
if (i == 0) {
|
||||
result[i] = leftHandSide;
|
||||
} else {
|
||||
result[i] = args[i - 1];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public ExpressionModel getLeftHandSide() {
|
||||
return leftHandSide;
|
||||
}
|
||||
|
||||
public Arguments getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
if (leftHandSide.getResult().resolvesToValueOrNull() && leftHandSide.getResult().getKind() != ExpressionResult.Kind.NULL) {
|
||||
TypeModel lhsType = leftHandSide.getResult().getValueType();
|
||||
targetMethod = bestTargetMethod(lhsType.getMethods(name, true), arguments);
|
||||
return ExpressionResult.fromMethodResult(targetMethod);
|
||||
} else if (leftHandSide.getResult().getKind() == ExpressionResult.Kind.POINTS_TO_TYPE) {
|
||||
TypeModel staticType = ((ExpressionResult.PointsToType) leftHandSide.getResult()).getType();
|
||||
targetMethod = bestTargetMethod(staticType.getMethods(name, true), arguments);
|
||||
return ExpressionResult.fromMethodResult(targetMethod);
|
||||
} else {
|
||||
leftHandSide.getSource().annotate(ErrorType.INTERNAL_ERROR, "Failed to resolve method target");
|
||||
return ExpressionResult.INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
private MethodModel targetMethod = null;
|
||||
|
||||
@Override
|
||||
public boolean hasTargetMethod() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodModel getTargetMethod() {
|
||||
// TODO Auto-generated method stub
|
||||
return targetMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
arguments.generate(w, getTargetMethod(), true);
|
||||
if (!getTargetMethod().isStatic()) {
|
||||
// TODO: Handle outer-this calls
|
||||
getLeftHandSide().generate(w);
|
||||
}
|
||||
w.genCall(getTargetMethod().getMethodSignature());
|
||||
return getTargetMethod().getMethodSignature().returnType;
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
84
slangc/model/expressions/OuterThisExpression.sauce
Normal file
84
slangc/model/expressions/OuterThisExpression.sauce
Normal file
@@ -0,0 +1,84 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.TypeLevel;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.model.UserTypeModel;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class OuterThisExpression extends ExpressionModel implements ExpressionOwner {
|
||||
private TypeModel leftHandSide;
|
||||
|
||||
public OuterThisExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
Node t = ((Branch)source).getSubnode(0);
|
||||
leftHandSide = owner.resolveType(t);//ExpressionModel.construct(this, ((Branch)sourceFile).getSubnode(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Outer this expression of " + leftHandSide);
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public TypeModel getType() {
|
||||
return leftHandSide;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return NO_SUBEXPRESSIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
// TODO Should probably check that the outer this actually makes sense first
|
||||
return new ExpressionResult.TypedValue(getType());
|
||||
}
|
||||
|
||||
public static TypeSignature generatePossibleOuterThis(BytecodeInstructionWriter w, UserTypeModel thisThis, TypeModel desiredOuter) {
|
||||
return generatePossibleOuterThis(w, thisThis, desiredOuter, false);
|
||||
}
|
||||
|
||||
private static TypeSignature generatePossibleOuterThis(BytecodeInstructionWriter w, UserTypeModel thisThis, TypeModel desiredOuter, boolean alreadyRecursing) {
|
||||
if ((thisThis == desiredOuter || thisThis.inherits(desiredOuter)) && !alreadyRecursing) {
|
||||
w.genThis();
|
||||
return thisThis.getTypeSignature();
|
||||
} else if (thisThis.isNonStaticInnerType()) {
|
||||
TypeModel outer = thisThis.getOwner().getNearestType();
|
||||
if (!alreadyRecursing) {
|
||||
w.genThis();
|
||||
}
|
||||
w.genOuterThis();
|
||||
if (outer == desiredOuter || outer.inherits(desiredOuter)) {
|
||||
return outer.getTypeSignature();
|
||||
} else {
|
||||
return generatePossibleOuterThis(w, (UserTypeModel) outer, desiredOuter, true);
|
||||
}
|
||||
} else {
|
||||
w.genError("Bad outer this, can't get to " + desiredOuter + " from " + thisThis);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
return generatePossibleOuterThis(w, (UserTypeModel)getMethodOrField().getOwner(), leftHandSide);
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
110
slangc/model/expressions/ReferenceExpression.sauce
Normal file
110
slangc/model/expressions/ReferenceExpression.sauce
Normal file
@@ -0,0 +1,110 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.FieldModel;
|
||||
import slangc.model.LocalStorageModel;
|
||||
import slangc.model.Named;
|
||||
import slangc.model.StorageSlot;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.model.UserTypeModel;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.ErrorType;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class ReferenceExpression extends ExpressionModel {
|
||||
private String name;
|
||||
private Named resolvedNamedEntity;
|
||||
|
||||
public ReferenceExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
name = UserTypeModel.plainName(((Branch)source).getSubnode(0));
|
||||
// This now waits until expressions are resolved later
|
||||
//resolvedNamedEntity = lookupSimpleName(name);
|
||||
//sourceFile.annotate(ErrorType.INTERNAL_ERROR, "Unrecognised expression (Internal error/TODO)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Reference expression '" + name + "' -> " + resolvedNamedEntity);
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Named getResolvedNamedEntity() {
|
||||
return resolvedNamedEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return NO_SUBEXPRESSIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
if (resolvedNamedEntity == null) {
|
||||
resolvedNamedEntity = lookupSimpleName(name);
|
||||
}
|
||||
//System.err.println("Resolved to " + resolvedNamedEntity);
|
||||
if (resolvedNamedEntity == null) {
|
||||
if (!(getOwner() instanceof SubreferenceExpression)) {
|
||||
getSource().annotate(ErrorType.INTERNAL_ERROR, "Failed to resolve '" + name + "'");
|
||||
}
|
||||
return new ExpressionResult.StartOfName(name);
|
||||
} else if (resolvedNamedEntity instanceof TypeModel) {
|
||||
return new ExpressionResult.PointsToType((TypeModel) resolvedNamedEntity);
|
||||
} else if (resolvedNamedEntity instanceof StorageSlot) {
|
||||
return new ExpressionResult.PointsToStorageSlot((StorageSlot) resolvedNamedEntity);
|
||||
} else {
|
||||
throw new Error("Reference resolved to invalid entity: " + resolvedNamedEntity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
if (getResolvedNamedEntity() instanceof FieldModel) {
|
||||
FieldModel f = (FieldModel)getResolvedNamedEntity();
|
||||
if (!f.isStatic()) {
|
||||
OuterThisExpression.generatePossibleOuterThis(w, (UserTypeModel)getMethodOrField().getOwner(), f.getOwner());
|
||||
}
|
||||
w.genLoad(f.getFieldSignature());
|
||||
return f.getFieldSignature().storageType;
|
||||
} else if (getResolvedNamedEntity() instanceof LocalStorageModel) {
|
||||
LocalStorageModel l = (LocalStorageModel)getResolvedNamedEntity();
|
||||
// TODO: Handle upvalues!
|
||||
w.genLoadLocalOrParam(l.getStorageType().getTypeSignature(), l.getIndex());
|
||||
return l.getStorageType().getTypeSignature();
|
||||
} else {
|
||||
w.genError("TODO: innerGenerate for " + Type.of(this) + " with " + getResolvedNamedEntity());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateStore(BytecodeInstructionWriter w, TypeSignature storing) {
|
||||
if (getResolvedNamedEntity() instanceof FieldModel) {
|
||||
FieldModel f = (FieldModel)getResolvedNamedEntity();
|
||||
if (!f.isStatic()) {
|
||||
OuterThisExpression.generatePossibleOuterThis(w, (UserTypeModel)getMethodOrField().getOwner(), f.getOwner());
|
||||
}
|
||||
w.genStore(f.getFieldSignature());
|
||||
} else if (getResolvedNamedEntity() instanceof LocalStorageModel) {
|
||||
LocalStorageModel l = (LocalStorageModel)getResolvedNamedEntity();
|
||||
// TODO: Handle upvalues!
|
||||
w.genStoreLocalOrParam(l.getStorageType().getTypeSignature(), l.getIndex());
|
||||
} else {
|
||||
w.genError("TODO: generateStore for " + getResolvedNamedEntity());
|
||||
}
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
223
slangc/model/expressions/SubreferenceExpression.sauce
Normal file
223
slangc/model/expressions/SubreferenceExpression.sauce
Normal file
@@ -0,0 +1,223 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ArrayTypeModel;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.FieldModel;
|
||||
import slangc.model.LocalStorageModel;
|
||||
import slangc.model.Named;
|
||||
import slangc.model.PackageModel;
|
||||
import slangc.model.StorageSlot;
|
||||
import slangc.model.SystemModel;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.model.UserTypeModel;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.ErrorType;
|
||||
import slangc.parser.Node;
|
||||
import slangc.parser.WarningType;
|
||||
|
||||
public class SubreferenceExpression extends ExpressionModel implements ExpressionOwner {
|
||||
private ExpressionModel leftHandSide;
|
||||
private String name;
|
||||
private SpecialFieldKind specialFieldKind = null;
|
||||
|
||||
public static enum SpecialFieldKind {
|
||||
NOT_SPECIAL,
|
||||
ARRAY_LENGTH
|
||||
}
|
||||
|
||||
public SubreferenceExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
leftHandSide = ExpressionModel.construct(this, ((Branch)source).getSubnode(0));
|
||||
name = UserTypeModel.plainName(((Branch)source).getSubnode(2));
|
||||
//sourceFile.annotate(ErrorType.INTERNAL_ERROR, "Unrecognised expression (Internal error/TODO)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Subreference expression '" + name + "' of:");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
leftHandSide.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return new ExpressionModel[] {leftHandSide};
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public ExpressionModel getLeftHandSide() {
|
||||
return leftHandSide;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
/* When resolving, we initially set the special field kind to NOT_SPECIAL and later
|
||||
* set it to ARRAY_LENGTH if necessary.
|
||||
*/
|
||||
specialFieldKind = SpecialFieldKind.NOT_SPECIAL;
|
||||
|
||||
/* If the left-hand-side resolves to the start of a name (e.g. "x.y") rather than
|
||||
* something like a variable or field (e.g. if "x" was declared in the scope) then
|
||||
* we expect that at some point along the chain (e.g. at "x.y.Z") it will resolve to
|
||||
* a type (in this case a type named "Z" in the package "x.y").
|
||||
*
|
||||
* This requires some special handling between Reference/Subreference and ExpressionResult.
|
||||
*/
|
||||
if (leftHandSide.getResult().getKind() == ExpressionResult.Kind.START_OF_NAME) {
|
||||
ExpressionResult.StartOfName start = (ExpressionResult.StartOfName) leftHandSide.getResult();
|
||||
SystemModel system = getOwner().getMethodOrField().getOwner().getPackage().getSystem();// TODO: Make easier way of finding this
|
||||
/* If the name so far (without adding this subreference) can resolve to a package name, then
|
||||
* we check if a type with our subreference's name exists within that package. If no type is
|
||||
* found, we fall back to the default behaviour (in case an enclosing Subreference gives us
|
||||
* more information and it ends up resolving to a type in a subpackage instead).
|
||||
*/
|
||||
if (system.hasPackage(start.getNameSoFar())) {
|
||||
PackageModel pkg = system.getPackage(start.getNameSoFar());
|
||||
if (pkg.hasType(name)) {
|
||||
return new ExpressionResult.PointsToType(pkg.getType(name));
|
||||
}
|
||||
}
|
||||
/* If we didn't resolve to a type here, the default behaviour is to create a new StartOfName
|
||||
* with this subreference name added.
|
||||
* This allows an outer Subreference to easily determine it's full name for further lookup.
|
||||
*/
|
||||
String nameSoFar = start.getNameSoFar() + "." + name;
|
||||
if (!(getOwner() instanceof SubreferenceExpression)) {
|
||||
getSource().annotate(ErrorType.INTERNAL_ERROR, "Failed to resolve '" + nameSoFar + "'");
|
||||
}
|
||||
return new ExpressionResult.StartOfName(nameSoFar);
|
||||
}
|
||||
|
||||
/* If the left-hand-side points to a type, rather than producing some kind of runtime typeName, then
|
||||
* we should only look up subtypes or static fields.
|
||||
*/
|
||||
if (leftHandSide.getResult().getKind() == ExpressionResult.Kind.POINTS_TO_TYPE) {
|
||||
TypeModel lhsType = ((ExpressionResult.PointsToType) leftHandSide.getResult()).getType();
|
||||
|
||||
if (lhsType.hasInnerType(name)) {
|
||||
return new ExpressionResult.PointsToType(lhsType.getInnerType(name));
|
||||
} else if (lhsType.hasField(name)) {
|
||||
FieldModel m = lhsType.getField(name);
|
||||
if (!m.isStatic()) {
|
||||
getSource().annotate(ErrorType.INTERNAL_ERROR, "The field '" + name + "' in type " + lhsType + " cannot be used in a static context");
|
||||
return ExpressionResult.INVALID;
|
||||
}
|
||||
return new ExpressionResult.PointsToStorageSlot(lhsType.getField(name));
|
||||
} else {
|
||||
getSource().annotate(ErrorType.INTERNAL_ERROR, "Can't find static field or inner type '" + name + "' in type " + lhsType + " of " + leftHandSide.getResult());
|
||||
return ExpressionResult.INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise we're dealing with a typeName, and should ideally be looking for an instance field
|
||||
* (aside from a few edge cases...)
|
||||
*/
|
||||
if (leftHandSide.getResult().resolvesToValueOrNull()) {
|
||||
if (leftHandSide.getResult().getKind() == ExpressionResult.Kind.NULL) {
|
||||
getSource().annotate(ErrorType.INTERNAL_ERROR, "Can't find field or inner type '" + name + "' within, uh, null");
|
||||
return ExpressionResult.INVALID;
|
||||
}
|
||||
// TODO: Handling of duck types and/or unresolved lambdas
|
||||
TypeModel valueType = leftHandSide.getResult().getValueType();
|
||||
|
||||
|
||||
// Special case of array length results in an integer
|
||||
if (valueType instanceof ArrayTypeModel && getSystem().isArrayLengthName(name)) {//name.equals("length")) {
|
||||
specialFieldKind = SpecialFieldKind.ARRAY_LENGTH;
|
||||
return new ExpressionResult.TypedValue((TypeModel) lookupSimpleName("int"));
|
||||
}
|
||||
|
||||
if (valueType.hasInnerType(name)) {
|
||||
return new ExpressionResult.PointsToType(valueType.getInnerType(name));
|
||||
} else if (valueType.hasField(name)) {
|
||||
FieldModel m = valueType.getField(name);
|
||||
// If a static field is referred to in a non-static context we should at least add a warning...
|
||||
if (m.isStatic()) {
|
||||
getSource().annotate(WarningType.INTERNAL_WARNING, "The field '" + name + "' in type " + valueType + " is static and shouldn't be used from an instance");
|
||||
}
|
||||
return new ExpressionResult.PointsToStorageSlot(valueType.getField(name));
|
||||
} else {
|
||||
getSource().annotate(ErrorType.INTERNAL_ERROR, "Can't find instance field or inner type '" + name + "' in type " + valueType + " of " + leftHandSide.getResult());
|
||||
return ExpressionResult.INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public SpecialFieldKind getSpecialFieldKind() {
|
||||
return specialFieldKind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
switch (getSpecialFieldKind()) {
|
||||
case SpecialFieldKind.ARRAY_LENGTH:
|
||||
leftHandSide.generate(w);
|
||||
w.genArrayLength();
|
||||
return getSystem().getDefaultInt32Type().getTypeSignature();
|
||||
case SpecialFieldKind.NOT_SPECIAL:{
|
||||
ExpressionResult.PointsToStorageSlot s = (ExpressionResult.PointsToStorageSlot)getResult();
|
||||
StorageSlot slot = s.getSlot();
|
||||
if (slot instanceof FieldModel) {
|
||||
FieldModel f = (FieldModel)slot;
|
||||
if (!f.isStatic()) {
|
||||
leftHandSide.generate(w);
|
||||
}
|
||||
w.genLoad(f.getFieldSignature());
|
||||
return f.getStorageType().getTypeSignature();
|
||||
} else {
|
||||
w.genError("TODO: innerGenerate for " + Type.of(this) + " with slot " + slot);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
default:
|
||||
w.genError("TODO: in innerGenerate for " + Type.of(this));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateStore(BytecodeInstructionWriter w, TypeSignature storing) {
|
||||
|
||||
switch (getSpecialFieldKind()) {
|
||||
case SpecialFieldKind.ARRAY_LENGTH:
|
||||
w.genError("Can't assign array length");
|
||||
break;
|
||||
case SpecialFieldKind.NOT_SPECIAL:{
|
||||
ExpressionResult.PointsToStorageSlot s = (ExpressionResult.PointsToStorageSlot)getResult();
|
||||
StorageSlot slot = s.getSlot();
|
||||
if (slot instanceof FieldModel) {
|
||||
FieldModel f = (FieldModel)slot;
|
||||
if (!f.isStatic()) {
|
||||
leftHandSide.generate(w);
|
||||
}
|
||||
w.genStore(f.getFieldSignature());
|
||||
} else {
|
||||
w.genError("TODO: generateStore for " + Type.of(this) + " with slot " + slot);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
w.genError("TODO: in generateStore for " + Type.of(this));
|
||||
}
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ClauseModel;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.MethodModel;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.model.UserTypeModel;
|
||||
import slangc.model.clauses.Arguments;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class SuperConstructorCallExpression extends ExpressionModel implements ExpressionOwner {
|
||||
private Arguments arguments;
|
||||
private boolean approvedLocation = false;
|
||||
|
||||
public SuperConstructorCallExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
|
||||
arguments = (Arguments)ClauseModel.construct(this, ((Branch)source).getSubnode(1));
|
||||
//sourceFile.annotate(ErrorType.INTERNAL_ERROR, "Unrecognised expression (Internal error/TODO)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Super constructor call of:");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
arguments.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public Arguments getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return arguments.getSubexpressions();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
targetMethod = bestTargetMethod(((UserTypeModel)getMethodOrField().getOwner()).getBaseClass().getInstanceConstructors(), arguments);
|
||||
// Super/this constructor calls shouldn't be used within expressions
|
||||
// so they can be assumed to return void even though logically they kind-of
|
||||
// return the object they create
|
||||
return ExpressionResult.VOID;
|
||||
}
|
||||
|
||||
private MethodModel targetMethod = null;
|
||||
|
||||
@Override
|
||||
public boolean hasTargetMethod() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodModel getTargetMethod() {
|
||||
// TODO Auto-generated method stub
|
||||
return targetMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
if (!isApprovedLocation()) {
|
||||
w.genError("Constructors can't be called in this context");
|
||||
}
|
||||
//w.genThis();
|
||||
arguments.generate(w, getTargetMethod(), true);
|
||||
w.genNestedConstructorCall(getTargetMethod().getMethodSignature());
|
||||
return TypeSignature.VOID;
|
||||
}
|
||||
|
||||
public boolean isApprovedLocation() {
|
||||
return approvedLocation;
|
||||
}
|
||||
|
||||
public void setApprovedLocation(boolean approvedLocation) {
|
||||
this.approvedLocation = approvedLocation;
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
88
slangc/model/expressions/SuperMethodCallExpression.sauce
Normal file
88
slangc/model/expressions/SuperMethodCallExpression.sauce
Normal file
@@ -0,0 +1,88 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ClauseModel;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.MethodModel;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.model.UserTypeModel;
|
||||
import slangc.model.clauses.Arguments;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class SuperMethodCallExpression extends ExpressionModel implements ExpressionOwner {
|
||||
private String name;
|
||||
private Arguments arguments;
|
||||
|
||||
public SuperMethodCallExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
name = UserTypeModel.plainName(((Branch)((Branch)source).getSubnode(2)).getSubnode(0));
|
||||
|
||||
arguments = (Arguments)ClauseModel.construct(this, ((Branch)source).getSubnode(3));
|
||||
//sourceFile.annotate(ErrorType.INTERNAL_ERROR, "Unrecognised expression (Internal error/TODO)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Super method call expression '" + name + "' of:");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
arguments.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
targetMethod = bestTargetMethod(((UserTypeModel) getOwner().getMethodOrField().getOwner()).getBaseClass().getMethods(name, true), arguments);
|
||||
return ExpressionResult.fromMethodResult(targetMethod);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public Arguments getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return arguments.getSubexpressions();
|
||||
}
|
||||
|
||||
private MethodModel targetMethod = null;
|
||||
|
||||
@Override
|
||||
public boolean hasTargetMethod() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodModel getTargetMethod() {
|
||||
// TODO Auto-generated method stub
|
||||
return targetMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
arguments.generate(w, getTargetMethod(), true);
|
||||
if (!getTargetMethod().isStatic()) {
|
||||
// TODO: Handle outer-this calls
|
||||
w.genThis();
|
||||
}
|
||||
w.genCall(getTargetMethod().getMethodSignature(), true);
|
||||
return getTargetMethod().getMethodSignature().returnType;
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
96
slangc/model/expressions/SuperReferenceExpression.sauce
Normal file
96
slangc/model/expressions/SuperReferenceExpression.sauce
Normal file
@@ -0,0 +1,96 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.FieldModel;
|
||||
import slangc.model.Named;
|
||||
import slangc.model.StorageSlot;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.model.UserTypeModel;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.ErrorType;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class SuperReferenceExpression extends ExpressionModel implements ExpressionOwner {
|
||||
private String name;
|
||||
|
||||
public SuperReferenceExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
name = UserTypeModel.plainName(((Branch)source).getSubnode(2));
|
||||
//sourceFile.annotate(ErrorType.INTERNAL_ERROR, "Unrecognised expression (Internal error/TODO)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> SuperReference expression '" + name + "'");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return NO_SUBEXPRESSIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
TypeModel superType = ((UserTypeModel) getOwner().getMethodOrField().getOwner()).getBaseClass();
|
||||
if (superType.hasInnerType(name)) {
|
||||
return new ExpressionResult.PointsToType(superType.getInnerType(name));
|
||||
} else if (superType.hasField(name, true)) {
|
||||
return new ExpressionResult.PointsToStorageSlot(superType.getField(name, true));
|
||||
} else {
|
||||
getSource().annotate(ErrorType.INTERNAL_ERROR, "Can't find '" + name + "' within super-type " + superType);
|
||||
return ExpressionResult.INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
ExpressionResult.PointsToStorageSlot s = (ExpressionResult.PointsToStorageSlot)getResult();
|
||||
StorageSlot slot = s.getSlot();
|
||||
if (slot instanceof FieldModel) {
|
||||
FieldModel f = (FieldModel)slot;
|
||||
if (!f.isStatic()) {
|
||||
w.genThis();
|
||||
}
|
||||
w.genLoad(f.getFieldSignature());
|
||||
return f.getStorageType().getTypeSignature();
|
||||
} else {
|
||||
w.genError("TODO: innerGenerate for " + Type.of(this) + " with slot " + slot);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateStore(BytecodeInstructionWriter w, TypeSignature storing) {
|
||||
ExpressionResult.PointsToStorageSlot s = (ExpressionResult.PointsToStorageSlot)getResult();
|
||||
StorageSlot slot = s.getSlot();
|
||||
if (slot instanceof FieldModel) {
|
||||
FieldModel f = (FieldModel)slot;
|
||||
if (!f.isStatic()) {
|
||||
w.genThis();
|
||||
}
|
||||
w.genStore(f.getFieldSignature());
|
||||
} else {
|
||||
w.genError("TODO: generateStore for " + Type.of(this) + " with slot " + slot);
|
||||
}
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
93
slangc/model/expressions/ThisConstructorCallExpression.sauce
Normal file
93
slangc/model/expressions/ThisConstructorCallExpression.sauce
Normal file
@@ -0,0 +1,93 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ClauseModel;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.MethodModel;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.model.UserTypeModel;
|
||||
import slangc.model.clauses.Arguments;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class ThisConstructorCallExpression extends ExpressionModel implements ExpressionOwner {
|
||||
private Arguments arguments;
|
||||
private boolean approvedLocation = false;
|
||||
|
||||
public ThisConstructorCallExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
|
||||
arguments = (Arguments)ClauseModel.construct(this, ((Branch)source).getSubnode(1));
|
||||
//sourceFile.annotate(ErrorType.INTERNAL_ERROR, "Unrecognised expression (Internal error/TODO)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> This constructor call of:");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
arguments.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public Arguments getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return arguments.getSubexpressions();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
targetMethod = bestTargetMethod(((UserTypeModel)getMethodOrField().getOwner()).getInstanceConstructors(), arguments);
|
||||
// Super/this constructor calls shouldn't be used within expressions
|
||||
// so they can be assumed to return void even though logically they kind-of
|
||||
// return the object they create
|
||||
return ExpressionResult.VOID;
|
||||
}
|
||||
|
||||
private MethodModel targetMethod = null;
|
||||
|
||||
@Override
|
||||
public boolean hasTargetMethod() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodModel getTargetMethod() {
|
||||
// TODO Auto-generated method stub
|
||||
return targetMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
if (!isApprovedLocation()) {
|
||||
w.genError("Constructors can't be called in this context");
|
||||
}
|
||||
//w.genThis();
|
||||
arguments.generate(w, getTargetMethod(), true);
|
||||
w.genNestedConstructorCall(getTargetMethod().getMethodSignature());
|
||||
return TypeSignature.VOID;
|
||||
}
|
||||
|
||||
public boolean isApprovedLocation() {
|
||||
return approvedLocation;
|
||||
}
|
||||
|
||||
public void setApprovedLocation(boolean approvedLocation) {
|
||||
this.approvedLocation = approvedLocation;
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
41
slangc/model/expressions/ThisExpression.sauce
Normal file
41
slangc/model/expressions/ThisExpression.sauce
Normal file
@@ -0,0 +1,41 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class ThisExpression extends ExpressionModel {
|
||||
public ThisExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> This expression");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return NO_SUBEXPRESSIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
return new ExpressionResult.TypedValue(getMethodOrField().getOwner());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
w.genThis();
|
||||
return getMethodOrField().getOwner().getTypeSignature();
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
88
slangc/model/expressions/ThisMethodCallExpression.sauce
Normal file
88
slangc/model/expressions/ThisMethodCallExpression.sauce
Normal file
@@ -0,0 +1,88 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ClauseModel;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.MethodModel;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.model.UserTypeModel;
|
||||
import slangc.model.clauses.Arguments;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class ThisMethodCallExpression extends ExpressionModel implements ExpressionOwner {
|
||||
private String name;
|
||||
private Arguments arguments;
|
||||
|
||||
public ThisMethodCallExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
name = UserTypeModel.plainName(((Branch)((Branch)source).getSubnode(2)).getSubnode(0));
|
||||
|
||||
arguments = (Arguments)ClauseModel.construct(this, ((Branch)source).getSubnode(3));
|
||||
//sourceFile.annotate(ErrorType.INTERNAL_ERROR, "Unrecognised expression (Internal error/TODO)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> This method call expression '" + name + "' of:");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
arguments.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
targetMethod = bestTargetMethod(getOwner().getMethodOrField().getOwner().getMethods(name, true), arguments);
|
||||
return ExpressionResult.fromMethodResult(targetMethod);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public Arguments getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return arguments.getSubexpressions();
|
||||
}
|
||||
|
||||
private MethodModel targetMethod = null;
|
||||
|
||||
@Override
|
||||
public boolean hasTargetMethod() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodModel getTargetMethod() {
|
||||
// TODO Auto-generated method stub
|
||||
return targetMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
arguments.generate(w, getTargetMethod(), true);
|
||||
if (!getTargetMethod().isStatic()) {
|
||||
// TODO: Handle outer-this calls
|
||||
w.genThis();
|
||||
}
|
||||
w.genCall(getTargetMethod().getMethodSignature());
|
||||
return getTargetMethod().getMethodSignature().returnType;
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
68
slangc/model/expressions/TypeExpression.sauce
Normal file
68
slangc/model/expressions/TypeExpression.sauce
Normal file
@@ -0,0 +1,68 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.model.TypeModel;
|
||||
import slangc.parser.Branch;
|
||||
import slangc.parser.Node;
|
||||
import slangc.parser.NodeType;
|
||||
|
||||
public class TypeExpression extends ExpressionModel implements ExpressionOwner {
|
||||
private TypeModel leftHandSide;
|
||||
|
||||
public TypeExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
Node t = ((Branch)source).getSubnode(0);
|
||||
if (t.getNodeType() == NodeType.NO_RETURN_TYPE) {
|
||||
leftHandSide = null;
|
||||
} else {
|
||||
leftHandSide = owner.resolveType(t);//ExpressionModel.construct(this, ((Branch)sourceFile).getSubnode(0));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Type expression (.class) of " + leftHandSide);
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return NO_SUBEXPRESSIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeModel getExpectedResult(ExpressionModel e) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public TypeModel getType() {
|
||||
return leftHandSide;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
// For now we just find the "Class" type
|
||||
// TODO: Make this more robust/configurable
|
||||
return new ExpressionResult.TypedValue(getSystem().getDefaultTypeType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
if (getType() == null) { // void
|
||||
w.genTypeObject(TypeSignature.VOID);
|
||||
} else {
|
||||
w.genTypeObject(getType().getTypeSignature());
|
||||
}
|
||||
return getSystem().getDefaultTypeType().getTypeSignature();
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
122
slangc/model/expressions/UnaryExpression.sauce
Normal file
122
slangc/model/expressions/UnaryExpression.sauce
Normal file
@@ -0,0 +1,122 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
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;
|
||||
|
||||
public class UnaryExpression extends ExpressionModel implements ExpressionOwner {
|
||||
String operator;
|
||||
ExpressionModel rightHandSide;
|
||||
|
||||
public UnaryExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
operator = BinaryExpression.getOpName(((Branch)source).getSubnode(0));
|
||||
rightHandSide = ExpressionModel.construct(this, ((Branch)source).getSubnode(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> Unary expression (" + getSource().getNodeType() + ")");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
rightHandSide.dump(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return new ExpressionModel[] {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();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
if (rightHandSide.getResult().resolvesToValueOrNull() && rightHandSide.getResult().getKind() != ExpressionResult.Kind.NULL) {
|
||||
return new ExpressionResult.TypedValue(rightHandSide.getResult().getValueType());
|
||||
} else {
|
||||
return ExpressionResult.INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
public String getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
String op = getOperator();
|
||||
if (op.equals("+")) {
|
||||
w.genConst(w.getTarget().getHeap().getConstInt32("0"));
|
||||
rightHandSide.generate(w);
|
||||
return BinaryExpression.generateALUOp(w, getSystem().getDefaultInt32Type(), "+", rightHandSide.getResult().getValueType()).getTypeSignature();
|
||||
} else if (op.equals("-")) {
|
||||
if (rightHandSide instanceof LiteralExpression && ((LiteralExpression)rightHandSide).canNegate()) {
|
||||
LiteralExpression lrhs = (LiteralExpression) rightHandSide;
|
||||
lrhs.negate();
|
||||
return lrhs.generate(w);
|
||||
} else {
|
||||
w.genConst(w.getTarget().getHeap().getConstInt32("0"));
|
||||
rightHandSide.generate(w);
|
||||
return BinaryExpression.generateALUOp(w, getSystem().getDefaultInt32Type(), "-", rightHandSide.getResult().getValueType()).getTypeSignature();
|
||||
}
|
||||
} else if (op.equals("~")) {
|
||||
// TODO: Make sure this works for non-int types
|
||||
w.genConst(w.getTarget().getHeap().getConstInt32("-1"));
|
||||
rightHandSide.generate(w);
|
||||
return BinaryExpression.generateALUOp(w, getSystem().getDefaultInt32Type(), "^", rightHandSide.getResult().getValueType()).getTypeSignature();
|
||||
} else if (op.equals("!")) {
|
||||
rightHandSide.generate(w);
|
||||
w.genNot();
|
||||
return getSystem().getDefaultBooleanType().getTypeSignature();
|
||||
} else if (op.equals("++")) {
|
||||
TypeSignature rhsType = rightHandSide.generate(w);
|
||||
w.genConst(w.getTarget().getHeap().getConstInt32("1"));
|
||||
TypeModel rt = BinaryExpression.generateALUOp(w, rightHandSide.getResult().getValueType(), "+", getSystem().getDefaultInt32Type());
|
||||
if (!rt.getTypeSignature().mappableEquals(rightHandSide.getResult().getValueType().getTypeSignature())) {
|
||||
w.genConvert(rt.getTypeSignature(), rightHandSide.getResult().getValueType().getTypeSignature());
|
||||
}
|
||||
rightHandSide.generateStore(w, rightHandSide.getResult().getValueType().getTypeSignature());
|
||||
return rightHandSide.generate(w);
|
||||
} else if (op.equals("--")) {
|
||||
TypeSignature rhsType = rightHandSide.generate(w);
|
||||
w.genConst(w.getTarget().getHeap().getConstInt32("1"));
|
||||
TypeModel rt = BinaryExpression.generateALUOp(w, rightHandSide.getResult().getValueType(), "-", getSystem().getDefaultInt32Type());
|
||||
if (!rt.getTypeSignature().mappableEquals(rightHandSide.getResult().getValueType().getTypeSignature())) {
|
||||
w.genConvert(rt.getTypeSignature(), rightHandSide.getResult().getValueType().getTypeSignature());
|
||||
}
|
||||
rightHandSide.generateStore(w, rightHandSide.getResult().getValueType().getTypeSignature());
|
||||
return rightHandSide.generate(w);
|
||||
} else {
|
||||
w.genError("TODO: innerGenerate for " + Type.of(this) + " with '" + getOperator() + "'");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
44
slangc/model/expressions/UnrecognisedExpression.sauce
Normal file
44
slangc/model/expressions/UnrecognisedExpression.sauce
Normal file
@@ -0,0 +1,44 @@
|
||||
package slangc.model.expressions;
|
||||
|
||||
import slangc.api.BytecodeInstructionWriter;
|
||||
import slangc.api.Reporter;
|
||||
import slangc.bytecode.TypeSignature;
|
||||
import slangc.model.ExpressionModel;
|
||||
import slangc.model.ExpressionOwner;
|
||||
import slangc.model.ExpressionResult;
|
||||
import slangc.parser.ErrorType;
|
||||
import slangc.parser.Node;
|
||||
|
||||
public class UnrecognisedExpression extends ExpressionModel {
|
||||
|
||||
public UnrecognisedExpression(ExpressionOwner owner, Node source) {
|
||||
super(owner, source);
|
||||
source.annotate(ErrorType.INTERNAL_ERROR, "Unrecognised expression (Internal error/TODO)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Reporter reporter, String indent, String incr) {
|
||||
reporter.note("DUMP", indent + "> TODO: Unrecognised expression (" + getSource().getNodeType() + ")");
|
||||
dumpResolved(reporter, indent + incr, incr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionModel[] getSubexpressions() {
|
||||
return NO_SUBEXPRESSIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExpressionResult resolveResult() {
|
||||
return ExpressionResult.INVALID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSignature innerGenerate(BytecodeInstructionWriter w) {
|
||||
w.genError("TODO: innerGenerate for " + Type.of(this));
|
||||
return null;
|
||||
}
|
||||
|
||||
public TypeModel resolveType(Node n) {
|
||||
return super.resolveType(n); // TODO: Better support for interfaces
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user