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