fix strlen

This commit is contained in:
Irmen de Jong 2019-08-11 14:02:53 +02:00
parent fe5b225732
commit 2ce6bc5946
7 changed files with 78 additions and 17 deletions

View File

@ -10,13 +10,13 @@ class SyntaxError(override var message: String, val position: Position) : AstExc
override fun toString() = "$position Syntax error: $message" override fun toString() = "$position Syntax error: $message"
} }
class NameError(override var message: String, val position: Position) : AstException(message) { open class NameError(override var message: String, val position: Position) : AstException(message) {
override fun toString() = "$position Name error: $message" override fun toString() = "$position Name error: $message"
} }
open class ExpressionError(message: String, val position: Position) : AstException(message) { class ExpressionError(message: String, val position: Position) : AstException(message) {
override fun toString() = "$position Error: $message" override fun toString() = "$position Error: $message"
} }
class UndefinedSymbolError(symbol: IdentifierReference) class UndefinedSymbolError(symbol: IdentifierReference)
: ExpressionError("undefined symbol: ${symbol.nameInSource.joinToString(".")}", symbol.position) : NameError("undefined symbol: ${symbol.nameInSource.joinToString(".")}", symbol.position)

View File

@ -326,7 +326,7 @@ class NumericLiteralValue(val type: DataType, // only numerical types allowed
operator fun compareTo(other: NumericLiteralValue): Int = number.toDouble().compareTo(other.number.toDouble()) operator fun compareTo(other: NumericLiteralValue): Int = number.toDouble().compareTo(other.number.toDouble())
fun cast(targettype: DataType): NumericLiteralValue? { fun cast(targettype: DataType): NumericLiteralValue {
if(type==targettype) if(type==targettype)
return this return this
val numval = number.toDouble() val numval = number.toDouble()
@ -381,7 +381,7 @@ class NumericLiteralValue(val type: DataType, // only numerical types allowed
} }
else -> {} else -> {}
} }
return null // invalid type conversion from $this to $targettype throw ExpressionError("can't cast $type into $targettype", position)
} }
} }

View File

