mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-08-02 09:29:35 +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(.)c1(.*)", null, null , "$1vd$2c1$3", null, null));
|
||||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)vw(.)c2(.*)", null, null , "$1vd$2c2$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
|
// 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("(.*)vwuc1(.*)", null, null , "$1vdsc1$2", null, null));
|
||||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)vwuc2(.*)", null, null , "$1vdsc2$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
|
// 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
|
// 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)
|
// 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.CharStream;
|
||||||
import org.antlr.v4.runtime.ParserRuleContext;
|
import org.antlr.v4.runtime.ParserRuleContext;
|
||||||
|
import org.antlr.v4.runtime.Token;
|
||||||
import org.antlr.v4.runtime.misc.Interval;
|
import org.antlr.v4.runtime.misc.Interval;
|
||||||
|
|
||||||
/** Contains information about the source of a program statement */
|
/** Contains information about the source of a program statement */
|
||||||
@ -15,9 +16,13 @@ public class StatementSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
CharStream stream = context.getStart().getInputStream();
|
Token contextStart = context.getStart();
|
||||||
Interval interval = new Interval(context.getStart().getStartIndex(), context.getStop().getStopIndex());
|
if(contextStart != null) {
|
||||||
String sourceMessage = "File "+stream.getSourceName()+"\nLine "+context.getStart().getLine()+ "\n" +stream.getText(interval);
|
CharStream stream = contextStart.getInputStream();
|
||||||
return sourceMessage;
|
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;
|
package dk.camelot64.kickc.model.symbols;
|
||||||
|
|
||||||
|
import dk.camelot64.kickc.model.CompileError;
|
||||||
import dk.camelot64.kickc.model.Program;
|
import dk.camelot64.kickc.model.Program;
|
||||||
import dk.camelot64.kickc.model.Registers;
|
import dk.camelot64.kickc.model.Registers;
|
||||||
import dk.camelot64.kickc.model.VariableRegisterWeights;
|
import dk.camelot64.kickc.model.VariableRegisterWeights;
|
||||||
@ -97,7 +98,7 @@ public abstract class Scope implements Symbol {
|
|||||||
|
|
||||||
public Symbol add(Symbol symbol) {
|
public Symbol add(Symbol symbol) {
|
||||||
if(symbols.get(symbol.getLocalName()) != null) {
|
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);
|
symbols.put(symbol.getLocalName(), symbol);
|
||||||
return symbol;
|
return symbol;
|
||||||
|
@ -299,7 +299,12 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
|||||||
public Object visitDeclVariable(KickCParser.DeclVariableContext ctx) {
|
public Object visitDeclVariable(KickCParser.DeclVariableContext ctx) {
|
||||||
SymbolType type = (SymbolType) visit(ctx.typeDecl());
|
SymbolType type = (SymbolType) visit(ctx.typeDecl());
|
||||||
String varName = ctx.NAME().getText();
|
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
|
// Add directives
|
||||||
addDirectives(type, lValue, ctx.directive());
|
addDirectives(type, lValue, ctx.directive());
|
||||||
// Array / String variables are implicitly constant
|
// Array / String variables are implicitly constant
|
||||||
@ -669,7 +674,11 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
|||||||
Variable lValue;
|
Variable lValue;
|
||||||
if(forDeclCtx.typeDecl() != null) {
|
if(forDeclCtx.typeDecl() != null) {
|
||||||
SymbolType type = (SymbolType) visit(forDeclCtx.typeDecl());
|
SymbolType type = (SymbolType) visit(forDeclCtx.typeDecl());
|
||||||
|
try {
|
||||||
lValue = getCurrentSymbols().addVariable(varName, type);
|
lValue = getCurrentSymbols().addVariable(varName, type);
|
||||||
|
} catch(CompileError e) {
|
||||||
|
throw new CompileError(e.getMessage(), new StatementSource(forDeclCtx));
|
||||||
|
}
|
||||||
// Add directives
|
// Add directives
|
||||||
addDirectives(type, lValue, forDeclCtx.directive());
|
addDirectives(type, lValue, forDeclCtx.directive());
|
||||||
} else {
|
} else {
|
||||||
|
@ -68,7 +68,8 @@ public class Pass2ConstantIdentification extends Pass2SsaOptimization {
|
|||||||
throw new CompileError(
|
throw new CompileError(
|
||||||
"Constant variable has a non-matching type \n variable: " + variable.toString(getProgram()) +
|
"Constant variable has a non-matching type \n variable: " + variable.toString(getProgram()) +
|
||||||
"\n value: (" + valueType.toString() + ") " + constVal.calculateLiteral(getScope()) +
|
"\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.AsmProgram;
|
||||||
import dk.camelot64.kickc.asm.AsmSegment;
|
import dk.camelot64.kickc.asm.AsmSegment;
|
||||||
import dk.camelot64.kickc.model.*;
|
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.RValue;
|
||||||
import dk.camelot64.kickc.model.values.VariableRef;
|
import dk.camelot64.kickc.model.values.VariableRef;
|
||||||
import dk.camelot64.kickc.model.statements.Statement;
|
import dk.camelot64.kickc.model.statements.Statement;
|
||||||
@ -110,16 +111,17 @@ public class Pass4AssertNoCpuClobber extends Pass2Base {
|
|||||||
// Alive and not assigned to - clobber not allowed!
|
// Alive and not assigned to - clobber not allowed!
|
||||||
if(clobberRegisters.contains(aliveVarRegister)) {
|
if(clobberRegisters.contains(aliveVarRegister)) {
|
||||||
if(verbose) {
|
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;
|
clobberProblem = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(verbose && clobberProblem) {
|
|
||||||
getLog().append(asm.toString(true));
|
|
||||||
}
|
|
||||||
return clobberProblem;
|
return clobberProblem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,11 @@ public class TestPrograms {
|
|||||||
AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false);
|
AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoLocalScope() throws IOException, URISyntaxException {
|
||||||
|
assertError("nolocalscope", "Symbol already declared");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTypeMix() throws IOException, URISyntaxException {
|
public void testTypeMix() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("type-mix");
|
compileAndCompare("type-mix");
|
||||||
@ -288,7 +293,7 @@ public class TestPrograms {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUnrollInfinite() throws IOException, URISyntaxException {
|
public void testUnrollInfinite() throws IOException, URISyntaxException {
|
||||||
assertError("unroll-infinite", "Loop cannot be unrolled.");
|
assertError("unroll-infinite", "Loop cannot be unrolled.", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -1143,7 +1148,7 @@ public class TestPrograms {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoReturn() throws IOException, URISyntaxException {
|
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
|
@Test
|
||||||
@ -1158,7 +1163,7 @@ public class TestPrograms {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInvalidConstType() throws IOException, URISyntaxException {
|
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
|
@Test
|
||||||
@ -1173,12 +1178,12 @@ public class TestPrograms {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testArrayLengthMismatch() throws IOException, URISyntaxException {
|
public void testArrayLengthMismatch() throws IOException, URISyntaxException {
|
||||||
assertError("array-length-mismatch", "Array length mismatch");
|
assertError("array-length-mismatch", "Array length mismatch", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStringLengthMismatch() throws IOException, URISyntaxException {
|
public void testStringLengthMismatch() throws IOException, URISyntaxException {
|
||||||
assertError("string-length-mismatch", "Array length mismatch");
|
assertError("string-length-mismatch", "Array length mismatch", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -1188,17 +1193,17 @@ public class TestPrograms {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegisterClobber() throws IOException, URISyntaxException {
|
public void testRegisterClobber() throws IOException, URISyntaxException {
|
||||||
assertError("register-clobber", "CLOBBER ERROR");
|
assertError("register-clobber", "register clobber problem", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRecursionError() throws IOException, URISyntaxException {
|
public void testRecursionError() throws IOException, URISyntaxException {
|
||||||
assertError("recursion-error", "Recursion");
|
assertError("recursion-error", "Recursion", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRecursionComplexError() throws IOException, URISyntaxException {
|
public void testRecursionComplexError() throws IOException, URISyntaxException {
|
||||||
assertError("recursion-error-complex", "Recursion");
|
assertError("recursion-error-complex", "Recursion", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -1223,7 +1228,7 @@ public class TestPrograms {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoInlineInterrupt() throws IOException, URISyntaxException {
|
public void testNoInlineInterrupt() throws IOException, URISyntaxException {
|
||||||
assertError("no-inlineinterrupt", "Interrupts cannot be inlined");
|
assertError("no-inlineinterrupt", "Interrupts cannot be inlined", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -1233,12 +1238,12 @@ public class TestPrograms {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoParamInterrupt() throws IOException, URISyntaxException {
|
public void testNoParamInterrupt() throws IOException, URISyntaxException {
|
||||||
assertError("no-paraminterrupt", "Interrupts cannot have parameters.");
|
assertError("no-paraminterrupt", "Interrupts cannot have parameters.", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoReturnInterrupt() throws IOException, URISyntaxException {
|
public void testNoReturnInterrupt() throws IOException, URISyntaxException {
|
||||||
assertError("no-returninterrupt", "Interrupts cannot return anything.");
|
assertError("no-returninterrupt", "Interrupts cannot return anything.", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -1247,12 +1252,20 @@ public class TestPrograms {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void assertError(String kcFile, String expectError) throws IOException, URISyntaxException {
|
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 {
|
try {
|
||||||
compileAndCompare(kcFile);
|
compileAndCompare(kcFile);
|
||||||
} catch(CompileError e) {
|
} catch(CompileError e) {
|
||||||
System.out.println("Got error: " + e.getMessage());
|
System.out.println("Got error: " + e.getMessage());
|
||||||
// expecting error!
|
// expecting error!
|
||||||
assertTrue("Error message expected '" + expectError + "' - was:" + e.getMessage(), e.getMessage().contains(expectError));
|
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;
|
return;
|
||||||
}
|
}
|
||||||
fail("Expected compile error.");
|
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…
Reference in New Issue
Block a user