Skip to content

Commit

Permalink
more helpful error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
irmen committed Sep 29, 2024
1 parent a6107fc commit 413b86c
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 51 deletions.
15 changes: 11 additions & 4 deletions compiler/src/prog8/compiler/astprocessing/AstChecker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -585,14 +585,22 @@ internal class AstChecker(private val program: Program,
checkMultiAssignment(assignment, fcall, fcallTarget)
} else if(fcallTarget!=null) {
if(fcallTarget.returntypes.size!=1) {
errors.err("number of assignment targets doesn't match number of return values from the subroutine", fcall.position)
return
return numberOfReturnValuesError(1, fcallTarget.returntypes, fcall.position)
}
}

super.visit(assignment)
}

private fun numberOfReturnValuesError(actual: Int, expectedTypes: List<DataType>, position: Position) {
if(actual<expectedTypes.size) {
val missing = expectedTypes.drop(actual).joinToString(", ")
errors.err("some return values are not assigned: expected ${expectedTypes.size} got $actual, missing assignments for: $missing", position)
}
else
errors.err("too many return values are assigned: expected ${expectedTypes.size} got $actual", position)
}

private fun checkMultiAssignment(assignment: Assignment, fcall: IFunctionCall?, fcallTarget: Subroutine?) {
// multi-assign: check the number of assign targets vs. the number of return values of the subroutine
// also check the types of the variables vs the types of each return value
Expand All @@ -602,8 +610,7 @@ internal class AstChecker(private val program: Program,
}
val targets = assignment.target.multi!!
if(fcallTarget.returntypes.size!=targets.size) {
errors.err("number of assignment targets doesn't match number of return values from the subroutine", fcall.position)
return
return numberOfReturnValuesError(targets.size, fcallTarget.returntypes, fcall.position)
}
fcallTarget.returntypes.zip(targets).withIndex().forEach { (index, p) ->
val (returnType, target) = p
Expand Down
13 changes: 11 additions & 2 deletions compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ internal class AstIdentifiersChecker(private val errors: IErrorReporter,
errors.warn("name '$name' shadows the definition at ${existing.position.file} line ${existing.position.line}", position)
}

private fun invalidNumberOfArgsError(pos: Position, numArgs: Int, params: List<String>) {
if(numArgs<params.size) {
val missing = params.drop(numArgs).joinToString(", ")
errors.err("invalid number of arguments: expected ${params.size} got $numArgs, missing: $missing", pos)
}
else
errors.err("invalid number of arguments: expected ${params.size} got $numArgs", pos)
}

override fun visit(block: Block) {
val existing = blocks[block.name]
if(existing!=null) {
Expand Down Expand Up @@ -166,15 +175,15 @@ internal class AstIdentifiersChecker(private val errors: IErrorReporter,
val expectedNumberOfArgs: Int = target.parameters.size
if(call.args.size != expectedNumberOfArgs) {
val pos = (if(call.args.any()) call.args[0] else (call as Node)).position
errors.err("invalid number of arguments", pos)
invalidNumberOfArgsError(pos, call.args.size, target.parameters.map { it.name })
}
}
is BuiltinFunctionPlaceholder -> {
val func = BuiltinFunctions.getValue(target.name)
val expectedNumberOfArgs: Int = func.parameters.size
if(call.args.size != expectedNumberOfArgs) {
val pos = (if(call.args.any()) call.args[0] else (call as Node)).position
errors.err("invalid number of arguments", pos)
invalidNumberOfArgsError(pos, call.args.size, func.parameters.map {it.name })
}
if(target.name=="memory") {
val name = call.args[0] as? StringLiteral
Expand Down
9 changes: 2 additions & 7 deletions docs/source/todo.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,6 @@ TODO

Regenerate skeleton doc files.

"invalid number of arguments" -> print the list of missing arguments

callfar() should allow setting an argument in the X register as well?

Add a new SublimeText syntax file for prog8, and also install this for bat: https://github.com/sharkdp/bat?tab=readme-ov-file#adding-new-syntaxes--language-definitions

Improve register load order in subroutine call args assignments:
in certain situations, the "wrong" order of evaluation of function call arguments is done which results
in overwriting registers that already got their value, which requires a lot of stack juggling (especially on plain 6502 cpu!)
Expand All @@ -17,8 +11,9 @@ Maybe this routine can be made more intelligent. See usesOtherRegistersWhileEva

Future Things and Ideas
^^^^^^^^^^^^^^^^^^^^^^^
Compiler:

- Add a new SublimeText syntax file for prog8, and also install this for bat: https://github.com/sharkdp/bat?tab=readme-ov-file#adding-new-syntaxes--language-definitions
- callfar() should allow setting an argument in the X register as well?
- AST weirdness: why is call(...) a normal FunctionCallStatement and not a BuiltinFunctionCall? What does ror() produce for instance?
- Can we support signed % (remainder) somehow?
- Don't add "random" rts to %asm blocks but instead give a warning about it? (but this breaks existing behavior that others already depend on... command line switch? block directive?)
Expand Down
47 changes: 9 additions & 38 deletions examples/test.p8
Original file line number Diff line number Diff line change
@@ -1,48 +1,19 @@
%import textio
%import string
%import compression
%import test_stack
%zeropage basicsafe
%option no_sysinit

main {
sub start() {
test_stack.test()

txt.print_uwhex(cbm.CHROUT, true)
txt.print_uwhex(&cbm.CHROUT, true)
txt.nl()

cx16.r0 = &function1
callfar(0, $ffd2, $0031)
callfar(0, cbm.CHROUT, $000d)
callfar(0, function1, $6660)
callfar(0, cx16.r0, $ffff)
cx16.r0 -=10
callfar(0, cx16.r0+10, $eeee)

cx16.r0 = &function2
callfar(0, $ffd2, $0032)
callfar(0, cbm.CHROUT, $000d)
callfar(0, function2, $6660)
callfar(0, cx16.r0, $ffff)
cx16.r0 -=10
callfar(0, cx16.r0+10, $eeee)

test_stack.test()
cx16.r0++

sub function1(uword arg) {
txt.print("function 1 arg=")
txt.print_uwhex(arg, false)
txt.nl()
}
cx16.r0L = returns3()
cx16.r0L, cx16.r1L, cx16.r2L, cx16.r3L = returns3()
txt.print_uwhex()
txt.print_uwhex(1, true, 2, 3)
}

sub function2(uword arg) {
txt.print("function 2 arg=")
txt.print_uwhex(arg, false)
txt.nl()
}
asmsub returns3() -> ubyte @A, ubyte @X, bool @Pc {
%asm {{
rts
}}
}
}

0 comments on commit 413b86c

Please sign in to comment.