mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-17 10:30:43 +00:00
Added missing line number to error when encountering symbol that has already been declared.
This commit is contained in:
parent
241f8bec4d
commit
3090fe4849
@ -479,17 +479,17 @@ class AsmFragmentTemplateSynthesisRule {
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)vw(.)c1(.*)", null, null , "$1vd$2c1$3", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)vw(.)c2(.*)", null, null , "$1vd$2c2$3", null, null));
|
||||
|
||||
/* Removed pending optimization!
|
||||
/* Removed awaiting optimization
|
||||
// Rewrite constant unsigned word values to constant signed dword values
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)vwuc1(.*)", null, null , "$1vdsc1$2", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)vwuc2(.*)", null, null , "$1vdsc2$2", null, null));
|
||||
*/
|
||||
|
||||
/*
|
||||
/* Removed awaiting optimization
|
||||
// Rewrite any zeropage pointer as an unsigned word zeropage values
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)p..z(.)(.*)", null, null , "$1vwuz$2$3", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)p..z(.)(.*)", ".*p..z._deref.*", null , "$1vwuz$2$3", null, null));
|
||||
// Rewrite any constant pointer as an constant unsigned word
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)p..c(.)(.*)", null, null , "$1vwuc$2$3", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)p..c(.)(.*)", ".*p..z._deref.*", null , "$1vwuc$2$3", null, null));
|
||||
*/
|
||||
|
||||
// Synthesize some constant pointers as constant words (remove when the above section can be included)
|
||||
|
@ -2,6 +2,7 @@ package dk.camelot64.kickc.model.statements;
|
||||
|
||||
import org.antlr.v4.runtime.CharStream;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.misc.Interval;
|
||||
|
||||
/** Contains information about the source of a program statement */
|
||||
@ -15,9 +16,13 @@ public class StatementSource {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
CharStream stream = context.getStart().getInputStream();
|
||||
Interval interval = new Interval(context.getStart().getStartIndex(), context.getStop().getStopIndex());
|
||||
String sourceMessage = "File "+stream.getSourceName()+"\nLine "+context.getStart().getLine()+ "\n" +stream.getText(interval);
|
||||
return sourceMessage;
|
||||
Token contextStart = context.getStart();
|
||||
if(contextStart != null) {
|
||||
CharStream stream = contextStart.getInputStream();
|
||||
Interval interval = new Interval(contextStart.getStartIndex(), context.getStop().getStopIndex());
|
||||
return "File " + stream.getSourceName() + "\nLine " + contextStart.getLine() + "\n" + stream.getText(interval);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package dk.camelot64.kickc.model.symbols;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.Registers;
|
||||
import dk.camelot64.kickc.model.VariableRegisterWeights;
|
||||
@ -97,7 +98,7 @@ public abstract class Scope implements Symbol {
|
||||
|
||||
public Symbol add(Symbol symbol) {
|
||||
if(symbols.get(symbol.getLocalName()) != null) {
|
||||
throw new RuntimeException("Symbol already declared " + symbol.getLocalName());
|
||||
throw new CompileError("Symbol already declared " + symbol.getLocalName());
|
||||
}
|
||||
symbols.put(symbol.getLocalName(), symbol);
|
||||
return symbol;
|
||||
|
@ -299,7 +299,12 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
public Object visitDeclVariable(KickCParser.DeclVariableContext ctx) {
|
||||
SymbolType type = (SymbolType) visit(ctx.typeDecl());
|
||||
String varName = ctx.NAME().getText();
|
||||
VariableUnversioned lValue = getCurrentSymbols().addVariable(varName, type);
|
||||
VariableUnversioned lValue;
|
||||
try {
|
||||
lValue = getCurrentSymbols().addVariable(varName, type);
|
||||
} catch(CompileError e) {
|
||||
throw new CompileError(e.getMessage(), new StatementSource(ctx));
|
||||
}
|
||||
// Add directives
|
||||
addDirectives(type, lValue, ctx.directive());
|
||||
// Array / String variables are implicitly constant
|
||||
@ -669,7 +674,11 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
Variable lValue;
|
||||
if(forDeclCtx.typeDecl() != null) {
|
||||
SymbolType type = (SymbolType) visit(forDeclCtx.typeDecl());
|
||||
lValue = getCurrentSymbols().addVariable(varName, type);
|
||||
try {
|
||||
lValue = getCurrentSymbols().addVariable(varName, type);
|
||||
} catch(CompileError e) {
|
||||
throw new CompileError(e.getMessage(), new StatementSource(forDeclCtx));
|
||||
}
|
||||
// Add directives
|
||||
addDirectives(type, lValue, forDeclCtx.directive());
|
||||
} else {
|
||||
|
@ -68,7 +68,8 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
||||
throw new CompileError(
|
||||
"Constant variable has a non-matching type \n variable: " + variable.toString(getProgram()) +
|
||||
"\n value: (" + valueType.toString() + ") " + constVal.calculateLiteral(getScope()) +
|
||||
"\n value definition: " + constVal.toString(getProgram()));
|
||||
"\n value definition: " + constVal.toString(getProgram())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import dk.camelot64.kickc.asm.AsmClobber;
|
||||
import dk.camelot64.kickc.asm.AsmProgram;
|
||||
import dk.camelot64.kickc.asm.AsmSegment;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.statements.StatementSource;
|
||||
import dk.camelot64.kickc.model.values.RValue;
|
||||
import dk.camelot64.kickc.model.values.VariableRef;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
@ -110,16 +111,17 @@ public class Pass4AssertNoCpuClobber extends Pass2Base {
|
||||
// Alive and not assigned to - clobber not allowed!
|
||||
if(clobberRegisters.contains(aliveVarRegister)) {
|
||||
if(verbose) {
|
||||
getLog().append("Error! Alive variable " + aliveVar + " register " + aliveVarRegister + " clobbered by the ASM generated by statement " + statement);
|
||||
throw new CompileError(
|
||||
"Error! Generated ASM has register clobber problem. " +
|
||||
"Alive variable "+aliveVar + " register " + aliveVarRegister + " clobbered by the ASM generated by statement "+statement.toString(getProgram(), true),
|
||||
statement.getSource()
|
||||
);
|
||||
}
|
||||
clobberProblem = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(verbose && clobberProblem) {
|
||||
getLog().append(asm.toString(true));
|
||||
}
|
||||
return clobberProblem;
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,7 @@ public class TestFragments {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a specific fragment can be succesfully loaded/synthesized
|
||||
* Test that a specific fragment can be succesfully loaded/synthesized
|
||||
* @param signature The fragment signature
|
||||
*/
|
||||
private void testFragmentExists(String signature) {
|
||||
|
@ -44,6 +44,11 @@ public class TestPrograms {
|
||||
AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoLocalScope() throws IOException, URISyntaxException {
|
||||
assertError("nolocalscope", "Symbol already declared");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypeMix() throws IOException, URISyntaxException {
|
||||
compileAndCompare("type-mix");
|
||||
@ -288,7 +293,7 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testUnrollInfinite() throws IOException, URISyntaxException {
|
||||
assertError("unroll-infinite", "Loop cannot be unrolled.");
|
||||
assertError("unroll-infinite", "Loop cannot be unrolled.", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1143,7 +1148,7 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testNoReturn() throws IOException, URISyntaxException {
|
||||
assertError("noreturn", "Method must end with a return statement");
|
||||
assertError("noreturn", "Method must end with a return statement", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1158,7 +1163,7 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testInvalidConstType() throws IOException, URISyntaxException {
|
||||
assertError("invalid-consttype", "Constant variable has a non-matching type");
|
||||
assertError("invalid-consttype", "Constant variable has a non-matching type", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1173,12 +1178,12 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testArrayLengthMismatch() throws IOException, URISyntaxException {
|
||||
assertError("array-length-mismatch", "Array length mismatch");
|
||||
assertError("array-length-mismatch", "Array length mismatch", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringLengthMismatch() throws IOException, URISyntaxException {
|
||||
assertError("string-length-mismatch", "Array length mismatch");
|
||||
assertError("string-length-mismatch", "Array length mismatch", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1188,17 +1193,17 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testRegisterClobber() throws IOException, URISyntaxException {
|
||||
assertError("register-clobber", "CLOBBER ERROR");
|
||||
assertError("register-clobber", "register clobber problem", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecursionError() throws IOException, URISyntaxException {
|
||||
assertError("recursion-error", "Recursion");
|
||||
assertError("recursion-error", "Recursion", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecursionComplexError() throws IOException, URISyntaxException {
|
||||
assertError("recursion-error-complex", "Recursion");
|
||||
assertError("recursion-error-complex", "Recursion", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1223,7 +1228,7 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testNoInlineInterrupt() throws IOException, URISyntaxException {
|
||||
assertError("no-inlineinterrupt", "Interrupts cannot be inlined");
|
||||
assertError("no-inlineinterrupt", "Interrupts cannot be inlined", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1233,12 +1238,12 @@ public class TestPrograms {
|
||||
|
||||
@Test
|
||||
public void testNoParamInterrupt() throws IOException, URISyntaxException {
|
||||
assertError("no-paraminterrupt", "Interrupts cannot have parameters.");
|
||||
assertError("no-paraminterrupt", "Interrupts cannot have parameters.", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoReturnInterrupt() throws IOException, URISyntaxException {
|
||||
assertError("no-returninterrupt", "Interrupts cannot return anything.");
|
||||
assertError("no-returninterrupt", "Interrupts cannot return anything.", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1247,12 +1252,20 @@ public class TestPrograms {
|
||||
}
|
||||
|
||||
private void assertError(String kcFile, String expectError) throws IOException, URISyntaxException {
|
||||
assertError(kcFile, expectError, true);
|
||||
}
|
||||
|
||||
private void assertError(String kcFile, String expectError, boolean expectLineNumber) throws IOException, URISyntaxException {
|
||||
try {
|
||||
compileAndCompare(kcFile);
|
||||
} catch(CompileError e) {
|
||||
System.out.println("Got error: " + e.getMessage());
|
||||
// expecting error!
|
||||
assertTrue("Error message expected '" + expectError + "' - was:" + e.getMessage(), e.getMessage().contains(expectError));
|
||||
if(expectLineNumber) {
|
||||
// expecting line number!
|
||||
assertTrue("Error message expected line number - was:" + e.getMessage(), e.getMessage().contains("Line"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
fail("Expected compile error.");
|
||||
|
10
src/test/kc/nolocalscope.kc
Normal file
10
src/test/kc/nolocalscope.kc
Normal file
@ -0,0 +1,10 @@
|
||||
// Illustrates problem with not introducing local scopes inside loops etc
|
||||
|
||||
import "print"
|
||||
|
||||
void main() {
|
||||
for (byte i: 0..5)
|
||||
print_ln();
|
||||
for (byte i: 0..5)
|
||||
print_str_ln(" xxxxx@");
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user