@ -848,9 +848,12 @@ internal class AstChecker(private val program: Program,
if(args.size!=func.parameters.size) if(args.size!=func.parameters.size)
checkResult.add(SyntaxError("invalid number of arguments", position)) checkResult.add(SyntaxError("invalid number of arguments", position))
else { else {
val paramTypesForAddressOf = PassByReferenceDatatypes + DataType.UWORD
for (arg in args.withIndex().zip(func.parameters)) { for (arg in args.withIndex().zip(func.parameters)) {
val argDt=arg.first.value.inferType(program) val argDt=arg.first.value.inferType(program)
if(argDt!=null && !(argDt isAssignableTo arg.second.possibleDatatypes)) { if (argDt != null
&& !(argDt isAssignableTo arg.second.possibleDatatypes)
&& (argDt != DataType.UWORD || arg.second.possibleDatatypes.intersect(paramTypesForAddressOf).isEmpty())) {
checkResult.add(ExpressionError("builtin function '${target.name}' argument ${arg.first.index + 1} has invalid type $argDt, expected ${arg.second.possibleDatatypes}", position)) checkResult.add(ExpressionError("builtin function '${target.name}' argument ${arg.first.index + 1} has invalid type $argDt, expected ${arg.second.possibleDatatypes}", position))
} }
} }
@ -867,6 +870,14 @@ internal class AstChecker(private val program: Program,
else if(dt1 !in NumericDatatypes) else if(dt1 !in NumericDatatypes)
checkResult.add(ExpressionError("swap requires args of numerical type", position)) checkResult.add(ExpressionError("swap requires args of numerical type", position))
} }
else if(target.name=="all" || target.name=="any") {
if((args[0] as? AddressOf)?.identifier?.targetVarDecl(program.namespace)?.datatype in StringDatatypes) {
checkResult.add(ExpressionError("any/all on a string is useless (is always true unless the string is empty)", position))
}
if(args[0].inferType(program) in StringDatatypes) {
checkResult.add(ExpressionError("any/all on a string is useless (is always true unless the string is empty)", position))
}
}
} }
} else if(target is Subroutine) { } else if(target is Subroutine) {
if(args.size!=target.parameters.size) if(args.size!=target.parameters.size)

View File

@ -381,7 +381,14 @@ internal fun fixupArrayDatatype(array: ReferenceLiteralValue, vardecl: VarDecl,
val arrayDt = array.type val arrayDt = array.type
if(arrayDt!=vardecl.datatype) { if(arrayDt!=vardecl.datatype) {
// fix the datatype of the array (also on the heap) to match the vardecl // fix the datatype of the array (also on the heap) to match the vardecl
val litval2 = array.cast(vardecl.datatype)!! val litval2 =
try {
array.cast(vardecl.datatype)!!
} catch(x: ExpressionError) {
// couldn't cast permanently.
// instead, simply adjust the array type and trust the AstChecker to report the exact error
ReferenceLiteralValue(vardecl.datatype, null, array.array, array.heapId, array.position)
}
vardecl.value = litval2 vardecl.value = litval2
litval2.linkParents(vardecl) litval2.linkParents(vardecl)
litval2.addToHeap(heap) // TODO is the previous array discarded from the resulting asm code? litval2.addToHeap(heap) // TODO is the previous array discarded from the resulting asm code?

View File

@ -135,10 +135,11 @@ internal class VarInitValueAndAddressOfCreator(private val program: Program): IA
} }
private fun addAddressOfExprIfNeededForBuiltinFuncs(signature: FunctionSignature, args: MutableList<Expression>, parent: Statement) { private fun addAddressOfExprIfNeededForBuiltinFuncs(signature: FunctionSignature, args: MutableList<Expression>, parent: Statement) {
// val paramTypesForAddressOf = PassByReferenceDatatypes + DataType.UWORD
for(arg in args.withIndex().zip(signature.parameters)) { for(arg in args.withIndex().zip(signature.parameters)) {
val argvalue = arg.first.value val argvalue = arg.first.value
val argDt = argvalue.inferType(program) val argDt = argvalue.inferType(program)
if(DataType.UWORD in arg.second.possibleDatatypes && argDt in PassByReferenceDatatypes) { if(argDt in PassByReferenceDatatypes && DataType.UWORD in arg.second.possibleDatatypes) {
if(argvalue !is IdentifierReference) if(argvalue !is IdentifierReference)
throw CompilerException("pass-by-reference parameter isn't an identifier? $argvalue") throw CompilerException("pass-by-reference parameter isn't an identifier? $argvalue")
val addrOf = AddressOf(argvalue, argvalue.position) val addrOf = AddressOf(argvalue, argvalue.position)

View File

@ -11,6 +11,7 @@ import prog8.ast.statements.AssignTarget
import prog8.ast.statements.FunctionCallStatement import prog8.ast.statements.FunctionCallStatement
import prog8.compiler.CompilationOptions import prog8.compiler.CompilationOptions
import prog8.compiler.Zeropage import prog8.compiler.Zeropage
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX
@ -79,7 +80,18 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
asmgen.assignFromEvalResult(firstTarget) asmgen.assignFromEvalResult(firstTarget)
asmgen.assignFromEvalResult(secondTarget) asmgen.assignFromEvalResult(secondTarget)
} }
// TODO: any(f), all(f), max(f), min(f), sum(f) "strlen" -> {
val identifierName = asmgen.asmIdentifierName(fcall.arglist[0] as IdentifierReference)
asmgen.out("""
lda #<$identifierName
sta $ESTACK_LO_HEX,x
lda #>$identifierName
sta $ESTACK_HI_HEX,x
dex
jsr prog8_lib.func_strlen
""")
}
// TODO: any(f), all(f), max(f), min(f), sum(f), avg(f)
"sin", "cos", "tan", "atan", "sin", "cos", "tan", "atan",
"ln", "log2", "sqrt", "rad", "ln", "log2", "sqrt", "rad",
"deg", "round", "floor", "ceil", "deg", "round", "floor", "ceil",

View File

@ -1,17 +1,47 @@
%import c64lib %import c64lib
%import c64utils %import c64utils
%import c64flt
%zeropage dontuse
main { main {
sub start() { sub start() {
A = testsub(33) byte[] barr = [-100, 0, 99, -122, 22]
} ubyte[] ubarr = [100, 0, 99, 199, 22]
word[] warr = [-1000, 0, 999, -4444, 222]
uword[] uwarr = [1000, 0, 222, 4444, 999]
float[] farr = [-1000.1, 0, 999.9, -4444.4, 222.2]
str name = "irmen"
ubyte ub
byte bb
word ww
uword uw
float ff
asmsub testsub(ubyte foo @stack) -> ubyte @stack { ; LEN/STRLEN
%asm {{ ubyte length = len(name)
Y=44 if(length!=5) c64scr.print("error len1\n")
rts length = len(uwarr)
}} if(length!=5) c64scr.print("error len2\n")
} length=strlen(name)
if(length!=5) c64scr.print("error strlen1\n")
name[3] = 0
length=strlen(name)
if(length!=3) c64scr.print("error strlen2\n")
; MAX
; ub = max(ubarr)
; bb = max(barr)
; ww = max(warr)
; uw = max(uwarr)
; ff = max(farr)
; word ww = sum(barr)
; uword uw = sum(ubarr)
; ww = sum(warr)
; uw = sum(uwarr)
; float ff = sum(farr)
c64scr.print("\nyou should see no errors above.")
}
} }