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.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; } public IVal apply(long lineNumber, IVal function, IVal ... parameters) { try { MultiFunction mfun = Types.matchFunction(function.getType(), parameters.length); return applyWithEffect(lineNumber, mfun.effect, mfun.returnType, function, parameters); } catch (MatchException e) { throw new InternalCompilerError(e); } } public IVal applyWithEffectChecked(long lineNumber, 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(lineNumber, 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.location = 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(ICont cont, IVal ... parameters) { block.setExit(new Jump(cont.createOccurrence(), ValRef.createOccurrences(parameters))); block = null; } public void if_(IVal condition, ICont thenTarget, ICont elseTarget) { block.setExit(new If(condition.createOccurrence(), thenTarget.createOccurrence(), elseTarget.createOccurrence())); block = null; } public void branchAwayIf(IVal condition, ICont target) { SSABlock newBlock = new SSABlock(Type.EMPTY_ARRAY); block.getParent().addBlock(newBlock); block.setExit(new If(condition.createOccurrence(), target.createOccurrence(), newBlock.createOccurrence())); this.block = newBlock; } public void branchAwayUnless(IVal condition, ICont target) { SSABlock newBlock = new SSABlock(Type.EMPTY_ARRAY); block.getParent().addBlock(newBlock); block.setExit(new If(condition.createOccurrence(), newBlock.createOccurrence(), target.createOccurrence())); this.block = newBlock; } public void return_(IVal val) { jump(block.getParent().getReturnCont(), val); } public void switch_(IVal val, Branch[] branches) { block.setExit(new Switch(val.createOccurrence(), BranchRef.toBranchRefs(branches))); block = null; } public void throw_(long location, TypeDesc exceptionClass, String description) { Throw exit = new Throw(exceptionClass, description); exit.location = location; 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)); } }