Initial commit of main compiler sources (or should I say ... SAUCES!)

This commit is contained in:
2025-06-08 23:58:21 +10:00
parent 60c566025c
commit 06f2613083
214 changed files with 22210 additions and 0 deletions

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

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

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

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

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

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

View 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();
}
}

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

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

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

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

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

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

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

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

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

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

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

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

View File

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

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

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

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

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

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

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

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

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