mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 01:29:28 +00:00
min/max give proper error for string args
als implmented more vm builtin functions/syscalls
This commit is contained in:
parent
bf7f4bba7b
commit
349e5a15e9
5
.idea/misc.xml
generated
5
.idea/misc.xml
generated
@ -22,4 +22,9 @@
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
<component name="SwUserDefinedSpecifications">
|
||||
<option name="specTypeByUrl">
|
||||
<map />
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
@ -2,6 +2,7 @@ package prog8.codegen.virtual
|
||||
|
||||
import prog8.code.StStaticVariable
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.ArrayToElementTypes
|
||||
import prog8.code.core.AssemblyError
|
||||
import prog8.code.core.DataType
|
||||
import prog8.vm.Opcode
|
||||
@ -13,10 +14,10 @@ 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" -> TODO()
|
||||
"sum" -> TODO()
|
||||
"any" -> TODO()
|
||||
"all" -> TODO()
|
||||
"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")
|
||||
"cmp" -> TODO("cmp() can't be used on vm because no processor status bits implemented")
|
||||
"sgn" -> funcSgn(call, resultRegister)
|
||||
@ -70,22 +71,113 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
}
|
||||
}
|
||||
|
||||
private fun funcMax(call: PtBuiltinFunctionCall, resultRegister: Int): VmCodeChunk {
|
||||
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()
|
||||
val arrayName = (call.args.single() as PtIdentifier).targetName
|
||||
val array = codeGen.symbolTable.flat.getValue(arrayName) as StStaticVariable
|
||||
when (array.dt) {
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W -> {
|
||||
TODO("max word array")
|
||||
}
|
||||
DataType.STR -> {
|
||||
TODO("max string")
|
||||
}
|
||||
else -> {
|
||||
TODO("max byte array")
|
||||
}
|
||||
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
|
||||
val elementDt: VmDataType = codeGen.vmType(ArrayToElementTypes.getValue(array.dt))
|
||||
val syscall =
|
||||
when(array.dt) {
|
||||
DataType.ARRAY_UB,
|
||||
DataType.ARRAY_B -> Syscall.ANY_BYTE
|
||||
DataType.ARRAY_UW,
|
||||
DataType.ARRAY_W -> Syscall.ANY_WORD
|
||||
DataType.ARRAY_F -> TODO("float any")
|
||||
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 funcAll(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.ALL_BYTE
|
||||
DataType.ARRAY_UW,
|
||||
DataType.ARRAY_W -> Syscall.ALL_WORD
|
||||
DataType.ARRAY_F -> TODO("float all")
|
||||
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 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
|
||||
}
|
||||
|
||||
@ -151,7 +243,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
when(array.dt) {
|
||||
DataType.ARRAY_UB, DataType.ARRAY_B, DataType.STR -> Syscall.REVERSE_BYTES
|
||||
DataType.ARRAY_UW, DataType.ARRAY_W -> Syscall.REVERSE_WORDS
|
||||
DataType.FLOAT -> TODO("reverse floats")
|
||||
DataType.ARRAY_F -> TODO("float reverse")
|
||||
else -> throw IllegalArgumentException("weird type to reverse")
|
||||
}
|
||||
val code = VmCodeChunk()
|
||||
@ -170,7 +262,7 @@ internal class BuiltinFuncGen(private val codeGen: CodeGen, private val exprGen:
|
||||
DataType.ARRAY_B -> Syscall.SORT_BYTE
|
||||
DataType.ARRAY_UW -> Syscall.SORT_UWORD
|
||||
DataType.ARRAY_W -> Syscall.SORT_WORD
|
||||
DataType.FLOAT -> TODO("float sort")
|
||||
DataType.ARRAY_F -> TODO("float sort")
|
||||
DataType.STR -> Syscall.SORT_UBYTE
|
||||
else -> throw IllegalArgumentException("weird type to sort")
|
||||
}
|
||||
|
@ -1069,11 +1069,15 @@ internal class AstChecker(private val program: Program,
|
||||
errors.err("swap requires args of numerical type", position)
|
||||
}
|
||||
else if(target.name=="all" || target.name=="any") {
|
||||
if((args[0] as? AddressOf)?.identifier?.targetVarDecl(program)?.datatype == DataType.STR) {
|
||||
if((args[0] as? AddressOf)?.identifier?.targetVarDecl(program)?.datatype == DataType.STR
|
||||
|| args[0].inferType(program).getOr(DataType.STR) == DataType.STR) {
|
||||
errors.err("any/all on a string is useless (is always true unless the string is empty)", position)
|
||||
}
|
||||
if(args[0].inferType(program).getOr(DataType.STR) == DataType.STR) {
|
||||
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) {
|
||||
|
@ -3,9 +3,7 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- min/max/any/all should give error when string arg is given instead of array
|
||||
- can't use abs() etc in pipe expression because return type depends on argument type
|
||||
- vm: add support for all builtin functions
|
||||
- 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
|
||||
@ -14,6 +12,7 @@ For next release
|
||||
If we can do that why not perhaps also able to inline multi-line subroutines? Why would it be limited to just 1 line? Maybe to protect against code size bloat.
|
||||
Inlined subroutines cannot contain further nested subroutines!
|
||||
Once this works, look for library subroutines that should be inlined.
|
||||
- vm: add support for status bits, status-branch instructions, and cmp() and abs() functions.
|
||||
|
||||
...
|
||||
|
||||
|
@ -9,8 +9,6 @@ main {
|
||||
|
||||
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("abcde"))
|
||||
txt.nl()
|
||||
txt.print_w(max(values))
|
||||
txt.nl()
|
||||
txt.print_w(min(values))
|
||||
|
@ -25,8 +25,22 @@ SYSCALLS:
|
||||
16 = sort_byte array
|
||||
17 = sort_uword array
|
||||
18 = sort_word array
|
||||
19 = reverse_bytes array
|
||||
20 = reverse_words array
|
||||
19 = max_ubyte array
|
||||
20 = max_byte array
|
||||
21 = max_uword array
|
||||
22 = max_word array
|
||||
23 = min_ubyte array
|
||||
24 = min_byte array
|
||||
25 = min_uword array
|
||||
26 = min_word array
|
||||
27 = sum_byte array
|
||||
28 = sum_word array
|
||||
29 = any_byte array
|
||||
30 = any_word array
|
||||
31 = all_byte array
|
||||
32 = all_word array
|
||||
33 = reverse_bytes array
|
||||
34 = reverse_words array
|
||||
*/
|
||||
|
||||
enum class Syscall {
|
||||
@ -49,8 +63,22 @@ enum class Syscall {
|
||||
SORT_BYTE,
|
||||
SORT_UWORD,
|
||||
SORT_WORD,
|
||||
REVERSE_BYTES, // TODO not as syscall
|
||||
REVERSE_WORDS // TODO not as syscall
|
||||
MAX_UBYTE,
|
||||
MAX_BYTE,
|
||||
MAX_UWORD,
|
||||
MAX_WORD,
|
||||
MIN_UBYTE,
|
||||
MIN_BYTE,
|
||||
MIN_UWORD,
|
||||
MIN_WORD,
|
||||
SUM_BYTE,
|
||||
SUM_WORD,
|
||||
ANY_BYTE,
|
||||
ANY_WORD,
|
||||
ALL_BYTE,
|
||||
ALL_WORD,
|
||||
REVERSE_BYTES,
|
||||
REVERSE_WORDS
|
||||
}
|
||||
|
||||
object SysCalls {
|
||||
@ -168,6 +196,112 @@ object SysCalls {
|
||||
vm.memory.setUW(address+index*2, value)
|
||||
}
|
||||
}
|
||||
Syscall.MAX_UBYTE -> {
|
||||
val address = vm.registers.getUW(0).toInt()
|
||||
val length = vm.registers.getUB(1).toInt()
|
||||
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
|
||||
val value = addresses.map { vm.memory.getUB(it) }.maxOf { it }
|
||||
vm.registers.setUB(0, value)
|
||||
}
|
||||
Syscall.MAX_BYTE -> {
|
||||
val address = vm.registers.getUW(0).toInt()
|
||||
val length = vm.registers.getUB(1).toInt()
|
||||
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
|
||||
val value = addresses.map { vm.memory.getSB(it) }.maxOf { it }
|
||||
vm.registers.setSB(0, value)
|
||||
}
|
||||
Syscall.MAX_UWORD -> {
|
||||
val address = vm.registers.getUW(0).toInt()
|
||||
val length = vm.registers.getUB(1).toInt()
|
||||
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
|
||||
val value = addresses.map { vm.memory.getUW(it) }.maxOf { it }
|
||||
vm.registers.setUW(0, value)
|
||||
}
|
||||
Syscall.MAX_WORD -> {
|
||||
val address = vm.registers.getUW(0).toInt()
|
||||
val length = vm.registers.getUB(1).toInt()
|
||||
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
|
||||
val value = addresses.map { vm.memory.getSW(it) }.maxOf { it }
|
||||
vm.registers.setSW(0, value)
|
||||
}
|
||||
Syscall.MIN_UBYTE -> {
|
||||
val address = vm.registers.getUW(0).toInt()
|
||||
val length = vm.registers.getUB(1).toInt()
|
||||
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
|
||||
val value = addresses.map { vm.memory.getUB(it) }.minOf { it }
|
||||
vm.registers.setUB(0, value)
|
||||
}
|
||||
Syscall.MIN_BYTE -> {
|
||||
val address = vm.registers.getUW(0).toInt()
|
||||
val length = vm.registers.getUB(1).toInt()
|
||||
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
|
||||
val value = addresses.map { vm.memory.getSB(it) }.minOf { it }
|
||||
vm.registers.setSB(0, value)
|
||||
}
|
||||
Syscall.MIN_UWORD -> {
|
||||
val address = vm.registers.getUW(0).toInt()
|
||||
val length = vm.registers.getUB(1).toInt()
|
||||
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
|
||||
val value = addresses.map { vm.memory.getUW(it) }.minOf { it }
|
||||
vm.registers.setUW(0, value)
|
||||
}
|
||||
Syscall.MIN_WORD -> {
|
||||
val address = vm.registers.getUW(0).toInt()
|
||||
val length = vm.registers.getUB(1).toInt()
|
||||
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
|
||||
val value = addresses.map { vm.memory.getSW(it) }.minOf { it }
|
||||
vm.registers.setSW(0, value)
|
||||
}
|
||||
Syscall.SUM_BYTE -> {
|
||||
val address = vm.registers.getUW(0).toInt()
|
||||
val length = vm.registers.getUB(1).toInt()
|
||||
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
|
||||
val value = addresses.map { vm.memory.getUB(it) }.sum()
|
||||
vm.registers.setUB(0, value.toUByte())
|
||||
}
|
||||
Syscall.SUM_WORD -> {
|
||||
val address = vm.registers.getUW(0).toInt()
|
||||
val length = vm.registers.getUB(1).toInt()
|
||||
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
|
||||
val value = addresses.map { vm.memory.getUW(it) }.sum()
|
||||
vm.registers.setUW(0, value.toUShort())
|
||||
}
|
||||
Syscall.ANY_BYTE -> {
|
||||
val address = vm.registers.getUW(0).toInt()
|
||||
val length = vm.registers.getUB(1).toInt()
|
||||
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
|
||||
if(addresses.any { vm.memory.getUB(it).toInt()!=0 })
|
||||
vm.registers.setUB(0, 1u)
|
||||
else
|
||||
vm.registers.setUB(0, 0u)
|
||||
}
|
||||
Syscall.ANY_WORD -> {
|
||||
val address = vm.registers.getUW(0).toInt()
|
||||
val length = vm.registers.getUB(1).toInt()
|
||||
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
|
||||
if(addresses.any { vm.memory.getUW(it).toInt()!=0 })
|
||||
vm.registers.setUB(0, 1u)
|
||||
else
|
||||
vm.registers.setUB(0, 0u)
|
||||
}
|
||||
Syscall.ALL_BYTE -> {
|
||||
val address = vm.registers.getUW(0).toInt()
|
||||
val length = vm.registers.getUB(1).toInt()
|
||||
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
|
||||
if(addresses.all { vm.memory.getUB(it).toInt()!=0 })
|
||||
vm.registers.setUB(0, 1u)
|
||||
else
|
||||
vm.registers.setUB(0, 0u)
|
||||
}
|
||||
Syscall.ALL_WORD -> {
|
||||
val address = vm.registers.getUW(0).toInt()
|
||||
val length = vm.registers.getUB(1).toInt()
|
||||
val addresses = IntProgression.fromClosedRange(address, address+length*2-2, 2)
|
||||
if(addresses.all { vm.memory.getUW(it).toInt()!=0 })
|
||||
vm.registers.setUB(0, 1u)
|
||||
else
|
||||
vm.registers.setUB(0, 0u)
|
||||
}
|
||||
else -> TODO("syscall ${call.name}")
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user