package org.simantics.scl.compiler.internal.codegen.writer; import org.cojen.classfile.TypeDesc; import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; import org.simantics.scl.compiler.errors.Locations; import org.simantics.scl.compiler.internal.codegen.continuations.Branch; import org.simantics.scl.compiler.internal.codegen.continuations.BranchRef; import org.simantics.scl.compiler.internal.codegen.continuations.ICont; import org.simantics.scl.compiler.internal.codegen.references.BoundVar; import org.simantics.scl.compiler.internal.codegen.references.IVal; import org.simantics.scl.compiler.internal.codegen.references.ValRef; import org.simantics.scl.compiler.internal.codegen.ssa.SSABlock; import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction; import org.simantics.scl.compiler.internal.codegen.ssa.SSAObject; import org.simantics.scl.compiler.internal.codegen.ssa.exits.If; import org.simantics.scl.compiler.internal.codegen.ssa.exits.Jump; import org.simantics.scl.compiler.internal.codegen.ssa.exits.Switch; import org.simantics.scl.compiler.internal.codegen.ssa.exits.Throw; import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetApply; import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetFunctions; import org.simantics.scl.compiler.top.SCLCompilerConfiguration; import org.simantics.scl.compiler.types.TVar; import org.simantics.scl.compiler.types.Type; import org.simantics.scl.compiler.types.Types; import org.simantics.scl.compiler.types.exceptions.MatchException; import org.simantics.scl.compiler.types.util.MultiFunction; public class CodeWriter { ModuleWriter moduleWriter; SSABlock block; public CodeWriter(ModuleWriter moduleWriter, SSABlock block) { this.moduleWriter = moduleWriter; this.block = block; } private int lineNumber(long location) { if(location == Locations.NO_LOCATION) return -1; else { int position = Locations.beginOf(location); int line = moduleWriter.lineLocator.lineNumberFromPosition(position); //System.out.println("location=" + location + ", position=" + position + ", line=" + line); return line + 1; } } public IVal apply(long location, IVal function, IVal ... parameters) { try { MultiFunction mfun = Types.matchFunction(function.getType(), parameters.length); return applyWithEffect(location, mfun.effect, mfun.returnType, function, parameters); } catch (MatchException e) { throw new InternalCompilerError(e); } } public IVal applyWithEffectChecked(long location, Type effect, Type returnType, IVal function, IVal ... parameters) { try { MultiFunction mfun = Types.matchFunction(function.getType(), parameters.length); if(!Types.equals(effect, mfun.effect)) throw new InternalCompilerError(); if(!Types.equals(returnType, mfun.returnType)) throw new InternalCompilerError(); } catch (MatchException e) { throw new InternalCompilerError(e); } return applyWithEffect(location, effect, returnType, function, parameters); } public IVal applyWithEffect(long location, Type effect, Type returnType, IVal function, IVal ... parameters) { BoundVar var = new BoundVar(returnType); LetApply apply = new LetApply(var, effect, function.createOccurrence(), ValRef.createOccurrences(parameters)); apply.lineNumber = lineNumber(location); block.addStatement(apply); return var; } public CodeWriter createBlock() { SSABlock newBlock = new SSABlock(Type.EMPTY_ARRAY); block.getParent().addBlock(newBlock); return new CodeWriter(moduleWriter, newBlock); } public CodeWriter createBlock(Type ... parameterTypes) { SSABlock newBlock = new SSABlock(parameterTypes); block.getParent().addBlock(newBlock); return new CodeWriter(moduleWriter, newBlock); } public CodeWriter createFunction(TVar[] typeParameters, Type effect, Type returnType, Type[] parameterTypes) { if(SCLCompilerConfiguration.DEBUG) if(effect == null) throw new InternalCompilerError(); SSAFunction function = new SSAFunction(typeParameters, effect, returnType); SSABlock block = new SSABlock(parameterTypes); function.addBlock(block); BoundVar target = new BoundVar(function.getType()); function.setTarget(target); this.block.addStatement(new LetFunctions(function)); return new CodeWriter(moduleWriter, block); } public RecursiveDefinitionWriter createRecursiveDefinition() { LetFunctions let = new LetFunctions(); block.addStatement(let); return new RecursiveDefinitionWriter(moduleWriter, let); } public void continueAs(CodeWriter codeWriter) { this.block = codeWriter.block; codeWriter.block = null; } public IVal[] getParameters() { return block.getParameters(); } public ICont getContinuation() { return block; } public void jump(long location, ICont cont, IVal ... parameters) { block.setExit(new Jump( lineNumber(location), cont.createOccurrence(), ValRef.createOccurrences(parameters))); block = null; } public void if_(long location, IVal condition, ICont thenTarget, ICont elseTarget) { block.setExit(new If( lineNumber(location), condition.createOccurrence(), thenTarget.createOccurrence(), elseTarget.createOccurrence())); block = null; } public void branchAwayIf(long location, IVal condition, ICont target) { SSABlock newBlock = new SSABlock(Type.EMPTY_ARRAY); block.getParent().addBlock(newBlock); block.setExit(new If( lineNumber(location), condition.createOccurrence(), target.createOccurrence(), newBlock.createOccurrence())); this.block = newBlock; } public void branchAwayUnless(long location, IVal condition, ICont target) { SSABlock newBlock = new SSABlock(Type.EMPTY_ARRAY); block.getParent().addBlock(newBlock); block.setExit(new If( lineNumber(location), condition.createOccurrence(), newBlock.createOccurrence(), target.createOccurrence())); this.block = newBlock; } public void return_(long location, IVal val) { jump(lineNumber(location), block.getParent().getReturnCont(), val); } public void switch_(long location, IVal val, Branch[] branches) { block.setExit(new Switch(lineNumber(location), val.createOccurrence(), BranchRef.toBranchRefs(branches))); block = null; } public void throw_(long location, TypeDesc exceptionClass, String description) { Throw exit = new Throw(lineNumber(location), exceptionClass, description); block.setExit(exit); block = null; } public ModuleWriter getModuleWriter() { return moduleWriter; } public SSAFunction getFunction() { return block.getParent(); } public boolean isUnfinished() { return block != null; } public void defineObject(SSAObject object) { this.block.addStatement(new LetFunctions(object)); } }