}
public void convertToSSA() {
- ModuleWriter mw = new ModuleWriter(compilationContext.namingPolicy.getModuleClassName());
+ ModuleWriter mw = new ModuleWriter(compilationContext.namingPolicy.getModuleClassName(), compilationContext.lineLocator);
for(SCLValue value : module.getValues()) {
//System.out.println(value.getName().name + " :: " + value.getType());
Expression expression = value.getExpression();
IVal[] parameterVals = w.getParameters();
for(int i=0;i<decomposed.parameters.length;++i)
decomposed.parameters[i].setVal(parameterVals[i]);
- w.return_(decomposed.body.toVal(compilationContext, w));
+ w.return_(expression.location, decomposed.body.toVal(compilationContext, w));
} catch(RuntimeException e) {
long location = value.getExpression().location;
if(location == Locations.NO_LOCATION)
import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
import org.simantics.scl.compiler.internal.codegen.utils.JavaNamingPolicy;
import org.simantics.scl.compiler.internal.header.ModuleHeader;
+import org.simantics.scl.compiler.internal.parsing.utils.LineLocator;
import org.simantics.scl.compiler.module.ConcreteModule;
import org.simantics.scl.compiler.module.debug.ModuleDebugInfo;
import org.simantics.scl.compiler.module.repository.ModuleRepository;
public class CompilationContext implements EnvironmentalContext {
public final ErrorLog errorLog = new ErrorLog();
+ public LineLocator lineLocator;
public ModuleRepository moduleRepository;
public Environment environment;
public JavaTypeTranslator javaTypeTranslator;
package org.simantics.scl.compiler.compilation;
-import java.io.IOException;
-import java.io.Reader;
+import java.io.StringReader;
import java.util.ArrayList;
import java.util.Map;
import org.simantics.scl.compiler.environment.EnvironmentFactory;
import org.simantics.scl.compiler.errors.ErrorLog;
import org.simantics.scl.compiler.internal.codegen.types.JavaReferenceValidatorFactory;
-import org.simantics.scl.compiler.internal.header.ModuleHeader;
import org.simantics.scl.compiler.internal.parsing.declarations.DeclarationAst;
import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
import org.simantics.scl.compiler.internal.parsing.parser.SCLParserImpl;
import org.simantics.scl.compiler.internal.parsing.parser.SCLParserOptions;
+import org.simantics.scl.compiler.internal.parsing.utils.LineLocators;
import org.simantics.scl.compiler.module.ConcreteModule;
import org.simantics.scl.compiler.module.options.ModuleCompilationOptions;
import org.simantics.scl.compiler.top.ModuleInitializer;
}
@SuppressWarnings("unchecked")
- public void addSource(Reader sourceReader) {
+ public void addSource(String source) {
if(SCLCompilerConfiguration.ENABLE_TIMING) initializeTiming();
try {
- SCLParserImpl parser = new SCLParserImpl(sourceReader);
+ compilationContext.lineLocator = LineLocators.createLineLocator(source);
+ SCLParserImpl parser = new SCLParserImpl(new StringReader(source));
parser.setParserOptions(SCLParserOptions.MODULE_DEFAULT);
parser.setCompilationContext(compilationContext);
if(!parser.isEmpty())
compilationContext.errorLog.log(e.location, e.getMessage());
} catch(Exception e) {
compilationContext.errorLog.log(e);
- } finally {
- try {
- sourceReader.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
}
if(SCLCompilerConfiguration.ENABLE_TIMING) phaseFinished("Parsing");
}
}
else /*if(parameters.length < def.getArity())*/ {
def.applyTypes(functionRef.getTypeParameters());
- def.apply(parameters);
+ def.apply(apply.lineNumber, parameters);
def.setTarget(apply.getTarget());
new LetFunctions(def).insertBefore(apply);
apply.getFunction().remove();
apply.detachThisAndSuccessors();
block.getExit().destroy();
- block.setExit(new Throw2(apply.getParameters()[0]));
+ block.setExit(new Throw2(apply.lineNumber, apply.getParameters()[0]));
context.markModified("inline-throw");
}
}
PlanRealizer realizer = new PlanRealizer(cachedContext, this, runtimeRulesetVariable, implementationParameters[0], plan.ops);
realizer.nextOp(methodWriter);
if(methodWriter.isUnfinished())
- methodWriter.return_(BooleanConstant.TRUE);
+ methodWriter.return_(rule.location, BooleanConstant.TRUE);
}
}
if(!includes.isEmpty() || extensible) {
methodWriter.apply(Locations.NO_LOCATION,
new JavaMethod(true, runtimeRulesetClassName, "register", Types.PROC, Types.UNIT, new Type[] {runtimeRulesetType, Types.CHRContext}),
object.getTarget(), methodWriter.getParameters()[0]);
- methodWriter.return_(NoRepConstant.UNIT);
+ methodWriter.return_(location, NoRepConstant.UNIT);
}
{
CodeWriter methodWriter = object.createMethod(w.getModuleWriter(), TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {Types.CHRContext});
methodWriter.apply(Locations.NO_LOCATION,
new JavaMethod(true, runtimeRulesetClassName, "unregister", Types.PROC, Types.UNIT, new Type[] {runtimeRulesetType, Types.CHRContext}),
object.getTarget(), methodWriter.getParameters()[0]);
- methodWriter.return_(NoRepConstant.UNIT);
+ methodWriter.return_(location, NoRepConstant.UNIT);
}
}
if(initConstraint != null) {
planContext.partnerFacts.add(new PartnerFact(true, activeId, constraint, inputVal, constraint.mayBeRemoved(), killAfterMatch, null, null, end == null ? null : end.getContinuation()));
planContext.nextOp(w);
if(end != null)
- end.return_(BooleanConstant.FALSE);
+ end.return_(location, BooleanConstant.FALSE);
}
}
for(int i=0;i<expressions.length;++i)
if(((boundMask>>i)&1)==1)
parameters.add(expressions[i].toVal(context, w));
- w.jump(bodyContinuation, w.apply(location,
+ w.jump(location, bodyContinuation, w.apply(location,
constraint.fetchFromIndex(context, boundMask), parameters.toArray(new IVal[parameters.size()])));
- body.branchAwayIf(body.apply(location, NullCheck.INSTANCE.createSpecialization(constraint.factType), fact),
+ body.branchAwayIf(location, body.apply(location, NullCheck.INSTANCE.createSpecialization(constraint.factType), fact),
end.getContinuation());
IVal id = body.apply(location, constraint.accessId, fact);
for(PartnerFact partnerFact : planContext.partnerFacts)
if(partnerFact.active && !passive) {
- body.branchAwayUnless(body.apply(location, JavaComparisonOperation.ILESS, id, partnerFact.id),
+ body.branchAwayUnless(location, body.apply(location, JavaComparisonOperation.ILESS, id, partnerFact.id),
nextFact.getContinuation());
}
else if(partnerFact.constraint == constraint) {
- body.branchAwayIf(body.apply(location, JavaComparisonOperation.IEQUAL, id, partnerFact.id),
+ body.branchAwayIf(location, body.apply(location, JavaComparisonOperation.IEQUAL, id, partnerFact.id),
nextFact.getContinuation());
}
planContext.partnerFacts.add(new PartnerFact(false, id, constraint, fact, constraint.mayBeRemoved(), killAfterMatch, nextElement, bodyContinuation, end.getContinuation()));
planContext.nextOp(body);
if(body.isUnfinished())
- body.jump(nextFact.getContinuation());
- nextFact.jump(bodyContinuation, nextFact.apply(location, nextElement, fact));
+ body.jump(location, nextFact.getContinuation());
+ nextFact.jump(location, bodyContinuation, nextFact.apply(location, nextElement, fact));
w.continueAs(end);
}
ArrayList<Row2> rows = new ArrayList<Row2>(1);
rows.add(new Row2(new Expression[] {pattern}, body.getContinuation()));
- PatternMatchingCompiler2.split(w, context, scrutineeVals, end.getContinuation(), rows);
+ PatternMatchingCompiler2.split(location, w, context, scrutineeVals, end.getContinuation(), rows);
planContext.nextOp(body);
if(body.isUnfinished())
- body.jump(end.getContinuation());
+ body.jump(location, end.getContinuation());
w.continueAs(end);
}
ICont bodyContinuation = body.getContinuation();
CodeWriter end = w.createBlock();
- w.jump(body.getContinuation(), IntegerConstant.ZERO);
+ w.jump(location, body.getContinuation(), IntegerConstant.ZERO);
IVal index = body.getParameters()[0];
- body.branchAwayIf(body.apply(location, JavaComparisonOperation.IEQUAL, index, listLength),
+ body.branchAwayIf(location, body.apply(location, JavaComparisonOperation.IEQUAL, index, listLength),
end.getContinuation());
variable.setVal(body.apply(location, ListElement.INSTANCE.createSpecialization(componentType), listValue, index));
nextOp(body);
if(body.isUnfinished())
- body.jump(bodyContinuation, body.apply(location, IncreaseByOne.INSTANCE, index));
+ body.jump(location, bodyContinuation, body.apply(location, IncreaseByOne.INSTANCE, index));
w.continueAs(end);
}
CodeWriter end = w.createBlock();
CodeWriter body = w.createBlock(componentType);
- w.switch_(maybeValue, new Branch[] {
+ w.switch_(location, maybeValue, new Branch[] {
new Branch(JustConstant.INSTANCE, body.getContinuation()),
new Branch(null, end.getContinuation())
});
variable.setVal(body.getParameters()[0]);
nextOp(body);
if(body.isUnfinished())
- body.jump(end.getContinuation());
+ body.jump(location, end.getContinuation());
w.continueAs(end);
}
public void check(long location, CodeWriter w, IVal booleanValue) {
CodeWriter end = w.createBlock();
- w.branchAwayUnless(booleanValue, end.getContinuation());
+ w.branchAwayUnless(location, booleanValue, end.getContinuation());
nextOp(w);
if(w.isUnfinished())
- w.jump(end.getContinuation());
+ w.jump(location, end.getContinuation());
w.continueAs(end);
}
CodeWriter end = w.createBlock();
CodeWriter body = w.createBlock(componentType);
- w.switch_(maybeValue, new Branch[] {
+ w.switch_(location, maybeValue, new Branch[] {
new Branch(JustConstant.INSTANCE, body.getContinuation()),
new Branch(null, end.getContinuation())
});
- body.branchAwayUnless(body.apply(location,
+ body.branchAwayUnless(location, body.apply(location,
EqualsFunction.INSTANCE.createSpecialization(componentType),
value, body.getParameters()[0]), end.getContinuation());
nextOp(body);
if(body.isUnfinished())
- body.jump(end.getContinuation());
+ body.jump(location, end.getContinuation());
w.continueAs(end);
}
for(PartnerFact activeFact : planContext.partnerFacts) {
if(activeFact.killAfterMatch) {
if(activeFact.nextFact == null)
- w.jump(activeFact.finishCont);
+ w.jump(location, activeFact.finishCont);
else {
CodeWriter iterateAlive = w.createBlock(activeFact.constraint.factType);
- w.jump(iterateAlive.getContinuation(), w.apply(location, activeFact.nextFact, activeFact.factVar));
+ w.jump(location, iterateAlive.getContinuation(), w.apply(location, activeFact.nextFact, activeFact.factVar));
iterateUntilLiveFactFound(iterateAlive, activeFact);
}
break;
}
else if(activeFact.mayBeRemoved) {
if(activeFact.nextFact == null) {
- w.branchAwayUnless(activeFact.isAlive(location, w), activeFact.finishCont);
+ w.branchAwayUnless(location, activeFact.isAlive(location, w), activeFact.finishCont);
}
else {
CodeWriter failure = w.createBlock();
CodeWriter iterateAlive = w.createBlock(activeFact.constraint.factType);
- w.branchAwayUnless(activeFact.isAlive(location, w), failure.getContinuation());
- failure.jump(iterateAlive.getContinuation(), failure.apply(location, activeFact.nextFact, activeFact.factVar));
+ w.branchAwayUnless(location, activeFact.isAlive(location, w), failure.getContinuation());
+ failure.jump(location, iterateAlive.getContinuation(), failure.apply(location, activeFact.nextFact, activeFact.factVar));
iterateUntilLiveFactFound(iterateAlive, activeFact);
}
}
CHRConstraint constraint = activeFact.constraint;
IVal fact = w.getParameters()[0];
CodeWriter dead = w.createBlock();
- w.branchAwayIf(w.apply(location, NullCheck.INSTANCE.createSpecialization(constraint.factType), fact), activeFact.finishCont);
- w.branchAwayUnless(activeFact.isAlive(location, w, fact), dead.getContinuation());
- w.jump(activeFact.continueCont, fact);
- dead.jump(initialContinuation, dead.apply(location, activeFact.nextFact, fact));
+ w.branchAwayIf(location, w.apply(location, NullCheck.INSTANCE.createSpecialization(constraint.factType), fact), activeFact.finishCont);
+ w.branchAwayUnless(location, activeFact.isAlive(location, w, fact), dead.getContinuation());
+ w.jump(location, activeFact.continueCont, fact);
+ dead.jump(location, initialContinuation, dead.apply(location, activeFact.nextFact, fact));
}
}
CodeWriter thenBlock = w.createBlock();
if(else_ != null) {
CodeWriter elseBlock = w.createBlock();
- w.if_(conditionVal, thenBlock.getContinuation(), elseBlock.getContinuation());
+ w.if_(location, conditionVal, thenBlock.getContinuation(), elseBlock.getContinuation());
IVal elseVal = else_.toVal(context, elseBlock);
- elseBlock.jump(joinPoint.getContinuation(), elseVal);
+ elseBlock.jump(location, joinPoint.getContinuation(), elseVal);
}
else {
- w.if_(conditionVal, thenBlock.getContinuation(), joinPoint.getContinuation());
+ w.if_(location, conditionVal, thenBlock.getContinuation(), joinPoint.getContinuation());
}
IVal thenVal = then_.toVal(context, thenBlock);
- thenBlock.jump(joinPoint.getContinuation(), thenVal);
+ thenBlock.jump(location, joinPoint.getContinuation(), thenVal);
w.continueAs(joinPoint);
return w.getParameters()[0];
IVal[] parameters = newW.getParameters();
for(int j=0;j<parameters.length;++j)
decomposed.parameters[j].setVal(parameters[j]);
- newW.return_(decomposed.body.toVal(context, newW));
+ newW.return_(assignments[i].value.location, decomposed.body.toVal(context, newW));
}
return in.toVal(context, w);
}
CodeWriter joinPoint = w.createBlock(getType());
CodeWriter failurePoint = w.createBlock(); // TODO generate only one failurePoint per function
- PatternMatchingCompiler.split(w, context, scrutineeVals, joinPoint.getContinuation(), failurePoint.getContinuation(), rows);
+ PatternMatchingCompiler.split(location, w, context, scrutineeVals, joinPoint.getContinuation(), failurePoint.getContinuation(), rows);
failurePoint.throw_(location, Throw.MatchingException, "Matching failure at: " + toString());
w.continueAs(joinPoint);
return w.getParameters()[0];
IVal functionVal = newW.getFunction().getTarget();
for(int i=0;i<parameters.length;++i)
decomposed.parameters[i].setVal(parameters[i]);
- newW.return_(decomposed.body.toVal(context, newW));
+ newW.return_(decomposed.body.location, decomposed.body.toVal(context, newW));
return functionVal;
}
for(Expression guard : expressions[i].guards) {
CodeWriter nextW = w.createBlock();
- w.if_(guard.toVal(context, w), nextW.getContinuation(), failure);
+ w.if_(guard.location, guard.toVal(context, w), nextW.getContinuation(), failure);
w = nextW;
}
- w.jump(success, expressions[i].value.toVal(context, w));
+ w.jump(expressions[i].location, success, expressions[i].value.toVal(context, w));
}
}
);
block.addStatement(apply);
- block.setExit(new Jump(runProcFunction.getReturnCont().createOccurrence(),
+ block.setExit(new Jump(-1, runProcFunction.getReturnCont().createOccurrence(),
x.createOccurrence()));
runProcFunction.addBlock(block);
proxyParameters[i] = new BoundVar(oldParameters[i].getType());
SSABlock block = new SSABlock(proxyParameters);
function.addBlock(block);
- block.setExit(new Jump(createOccurrence(),
+ block.setExit(new Jump(-1, createOccurrence(),
ValRef.concat(ValRef.createOccurrences(newParameters),
ValRef.createOccurrences(proxyParameters))));
return block;
for(BranchRef branch : sw.getBranches()) {
if(branch.constructor == function) {
sw.destroy();
- setExit(new Jump(branch.cont.getBinding().createOccurrence(),
+ setExit(new Jump(sw.lineNumber, branch.cont.getBinding().createOccurrence(),
ValRef.copy(apply.getParameters())));
return true;
}
* [a]
*/
sw.destroy();
- setExit(new Jump(branch.cont.getBinding().createOccurrence()));
+ setExit(new Jump(sw.lineNumber, branch.cont.getBinding().createOccurrence()));
}
}
}
public abstract class SSAExit implements Printable {
SSABlock parent;
- public long location;
+ public final int lineNumber;
+
+ public SSAExit(int lineNumber) {
+ this.lineNumber = lineNumber;
+ }
public abstract void generateCode(MethodBuilder mb);
for(SSABlock block = f.firstBlock; block != null; block = block.next)
block.parent = this;
lastBlock.next = f.firstBlock;
- f.firstBlock.prev = lastBlock;
+ f.firstBlock.prev = lastBlock;
lastBlock = f.lastBlock;
firstBlock.firstStatement = firstBlock.lastStatement = null;
effect = f.effect;
BoundVar[] newParameters = BoundVar.copy(f.firstBlock.parameters);
firstBlock.setParameters(BoundVar.concat(getParameters(), newParameters));
- firstBlock.setExit(new Jump(f.firstBlock.createOccurrence(), ValRef.createOccurrences(newParameters)));
+ firstBlock.setExit(new Jump(-1, f.firstBlock.createOccurrence(), ValRef.createOccurrences(newParameters)));
context.markModified("SSAFunction.simplify-simple-lambda");
}
parameter.parent = firstBlock;
}
- public void apply(ValRef[] parameters) {
+ public void apply(int lineNumber, ValRef[] parameters) {
if(parameters.length == 0)
return;
if(firstBlock.hasNoOccurences()) {
else {
BoundVar[] newVars = new BoundVar[getArity()-parameters.length];
SSABlock block = new SSABlock(newVars);
- block.setExit(new Jump(firstBlock.createOccurrence(),
+ block.setExit(new Jump(lineNumber, firstBlock.createOccurrence(),
ValRef.concat(ValRef.copy(parameters), ValRef.createOccurrences(newVars))));
addBlockInFront(block);
}
System.out.println("Create class " + moduleClassName);
final ClassBuilder classFile = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, moduleClassName,
"java/lang/Object");
- classFile.setSourceFile("_SCL_Module");
+ classFile.setSourceFile(moduleBuilder.getNamingPolicy().getModuleName());
functions.forEachValue(new TObjectProcedure<SCLConstant>() {
@Override
public boolean execute(SCLConstant function) {
SSABlock parent;
SSAStatement prev;
SSAStatement next;
- public long location;
+ public int lineNumber = -2;
public void detach() {
if(prev == null)
private ContRef thenTarget;
private ContRef elseTarget;
- public If(ValRef condition, ContRef thenTarget, ContRef elseTarget) {
+ public If(int lineNumber, ValRef condition, ContRef thenTarget, ContRef elseTarget) {
+ super(lineNumber);
setCondition(condition);
setThenTarget(thenTarget);
setElseTarget(elseTarget);
@Override
public void generateCode(MethodBuilder mb) {
+ mb.lineNumber(lineNumber);
Val binding = condition.getBinding();
simplifyTestCode: if(binding instanceof BoundVar) {
BoundVar boundVar = (BoundVar)binding;
@Override
public SSAExit copy(CopyContext context) {
- return new If(context.copy(condition),
+ If copy = new If(lineNumber,
+ context.copy(condition),
context.copy(thenTarget),
context.copy(elseTarget));
+ return copy;
}
@Override
if(cond instanceof BooleanConstant) {
SSAExit newExit;
if(((BooleanConstant) cond).getValue()) {
- newExit = new Jump(thenTarget);
+ newExit = new Jump(lineNumber, thenTarget);
elseTarget.remove();
}
else {
- newExit = new Jump(elseTarget);
+ newExit = new Jump(lineNumber, elseTarget);
thenTarget.remove();
}
condition.remove();
else if(thenTarget.getBinding() == elseTarget.getBinding()) {
elseTarget.remove();
condition.remove();
- getParent().setExit(new Jump(thenTarget));
+ getParent().setExit(new Jump(lineNumber, thenTarget));
context.markModified("equal-branches-if");
}
}
private ContRef target;
private ValRef[] parameters;
- public Jump(ContRef target, ValRef ... parameters) {
+ public Jump(int lineNumber, ContRef target, ValRef ... parameters) {
+ super(lineNumber);
setTarget(target);
setParameters(parameters);
}
}
@Override
- public void generateCode(MethodBuilder mb) {
+ public void generateCode(MethodBuilder mb) {
+ mb.lineNumber(lineNumber);
mb.jump(target, ValRef.getBindings(parameters));
}
@Override
public SSAExit copy(CopyContext context) {
- return new Jump(context.copy(target), context.copy(parameters));
+ return new Jump(lineNumber, context.copy(target), context.copy(parameters));
}
@Override
ValRef scrutinee;
BranchRef[] branches;
- public Switch(ValRef scrutinee, BranchRef[] branches) {
+ public Switch(int lineNumber, ValRef scrutinee, BranchRef[] branches) {
+ super(lineNumber);
this.scrutinee = scrutinee;
this.branches = branches;
scrutinee.setParent(this);
@Override
public void generateCode(MethodBuilder mb) {
+ mb.lineNumber(lineNumber);
if(isIntegerSwitch()) {
generateIntegerSwitch(mb);
return;
@Override
public SSAExit copy(CopyContext context) {
- return new Switch(context.copy(scrutinee),
+ return new Switch(lineNumber, context.copy(scrutinee),
BranchRef.copy(context, branches));
}
SSAExit newExit;
if(thenTarget == elseTarget) {
scrutinee.remove();
- newExit = new Jump(thenTarget);
+ newExit = new Jump(lineNumber, thenTarget);
}
else {
- newExit = new If(scrutinee,
+ newExit = new If(lineNumber,
+ scrutinee,
thenTarget,
elseTarget);
}
}
else if(branches.length == 1 && isConstructorParameterless(branches[0])) {
scrutinee.remove();
- getParent().setExit(new Jump(branches[0].cont));
+ getParent().setExit(new Jump(lineNumber, branches[0].cont));
}
}
TypeDesc exceptionClass;
String description;
- public Throw(TypeDesc exceptionClass, String description) {
+ public Throw(int lineNumber, TypeDesc exceptionClass, String description) {
+ super(lineNumber);
this.exceptionClass = exceptionClass;
this.description = description;
}
@Override
public void generateCode(MethodBuilder mb) {
- //mb.push(exception.getBinding());
- //cb.mapLineNumber(location);
+ mb.lineNumber(lineNumber);
mb.newObject(exceptionClass);
mb.dup();
if(description == null)
@Override
public SSAExit copy(CopyContext context) {
- return new Throw(exceptionClass, description);
+ return new Throw(lineNumber, exceptionClass, description);
}
@Override
ValRef exception;
- public Throw2(ValRef exception) {
+ public Throw2(int lineNumber, ValRef exception) {
+ super(lineNumber);
this.exception = exception;
}
@Override
public void generateCode(MethodBuilder mb) {
+ mb.lineNumber(lineNumber);
mb.pushBoxed(exception.getBinding());
mb.throwObject();
}
@Override
public SSAExit copy(CopyContext context) {
- return new Throw2(exception.copy());
+ return new Throw2(lineNumber, exception.copy());
}
@Override
}
public void push(MethodBuilder mb) {
- //mb.getCodeBuilder().mapLineNumber(lineNumber);
+ int oldLineNumber = mb.lineNumber(lineNumber);
Val f = getFunction().getBinding();
Val[] ps = ValRef.getBindings(getParameters());
if(f instanceof Constant) {
mb.genericApply(ps.length);
mb.unbox(target.getType());
}
+ mb.lineNumber(oldLineNumber);
}
@Override
public void generateCode(MethodBuilder mb) {
if(!target.generateOnFly) {
+ mb.lineNumber(lineNumber);
push(mb);
mb.store(target);
}
public void bodyToString(PrintingContext context) {
if(context.getErrorMarker() == this)
context.append("!> ");
+ context.append("L" + lineNumber + ": ");
if(hasEffect()) {
context.append("<");
context.append(effect);
// Merge blocks
thisFunction.mergeBlocks(function);
- headBlock.setExit(new Jump(function.getFirstBlock().createOccurrence(),
- parameters));
+ headBlock.setExit(new Jump(lineNumber, function.getFirstBlock().createOccurrence(), parameters));
function.getReturnCont().replaceWith(tailBlock);
this.function.remove();
private MethodVisitor methodVisitor;
private LocalVariable[] parameters;
private int localVariableCount = 0;
+ private int currentLineNumber = -1;
public MethodBuilderBase(ClassBuilder classBuilder, boolean isStatic, MethodVisitor methodVisitor, TypeDesc[] parameterTypes) {
this.classBuilder = classBuilder;
methodVisitor.visitLdcInsn(Type.getType(value.getDescriptor()));
}
+
+ public int lineNumber(int lineNumber) {
+ if(lineNumber != currentLineNumber) {
+ int oldLineNumber = currentLineNumber;
+ Label label = createLabel();
+ setLocation(label);
+ methodVisitor.visitLineNumber(lineNumber, label);
+ currentLineNumber = lineNumber;
+ return oldLineNumber;
+ }
+ else
+ return currentLineNumber;
+ }
+
public void dup() {
methodVisitor.visitInsn(Opcodes.DUP);
}
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;
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 lineNumber, IVal function, IVal ... parameters) {
+ public IVal apply(long location, IVal function, IVal ... parameters) {
try {
MultiFunction mfun = Types.matchFunction(function.getType(), parameters.length);
- return applyWithEffect(lineNumber,
+ return applyWithEffect(location,
mfun.effect,
mfun.returnType,
function, parameters);
}
}
- public IVal applyWithEffectChecked(long lineNumber, Type effect, Type returnType, IVal function, IVal ... parameters) {
+ 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))
} catch (MatchException e) {
throw new InternalCompilerError(e);
}
- return applyWithEffect(lineNumber, effect, returnType, function, parameters);
+ return applyWithEffect(location, effect, returnType, function, parameters);
}
public IVal applyWithEffect(long location, Type effect, Type returnType, IVal function, IVal ... parameters) {
effect,
function.createOccurrence(),
ValRef.createOccurrences(parameters));
- apply.location = location;
+ apply.lineNumber = lineNumber(location);
block.addStatement(apply);
return var;
}
return block;
}
- public void jump(ICont cont, IVal ... parameters) {
- block.setExit(new Jump(cont.createOccurrence(),
+ 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_(IVal condition, ICont thenTarget, ICont elseTarget) {
- block.setExit(new If(condition.createOccurrence(),
+ 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(IVal condition, ICont target) {
+ public void branchAwayIf(long location, IVal condition, ICont target) {
SSABlock newBlock = new SSABlock(Type.EMPTY_ARRAY);
block.getParent().addBlock(newBlock);
- block.setExit(new If(condition.createOccurrence(),
+ block.setExit(new If(
+ lineNumber(location),
+ condition.createOccurrence(),
target.createOccurrence(),
newBlock.createOccurrence()));
this.block = newBlock;
}
- public void branchAwayUnless(IVal condition, ICont target) {
+ public void branchAwayUnless(long location, IVal condition, ICont target) {
SSABlock newBlock = new SSABlock(Type.EMPTY_ARRAY);
block.getParent().addBlock(newBlock);
- block.setExit(new If(condition.createOccurrence(),
+ block.setExit(new If(
+ lineNumber(location),
+ condition.createOccurrence(),
newBlock.createOccurrence(),
target.createOccurrence()));
this.block = newBlock;
}
- public void return_(IVal val) {
- jump(block.getParent().getReturnCont(), val);
+ public void return_(long location, IVal val) {
+ jump(lineNumber(location), block.getParent().getReturnCont(), val);
}
- public void switch_(IVal val, Branch[] branches) {
- block.setExit(new Switch(val.createOccurrence(), BranchRef.toBranchRefs(branches)));
+ 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(exceptionClass, description);
- exit.location = location;
+ Throw exit = new Throw(lineNumber(location), exceptionClass, description);
block.setExit(exit);
block = null;
}
import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
import org.simantics.scl.compiler.internal.codegen.ssa.SSAModule;
import org.simantics.scl.compiler.internal.codegen.ssa.StaticField;
+import org.simantics.scl.compiler.internal.parsing.utils.LineLocator;
import org.simantics.scl.compiler.types.TVar;
import org.simantics.scl.compiler.types.Type;
import org.simantics.scl.runtime.tuple.Tuple2;
public class ModuleWriter {
SSAModule module;
+ LineLocator lineLocator;
String moduleClassName;
THashMap<Tuple2, JavaStaticField> externalConstantMap =
new THashMap<Tuple2, JavaStaticField>();
int externalConstantId = 0;
- public ModuleWriter(String moduleClassName) {
+ public ModuleWriter(String moduleClassName, LineLocator lineLocator) {
this.module = new SSAModule();
this.moduleClassName = moduleClassName;
+ this.lineLocator = lineLocator;
}
public CodeWriter createFunction(SCLConstant constant, TVar[] typeParameters,
return newVals;
}
- private static void splitByConstructors(CodeWriter w, final CompilationContext context, IVal[] scrutinee, final ICont success, ICont failure, List<Row> rows, int columnId) {
+ private static void splitByConstructors(long location, CodeWriter w, final CompilationContext context, IVal[] scrutinee, final ICont success, ICont failure, List<Row> rows, int columnId) {
THashMap<Object, ExpressionMatrix> matrixMap = new THashMap<Object, ExpressionMatrix>();
ArrayList<Branch> branches = new ArrayList<Branch>();
ArrayList<ExpressionMatrix> matrices = new ArrayList<ExpressionMatrix>();
CodeWriter newW = w.createBlock();
ICont cont = newW.getContinuation();
branches.add(new Branch(null, cont));
- split(newW, context, scrutinee, success, failure, rows.subList(i, rows.size()));
+ split(location, newW, context, scrutinee, success, failure, rows.subList(i, rows.size()));
failure = cont;
}
else {
}
for(ExpressionMatrix mx : matrices)
- split(mx.w, context, mx.scrutinee, success, failure, mx.rows);
- w.switch_(scrutinee[columnId], branches.toArray(new Branch[branches.size()]));
+ split(location, mx.w, context, mx.scrutinee, success, failure, mx.rows);
+ w.switch_(location, scrutinee[columnId], branches.toArray(new Branch[branches.size()]));
}
- private static void splitByViewPattern(CodeWriter w, CompilationContext context, IVal[] scrutinee, ICont success,
+ private static void splitByViewPattern(long location, CodeWriter w, CompilationContext context, IVal[] scrutinee, ICont success,
ICont failure, List<Row> rows, int viewPatternColumn) {
Row firstRow = rows.get(0);
EViewPattern firstViewPattern = (EViewPattern)firstRow.patterns[viewPatternColumn];
firstViewPattern.expression.toVal(context, w),
scrutinee[viewPatternColumn]);
if(i == rows.size()) {
- split(w, context, newScrutinee, success, failure, rows);
+ split(location, w, context, newScrutinee, success, failure, rows);
}
else {
CodeWriter cont = w.createBlock();
- split(w, context, newScrutinee, success, cont.getContinuation(), rows.subList(0, i));
- split(cont, context, scrutinee, success, failure, rows.subList(i, rows.size()));
+ split(location, w, context, newScrutinee, success, cont.getContinuation(), rows.subList(0, i));
+ split(location, cont, context, scrutinee, success, failure, rows.subList(i, rows.size()));
}
}
- public static void split(CodeWriter w, CompilationContext context, IVal[] scrutinee, ICont success, ICont failure, List<Row> rows) {
+ public static void split(long location, CodeWriter w, CompilationContext context, IVal[] scrutinee, ICont success, ICont failure, List<Row> rows) {
Row firstRow = rows.get(0);
Expression[] patterns = firstRow.patterns;
if(scrutinee.length != patterns.length)
viewPatternColumn = i;
}
else if(!(pattern instanceof EVariable)) {
- splitByConstructors(w, context, scrutinee, success, failure, rows, i);
+ splitByConstructors(location, w, context, scrutinee, success, failure, rows, i);
return;
}
}
if(viewPatternColumn >= 0) {
- splitByViewPattern(w, context, scrutinee, success, failure, rows, viewPatternColumn);
+ splitByViewPattern(location, w, context, scrutinee, success, failure, rows, viewPatternColumn);
return;
}
CodeWriter newW = w.createBlock();
ICont cont = newW.getContinuation();
group.compile(context, w, success, cont);
- split(newW, context, scrutinee, success, failure, rows.subList(1, rows.size()));
+ split(location, newW, context, scrutinee, success, failure, rows.subList(1, rows.size()));
}
}
else
- w.jump(success, firstRow.value.toVal(context, w));
+ w.jump(location, success, firstRow.value.toVal(context, w));
}
}
return newVals;
}
- private static void splitByConstructors(CodeWriter w, final CompilationContext context, IVal[] scrutinee, ICont failure, List<Row2> rows, int columnId) {
+ private static void splitByConstructors(long location, CodeWriter w, final CompilationContext context, IVal[] scrutinee, ICont failure, List<Row2> rows, int columnId) {
THashMap<Object, ExpressionMatrix> matrixMap = new THashMap<Object, ExpressionMatrix>();
ArrayList<Branch> branches = new ArrayList<Branch>();
ArrayList<ExpressionMatrix> matrices = new ArrayList<ExpressionMatrix>();
CodeWriter newW = w.createBlock();
ICont cont = newW.getContinuation();
branches.add(new Branch(null, cont));
- split(newW, context, scrutinee, failure, rows.subList(i, rows.size()));
+ split(location, newW, context, scrutinee, failure, rows.subList(i, rows.size()));
failure = cont;
}
else {
}
for(ExpressionMatrix mx : matrices)
- split(mx.w, context, mx.scrutinee, failure, mx.rows);
- w.switch_(scrutinee[columnId], branches.toArray(new Branch[branches.size()]));
+ split(location, mx.w, context, mx.scrutinee, failure, mx.rows);
+ w.switch_(location, scrutinee[columnId], branches.toArray(new Branch[branches.size()]));
}
- private static void splitByViewPattern(CodeWriter w, CompilationContext context, IVal[] scrutinee, ICont failure, List<Row2> rows, int viewPatternColumn) {
+ private static void splitByViewPattern(long location, CodeWriter w, CompilationContext context, IVal[] scrutinee, ICont failure, List<Row2> rows, int viewPatternColumn) {
Row2 firstRow = rows.get(0);
EViewPattern firstViewPattern = (EViewPattern)firstRow.patterns[viewPatternColumn];
firstRow.patterns[viewPatternColumn] = firstViewPattern.pattern;
firstViewPattern.expression.toVal(context, w),
scrutinee[viewPatternColumn]);
if(i == rows.size()) {
- split(w, context, newScrutinee, failure, rows);
+ split(location, w, context, newScrutinee, failure, rows);
}
else {
CodeWriter cont = w.createBlock();
- split(w, context, newScrutinee, cont.getContinuation(), rows.subList(0, i));
- split(cont, context, scrutinee, failure, rows.subList(i, rows.size()));
+ split(location, w, context, newScrutinee, cont.getContinuation(), rows.subList(0, i));
+ split(location, cont, context, scrutinee, failure, rows.subList(i, rows.size()));
}
}
- public static void split(CodeWriter w, CompilationContext context, IVal[] scrutinee, ICont failure, List<Row2> rows) {
+ public static void split(long location, CodeWriter w, CompilationContext context, IVal[] scrutinee, ICont failure, List<Row2> rows) {
Row2 firstRow = rows.get(0);
Expression[] patterns = firstRow.patterns;
if(scrutinee.length != patterns.length)
viewPatternColumn = i;
}
else if(!(pattern instanceof EVariable)) {
- splitByConstructors(w, context, scrutinee, failure, rows, i);
+ splitByConstructors(location, w, context, scrutinee, failure, rows, i);
return;
}
}
if(viewPatternColumn >= 0) {
- splitByViewPattern(w, context, scrutinee, failure, rows, viewPatternColumn);
+ splitByViewPattern(location, w, context, scrutinee, failure, rows, viewPatternColumn);
return;
}
// The first row has only variable patterns: no matching needed
for(int i=0;i<patterns.length;++i)
((EVariable)patterns[i]).getVariable().setVal(scrutinee[i]);
- w.jump(firstRow.continuation);
+ w.jump(location, firstRow.continuation);
}
}
--- /dev/null
+package org.simantics.scl.compiler.internal.parsing.utils;
+
+public abstract class LineLocator {
+ final protected int[] rowStarts;
+
+ public LineLocator(int[] rowStarts) {
+ this.rowStarts = rowStarts;
+ }
+
+ public abstract int lineNumberFromPosition(int position);
+
+ public int columnNumber(int line, int position) {
+ return position - rowStarts[line];
+ }
+}
--- /dev/null
+package org.simantics.scl.compiler.internal.parsing.utils;
+
+import gnu.trove.list.array.TIntArrayList;
+
+public class LineLocators {
+
+ private static class ByteArrayLineLocator extends LineLocator {
+ private final byte[] lineNumbers;
+ private final int maxLine;
+
+ public ByteArrayLineLocator(int[] rowStarts) {
+ super(rowStarts);
+ int lastRow = rowStarts.length-1;
+ this.lineNumbers = new byte[rowStarts[lastRow]];
+ this.maxLine = rowStarts.length-1;
+
+ int position = 0;
+ int line = 0;
+ while(line < maxLine) {
+ int endPosition = rowStarts[line+1];
+ while(position < endPosition)
+ lineNumbers[position++] = (byte)line;
+ ++line;
+ }
+ }
+
+ @Override
+ public int lineNumberFromPosition(int position) {
+ if(position <= 0)
+ return 0;
+ if(position >= lineNumbers.length)
+ return maxLine;
+ return (int)lineNumbers[position];
+ }
+ }
+
+ private static class CharArrayLineLocator extends LineLocator {
+ private final char[] lineNumbers;
+ private final int maxLine;
+
+ public CharArrayLineLocator(int[] rowStarts) {
+ super(rowStarts);
+ int lastRow = rowStarts.length-1;
+ this.lineNumbers = new char[rowStarts[lastRow]];
+ this.maxLine = rowStarts.length-1;
+
+ int position = 0;
+ int line = 0;
+ while(line < maxLine) {
+ int endPosition = rowStarts[line+1];
+ while(position < endPosition)
+ lineNumbers[position++] = (char)line;
+ ++line;
+ }
+ }
+
+ @Override
+ public int lineNumberFromPosition(int position) {
+ if(position <= 0)
+ return 0;
+ if(position >= lineNumbers.length)
+ return maxLine;
+ return (int)lineNumbers[position];
+ }
+ }
+
+ private static class IntArrayLineLocator extends LineLocator {
+ private final int[] lineNumbers;
+ private final int maxLine;
+
+ public IntArrayLineLocator(int[] rowStarts) {
+ super(rowStarts);
+ int lastRow = rowStarts.length-1;
+ this.lineNumbers = new int[rowStarts[lastRow]];
+ this.maxLine = rowStarts.length-1;
+
+ int position = 0;
+ int line = 0;
+ while(line < maxLine) {
+ int endPosition = rowStarts[line+1];
+ while(position < endPosition)
+ lineNumbers[position++] = line;
+ ++line;
+ }
+ }
+
+ @Override
+ public int lineNumberFromPosition(int position) {
+ if(position <= 0)
+ return 0;
+ if(position >= lineNumbers.length)
+ return maxLine;
+ return lineNumbers[position];
+ }
+ }
+
+ private static class BinarySearchLineLocator extends LineLocator {
+ public BinarySearchLineLocator(int[] rowStarts) {
+ super(rowStarts);
+ }
+
+ @Override
+ public int lineNumberFromPosition(int position) {
+ if(position <= 0)
+ return 0;
+ if(position >= rowStarts[rowStarts.length-1])
+ return rowStarts.length-1;
+ int low = 0;
+ int high = rowStarts.length-1;
+ // invariant, low <= lineNumber < high
+ while(low < high-1) {
+ int middle = (low+high) / 2;
+ if(position < rowStarts[middle])
+ high = middle;
+ else
+ low = middle;
+ }
+ return low;
+ }
+ }
+
+ private static class InterpolationSearchLineLocator extends LineLocator {
+ public InterpolationSearchLineLocator(int[] rowStarts) {
+ super(rowStarts);
+ }
+
+ @Override
+ public int lineNumberFromPosition(int position) {
+ if(position <= 0)
+ return 0;
+ if(position >= rowStarts[rowStarts.length-1])
+ return rowStarts.length-1;
+ int low = 0;
+ int lowPosition = 0;
+ int high = rowStarts.length-1;
+ int highPosition = rowStarts[high];
+ // invariant, low <= lineNumber < high
+ while(low < high-1) {
+ int delta = (int)((long)(high - low) * (position - lowPosition) / (highPosition - lowPosition));
+ int middle = low + delta;
+ if(middle == low)
+ ++middle;
+ if(position < rowStarts[middle]) {
+ high = middle;
+ highPosition = rowStarts[high];
+ }
+ else {
+ low = middle;
+ lowPosition = rowStarts[low];
+ }
+ }
+ return low;
+ }
+ }
+
+ public static final LineLocator DUMMY_LOCATOR = new LineLocator(new int[] {0}) {
+ @Override
+ public int lineNumberFromPosition(int position) {
+ return 0;
+ }
+ };
+
+ private static int[] findRowStarts(String source) {
+ TIntArrayList rowStarts = new TIntArrayList();
+ rowStarts.add(0);
+
+ int length = source.length();
+ for(int i=0;i<length;++i) {
+ char c = source.charAt(i);
+ if(c == '\n')
+ rowStarts.add(i+1);
+ }
+ return rowStarts.toArray();
+ }
+
+ public static LineLocator createLineLocator(String source) {
+ int[] rowStarts = findRowStarts(source);
+ if(rowStarts.length <= Byte.MAX_VALUE)
+ return new ByteArrayLineLocator(rowStarts);
+ else if(rowStarts.length <= Character.MAX_VALUE)
+ return new CharArrayLineLocator(rowStarts);
+ else
+ return new InterpolationSearchLineLocator(rowStarts);
+ }
+}
package org.simantics.scl.compiler.source;
import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
import org.simantics.scl.compiler.internal.codegen.types.JavaReferenceValidator;
import org.simantics.scl.compiler.internal.codegen.types.RuntimeJavaReferenceValidator;
}
@Override
- protected Reader getSourceReader(UpdateListener listener)
- throws IOException {
- return new StringReader(moduleText);
+ public String getSourceText(UpdateListener listener) throws IOException {
+ return moduleText;
}
@Override
import java.io.IOException;
import java.io.Reader;
+import java.io.StringReader;
import java.util.Arrays;
import org.simantics.scl.compiler.compilation.SCLCompiler;
return getClass().getClassLoader();
}
- protected abstract Reader getSourceReader(UpdateListener listener) throws IOException;
+ protected Reader getSourceReader(UpdateListener listener) throws IOException {
+ return new StringReader(getSourceText(listener));
+ }
+
protected JavaReferenceValidator<?, ?, ?, ?> getJavaReferenceValidator() {
return new RuntimeJavaReferenceValidator(getClassLoader());
}
public String getSourceText(UpdateListener listener) throws IOException {
Reader reader = getSourceReader(listener);
- char[] buffer = new char[65536];
+ char[] buffer = new char[4096];
int pos = 0;
try {
while(true) {
public Failable<Module> compileModule(final ModuleRepository environment, final UpdateListener listener, ModuleCompilationOptions options) {
SCLCompiler compiler = new SCLCompiler(options, getJavaReferenceValidatorFactory());
try {
- compiler.addSource(getSourceReader(listener));
+ String source = getSourceText(listener);
+ compiler.addSource(source);
compiler.compile(
new EnvironmentFactoryImpl(
environment,
import org.simantics.scl.compiler.internal.parsing.parser.SCLBlockParser;
import org.simantics.scl.compiler.internal.parsing.parser.SCLParserImpl;
import org.simantics.scl.compiler.internal.parsing.parser.SCLParserOptions;
+import org.simantics.scl.compiler.internal.parsing.utils.LineLocators;
import org.simantics.scl.compiler.runtime.MutableClassLoader;
import org.simantics.scl.compiler.runtime.RuntimeEnvironment;
import org.simantics.scl.compiler.types.TVar;
// Parse expression
if(expressionText != null) {
+ compilationContext.lineLocator = LineLocators.createLineLocator(expressionText);
try {
switch(parseMode) {
case BLOCK: {
throw new SCLExpressionCompilationException(errorLog.getErrors());
}
}
+ else
+ compilationContext.lineLocator = LineLocators.DUMMY_LOCATOR;
// Store local variables
ArrayList<Type> lvTypes = new ArrayList<Type>();
}
// Convert to SSA
- ModuleWriter mw = new ModuleWriter(namingPolicy.getModuleClassName());
+ ModuleWriter mw = new ModuleWriter(namingPolicy.getModuleClassName(), compilationContext.lineLocator);
DecomposedExpression decomposed =
DecomposedExpression.decompose(errorLog, expression);
IVal[] parameterVals = w.getParameters();
for(int i=0;i<decomposed.parameters.length;++i)
decomposed.parameters[i].setVal(parameterVals[i]);
- w.return_(decomposed.body.toVal(compilationContext, w));
+ w.return_(decomposed.body.location, decomposed.body.toVal(compilationContext, w));
} catch(RuntimeException e) {
errorLog.setExceptionPosition(expression.location);
+ errorLog.log(e);
throw new SCLExpressionCompilationException(errorLog.getErrors());
}
package org.simantics.tests.modelled.ui;
import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
import org.eclipse.ui.IPersistableElement;
import org.simantics.Simantics;
}
@Override
- protected Reader getSourceReader(UpdateListener listener) throws IOException {
- return new StringReader(moduleText);
+ public String getSourceText(UpdateListener listener) throws IOException {
+ return moduleText;
}
}