mirror of
https://github.com/irmen/prog8.git
synced 2024-06-26 07:29:32 +00:00
error when doing txt.print('@') where "@" was intended (byte for string parameter)
This commit is contained in:
parent
bc8126eb16
commit
f98ee326b4
|
@ -220,7 +220,7 @@ internal class AstChecker(private val program: Program,
|
|||
override fun visit(jump: Jump) {
|
||||
val ident = jump.identifier
|
||||
if(ident!=null) {
|
||||
val targetStatement = checkFunctionOrLabelExists(ident, jump)
|
||||
val targetStatement = ident.checkFunctionOrLabelExists(program, jump, errors)
|
||||
if(targetStatement!=null) {
|
||||
if(targetStatement is BuiltinFunctionPlaceholder)
|
||||
errors.err("can't jump to a builtin function", jump.position)
|
||||
|
@ -1068,7 +1068,7 @@ internal class AstChecker(private val program: Program,
|
|||
val stmtOfExpression = findParentNode<Statement>(functionCallExpr)
|
||||
?: throw FatalAstException("cannot determine statement scope of function call expression at ${functionCallExpr.position}")
|
||||
|
||||
val targetStatement = checkFunctionOrLabelExists(functionCallExpr.target, stmtOfExpression)
|
||||
val targetStatement = functionCallExpr.target.checkFunctionOrLabelExists(program, stmtOfExpression, errors)
|
||||
if(targetStatement!=null)
|
||||
checkFunctionCall(targetStatement, functionCallExpr.args, functionCallExpr.position)
|
||||
|
||||
|
@ -1120,7 +1120,7 @@ internal class AstChecker(private val program: Program,
|
|||
}
|
||||
|
||||
override fun visit(functionCallStatement: FunctionCallStatement) {
|
||||
val targetStatement = checkFunctionOrLabelExists(functionCallStatement.target, functionCallStatement)
|
||||
val targetStatement = functionCallStatement.target.checkFunctionOrLabelExists(program, functionCallStatement, errors)
|
||||
if(targetStatement!=null) {
|
||||
checkFunctionCall(targetStatement, functionCallStatement.args, functionCallStatement.position)
|
||||
checkUnusedReturnValues(functionCallStatement, targetStatement, errors)
|
||||
|
@ -1421,25 +1421,6 @@ internal class AstChecker(private val program: Program,
|
|||
errors.err("%asm containing IR code cannot be translated to 6502 assembly", inlineAssembly.position)
|
||||
}
|
||||
|
||||
private fun checkFunctionOrLabelExists(target: IdentifierReference, statement: Statement): Statement? {
|
||||
when (val targetStatement = target.targetStatement(program)) {
|
||||
is Label, is Subroutine, is BuiltinFunctionPlaceholder -> return targetStatement
|
||||
is VarDecl -> {
|
||||
if(statement is Jump) {
|
||||
if (targetStatement.datatype == DataType.UWORD)
|
||||
return targetStatement
|
||||
else
|
||||
errors.err("wrong address variable datatype, expected uword", target.position)
|
||||
}
|
||||
else
|
||||
errors.err("cannot call that: ${target.nameInSource.joinToString(".")}", target.position)
|
||||
}
|
||||
null -> errors.undefined(target.nameInSource, target.position)
|
||||
else -> errors.err("cannot call that: ${target.nameInSource.joinToString(".")}", target.position)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun checkValueTypeAndRangeString(targetDt: DataType, value: StringLiteral) : Boolean {
|
||||
return if (targetDt == DataType.STR) {
|
||||
when {
|
||||
|
|
|
@ -5,10 +5,7 @@ import prog8.ast.Program
|
|||
import prog8.ast.expressions.CharLiteral
|
||||
import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.expressions.NumericLiteral
|
||||
import prog8.ast.statements.Directive
|
||||
import prog8.ast.statements.InlineAssembly
|
||||
import prog8.ast.statements.Subroutine
|
||||
import prog8.ast.statements.VarDeclOrigin
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
import prog8.code.core.*
|
||||
|
@ -151,4 +148,25 @@ internal fun Subroutine.hasRtsInAsm(): Boolean {
|
|||
.asSequence()
|
||||
.filterIsInstance<InlineAssembly>()
|
||||
.any { it.hasReturnOrRts() }
|
||||
}
|
||||
|
||||
internal fun IdentifierReference.checkFunctionOrLabelExists(program: Program, statement: Statement, errors: IErrorReporter): Statement? {
|
||||
when (val targetStatement = this.targetStatement(program)) {
|
||||
is Label, is Subroutine, is BuiltinFunctionPlaceholder -> return targetStatement
|
||||
is VarDecl -> {
|
||||
if(statement is Jump) {
|
||||
if (targetStatement.datatype == DataType.UWORD)
|
||||
return targetStatement
|
||||
else
|
||||
errors.err("wrong address variable datatype, expected uword", this.position)
|
||||
}
|
||||
else
|
||||
errors.err("cannot call that: ${this.nameInSource.joinToString(".")}", this.position)
|
||||
}
|
||||
null -> {
|
||||
errors.undefined(this.nameInSource, this.position)
|
||||
}
|
||||
else -> errors.err("cannot call that: ${this.nameInSource.joinToString(".")}", this.position)
|
||||
}
|
||||
return null
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
package prog8.compiler.astprocessing
|
||||
|
||||
import prog8.ast.IFunctionCall
|
||||
import prog8.ast.Node
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.FatalAstException
|
||||
import prog8.ast.base.SyntaxError
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.findParentNode
|
||||
import prog8.ast.statements.*
|
||||
import prog8.ast.walk.AstWalker
|
||||
import prog8.ast.walk.IAstModification
|
||||
|
@ -201,4 +204,42 @@ class AstPreprocessor(val program: Program,
|
|||
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(bfc: BuiltinFunctionCall, parent: Node): Iterable<IAstModification> {
|
||||
val stmtOfExpression = findParentNode<Statement>(bfc)
|
||||
?: throw FatalAstException("cannot determine statement scope of function call expression at ${bfc.position}")
|
||||
checkStringParam(bfc as IFunctionCall, stmtOfExpression)
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(bfcs: BuiltinFunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
||||
checkStringParam(bfcs as IFunctionCall, bfcs)
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> {
|
||||
val stmtOfExpression = findParentNode<Statement>(functionCallExpr)
|
||||
?: throw FatalAstException("cannot determine statement scope of function call expression at ${functionCallExpr.position}")
|
||||
|
||||
checkStringParam(functionCallExpr as IFunctionCall, stmtOfExpression)
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
||||
checkStringParam(functionCallStatement as IFunctionCall, functionCallStatement)
|
||||
return noModifications
|
||||
}
|
||||
|
||||
private fun checkStringParam(call: IFunctionCall, stmt: Statement) {
|
||||
val targetStatement = call.target.checkFunctionOrLabelExists(program, stmt, errors)
|
||||
if(targetStatement!=null) {
|
||||
if(targetStatement is Subroutine) {
|
||||
for(arg in call.args.zip(targetStatement.parameters)) {
|
||||
if(arg.first.inferType(program).isBytes && arg.second.type==DataType.STR) {
|
||||
errors.err("cannot use byte value for string parameter", arg.first.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -351,5 +351,20 @@ main
|
|||
|
||||
compileText(VMTarget(), optimize=false, src, writeAssembly=false) shouldNotBe null
|
||||
}
|
||||
|
||||
test("char as str param is error") {
|
||||
val src = """
|
||||
main {
|
||||
sub start() {
|
||||
print('@')
|
||||
}
|
||||
|
||||
sub print(str message) {
|
||||
}
|
||||
}"""
|
||||
val errors = ErrorReporterForTests()
|
||||
compileText(VMTarget(), optimize=false, src, writeAssembly=false, errors = errors) shouldBe null
|
||||
errors.errors.single() shouldContain "cannot use byte value"
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -954,7 +954,15 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
|
|||
|
||||
override fun copy() = IdentifierReference(nameInSource, position)
|
||||
override fun constValue(program: Program): NumericLiteral? {
|
||||
val node = definingScope.lookup(nameInSource) ?: throw UndefinedSymbolError(this)
|
||||
val node = definingScope.lookup(nameInSource)
|
||||
if(node==null) {
|
||||
// maybe not a statement but perhaps a subroutine parameter?
|
||||
(definingScope as? Subroutine)?.let { sub ->
|
||||
if(sub.parameters.any { it.name==nameInSource.last() })
|
||||
return null
|
||||
}
|
||||
throw UndefinedSymbolError(this)
|
||||
}
|
||||
val vardecl = node as? VarDecl
|
||||
if(vardecl==null) {
|
||||
return null
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
TODO
|
||||
====
|
||||
|
||||
- don't allow txt.print('@') if possible, don't cast up a byte to str
|
||||
- [on branch:] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 ....
|
||||
- IR: reduce the number of branch instructions such as BEQ, BEQR, etc (gradually), replace with CMP(I) + status branch instruction
|
||||
- IR: reduce amount of CMP/CMPI after instructions that set the status bits correctly (LOADs? INC? etc), but only after setting the status bits is verified!
|
||||
|
|
|
@ -1,54 +1,8 @@
|
|||
%import textio
|
||||
%zeropage basicsafe
|
||||
|
||||
cbm2 {
|
||||
sub SETTIM(ubyte a, ubyte b, ubyte c) {
|
||||
}
|
||||
sub RDTIM16() -> uword {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
uword wvalue
|
||||
uword wvalue2
|
||||
print('@')
|
||||
}
|
||||
|
||||
txt.print("word square..")
|
||||
cbm.SETTIM(0,0,0)
|
||||
repeat 200 {
|
||||
for wvalue in 0 to 200 {
|
||||
cx16.r0 = wvalue*wvalue
|
||||
}
|
||||
}
|
||||
txt.print_uw(cbm.RDTIM16())
|
||||
txt.nl()
|
||||
|
||||
txt.print("word square via multiply new..")
|
||||
cbm.SETTIM(0,0,0)
|
||||
wvalue2 = wvalue
|
||||
repeat 200 {
|
||||
for wvalue in 0 to 200 {
|
||||
cx16.r0 = wvalue*wvalue2
|
||||
}
|
||||
}
|
||||
txt.print_uw(cbm.RDTIM16())
|
||||
txt.nl()
|
||||
|
||||
txt.print("word square verify..")
|
||||
for wvalue in 0 to 200 {
|
||||
wvalue2 = wvalue
|
||||
if wvalue*wvalue != wvalue*wvalue2 {
|
||||
txt.print("different! ")
|
||||
txt.print_uw(wvalue)
|
||||
txt.spc()
|
||||
txt.spc()
|
||||
txt.print_uw(wvalue*wvalue)
|
||||
txt.spc()
|
||||
txt.print_uw(wvalue*wvalue2)
|
||||
sys.exit(1)
|
||||
}
|
||||
}
|
||||
txt.nl()
|
||||
sub print(str message) {
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user