mirror of
https://github.com/irmen/prog8.git
synced 2025-01-23 00:31:14 +00:00
removed sum(), max(), min(). abs() now always returns uword type.
This greatly simplifies internal handling of builtin functions by always having one fixed return type.
This commit is contained in:
parent
349e5a15e9
commit
220246278a
@ -120,6 +120,7 @@ val WordDatatypes = arrayOf(DataType.UWORD, DataType.WORD)
|
||||
val IntegerDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD)
|
||||
val NumericDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT)
|
||||
val SignedDatatypes = arrayOf(DataType.BYTE, DataType.WORD, DataType.FLOAT)
|
||||
val IntegerArrayDatatypes = arrayOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W)
|
||||
val ArrayDatatypes = arrayOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F)
|
||||
val StringlyDatatypes = arrayOf(DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.UWORD)
|
||||
val IterableDatatypes = arrayOf(
|
||||
|
@ -947,7 +947,7 @@ $repeatLabel lda $counterVar
|
||||
assemblyLines.add(assembly)
|
||||
}
|
||||
|
||||
internal fun returnRegisterOfFunction(it: IdentifierReference, argumentTypesForBuiltinFunc: List<DataType>?): RegisterOrPair {
|
||||
internal fun returnRegisterOfFunction(it: IdentifierReference): RegisterOrPair {
|
||||
return when (val targetRoutine = it.targetStatement(program)!!) {
|
||||
is BuiltinFunctionPlaceholder -> {
|
||||
val func = BuiltinFunctions.getValue(targetRoutine.name)
|
||||
@ -956,16 +956,11 @@ $repeatLabel lda $counterVar
|
||||
in WordDatatypes -> RegisterOrPair.AY
|
||||
DataType.FLOAT -> RegisterOrPair.FAC1
|
||||
else -> {
|
||||
if(!func.hasReturn)
|
||||
throw AssemblyError("func has no returntype")
|
||||
else {
|
||||
val args = argumentTypesForBuiltinFunc!!.map { defaultZero(it, Position.DUMMY) }
|
||||
when(builtinFunctionReturnType(func.name, args, program).getOrElse { DataType.UNDEFINED }) {
|
||||
in ByteDatatypes -> RegisterOrPair.A
|
||||
in WordDatatypes -> RegisterOrPair.AY
|
||||
DataType.FLOAT -> RegisterOrPair.FAC1
|
||||
else -> throw AssemblyError("weird returntype")
|
||||
}
|
||||
when(builtinFunctionReturnType(func.name).getOrElse { DataType.UNDEFINED }) {
|
||||
in ByteDatatypes -> RegisterOrPair.A
|
||||
in WordDatatypes -> RegisterOrPair.AY
|
||||
DataType.FLOAT -> RegisterOrPair.FAC1
|
||||
else -> throw AssemblyError("weird returntype")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2827,7 +2822,7 @@ $repeatLabel lda $counterVar
|
||||
var valueDt = source.inferType(program).getOrElse { throw FatalAstException("invalid dt") }
|
||||
var valueSource: AsmAssignSource =
|
||||
if(source is IFunctionCall) {
|
||||
val resultReg = returnRegisterOfFunction(source.target, listOf(valueDt))
|
||||
val resultReg = returnRegisterOfFunction(source.target)
|
||||
assignExpressionToRegister(source, resultReg, valueDt in listOf(DataType.BYTE, DataType.WORD, DataType.FLOAT))
|
||||
AsmAssignSource(SourceStorageKind.REGISTER, program, this, valueDt, register = resultReg)
|
||||
} else {
|
||||
@ -2839,7 +2834,7 @@ $repeatLabel lda $counterVar
|
||||
segments.dropLast(1).forEach {
|
||||
it as IFunctionCall
|
||||
valueDt = translateUnaryFunctionCallWithArgSource(it.target, valueSource, false, subroutine)
|
||||
val resultReg = returnRegisterOfFunction(it.target, listOf(valueDt))
|
||||
val resultReg = returnRegisterOfFunction(it.target)
|
||||
valueSource = AsmAssignSource(SourceStorageKind.REGISTER, program, this, valueDt, register = resultReg)
|
||||
}
|
||||
// the last segment: unary function call taking a single param and optionally producing a result value.
|
||||
|
@ -63,7 +63,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
|
||||
return if(isStatement) {
|
||||
DataType.UNDEFINED
|
||||
} else {
|
||||
builtinFunctionReturnType(func.name, argExpressions, program).getOrElse { throw AssemblyError("unknown dt") }
|
||||
builtinFunctionReturnType(func.name).getOrElse { throw AssemblyError("unknown dt") }
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,8 +82,6 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
|
||||
"mkword" -> funcMkword(fcall, resultToStack, resultRegister)
|
||||
"abs" -> funcAbs(fcall, func, resultToStack, resultRegister, sscope)
|
||||
"swap" -> funcSwap(fcall)
|
||||
"min", "max" -> funcMinMax(fcall, func, resultToStack, resultRegister, sscope)
|
||||
"sum" -> funcSum(fcall, resultToStack, resultRegister, sscope)
|
||||
"any", "all" -> funcAnyAll(fcall, func, resultToStack, resultRegister, sscope)
|
||||
"sgn" -> funcSgn(fcall, func, resultToStack, resultRegister, sscope)
|
||||
"sin", "cos", "tan", "atan",
|
||||
@ -712,92 +710,15 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
|
||||
}
|
||||
} else {
|
||||
when (dt.getOr(DataType.UNDEFINED)) {
|
||||
DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${function.name}_b_into_A")
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${function.name}_w_into_A")
|
||||
DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${function.name}_f_into_A")
|
||||
DataType.ARRAY_B, DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${function.name}_b_into_A | ldy #0")
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${function.name}_w_into_A | ldy #0")
|
||||
DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${function.name}_f_into_A | ldy #0")
|
||||
else -> throw AssemblyError("weird type $dt")
|
||||
}
|
||||
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, scope, program, asmgen), CpuRegister.A)
|
||||
}
|
||||
}
|
||||
|
||||
private fun funcMinMax(fcall: IFunctionCall, function: FSignature, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: Subroutine?) {
|
||||
outputAddressAndLenghtOfArray(fcall.args[0])
|
||||
val dt = fcall.args.single().inferType(program)
|
||||
if(resultToStack) {
|
||||
when (dt.getOr(DataType.UNDEFINED)) {
|
||||
DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_${function.name}_ub_stack")
|
||||
DataType.ARRAY_B -> asmgen.out(" jsr prog8_lib.func_${function.name}_b_stack")
|
||||
DataType.ARRAY_UW -> asmgen.out(" jsr prog8_lib.func_${function.name}_uw_stack")
|
||||
DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_${function.name}_w_stack")
|
||||
DataType.ARRAY_F -> asmgen.out(" jsr floats.func_${function.name}_f_stack")
|
||||
else -> throw AssemblyError("weird type $dt")
|
||||
}
|
||||
} else {
|
||||
when (dt.getOr(DataType.UNDEFINED)) {
|
||||
DataType.ARRAY_UB, DataType.STR -> {
|
||||
asmgen.out(" jsr prog8_lib.func_${function.name}_ub_into_A")
|
||||
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, scope, program, asmgen), CpuRegister.A)
|
||||
}
|
||||
DataType.ARRAY_B -> {
|
||||
asmgen.out(" jsr prog8_lib.func_${function.name}_b_into_A")
|
||||
assignAsmGen.assignRegisterByte(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.A, false, scope, program, asmgen), CpuRegister.A)
|
||||
}
|
||||
DataType.ARRAY_UW -> {
|
||||
asmgen.out(" jsr prog8_lib.func_${function.name}_uw_into_AY")
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, scope, program, asmgen), RegisterOrPair.AY)
|
||||
}
|
||||
DataType.ARRAY_W -> {
|
||||
asmgen.out(" jsr prog8_lib.func_${function.name}_w_into_AY")
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, scope, program, asmgen), RegisterOrPair.AY)
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
asmgen.out(" jsr floats.func_${function.name}_f_fac1")
|
||||
assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, scope, program, asmgen))
|
||||
}
|
||||
else -> throw AssemblyError("weird type $dt")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun funcSum(fcall: IFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?, scope: Subroutine?) {
|
||||
outputAddressAndLenghtOfArray(fcall.args[0])
|
||||
val dt = fcall.args.single().inferType(program)
|
||||
if(resultToStack) {
|
||||
when (dt.getOr(DataType.UNDEFINED)) {
|
||||
DataType.ARRAY_UB, DataType.STR -> asmgen.out(" jsr prog8_lib.func_sum_ub_stack")
|
||||
DataType.ARRAY_B -> asmgen.out(" jsr prog8_lib.func_sum_b_stack")
|
||||
DataType.ARRAY_UW -> asmgen.out(" jsr prog8_lib.func_sum_uw_stack")
|
||||
DataType.ARRAY_W -> asmgen.out(" jsr prog8_lib.func_sum_w_stack")
|
||||
DataType.ARRAY_F -> asmgen.out(" jsr floats.func_sum_f_stack")
|
||||
else -> throw AssemblyError("weird type $dt")
|
||||
}
|
||||
} else {
|
||||
when (dt.getOr(DataType.UNDEFINED)) {
|
||||
DataType.ARRAY_UB, DataType.STR -> {
|
||||
asmgen.out(" jsr prog8_lib.func_sum_ub_into_AY")
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, scope, program, asmgen), RegisterOrPair.AY)
|
||||
}
|
||||
DataType.ARRAY_B -> {
|
||||
asmgen.out(" jsr prog8_lib.func_sum_b_into_AY")
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, scope, program, asmgen), RegisterOrPair.AY)
|
||||
}
|
||||
DataType.ARRAY_UW -> {
|
||||
asmgen.out(" jsr prog8_lib.func_sum_uw_into_AY")
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, scope, program, asmgen), RegisterOrPair.AY)
|
||||
}
|
||||
DataType.ARRAY_W -> {
|
||||
asmgen.out(" jsr prog8_lib.func_sum_w_into_AY")
|
||||
assignAsmGen.assignRegisterpairWord(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.AY, false, scope, program, asmgen), RegisterOrPair.AY)
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
asmgen.out(" jsr floats.func_sum_f_fac1")
|
||||
assignAsmGen.assignFAC1float(AsmAssignTarget.fromRegisters(resultRegister ?: RegisterOrPair.FAC1, true, scope, program, asmgen))
|
||||
}
|
||||
else -> throw AssemblyError("weird type $dt")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun funcSwap(fcall: IFunctionCall) {
|
||||
val first = fcall.args[0]
|
||||
|
@ -229,7 +229,7 @@ internal class AssignmentAsmGen(private val program: Program,
|
||||
asmgen.translateBuiltinFunctionCallExpression(value, false, assign.target.register)
|
||||
if(assign.target.register==null) {
|
||||
// still need to assign the result to the target variable/etc.
|
||||
val returntype = builtinFunctionReturnType(value.name, value.args, program)
|
||||
val returntype = builtinFunctionReturnType(value.name)
|
||||
if(!returntype.isKnown)
|
||||
throw AssemblyError("unknown dt")
|
||||
when(returntype.getOr(DataType.UNDEFINED)) {
|
||||
|
@ -13,9 +13,6 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
|
||||
fun translate(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
return when(call.name) {
|
||||
"max" -> funcMax(call, resultRegister)
|
||||
"min" -> funcMin(call, resultRegister)
|
||||
"sum" -> funcSum(call, resultRegister)
|
||||
"any" -> funcAny(call, resultRegister)
|
||||
"all" -> funcAll(call, resultRegister)
|
||||
"abs" -> TODO("abs once we can compare plus minus")
|
||||
@ -71,28 +68,6 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
}
|
||||
}
|
||||
|
||||
private fun funcSum(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
val elementDt: VmDataType = codeGen.vmType(ArrayToElementTypes.getValue(array.dt))
|
||||
val syscall =
|
||||
when(array.dt) {
|
||||
DataType.ARRAY_UB,
|
||||
DataType.ARRAY_B -> Syscall.SUM_BYTE
|
||||
DataType.ARRAY_UW,
|
||||
DataType.ARRAY_W -> Syscall.SUM_WORD
|
||||
DataType.ARRAY_F -> TODO("float sum")
|
||||
else -> throw IllegalArgumentException("weird type")
|
||||
}
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args[0], 0)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
if(resultRegister!=0)
|
||||
code += VmCodeInstruction(Opcode.LOADR, elementDt, reg1=resultRegister, reg2=0)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcAny(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
@ -137,50 +112,6 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcMax(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
val elementDt: VmDataType = codeGen.vmType(ArrayToElementTypes.getValue(array.dt))
|
||||
val syscall =
|
||||
when(array.dt) {
|
||||
DataType.ARRAY_UB -> Syscall.MAX_UBYTE
|
||||
DataType.ARRAY_B -> Syscall.MAX_BYTE
|
||||
DataType.ARRAY_UW -> Syscall.MAX_UWORD
|
||||
DataType.ARRAY_W -> Syscall.MAX_WORD
|
||||
DataType.ARRAY_F -> TODO("float max")
|
||||
else -> throw IllegalArgumentException("weird type")
|
||||
}
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args[0], 0)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
if(resultRegister!=0)
|
||||
code += VmCodeInstruction(Opcode.LOADR, elementDt, reg1=resultRegister, reg2=0)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcMin(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
val arrayName = call.args[0] as PtIdentifier
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName.targetName) as StStaticVariable
|
||||
val elementDt: VmDataType = codeGen.vmType(ArrayToElementTypes.getValue(array.dt))
|
||||
val syscall =
|
||||
when(array.dt) {
|
||||
DataType.ARRAY_UB -> Syscall.MIN_UBYTE
|
||||
DataType.ARRAY_B -> Syscall.MIN_BYTE
|
||||
DataType.ARRAY_UW -> Syscall.MIN_UWORD
|
||||
DataType.ARRAY_W -> Syscall.MIN_WORD
|
||||
DataType.ARRAY_F -> TODO("float min")
|
||||
else -> throw IllegalArgumentException("weird type")
|
||||
}
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args[0], 0)
|
||||
code += VmCodeInstruction(Opcode.LOAD, VmDataType.BYTE, reg1=1, value=array.length)
|
||||
code += VmCodeInstruction(Opcode.SYSCALL, value=syscall.ordinal)
|
||||
if(resultRegister!=0)
|
||||
code += VmCodeInstruction(Opcode.LOADR, elementDt, reg1=resultRegister, reg2=0)
|
||||
return code
|
||||
}
|
||||
|
||||
private fun funcSgn(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
val code = VmCodeChunk()
|
||||
code += exprGen.translateExpression(call.args.single(), 0)
|
||||
|
@ -267,6 +267,8 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr
|
||||
|
||||
override fun after(functionCallExpr: FunctionCallExpression, parent: Node): Iterable<IAstModification> {
|
||||
if(functionCallExpr.target.nameInSource == listOf("lsb")) {
|
||||
if(functionCallExpr.args.isEmpty())
|
||||
return noModifications
|
||||
val arg = functionCallExpr.args[0]
|
||||
if(arg is TypecastExpression) {
|
||||
val valueDt = arg.expression.inferType(program)
|
||||
@ -283,6 +285,8 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr
|
||||
}
|
||||
}
|
||||
else if(functionCallExpr.target.nameInSource == listOf("msb")) {
|
||||
if(functionCallExpr.args.isEmpty())
|
||||
return noModifications
|
||||
val arg = functionCallExpr.args[0]
|
||||
if(arg is TypecastExpression) {
|
||||
val valueDt = arg.expression.inferType(program)
|
||||
|
@ -353,85 +353,3 @@ func_all_f_stack .proc
|
||||
jsr a_times_5
|
||||
jmp prog8_lib.func_all_b_stack
|
||||
.pend
|
||||
|
||||
func_max_f_stack .proc
|
||||
jsr func_max_f_fac1
|
||||
jmp push_fac1
|
||||
.pend
|
||||
|
||||
func_max_f_fac1 .proc
|
||||
; -- max(array) -> fac1, array in P8ZP_SCRATCH_W1, num elts in A
|
||||
_loop_count = P8ZP_SCRATCH_REG
|
||||
stx floats_store_reg
|
||||
sta _loop_count
|
||||
lda #255
|
||||
sta _minmax_cmp+1 ; modifying
|
||||
lda #<_largest_neg_float
|
||||
ldy #>_largest_neg_float
|
||||
_minmax_entry jsr MOVFM
|
||||
- lda P8ZP_SCRATCH_W1
|
||||
ldy P8ZP_SCRATCH_W1+1
|
||||
jsr FCOMP
|
||||
_minmax_cmp cmp #255 ; modified
|
||||
bne +
|
||||
lda P8ZP_SCRATCH_W1
|
||||
ldy P8ZP_SCRATCH_W1+1
|
||||
jsr MOVFM
|
||||
+ lda P8ZP_SCRATCH_W1
|
||||
clc
|
||||
adc #5
|
||||
sta P8ZP_SCRATCH_W1
|
||||
bcc +
|
||||
inc P8ZP_SCRATCH_W1+1
|
||||
+ dec _loop_count
|
||||
bne -
|
||||
ldx floats_store_reg
|
||||
rts
|
||||
_largest_neg_float .byte 255,255,255,255,255 ; largest negative float -1.7014118345e+38
|
||||
.pend
|
||||
|
||||
func_min_f_stack .proc
|
||||
jsr func_min_f_fac1
|
||||
jmp push_fac1
|
||||
.pend
|
||||
|
||||
func_min_f_fac1 .proc
|
||||
; -- min(array) -> fac1, array in P8ZP_SCRATCH_W1, num elts in A
|
||||
sta func_max_f_fac1._loop_count
|
||||
lda #1
|
||||
sta func_max_f_fac1._minmax_cmp+1
|
||||
lda #<_largest_pos_float
|
||||
ldy #>_largest_pos_float
|
||||
jmp func_max_f_fac1._minmax_entry
|
||||
_largest_pos_float .byte 255,127,255,255,255 ; largest positive float
|
||||
rts
|
||||
.pend
|
||||
|
||||
|
||||
func_sum_f_stack .proc
|
||||
jsr func_sum_f_fac1
|
||||
jmp push_fac1
|
||||
.pend
|
||||
|
||||
func_sum_f_fac1 .proc
|
||||
; -- sum(array) -> fac1, array in P8ZP_SCRATCH_W1, num elts in A
|
||||
_loop_count = P8ZP_SCRATCH_REG
|
||||
stx floats_store_reg
|
||||
sta _loop_count
|
||||
lda #<FL_ZERO_const
|
||||
ldy #>FL_ZERO_const
|
||||
jsr MOVFM
|
||||
- lda P8ZP_SCRATCH_W1
|
||||
ldy P8ZP_SCRATCH_W1+1
|
||||
jsr FADD
|
||||
lda P8ZP_SCRATCH_W1
|
||||
clc
|
||||
adc #5
|
||||
sta P8ZP_SCRATCH_W1
|
||||
bcc +
|
||||
inc P8ZP_SCRATCH_W1+1
|
||||
+ dec _loop_count
|
||||
bne -
|
||||
ldx floats_store_reg
|
||||
rts
|
||||
.pend
|
||||
|
@ -260,394 +260,6 @@ func_rndw_stack .proc
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_min_ub_into_A .proc
|
||||
; -- min(ubarray) -> A. (array in P8ZP_SCRATCH_W1, num elements in A)
|
||||
tay
|
||||
dey
|
||||
lda #255
|
||||
sta P8ZP_SCRATCH_B1
|
||||
- lda (P8ZP_SCRATCH_W1),y
|
||||
cmp P8ZP_SCRATCH_B1
|
||||
bcs +
|
||||
sta P8ZP_SCRATCH_B1
|
||||
+ dey
|
||||
cpy #255
|
||||
bne -
|
||||
lda P8ZP_SCRATCH_B1
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_min_ub_stack .proc
|
||||
jsr func_min_ub_into_A
|
||||
sta P8ESTACK_LO,x
|
||||
dex
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_min_b_into_A .proc
|
||||
; -- min(barray) -> A. (array in P8ZP_SCRATCH_W1, num elements in A)
|
||||
tay
|
||||
dey
|
||||
lda #127
|
||||
sta P8ZP_SCRATCH_B1
|
||||
- lda (P8ZP_SCRATCH_W1),y
|
||||
clc
|
||||
sbc P8ZP_SCRATCH_B1
|
||||
bvc +
|
||||
eor #$80
|
||||
+ bpl +
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
sta P8ZP_SCRATCH_B1
|
||||
+ dey
|
||||
cpy #255
|
||||
bne -
|
||||
lda P8ZP_SCRATCH_B1
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_min_b_stack .proc
|
||||
jsr func_min_b_into_A
|
||||
sta P8ESTACK_LO,x
|
||||
dex
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_min_uw_into_AY .proc
|
||||
; -- min(uwarray) -> AY (array in P8ZP_SCRATCH_W1, num elements in A)
|
||||
asl a
|
||||
tay
|
||||
dey
|
||||
dey
|
||||
lda #$ff
|
||||
sta _result_minuw
|
||||
sta _result_minuw+1
|
||||
_loop
|
||||
iny
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
dey
|
||||
cmp _result_minuw+1
|
||||
bcc _less
|
||||
bne _gtequ
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
cmp _result_minuw
|
||||
bcs _gtequ
|
||||
_less lda (P8ZP_SCRATCH_W1),y
|
||||
sta _result_minuw
|
||||
iny
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
sta _result_minuw+1
|
||||
dey
|
||||
_gtequ dey
|
||||
dey
|
||||
cpy #254
|
||||
bne _loop
|
||||
lda _result_minuw
|
||||
ldy _result_minuw+1
|
||||
rts
|
||||
_result_minuw .word 0
|
||||
.pend
|
||||
|
||||
func_min_w_into_AY .proc
|
||||
; -- min(warray) -> AY (array in P8ZP_SCRATCH_W1, num elements in A)
|
||||
asl a
|
||||
tay
|
||||
dey
|
||||
dey
|
||||
lda #$ff
|
||||
sta _result_minw
|
||||
lda #$7f
|
||||
sta _result_minw+1
|
||||
_loop
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
cmp _result_minw
|
||||
iny
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
dey
|
||||
sbc _result_minw+1
|
||||
bvc +
|
||||
eor #$80
|
||||
+ bpl _gtequ
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
sta _result_minw
|
||||
iny
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
sta _result_minw+1
|
||||
dey
|
||||
_gtequ dey
|
||||
dey
|
||||
cpy #254
|
||||
bne _loop
|
||||
lda _result_minw
|
||||
ldy _result_minw+1
|
||||
rts
|
||||
_result_minw .word 0
|
||||
.pend
|
||||
|
||||
func_min_uw_stack .proc
|
||||
jsr func_min_uw_into_AY
|
||||
sta P8ESTACK_LO,x
|
||||
tya
|
||||
sta P8ESTACK_HI,x
|
||||
dex
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_min_w_stack .proc
|
||||
jsr func_min_w_into_AY
|
||||
sta P8ESTACK_LO,x
|
||||
tya
|
||||
sta P8ESTACK_HI,x
|
||||
dex
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_max_ub_into_A .proc
|
||||
; -- max(ubarray) -> A (array in P8ZP_SCRATCH_W1, num elements in A)
|
||||
tay
|
||||
dey
|
||||
lda #0
|
||||
sta P8ZP_SCRATCH_B1
|
||||
- lda (P8ZP_SCRATCH_W1),y
|
||||
cmp P8ZP_SCRATCH_B1
|
||||
bcc +
|
||||
sta P8ZP_SCRATCH_B1
|
||||
+ dey
|
||||
cpy #255
|
||||
bne -
|
||||
lda P8ZP_SCRATCH_B1
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_max_ub_stack .proc
|
||||
jsr func_max_ub_into_A
|
||||
sta P8ESTACK_LO,x
|
||||
dex
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_max_b_into_A .proc
|
||||
; -- max(barray) -> A (array in P8ZP_SCRATCH_W1, num elements in A)
|
||||
tay
|
||||
lda #-128
|
||||
sta P8ZP_SCRATCH_B1
|
||||
- lda (P8ZP_SCRATCH_W1),y
|
||||
sec
|
||||
sbc P8ZP_SCRATCH_B1
|
||||
bvc +
|
||||
eor #$80
|
||||
+ bmi +
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
sta P8ZP_SCRATCH_B1
|
||||
+ dey
|
||||
cpy #255
|
||||
bne -
|
||||
lda P8ZP_SCRATCH_B1
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_max_b_stack .proc
|
||||
jsr func_max_b_into_A
|
||||
sta P8ESTACK_LO,x
|
||||
dex
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_max_uw_into_AY .proc
|
||||
; -- max(uwarray) -> AY (array in P8ZP_SCRATCH_W1, num elements in A)
|
||||
asl a
|
||||
tay
|
||||
dey
|
||||
dey
|
||||
lda #0
|
||||
sta _result_maxuw
|
||||
sta _result_maxuw+1
|
||||
_loop
|
||||
iny
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
dey
|
||||
cmp _result_maxuw+1
|
||||
bcc _lesseq
|
||||
bne _greater
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
cmp _result_maxuw
|
||||
bcc _lesseq
|
||||
_greater lda (P8ZP_SCRATCH_W1),y
|
||||
sta _result_maxuw
|
||||
iny
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
sta _result_maxuw+1
|
||||
dey
|
||||
_lesseq dey
|
||||
dey
|
||||
cpy #254
|
||||
bne _loop
|
||||
lda _result_maxuw
|
||||
ldy _result_maxuw+1
|
||||
rts
|
||||
_result_maxuw .word 0
|
||||
.pend
|
||||
|
||||
func_max_uw_stack .proc
|
||||
jsr func_max_uw_into_AY
|
||||
sta P8ESTACK_LO,x
|
||||
tya
|
||||
sta P8ESTACK_HI,x
|
||||
dex
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_max_w_into_AY .proc
|
||||
; -- max(uwarray) -> AY (array in P8ZP_SCRATCH_W1, num elements in A)
|
||||
asl a
|
||||
tay
|
||||
dey
|
||||
dey
|
||||
lda #0
|
||||
sta _result_maxw
|
||||
lda #$80
|
||||
sta _result_maxw+1
|
||||
_loop
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
cmp _result_maxw
|
||||
iny
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
dey
|
||||
sbc _result_maxw+1
|
||||
bvc +
|
||||
eor #$80
|
||||
+ bmi _lesseq
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
sta _result_maxw
|
||||
iny
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
sta _result_maxw+1
|
||||
dey
|
||||
_lesseq dey
|
||||
dey
|
||||
cpy #254
|
||||
bne _loop
|
||||
lda _result_maxw
|
||||
ldy _result_maxw+1
|
||||
rts
|
||||
_result_maxw .word 0
|
||||
.pend
|
||||
|
||||
func_max_w_stack .proc
|
||||
jsr func_max_w_into_AY
|
||||
sta P8ESTACK_LO,x
|
||||
tya
|
||||
sta P8ESTACK_HI,x
|
||||
dex
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_sum_ub_into_AY .proc
|
||||
; -- sum(ubarray) -> AY (array in P8ZP_SCRATCH_W1, num elements in A)
|
||||
tay
|
||||
dey
|
||||
lda #0
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W2+1
|
||||
- lda (P8ZP_SCRATCH_W1),y
|
||||
clc
|
||||
adc P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W2
|
||||
bcc +
|
||||
inc P8ZP_SCRATCH_W2+1
|
||||
+ dey
|
||||
cpy #255
|
||||
bne -
|
||||
lda P8ZP_SCRATCH_W2
|
||||
ldy P8ZP_SCRATCH_W2+1
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_sum_ub_stack .proc
|
||||
jsr func_sum_ub_into_AY
|
||||
sta P8ESTACK_LO,x
|
||||
tya
|
||||
sta P8ESTACK_HI,x
|
||||
dex
|
||||
rts
|
||||
.pend
|
||||
|
||||
|
||||
func_sum_b_into_AY .proc
|
||||
; -- sum(barray) -> AY (array in P8ZP_SCRATCH_W1, num elements in A)
|
||||
tay
|
||||
dey
|
||||
lda #0
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W2+1
|
||||
_loop lda (P8ZP_SCRATCH_W1),y
|
||||
pha
|
||||
clc
|
||||
adc P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W2
|
||||
; sign extend the high byte
|
||||
pla
|
||||
and #$80
|
||||
beq +
|
||||
lda #$ff
|
||||
+ adc P8ZP_SCRATCH_W2+1
|
||||
sta P8ZP_SCRATCH_W2+1
|
||||
dey
|
||||
cpy #255
|
||||
bne _loop
|
||||
lda P8ZP_SCRATCH_W2
|
||||
ldy P8ZP_SCRATCH_W2+1
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_sum_b_stack .proc
|
||||
jsr func_sum_b_into_AY
|
||||
sta P8ESTACK_LO,x
|
||||
tya
|
||||
sta P8ESTACK_HI,x
|
||||
dex
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_sum_uw_into_AY .proc
|
||||
; -- sum(uwarray) -> AY (array in P8ZP_SCRATCH_W1, num elements in A)
|
||||
asl a
|
||||
tay
|
||||
dey
|
||||
dey
|
||||
lda #0
|
||||
sta P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W2+1
|
||||
- lda (P8ZP_SCRATCH_W1),y
|
||||
iny
|
||||
clc
|
||||
adc P8ZP_SCRATCH_W2
|
||||
sta P8ZP_SCRATCH_W2
|
||||
lda (P8ZP_SCRATCH_W1),y
|
||||
adc P8ZP_SCRATCH_W2+1
|
||||
sta P8ZP_SCRATCH_W2+1
|
||||
dey
|
||||
dey
|
||||
dey
|
||||
cpy #254
|
||||
bne -
|
||||
lda P8ZP_SCRATCH_W2
|
||||
ldy P8ZP_SCRATCH_W2+1
|
||||
rts
|
||||
.pend
|
||||
|
||||
func_sum_uw_stack .proc
|
||||
jsr func_sum_uw_into_AY
|
||||
sta P8ESTACK_LO,x
|
||||
tya
|
||||
sta P8ESTACK_HI,x
|
||||
dex
|
||||
rts
|
||||
.pend
|
||||
|
||||
|
||||
func_sum_w_into_AY = func_sum_uw_into_AY
|
||||
func_sum_w_stack = func_sum_uw_stack
|
||||
|
||||
|
||||
func_sort_ub .proc
|
||||
; 8bit unsigned sort
|
||||
|
@ -195,8 +195,8 @@ private class BuiltinFunctionsFacade(functions: Map<String, FSignature>): IBuilt
|
||||
override val names = functions.keys
|
||||
override val purefunctionNames = functions.filter { it.value.pure }.map { it.key }.toSet()
|
||||
|
||||
override fun constValue(name: String, args: List<Expression>, position: Position): NumericLiteral? {
|
||||
val func = BuiltinFunctions[name]
|
||||
override fun constValue(funcName: String, args: List<Expression>, position: Position): NumericLiteral? {
|
||||
val func = BuiltinFunctions[funcName]
|
||||
if(func!=null) {
|
||||
val exprfunc = func.constExpressionFunc
|
||||
if(exprfunc!=null) {
|
||||
@ -213,8 +213,7 @@ private class BuiltinFunctionsFacade(functions: Map<String, FSignature>): IBuilt
|
||||
}
|
||||
return null
|
||||
}
|
||||
override fun returnType(name: String, args: MutableList<Expression>) =
|
||||
builtinFunctionReturnType(name, args, program)
|
||||
override fun returnType(funcName: String) = builtinFunctionReturnType(funcName)
|
||||
}
|
||||
|
||||
fun parseImports(filepath: Path,
|
||||
|
@ -161,7 +161,7 @@ class IntermediateAstMaker(val program: Program) {
|
||||
}
|
||||
|
||||
private fun transform(srcNode: BuiltinFunctionCallStatement): PtBuiltinFunctionCall {
|
||||
val type = builtinFunctionReturnType(srcNode.name, srcNode.args, program).getOr(DataType.UNDEFINED)
|
||||
val type = builtinFunctionReturnType(srcNode.name).getOr(DataType.UNDEFINED)
|
||||
val noSideFx = BuiltinFunctions.getValue(srcNode.name).pure
|
||||
val call = PtBuiltinFunctionCall(srcNode.name, true, noSideFx, type, srcNode.position)
|
||||
for (arg in srcNode.args)
|
||||
|
@ -496,7 +496,7 @@ internal class AstChecker(private val program: Program,
|
||||
if(constVal==null) {
|
||||
val sourceDatatype = assignment.value.inferType(program)
|
||||
if (sourceDatatype.isUnknown) {
|
||||
if (assignment.value !is FunctionCallExpression)
|
||||
if (assignment.value !is FunctionCallExpression && assignment.value !is PipeExpression)
|
||||
errors.err("assignment value is invalid or has no proper datatype, maybe forgot '&' (address-of)", assignment.value.position)
|
||||
} else {
|
||||
checkAssignmentCompatible(targetDatatype.getOr(DataType.UNDEFINED),
|
||||
@ -986,14 +986,7 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
}
|
||||
else if(targetStatement is BuiltinFunctionPlaceholder) {
|
||||
val args = if(functionCallExpr.parent is IPipe) {
|
||||
// pipe segment, add implicit first argument
|
||||
val firstArgDt = BuiltinFunctions.getValue(targetStatement.name).parameters.first().possibleDatatypes.first()
|
||||
listOf(defaultZero(firstArgDt, functionCallExpr.position)) + functionCallExpr.args
|
||||
} else {
|
||||
functionCallExpr.args
|
||||
}
|
||||
if(builtinFunctionReturnType(targetStatement.name, args, program).isUnknown) {
|
||||
if(builtinFunctionReturnType(targetStatement.name).isUnknown) {
|
||||
if(functionCallExpr.parent is Expression || functionCallExpr.parent is Assignment)
|
||||
errors.err("function doesn't return a value", functionCallExpr.position)
|
||||
}
|
||||
@ -1074,12 +1067,6 @@ internal class AstChecker(private val program: Program,
|
||||
errors.err("any/all on a string is useless (is always true unless the string is empty)", position)
|
||||
}
|
||||
}
|
||||
else if(target.name=="min" || target.name=="max") {
|
||||
if((args[0] as? AddressOf)?.identifier?.targetVarDecl(program)?.datatype == DataType.STR
|
||||
|| args[0].inferType(program).getOr(DataType.STR) == DataType.STR) {
|
||||
errors.err("min/max operate on arrays, not on strings", position)
|
||||
}
|
||||
}
|
||||
} else if(target is Subroutine) {
|
||||
if(target.isAsmSubroutine) {
|
||||
for (arg in args.zip(target.parameters)) {
|
||||
@ -1509,7 +1496,7 @@ internal fun checkUnusedReturnValues(call: FunctionCallStatement, target: Statem
|
||||
else
|
||||
errors.warn("result values of subroutine call are discarded (use void?)", call.position)
|
||||
} else if (target is BuiltinFunctionPlaceholder) {
|
||||
val rt = builtinFunctionReturnType(target.name, call.args, program)
|
||||
val rt = builtinFunctionReturnType(target.name)
|
||||
if (rt.isKnown)
|
||||
errors.warn("result value of a function call is discarded (use void?)", call.position)
|
||||
}
|
||||
|
@ -114,12 +114,12 @@ internal class VerifyFunctionArgTypes(val program: Program, val errors: IErrorRe
|
||||
}
|
||||
|
||||
override fun visit(pipe: PipeExpression) {
|
||||
processPipe(pipe.source, pipe.segments, pipe)
|
||||
processPipe(pipe.source, pipe.segments)
|
||||
if(errors.noErrors()) {
|
||||
val last = (pipe.segments.last() as IFunctionCall).target
|
||||
when (val target = last.targetStatement(program)!!) {
|
||||
is BuiltinFunctionPlaceholder -> {
|
||||
if (!BuiltinFunctions.getValue(target.name).hasReturn)
|
||||
if (BuiltinFunctions.getValue(target.name).returnType==null)
|
||||
errors.err("invalid pipe expression; last term doesn't return a value", last.position)
|
||||
}
|
||||
is Subroutine -> {
|
||||
@ -135,13 +135,13 @@ internal class VerifyFunctionArgTypes(val program: Program, val errors: IErrorRe
|
||||
}
|
||||
|
||||
override fun visit(pipe: Pipe) {
|
||||
processPipe(pipe.source, pipe.segments, pipe)
|
||||
processPipe(pipe.source, pipe.segments)
|
||||
if(errors.noErrors()) {
|
||||
super.visit(pipe)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processPipe(source: Expression, segments: List<Expression>, scope: Node) {
|
||||
private fun processPipe(source: Expression, segments: List<Expression>) {
|
||||
|
||||
val sourceArg = (source as? IFunctionCall)?.args?.firstOrNull()
|
||||
if(sourceArg!=null && segments.any { (it as IFunctionCall).args.firstOrNull() === sourceArg})
|
||||
@ -160,7 +160,7 @@ internal class VerifyFunctionArgTypes(val program: Program, val errors: IErrorRe
|
||||
val func = BuiltinFunctions.getValue(target.name)
|
||||
if(func.parameters.size!=1)
|
||||
errors.err("can only use unary function", funccall.position)
|
||||
else if(!func.hasReturn && funccall !== segments.last())
|
||||
else if(func.returnType==null && funccall !== segments.last())
|
||||
errors.err("function must return a single value", funccall.position)
|
||||
|
||||
val paramDts = func.parameters.firstOrNull()?.possibleDatatypes
|
||||
@ -170,8 +170,7 @@ internal class VerifyFunctionArgTypes(val program: Program, val errors: IErrorRe
|
||||
if(errors.noErrors()) {
|
||||
// type can depend on the argument(s) of the function. For now, we only deal with unary functions,
|
||||
// so we know there must be a single argument. Take its type from the previous expression in the pipe chain.
|
||||
val zero = defaultZero(valueDt, funccall.position)
|
||||
valueDt = builtinFunctionReturnType(func.name, listOf(zero), program).getOrElse { DataType.UNDEFINED }
|
||||
valueDt = builtinFunctionReturnType(func.name).getOrElse { DataType.UNDEFINED }
|
||||
}
|
||||
}
|
||||
is Subroutine -> {
|
||||
|
@ -16,7 +16,6 @@ class TestBuiltinFunctions: FunSpec({
|
||||
func.parameters[0].name shouldBe "value"
|
||||
func.parameters[0].possibleDatatypes shouldBe NumericDatatypes
|
||||
func.pure shouldBe true
|
||||
func.hasReturn shouldBe true
|
||||
func.returnType shouldBe DataType.BYTE
|
||||
|
||||
val conv = func.callConvention(listOf(DataType.UBYTE))
|
||||
@ -34,7 +33,6 @@ class TestBuiltinFunctions: FunSpec({
|
||||
func.name shouldBe "rnd"
|
||||
func.parameters.size shouldBe 0
|
||||
func.pure shouldBe false
|
||||
func.hasReturn shouldBe true
|
||||
func.returnType shouldBe DataType.UBYTE
|
||||
|
||||
val conv = func.callConvention(emptyList())
|
||||
@ -53,7 +51,6 @@ class TestBuiltinFunctions: FunSpec({
|
||||
func.parameters[1].name shouldBe "value"
|
||||
func.parameters[1].possibleDatatypes shouldBe arrayOf(DataType.UBYTE)
|
||||
func.pure shouldBe false
|
||||
func.hasReturn shouldBe false
|
||||
func.returnType shouldBe null
|
||||
|
||||
val conv = func.callConvention(listOf(DataType.UWORD, DataType.UBYTE))
|
||||
@ -68,25 +65,5 @@ class TestBuiltinFunctions: FunSpec({
|
||||
conv.returns.floatFac1 shouldBe false
|
||||
conv.returns.reg shouldBe null
|
||||
}
|
||||
|
||||
test("func with variable return type") {
|
||||
val func = BuiltinFunctions.getValue("abs")
|
||||
func.name shouldBe "abs"
|
||||
func.parameters.size shouldBe 1
|
||||
func.parameters[0].name shouldBe "value"
|
||||
func.parameters[0].possibleDatatypes.toSet() shouldBe NumericDatatypes.toSet()
|
||||
func.pure shouldBe true
|
||||
func.hasReturn shouldBe true
|
||||
func.returnType shouldBe null
|
||||
|
||||
val conv = func.callConvention(listOf(DataType.UWORD))
|
||||
conv.params.size shouldBe 1
|
||||
conv.params[0].dt shouldBe DataType.UWORD
|
||||
conv.params[0].reg shouldBe RegisterOrPair.AY
|
||||
conv.params[0].variable shouldBe false
|
||||
conv.returns.dt shouldBe DataType.UWORD
|
||||
conv.returns.floatFac1 shouldBe false
|
||||
conv.returns.reg shouldBe RegisterOrPair.AY
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -604,7 +604,7 @@ class TestOptimization: FunSpec({
|
||||
uword @shared zz
|
||||
zz += 60 ; NOT ok to remove initializer, should evaluate to 60
|
||||
ubyte @shared xx
|
||||
xx = 6+abs(xx) ; is not an initializer because it references xx
|
||||
xx = 6+lsb(abs(xx)) ; is not an initializer because it references xx
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
@ -133,7 +133,7 @@ class TestPipes: FunSpec({
|
||||
|
||||
9999 |> abs() |> txt.print_uw()
|
||||
9999 |> txt.print_uw()
|
||||
99 |> abs() |> txt.print_ub()
|
||||
99 |> abs() |> lsb() |> txt.print_ub()
|
||||
99 |> txt.print_ub()
|
||||
}
|
||||
|
||||
@ -411,7 +411,7 @@ class TestPipes: FunSpec({
|
||||
uword ww = 9999
|
||||
ubyte bb = 99
|
||||
ww |> abs() |> txt.print_uw()
|
||||
bb |> abs() |> txt.print_ub()
|
||||
bb |> abs() |> lsb() |> txt.print_ub()
|
||||
}
|
||||
}
|
||||
"""
|
||||
@ -425,8 +425,9 @@ class TestPipes: FunSpec({
|
||||
|
||||
val pipebb = stmts[5] as Pipe
|
||||
pipebb.source shouldBe instanceOf<BuiltinFunctionCall>()
|
||||
pipebb.segments.size shouldBe 1
|
||||
pipebb.segments.size shouldBe 2
|
||||
pipebb.segments[0] shouldBe instanceOf<IFunctionCall>()
|
||||
pipebb.segments[1] shouldBe instanceOf<IFunctionCall>()
|
||||
}
|
||||
|
||||
test("pipe statement with type errors") {
|
||||
|
@ -11,12 +11,12 @@ internal object DummyFunctions : IBuiltinFunctions {
|
||||
override val names: Set<String> = emptySet()
|
||||
override val purefunctionNames: Set<String> = emptySet()
|
||||
override fun constValue(
|
||||
name: String,
|
||||
funcName: String,
|
||||
args: List<Expression>,
|
||||
position: Position,
|
||||
): NumericLiteral? = null
|
||||
|
||||
override fun returnType(name: String, args: MutableList<Expression>) = InferredTypes.InferredType.unknown()
|
||||
override fun returnType(funcName: String) = InferredTypes.InferredType.unknown()
|
||||
}
|
||||
|
||||
internal object DummyMemsizer : IMemSizer {
|
||||
|
@ -8,6 +8,6 @@ import prog8.code.core.Position
|
||||
interface IBuiltinFunctions {
|
||||
val names: Set<String>
|
||||
val purefunctionNames: Set<String>
|
||||
fun constValue(name: String, args: List<Expression>, position: Position): NumericLiteral?
|
||||
fun returnType(name: String, args: MutableList<Expression>): InferredTypes.InferredType
|
||||
fun constValue(funcName: String, args: List<Expression>, position: Position): NumericLiteral?
|
||||
fun returnType(funcName: String): InferredTypes.InferredType
|
||||
}
|
||||
|
@ -986,7 +986,7 @@ class FunctionCallExpression(override var target: IdentifierReference,
|
||||
val stmt = target.targetStatement(program) ?: return InferredTypes.unknown()
|
||||
when (stmt) {
|
||||
is BuiltinFunctionPlaceholder -> {
|
||||
return program.builtinFunctions.returnType(target.nameInSource[0], this.args)
|
||||
return program.builtinFunctions.returnType(target.nameInSource[0])
|
||||
}
|
||||
is Subroutine -> {
|
||||
if(stmt.returntypes.isEmpty())
|
||||
@ -1164,5 +1164,5 @@ class BuiltinFunctionCall(override var target: IdentifierReference,
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||
override fun referencesIdentifier(nameInSource: List<String>): Boolean = target.referencesIdentifier(nameInSource) || args.any{it.referencesIdentifier(nameInSource)}
|
||||
override fun inferType(program: Program) = program.builtinFunctions.returnType(name, this.args)
|
||||
override fun inferType(program: Program) = program.builtinFunctions.returnType(name)
|
||||
}
|
||||
|
@ -38,36 +38,26 @@ class FParam(val name: String, val possibleDatatypes: Array<DataType>)
|
||||
class FSignature(val name: String,
|
||||
val pure: Boolean, // does it have side effects?
|
||||
val parameters: List<FParam>,
|
||||
val hasReturn: Boolean, // is there a return value at all?
|
||||
val returnType: DataType?, // specify return type if fixed, otherwise null if it depends on the arguments
|
||||
val returnType: DataType?,
|
||||
val constExpressionFunc: ConstExpressionCaller? = null) {
|
||||
|
||||
init {
|
||||
require(hasReturn || returnType==null) { "$name has invalid return spec" }
|
||||
}
|
||||
|
||||
fun callConvention(actualParamTypes: List<DataType>): CallConvention {
|
||||
val returns: ReturnConvention
|
||||
if(hasReturn) {
|
||||
returns = when (returnType) {
|
||||
DataType.UBYTE, DataType.BYTE -> ReturnConvention(returnType, RegisterOrPair.A, false)
|
||||
DataType.UWORD, DataType.WORD -> ReturnConvention(returnType, RegisterOrPair.AY, false)
|
||||
DataType.FLOAT -> ReturnConvention(returnType, null, true)
|
||||
in PassByReferenceDatatypes -> ReturnConvention(returnType!!, RegisterOrPair.AY, false)
|
||||
else -> {
|
||||
// return type depends on arg type
|
||||
when (val paramType = actualParamTypes.first()) {
|
||||
DataType.UBYTE, DataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A, false)
|
||||
DataType.UWORD, DataType.WORD -> ReturnConvention(paramType, RegisterOrPair.AY, false)
|
||||
DataType.FLOAT -> ReturnConvention(paramType, null, true)
|
||||
in PassByReferenceDatatypes -> ReturnConvention(paramType, RegisterOrPair.AY, false)
|
||||
else -> ReturnConvention(paramType, null, false)
|
||||
}
|
||||
val returns: ReturnConvention = when (returnType) {
|
||||
DataType.UBYTE, DataType.BYTE -> ReturnConvention(returnType, RegisterOrPair.A, false)
|
||||
DataType.UWORD, DataType.WORD -> ReturnConvention(returnType, RegisterOrPair.AY, false)
|
||||
DataType.FLOAT -> ReturnConvention(returnType, null, true)
|
||||
in PassByReferenceDatatypes -> ReturnConvention(returnType!!, RegisterOrPair.AY, false)
|
||||
null -> ReturnConvention(null, null, false)
|
||||
else -> {
|
||||
// return type depends on arg type
|
||||
when (val paramType = actualParamTypes.first()) {
|
||||
DataType.UBYTE, DataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A, false)
|
||||
DataType.UWORD, DataType.WORD -> ReturnConvention(paramType, RegisterOrPair.AY, false)
|
||||
DataType.FLOAT -> ReturnConvention(paramType, null, true)
|
||||
in PassByReferenceDatatypes -> ReturnConvention(paramType, RegisterOrPair.AY, false)
|
||||
else -> ReturnConvention(paramType, null, false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
require(returnType==null)
|
||||
returns = ReturnConvention(null, null, false)
|
||||
}
|
||||
|
||||
return when {
|
||||
@ -95,167 +85,78 @@ class FSignature(val name: String,
|
||||
|
||||
private val functionSignatures: List<FSignature> = listOf(
|
||||
// this set of function have no return value and operate in-place:
|
||||
FSignature("rol" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), false,null),
|
||||
FSignature("ror" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), false, null),
|
||||
FSignature("rol2" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), false, null),
|
||||
FSignature("ror2" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), false, null),
|
||||
FSignature("sort" , false, listOf(FParam("array", ArrayDatatypes)), false, null),
|
||||
FSignature("reverse" , false, listOf(FParam("array", ArrayDatatypes)), false, null),
|
||||
FSignature("rol" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
|
||||
FSignature("ror" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
|
||||
FSignature("rol2" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
|
||||
FSignature("ror2" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
|
||||
FSignature("sort" , false, listOf(FParam("array", ArrayDatatypes)), null),
|
||||
FSignature("reverse" , false, listOf(FParam("array", ArrayDatatypes)), null),
|
||||
// cmp returns a status in the carry flag, but not a proper return value
|
||||
FSignature("cmp" , false, listOf(FParam("value1", IntegerDatatypes), FParam("value2", NumericDatatypes)), false, null),
|
||||
// these few have a return value depending on the argument(s):
|
||||
FSignature("max" , true, listOf(FParam("values", ArrayDatatypes)), true, null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMax) }, // type depends on args
|
||||
FSignature("min" , true, listOf(FParam("values", ArrayDatatypes)), true, null) { a, p, prg -> collectionArg(a, p, prg, ::builtinMin) }, // type depends on args
|
||||
FSignature("sum" , true, listOf(FParam("values", ArrayDatatypes)), true, null) { a, p, prg -> collectionArg(a, p, prg, ::builtinSum) }, // type depends on args
|
||||
FSignature("abs" , true, listOf(FParam("value", NumericDatatypes)), true, null, ::builtinAbs), // type depends on argument
|
||||
FSignature("len" , true, listOf(FParam("values", IterableDatatypes)), true, null, ::builtinLen), // type is UBYTE or UWORD depending on actual length
|
||||
FSignature("sizeof" , true, listOf(FParam("object", DataType.values())), true, DataType.UBYTE, ::builtinSizeof),
|
||||
FSignature("cmp" , false, listOf(FParam("value1", IntegerDatatypes), FParam("value2", NumericDatatypes)), null),
|
||||
FSignature("abs" , true, listOf(FParam("value", NumericDatatypes)), DataType.UWORD, ::builtinAbs),
|
||||
FSignature("len" , true, listOf(FParam("values", IterableDatatypes)), DataType.UWORD, ::builtinLen),
|
||||
// normal functions follow:
|
||||
FSignature("sgn" , true, listOf(FParam("value", NumericDatatypes)), true, DataType.BYTE, ::builtinSgn ),
|
||||
FSignature("sin" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::sin) },
|
||||
FSignature("cos" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::cos) },
|
||||
FSignature("tan" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::tan) },
|
||||
FSignature("atan" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::atan) },
|
||||
FSignature("ln" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::log) },
|
||||
FSignature("log2" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, ::log2) },
|
||||
FSignature("sqrt16" , true, listOf(FParam("value", arrayOf(DataType.UWORD))), true, DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { sqrt(it.toDouble()) } },
|
||||
FSignature("sqrt" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::sqrt) },
|
||||
FSignature("rad" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::toRadians) },
|
||||
FSignature("deg" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::toDegrees) },
|
||||
FSignature("round" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, ::round) },
|
||||
FSignature("floor" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, Math::floor) },
|
||||
FSignature("ceil" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), true, DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, Math::ceil) },
|
||||
FSignature("any" , true, listOf(FParam("values", ArrayDatatypes)), true, DataType.UBYTE) { a, p, prg -> collectionArg(a, p, prg, ::builtinAny) },
|
||||
FSignature("all" , true, listOf(FParam("values", ArrayDatatypes)), true, DataType.UBYTE) { a, p, prg -> collectionArg(a, p, prg, ::builtinAll) },
|
||||
FSignature("lsb" , true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), true, DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> (x and 255).toDouble() } },
|
||||
FSignature("msb" , true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), true, DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> (x ushr 8 and 255).toDouble()} },
|
||||
FSignature("mkword" , true, listOf(FParam("msb", arrayOf(DataType.UBYTE)), FParam("lsb", arrayOf(DataType.UBYTE))), true, DataType.UWORD, ::builtinMkword),
|
||||
FSignature("peek" , true, listOf(FParam("address", arrayOf(DataType.UWORD))), true, DataType.UBYTE),
|
||||
FSignature("peekw" , true, listOf(FParam("address", arrayOf(DataType.UWORD))), true, DataType.UWORD),
|
||||
FSignature("poke" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), false,null),
|
||||
FSignature("pokemon" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), false,null),
|
||||
FSignature("pokew" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UWORD))), false,null),
|
||||
FSignature("pop" , false, listOf(FParam("target", ByteDatatypes)), false, null),
|
||||
FSignature("popw" , false, listOf(FParam("target", WordDatatypes)), false, null),
|
||||
FSignature("push" , false, listOf(FParam("value", ByteDatatypes)), false, null),
|
||||
FSignature("pushw" , false, listOf(FParam("value", WordDatatypes)), false, null),
|
||||
FSignature("rsave" , false, emptyList(), false,null),
|
||||
FSignature("rsavex" , false, emptyList(), false,null),
|
||||
FSignature("rrestore" , false, emptyList(), false,null),
|
||||
FSignature("rrestorex" , false, emptyList(), false,null),
|
||||
FSignature("rnd" , false, emptyList(), true, DataType.UBYTE),
|
||||
FSignature("rndw" , false, emptyList(), true, DataType.UWORD),
|
||||
FSignature("rndf" , false, emptyList(), true, DataType.FLOAT),
|
||||
FSignature("memory" , true, listOf(FParam("name", arrayOf(DataType.STR)), FParam("size", arrayOf(DataType.UWORD)), FParam("alignment", arrayOf(DataType.UWORD))), true, DataType.UWORD),
|
||||
FSignature("swap" , false, listOf(FParam("first", NumericDatatypes), FParam("second", NumericDatatypes)), false, null),
|
||||
FSignature("callfar" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), false, null),
|
||||
FSignature("callrom" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), false, null),
|
||||
FSignature("syscall" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE))), true, DataType.UWORD, null),
|
||||
FSignature("syscall1" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE)), FParam("arg1", arrayOf(DataType.UWORD))), true, DataType.UWORD, null),
|
||||
FSignature("syscall2" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE)), FParam("arg1", arrayOf(DataType.UWORD)), FParam("arg2", arrayOf(DataType.UWORD))), true, DataType.UWORD, null),
|
||||
FSignature("syscall3" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE)), FParam("arg1", arrayOf(DataType.UWORD)), FParam("arg2", arrayOf(DataType.UWORD)), FParam("arg3", arrayOf(DataType.UWORD))), true, DataType.UWORD, null),
|
||||
FSignature("sizeof" , true, listOf(FParam("object", DataType.values())), DataType.UBYTE, ::builtinSizeof),
|
||||
FSignature("sgn" , true, listOf(FParam("value", NumericDatatypes)), DataType.BYTE, ::builtinSgn ),
|
||||
FSignature("sin" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::sin) },
|
||||
FSignature("cos" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::cos) },
|
||||
FSignature("tan" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::tan) },
|
||||
FSignature("atan" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::atan) },
|
||||
FSignature("ln" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::log) },
|
||||
FSignature("log2" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, ::log2) },
|
||||
FSignature("sqrt16" , true, listOf(FParam("value", arrayOf(DataType.UWORD))), DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { sqrt(it.toDouble()) } },
|
||||
FSignature("sqrt" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::sqrt) },
|
||||
FSignature("rad" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::toRadians) },
|
||||
FSignature("deg" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArg(a, p, prg, Math::toDegrees) },
|
||||
FSignature("round" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, ::round) },
|
||||
FSignature("floor" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, Math::floor) },
|
||||
FSignature("ceil" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg -> oneDoubleArgOutputWord(a, p, prg, Math::ceil) },
|
||||
FSignature("any" , true, listOf(FParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, prg -> collectionArg(a, p, prg, ::builtinAny) },
|
||||
FSignature("all" , true, listOf(FParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, prg -> collectionArg(a, p, prg, ::builtinAll) },
|
||||
FSignature("lsb" , true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> (x and 255).toDouble() } },
|
||||
FSignature("msb" , true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, prg -> oneIntArgOutputInt(a, p, prg) { x: Int -> (x ushr 8 and 255).toDouble()} },
|
||||
FSignature("mkword" , true, listOf(FParam("msb", arrayOf(DataType.UBYTE)), FParam("lsb", arrayOf(DataType.UBYTE))), DataType.UWORD, ::builtinMkword),
|
||||
FSignature("peek" , true, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.UBYTE),
|
||||
FSignature("peekw" , true, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.UWORD),
|
||||
FSignature("poke" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), null),
|
||||
FSignature("pokemon" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), null),
|
||||
FSignature("pokew" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UWORD))), null),
|
||||
FSignature("pop" , false, listOf(FParam("target", ByteDatatypes)), null),
|
||||
FSignature("popw" , false, listOf(FParam("target", WordDatatypes)), null),
|
||||
FSignature("push" , false, listOf(FParam("value", ByteDatatypes)), null),
|
||||
FSignature("pushw" , false, listOf(FParam("value", WordDatatypes)), null),
|
||||
FSignature("rsave" , false, emptyList(), null),
|
||||
FSignature("rsavex" , false, emptyList(), null),
|
||||
FSignature("rrestore" , false, emptyList(), null),
|
||||
FSignature("rrestorex" , false, emptyList(), null),
|
||||
FSignature("rnd" , false, emptyList(), DataType.UBYTE),
|
||||
FSignature("rndw" , false, emptyList(), DataType.UWORD),
|
||||
FSignature("rndf" , false, emptyList(), DataType.FLOAT),
|
||||
FSignature("memory" , true, listOf(FParam("name", arrayOf(DataType.STR)), FParam("size", arrayOf(DataType.UWORD)), FParam("alignment", arrayOf(DataType.UWORD))), DataType.UWORD),
|
||||
FSignature("swap" , false, listOf(FParam("first", NumericDatatypes), FParam("second", NumericDatatypes)), null),
|
||||
FSignature("callfar" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), null),
|
||||
FSignature("callrom" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), null),
|
||||
FSignature("syscall" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE))), DataType.UWORD, null),
|
||||
FSignature("syscall1" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE)), FParam("arg1", arrayOf(DataType.UWORD))), DataType.UWORD, null),
|
||||
FSignature("syscall2" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE)), FParam("arg1", arrayOf(DataType.UWORD)), FParam("arg2", arrayOf(DataType.UWORD))), DataType.UWORD, null),
|
||||
FSignature("syscall3" , false, listOf(FParam("callnr", arrayOf(DataType.UBYTE)), FParam("arg1", arrayOf(DataType.UWORD)), FParam("arg2", arrayOf(DataType.UWORD)), FParam("arg3", arrayOf(DataType.UWORD))), DataType.UWORD, null),
|
||||
)
|
||||
|
||||
val BuiltinFunctions = functionSignatures.associateBy { it.name }
|
||||
|
||||
|
||||
private fun builtinMax(array: List<Double>): Double = array.maxByOrNull { it }!!
|
||||
|
||||
private fun builtinMin(array: List<Double>): Double = array.minByOrNull { it }!!
|
||||
|
||||
private fun builtinSum(array: List<Double>): Double = array.sumOf { it }
|
||||
|
||||
private fun builtinAny(array: List<Double>): Double = if(array.any { it!=0.0 }) 1.0 else 0.0
|
||||
|
||||
private fun builtinAll(array: List<Double>): Double = if(array.all { it!=0.0 }) 1.0 else 0.0
|
||||
|
||||
fun builtinFunctionReturnType(function: String, args: List<Expression>, program: Program): InferredTypes.InferredType {
|
||||
|
||||
fun builtinFunctionReturnType(function: String): InferredTypes.InferredType {
|
||||
if(function in arrayOf("set_carry", "set_irqd", "clear_carry", "clear_irqd"))
|
||||
return InferredTypes.InferredType.void()
|
||||
|
||||
fun datatypeFromIterableArg(arglist: Expression): DataType {
|
||||
if(arglist is ArrayLiteral) {
|
||||
val dt = arglist.value.map {it.inferType(program).getOr(DataType.UNDEFINED)}.toSet()
|
||||
if(dt.any { it !in NumericDatatypes }) {
|
||||
throw FatalAstException("fuction $function only accepts array of numeric values")
|
||||
}
|
||||
if(DataType.FLOAT in dt) return DataType.FLOAT
|
||||
if(DataType.UWORD in dt) return DataType.UWORD
|
||||
if(DataType.WORD in dt) return DataType.WORD
|
||||
if(DataType.BYTE in dt) return DataType.BYTE
|
||||
return DataType.UBYTE
|
||||
}
|
||||
if(arglist is IdentifierReference) {
|
||||
val idt = arglist.inferType(program)
|
||||
return when(val dt = idt.getOrElse { throw FatalAstException("unknown dt") }) {
|
||||
DataType.STR, in NumericDatatypes -> dt
|
||||
in ArrayDatatypes -> ArrayToElementTypes.getValue(dt)
|
||||
else -> throw FatalAstException("function '$function' requires one argument which is an iterable")
|
||||
}
|
||||
}
|
||||
throw FatalAstException("function '$function' requires one argument which is an iterable")
|
||||
}
|
||||
|
||||
val func = BuiltinFunctions.getValue(function)
|
||||
if(func.returnType!=null)
|
||||
return InferredTypes.knownFor(func.returnType)
|
||||
if(!func.hasReturn)
|
||||
if(func.returnType==null)
|
||||
return InferredTypes.InferredType.void()
|
||||
|
||||
// function has return values, but the return type depends on the arguments
|
||||
if(args.isEmpty())
|
||||
return InferredTypes.InferredType.unknown()
|
||||
return when (function) {
|
||||
"abs" -> {
|
||||
val dt = args.single().inferType(program)
|
||||
return if(dt.isNumeric)
|
||||
dt
|
||||
else
|
||||
InferredTypes.InferredType.unknown()
|
||||
}
|
||||
"max", "min" -> {
|
||||
when(val dt = datatypeFromIterableArg(args.single())) {
|
||||
DataType.STR -> InferredTypes.knownFor(DataType.UBYTE)
|
||||
in NumericDatatypes -> InferredTypes.knownFor(dt)
|
||||
in ArrayDatatypes -> InferredTypes.knownFor(ArrayToElementTypes.getValue(dt))
|
||||
else -> InferredTypes.unknown()
|
||||
}
|
||||
}
|
||||
"sum" -> {
|
||||
when(datatypeFromIterableArg(args.single())) {
|
||||
DataType.UBYTE, DataType.UWORD -> InferredTypes.knownFor(DataType.UWORD)
|
||||
DataType.BYTE, DataType.WORD -> InferredTypes.knownFor(DataType.WORD)
|
||||
DataType.FLOAT -> InferredTypes.knownFor(DataType.FLOAT)
|
||||
DataType.ARRAY_UB, DataType.ARRAY_UW -> InferredTypes.knownFor(DataType.UWORD)
|
||||
DataType.ARRAY_B, DataType.ARRAY_W -> InferredTypes.knownFor(DataType.WORD)
|
||||
DataType.ARRAY_F -> InferredTypes.knownFor(DataType.FLOAT)
|
||||
DataType.STR -> InferredTypes.knownFor(DataType.UWORD)
|
||||
else -> InferredTypes.unknown()
|
||||
}
|
||||
}
|
||||
"len" -> {
|
||||
when(args.single().inferType(program).getOr(DataType.UNDEFINED)) {
|
||||
in ArrayDatatypes -> {
|
||||
val value = args.single() as? ArrayLiteral
|
||||
if(value!=null) {
|
||||
return if(value.value.size<256) InferredTypes.knownFor(DataType.UBYTE) else InferredTypes.knownFor(DataType.UWORD)
|
||||
} else {
|
||||
val targetVar = (args.single() as? IdentifierReference)?.targetVarDecl(program)
|
||||
if (targetVar?.isArray == true) {
|
||||
val length = targetVar.arraysize?.constIndex()
|
||||
if(length!=null)
|
||||
return if(length<256) InferredTypes.knownFor(DataType.UBYTE) else InferredTypes.knownFor(DataType.UWORD)
|
||||
}
|
||||
}
|
||||
return InferredTypes.knownFor(DataType.UWORD)
|
||||
}
|
||||
DataType.STR -> return InferredTypes.knownFor(DataType.UBYTE)
|
||||
else -> InferredTypes.unknown()
|
||||
}
|
||||
}
|
||||
else -> return InferredTypes.unknown()
|
||||
}
|
||||
return InferredTypes.knownFor(func.returnType)
|
||||
}
|
||||
|
||||
|
||||
|
@ -611,7 +611,7 @@ In most places where a number or other value is expected, you can use just the n
|
||||
If possible, the expression is parsed and evaluated by the compiler itself at compile time, and the (constant) resulting value is used in its place.
|
||||
Expressions that cannot be compile-time evaluated will result in code that calculates them at runtime.
|
||||
Expressions can contain procedure and function calls.
|
||||
There are various built-in functions such as sin(), cos(), min(), max() that can be used in expressions (see :ref:`builtinfunctions`).
|
||||
There are various built-in functions such as sin(), cos() that can be used in expressions (see :ref:`builtinfunctions`).
|
||||
You can also reference idendifiers defined elsewhere in your code.
|
||||
|
||||
Read the :ref:`syntaxreference` chapter for all details on the available operators and kinds of expressions you can write.
|
||||
@ -804,19 +804,10 @@ len(x)
|
||||
(use the ``string.length`` routine if you want to dynamically determine the length by counting to the
|
||||
first 0-byte)
|
||||
|
||||
max(x)
|
||||
Maximum of the values in the array value x
|
||||
|
||||
min(x)
|
||||
Minimum of the values in the array value x
|
||||
|
||||
reverse(array)
|
||||
Reverse the values in the array (in-place).
|
||||
Can be used after sort() to sort an array in descending order.
|
||||
|
||||
sum(x)
|
||||
Sum of the values in the array value x
|
||||
|
||||
sort(array)
|
||||
Sort the array in ascending order (in-place)
|
||||
Supported are arrays of bytes or word values.
|
||||
|
@ -3,7 +3,8 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- can't use abs() etc in pipe expression because return type depends on argument type
|
||||
- abs: remove support for floats. Just use floats.ABS()
|
||||
- ... this will solve: can't use abs() etc in pipe expression because return type depends on argument type
|
||||
- pipe operator: allow non-unary function calls in the pipe that specify the other argument(s) in the calls.
|
||||
- createAssemblyAndAssemble(): make it possible to actually get rid of the VarDecl nodes by fixing the rest of the code mentioned there.
|
||||
- allow "xxx" * constexpr (where constexpr is not a number literal), now gives expression error not same type
|
||||
|
@ -7,19 +7,8 @@
|
||||
main {
|
||||
sub start() {
|
||||
|
||||
word[] values = [1111, -222, -9999, 88, 20222, 0, 0, 1111]
|
||||
word[] values2 = [0,0,0,0,0,1,0,0,0]
|
||||
txt.print_w(max(values))
|
||||
txt.nl()
|
||||
txt.print_w(min(values))
|
||||
txt.nl()
|
||||
txt.print_w(sum(values))
|
||||
txt.nl()
|
||||
txt.print_ub(any(values))
|
||||
txt.nl()
|
||||
txt.print_ub(any(values2))
|
||||
txt.nl()
|
||||
txt.print_ub(all(values))
|
||||
ubyte qq = 99 as ubyte |> abs() |> abs()
|
||||
txt.print_ub(qq)
|
||||
txt.nl()
|
||||
|
||||
; uword other = $fe4a
|
||||
|
Loading…
x
Reference in New Issue
Block a user