mirror of
https://github.com/irmen/prog8.git
synced 2025-02-25 04:29:36 +00:00
made a lot more opcodes type-specific
This commit is contained in:
parent
42e4891fcf
commit
e8ba21d3ba
@ -3,7 +3,6 @@ package prog8.ast
|
|||||||
import org.antlr.v4.runtime.ParserRuleContext
|
import org.antlr.v4.runtime.ParserRuleContext
|
||||||
import org.antlr.v4.runtime.tree.TerminalNode
|
import org.antlr.v4.runtime.tree.TerminalNode
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
import prog8.compiler.target.c64.Mflpt5
|
|
||||||
import prog8.compiler.target.c64.Petscii
|
import prog8.compiler.target.c64.Petscii
|
||||||
import prog8.compiler.unescape
|
import prog8.compiler.unescape
|
||||||
import prog8.functions.BuiltinFunctions
|
import prog8.functions.BuiltinFunctions
|
||||||
|
@ -635,12 +635,54 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
"msb" -> stackvmProg.instr(Opcode.MSB)
|
"msb" -> stackvmProg.instr(Opcode.MSB)
|
||||||
"lsb" -> stackvmProg.instr(Opcode.LSB)
|
"lsb" -> stackvmProg.instr(Opcode.LSB)
|
||||||
"lsl" -> stackvmProg.instr(Opcode.SHL)
|
"lsl" -> {
|
||||||
"lsr" -> stackvmProg.instr(Opcode.SHR)
|
val arg = args.single()
|
||||||
"rol" -> stackvmProg.instr(Opcode.ROL)
|
when (arg.resultingDatatype(namespace, heap)) {
|
||||||
"ror" -> stackvmProg.instr(Opcode.ROR)
|
DataType.BYTE -> stackvmProg.instr(Opcode.SHL)
|
||||||
"rol2" -> stackvmProg.instr(Opcode.ROL2)
|
DataType.WORD -> stackvmProg.instr(Opcode.SHL_W)
|
||||||
"ror2" -> stackvmProg.instr(Opcode.ROR2)
|
else -> throw CompilerException("wrong datatype")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"lsr" -> {
|
||||||
|
val arg = args.single()
|
||||||
|
when (arg.resultingDatatype(namespace, heap)) {
|
||||||
|
DataType.BYTE -> stackvmProg.instr(Opcode.SHR)
|
||||||
|
DataType.WORD -> stackvmProg.instr(Opcode.SHR_W)
|
||||||
|
else -> throw CompilerException("wrong datatype")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"rol" -> {
|
||||||
|
val arg = args.single()
|
||||||
|
when (arg.resultingDatatype(namespace, heap)) {
|
||||||
|
DataType.BYTE -> stackvmProg.instr(Opcode.ROL)
|
||||||
|
DataType.WORD -> stackvmProg.instr(Opcode.ROL_W)
|
||||||
|
else -> throw CompilerException("wrong datatype")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"ror" -> {
|
||||||
|
val arg = args.single()
|
||||||
|
when (arg.resultingDatatype(namespace, heap)) {
|
||||||
|
DataType.BYTE -> stackvmProg.instr(Opcode.ROR)
|
||||||
|
DataType.WORD -> stackvmProg.instr(Opcode.ROR_W)
|
||||||
|
else -> throw CompilerException("wrong datatype")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"rol2" -> {
|
||||||
|
val arg = args.single()
|
||||||
|
when (arg.resultingDatatype(namespace, heap)) {
|
||||||
|
DataType.BYTE -> stackvmProg.instr(Opcode.ROL2)
|
||||||
|
DataType.WORD -> stackvmProg.instr(Opcode.ROL2_W)
|
||||||
|
else -> throw CompilerException("wrong datatype")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"ror2" -> {
|
||||||
|
val arg = args.single()
|
||||||
|
when (arg.resultingDatatype(namespace, heap)) {
|
||||||
|
DataType.BYTE -> stackvmProg.instr(Opcode.ROR2)
|
||||||
|
DataType.WORD -> stackvmProg.instr(Opcode.ROR2_W)
|
||||||
|
else -> throw CompilerException("wrong datatype")
|
||||||
|
}
|
||||||
|
}
|
||||||
"set_carry" -> stackvmProg.instr(Opcode.SEC)
|
"set_carry" -> stackvmProg.instr(Opcode.SEC)
|
||||||
"clear_carry" -> stackvmProg.instr(Opcode.CLC)
|
"clear_carry" -> stackvmProg.instr(Opcode.CLC)
|
||||||
"set_irqd" -> stackvmProg.instr(Opcode.SEI)
|
"set_irqd" -> stackvmProg.instr(Opcode.SEI)
|
||||||
@ -666,6 +708,8 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
val validDt = setOf(DataType.BYTE, DataType.WORD, DataType.FLOAT)
|
val validDt = setOf(DataType.BYTE, DataType.WORD, DataType.FLOAT)
|
||||||
if(leftDt !in validDt || rightDt !in validDt)
|
if(leftDt !in validDt || rightDt !in validDt)
|
||||||
throw CompilerException("invalid datatype(s) for operand(s)")
|
throw CompilerException("invalid datatype(s) for operand(s)")
|
||||||
|
if(leftDt!=rightDt)
|
||||||
|
throw CompilerException("operands have different datatypes")
|
||||||
val opcode = when(operator) {
|
val opcode = when(operator) {
|
||||||
// todo variants depending on leftdt/rightdt (b/w/f)
|
// todo variants depending on leftdt/rightdt (b/w/f)
|
||||||
"+" -> Opcode.ADD
|
"+" -> Opcode.ADD
|
||||||
@ -675,18 +719,96 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
"//" -> Opcode.FLOORDIV
|
"//" -> Opcode.FLOORDIV
|
||||||
"%" -> Opcode.REMAINDER
|
"%" -> Opcode.REMAINDER
|
||||||
"**" -> Opcode.POW
|
"**" -> Opcode.POW
|
||||||
"&" -> Opcode.BITAND
|
"&" -> {
|
||||||
"|" -> Opcode.BITOR
|
when(leftDt) {
|
||||||
"^" -> Opcode.BITXOR
|
DataType.BYTE -> Opcode.BITAND
|
||||||
"and" -> Opcode.AND
|
DataType.WORD -> Opcode.BITAND_W
|
||||||
"or" -> Opcode.OR
|
else -> throw CompilerException("only byte/word possible")
|
||||||
"xor" -> Opcode.XOR
|
}
|
||||||
"<" -> Opcode.LESS
|
}
|
||||||
">" -> Opcode.GREATER
|
"|" -> {
|
||||||
"<=" -> Opcode.LESSEQ
|
when(leftDt) {
|
||||||
">=" -> Opcode.GREATEREQ
|
DataType.BYTE -> Opcode.BITOR
|
||||||
"==" -> Opcode.EQUAL
|
DataType.WORD -> Opcode.BITOR_W
|
||||||
"!=" -> Opcode.NOTEQUAL
|
else -> throw CompilerException("only byte/word possible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"^" -> {
|
||||||
|
when(leftDt) {
|
||||||
|
DataType.BYTE -> Opcode.BITXOR
|
||||||
|
DataType.WORD -> Opcode.BITXOR_W
|
||||||
|
else -> throw CompilerException("only byte/word possible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"and" -> {
|
||||||
|
when(leftDt) {
|
||||||
|
DataType.BYTE -> Opcode.AND
|
||||||
|
DataType.WORD -> Opcode.AND_W
|
||||||
|
else -> throw CompilerException("only byte/word possible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"or" -> {
|
||||||
|
when(leftDt) {
|
||||||
|
DataType.BYTE -> Opcode.OR
|
||||||
|
DataType.WORD -> Opcode.OR_W
|
||||||
|
else -> throw CompilerException("only byte/word possible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"xor" -> {
|
||||||
|
when(leftDt) {
|
||||||
|
DataType.BYTE -> Opcode.XOR
|
||||||
|
DataType.WORD -> Opcode.XOR_W
|
||||||
|
else -> throw CompilerException("only byte/word possible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"<" -> {
|
||||||
|
when(leftDt) {
|
||||||
|
DataType.BYTE -> Opcode.LESS
|
||||||
|
DataType.WORD -> Opcode.LESS_W
|
||||||
|
DataType.FLOAT -> Opcode.LESS_F
|
||||||
|
else -> throw CompilerException("only byte/word/lfoat possible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
">" -> {
|
||||||
|
when(leftDt) {
|
||||||
|
DataType.BYTE -> Opcode.GREATER
|
||||||
|
DataType.WORD -> Opcode.GREATER_W
|
||||||
|
DataType.FLOAT -> Opcode.GREATER_F
|
||||||
|
else -> throw CompilerException("only byte/word/lfoat possible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"<=" -> {
|
||||||
|
when(leftDt) {
|
||||||
|
DataType.BYTE -> Opcode.LESSEQ
|
||||||
|
DataType.WORD -> Opcode.LESSEQ_W
|
||||||
|
DataType.FLOAT -> Opcode.LESSEQ_F
|
||||||
|
else -> throw CompilerException("only byte/word/lfoat possible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
">=" -> {
|
||||||
|
when(leftDt) {
|
||||||
|
DataType.BYTE -> Opcode.GREATEREQ
|
||||||
|
DataType.WORD -> Opcode.GREATEREQ_W
|
||||||
|
DataType.FLOAT -> Opcode.GREATEREQ_F
|
||||||
|
else -> throw CompilerException("only byte/word/lfoat possible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"==" -> {
|
||||||
|
when (leftDt) {
|
||||||
|
DataType.BYTE -> Opcode.EQUAL
|
||||||
|
DataType.WORD -> Opcode.EQUAL_W
|
||||||
|
DataType.FLOAT -> Opcode.EQUAL_F
|
||||||
|
else -> throw CompilerException("only byte/word/lfoat possible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"!=" -> {
|
||||||
|
when (leftDt) {
|
||||||
|
DataType.BYTE -> Opcode.NOTEQUAL
|
||||||
|
DataType.WORD -> Opcode.NOTEQUAL_W
|
||||||
|
DataType.FLOAT -> Opcode.NOTEQUAL_F
|
||||||
|
else -> throw CompilerException("only byte/word/lfoat possible")
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> throw FatalAstException("const evaluation for invalid operator $operator")
|
else -> throw FatalAstException("const evaluation for invalid operator $operator")
|
||||||
}
|
}
|
||||||
stackvmProg.instr(opcode)
|
stackvmProg.instr(opcode)
|
||||||
@ -698,8 +820,20 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
val opcode = when(operator) {
|
val opcode = when(operator) {
|
||||||
"+" -> Opcode.NOP
|
"+" -> Opcode.NOP
|
||||||
"-" -> Opcode.NEG // todo b/w/f
|
"-" -> Opcode.NEG // todo b/w/f
|
||||||
"~" -> Opcode.INV // todo b/w
|
"~" -> {
|
||||||
"not" -> Opcode.NOT // todo b/w (convert float to byte)
|
when(operandDt) {
|
||||||
|
DataType.BYTE -> Opcode.INV
|
||||||
|
DataType.WORD -> Opcode.INV_W
|
||||||
|
else -> throw CompilerException("only byte/word possible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"not" -> {
|
||||||
|
when(operandDt) {
|
||||||
|
DataType.BYTE -> Opcode.NOT
|
||||||
|
DataType.WORD -> Opcode.NOT_W
|
||||||
|
else -> throw CompilerException("only byte/word possible")
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> throw FatalAstException("const evaluation for invalid prefix operator $operator")
|
else -> throw FatalAstException("const evaluation for invalid prefix operator $operator")
|
||||||
}
|
}
|
||||||
stackvmProg.instr(opcode)
|
stackvmProg.instr(opcode)
|
||||||
@ -844,7 +978,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
stmt.target.arrayindexed!=null -> translate(stmt.target.arrayindexed!!, false)
|
stmt.target.arrayindexed!=null -> translate(stmt.target.arrayindexed!!, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
translateAugAssignOperator(stmt.aug_op)
|
translateAugAssignOperator(stmt.aug_op, stmt.value.resultingDatatype(namespace, heap))
|
||||||
}
|
}
|
||||||
|
|
||||||
// pop the result value back into the assignment target
|
// pop the result value back into the assignment target
|
||||||
@ -867,7 +1001,12 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translateAugAssignOperator(aug_op: String) {
|
private fun translateAugAssignOperator(aug_op: String, valueDt: DataType?) {
|
||||||
|
if(valueDt==null)
|
||||||
|
throw CompilerException("value datatype not known")
|
||||||
|
val validDt = setOf(DataType.BYTE, DataType.WORD, DataType.FLOAT)
|
||||||
|
if(valueDt !in validDt)
|
||||||
|
throw CompilerException("invalid datatype(s) for operand(s)")
|
||||||
val opcode = when(aug_op) {
|
val opcode = when(aug_op) {
|
||||||
"+=" -> Opcode.ADD
|
"+=" -> Opcode.ADD
|
||||||
"-=" -> Opcode.SUB
|
"-=" -> Opcode.SUB
|
||||||
@ -875,9 +1014,27 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||||||
"//=" -> Opcode.FLOORDIV
|
"//=" -> Opcode.FLOORDIV
|
||||||
"*=" -> Opcode.MUL
|
"*=" -> Opcode.MUL
|
||||||
"**=" -> Opcode.POW
|
"**=" -> Opcode.POW
|
||||||
"&=" -> Opcode.BITAND
|
"&=" -> {
|
||||||
"|=" -> Opcode.BITOR
|
when(valueDt) {
|
||||||
"^=" -> Opcode.BITXOR
|
DataType.BYTE -> Opcode.BITAND
|
||||||
|
DataType.WORD -> Opcode.BITAND_W
|
||||||
|
else -> throw CompilerException("only byte/word possible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"|=" -> {
|
||||||
|
when(valueDt) {
|
||||||
|
DataType.BYTE -> Opcode.BITOR
|
||||||
|
DataType.WORD -> Opcode.BITOR_W
|
||||||
|
else -> throw CompilerException("only byte/word possible")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"^=" -> {
|
||||||
|
when(valueDt) {
|
||||||
|
DataType.BYTE -> Opcode.BITXOR
|
||||||
|
DataType.WORD -> Opcode.BITXOR_W
|
||||||
|
else -> throw CompilerException("only byte/word possible")
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> throw CompilerException("invalid aug assignment operator $aug_op")
|
else -> throw CompilerException("invalid aug assignment operator $aug_op")
|
||||||
}
|
}
|
||||||
stackvmProg.instr(opcode)
|
stackvmProg.instr(opcode)
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
// Generated from /home/irmen/Projects/prog8/compiler/antlr/prog8.g4 by ANTLR 4.7
|
// Generated from /home/irmen/Projects/prog8/compiler/antlr/prog8.g4 by ANTLR 4.7
|
||||||
package prog8.parser;
|
package prog8.parser;
|
||||||
import org.antlr.v4.runtime.Lexer;
|
|
||||||
import org.antlr.v4.runtime.CharStream;
|
|
||||||
import org.antlr.v4.runtime.Token;
|
|
||||||
import org.antlr.v4.runtime.TokenStream;
|
|
||||||
import org.antlr.v4.runtime.*;
|
import org.antlr.v4.runtime.*;
|
||||||
import org.antlr.v4.runtime.atn.*;
|
import org.antlr.v4.runtime.atn.ATN;
|
||||||
|
import org.antlr.v4.runtime.atn.ATNDeserializer;
|
||||||
|
import org.antlr.v4.runtime.atn.LexerATNSimulator;
|
||||||
|
import org.antlr.v4.runtime.atn.PredictionContextCache;
|
||||||
import org.antlr.v4.runtime.dfa.DFA;
|
import org.antlr.v4.runtime.dfa.DFA;
|
||||||
import org.antlr.v4.runtime.misc.*;
|
|
||||||
|
|
||||||
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
|
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
|
||||||
public class prog8Lexer extends Lexer {
|
public class prog8Lexer extends Lexer {
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
// Generated from /home/irmen/Projects/prog8/compiler/antlr/prog8.g4 by ANTLR 4.7
|
// Generated from /home/irmen/Projects/prog8/compiler/antlr/prog8.g4 by ANTLR 4.7
|
||||||
package prog8.parser;
|
package prog8.parser;
|
||||||
import org.antlr.v4.runtime.atn.*;
|
|
||||||
import org.antlr.v4.runtime.dfa.DFA;
|
|
||||||
import org.antlr.v4.runtime.*;
|
import org.antlr.v4.runtime.*;
|
||||||
import org.antlr.v4.runtime.misc.*;
|
import org.antlr.v4.runtime.atn.ATN;
|
||||||
import org.antlr.v4.runtime.tree.*;
|
import org.antlr.v4.runtime.atn.ATNDeserializer;
|
||||||
|
import org.antlr.v4.runtime.atn.ParserATNSimulator;
|
||||||
|
import org.antlr.v4.runtime.atn.PredictionContextCache;
|
||||||
|
import org.antlr.v4.runtime.dfa.DFA;
|
||||||
|
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
|
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
|
||||||
public class prog8Parser extends Parser {
|
public class prog8Parser extends Parser {
|
||||||
|
@ -43,34 +43,50 @@ enum class Opcode {
|
|||||||
NEG, // todo b/w/f
|
NEG, // todo b/w/f
|
||||||
|
|
||||||
// bit shifts and bitwise arithmetic
|
// bit shifts and bitwise arithmetic
|
||||||
SHL, // todo b/w
|
SHL,
|
||||||
|
SHL_W,
|
||||||
SHL_MEM,
|
SHL_MEM,
|
||||||
SHL_MEM_W,
|
SHL_MEM_W,
|
||||||
SHL_VAR, // todo b/w
|
SHL_VAR,
|
||||||
SHR, // todo b/w
|
SHL_VAR_W,
|
||||||
|
SHR,
|
||||||
|
SHR_W,
|
||||||
SHR_MEM,
|
SHR_MEM,
|
||||||
SHR_MEM_W,
|
SHR_MEM_W,
|
||||||
SHR_VAR, // todo b/w
|
SHR_VAR,
|
||||||
ROL, // todo b/w
|
SHR_VAR_W,
|
||||||
|
ROL,
|
||||||
|
ROL_W,
|
||||||
ROL_MEM,
|
ROL_MEM,
|
||||||
ROL_MEM_W,
|
ROL_MEM_W,
|
||||||
ROL_VAR, // todo b/w
|
ROL_VAR,
|
||||||
ROR, // todo b/w
|
ROL_VAR_W,
|
||||||
|
ROR,
|
||||||
|
ROR_W,
|
||||||
ROR_MEM,
|
ROR_MEM,
|
||||||
ROR_MEM_W,
|
ROR_MEM_W,
|
||||||
ROR_VAR, // todo b/w
|
ROR_VAR,
|
||||||
ROL2, // todo b/w
|
ROR_VAR_W,
|
||||||
|
ROL2,
|
||||||
|
ROL2_W,
|
||||||
ROL2_MEM,
|
ROL2_MEM,
|
||||||
ROL2_MEM_W,
|
ROL2_MEM_W,
|
||||||
ROL2_VAR, // todo b/w
|
ROL2_VAR,
|
||||||
ROR2, // todo b/w
|
ROL2_VAR_W,
|
||||||
|
ROR2,
|
||||||
|
ROR2_W,
|
||||||
ROR2_MEM,
|
ROR2_MEM,
|
||||||
ROR2_MEM_W,
|
ROR2_MEM_W,
|
||||||
ROR2_VAR, // todo b/w
|
ROR2_VAR,
|
||||||
BITAND, // todo b/w
|
ROR2_VAR_W,
|
||||||
BITOR, // todo b/w
|
BITAND,
|
||||||
BITXOR, // todo b/w
|
BITAND_W,
|
||||||
INV, // todo b/w
|
BITOR,
|
||||||
|
BITOR_W,
|
||||||
|
BITXOR,
|
||||||
|
BITXOR_W,
|
||||||
|
INV,
|
||||||
|
INV_W,
|
||||||
LSB,
|
LSB,
|
||||||
MSB,
|
MSB,
|
||||||
|
|
||||||
@ -81,10 +97,14 @@ enum class Opcode {
|
|||||||
W2FLOAT, // convert word into floating point
|
W2FLOAT, // convert word into floating point
|
||||||
|
|
||||||
// logical operations
|
// logical operations
|
||||||
AND, // todo b/w (convert float to byte)
|
AND,
|
||||||
OR, // todo b/w (convert float to byte)
|
AND_W,
|
||||||
XOR, // todo b/w (convert float to byte)
|
OR,
|
||||||
NOT, // todo b/w (convert float to byte)
|
OR_W,
|
||||||
|
XOR,
|
||||||
|
XOR_W,
|
||||||
|
NOT,
|
||||||
|
NOT_W,
|
||||||
|
|
||||||
// increment, decrement
|
// increment, decrement
|
||||||
INC,
|
INC,
|
||||||
@ -101,12 +121,24 @@ enum class Opcode {
|
|||||||
DEC_VAR_F,
|
DEC_VAR_F,
|
||||||
|
|
||||||
// comparisons
|
// comparisons
|
||||||
LESS, // todo b/w/f ?
|
LESS,
|
||||||
GREATER, // todo b/w/f ?
|
LESS_W,
|
||||||
LESSEQ, // todo b/w/f ?
|
LESS_F,
|
||||||
GREATEREQ, // todo b/w/f ?
|
GREATER,
|
||||||
EQUAL, // todo b/w/f ?
|
GREATER_W,
|
||||||
NOTEQUAL, // todo b/w/f ?
|
GREATER_F,
|
||||||
|
LESSEQ,
|
||||||
|
LESSEQ_W,
|
||||||
|
LESSEQ_F,
|
||||||
|
GREATEREQ,
|
||||||
|
GREATEREQ_W,
|
||||||
|
GREATEREQ_F,
|
||||||
|
EQUAL,
|
||||||
|
EQUAL_W,
|
||||||
|
EQUAL_F,
|
||||||
|
NOTEQUAL,
|
||||||
|
NOTEQUAL_W,
|
||||||
|
NOTEQUAL_F,
|
||||||
|
|
||||||
// array access
|
// array access
|
||||||
READ_INDEXED_VAR,
|
READ_INDEXED_VAR,
|
||||||
@ -145,8 +177,9 @@ enum class Opcode {
|
|||||||
|
|
||||||
val opcodesWithVarArgument = setOf(
|
val opcodesWithVarArgument = setOf(
|
||||||
Opcode.INC_VAR, Opcode.INC_VAR_W, Opcode.DEC_VAR, Opcode.DEC_VAR_W,
|
Opcode.INC_VAR, Opcode.INC_VAR_W, Opcode.DEC_VAR, Opcode.DEC_VAR_W,
|
||||||
Opcode.SHR_VAR, Opcode.SHL_VAR, Opcode.ROL_VAR, Opcode.ROR_VAR,
|
Opcode.SHR_VAR, Opcode.SHR_VAR_W, Opcode.SHL_VAR, Opcode.SHL_VAR_W,
|
||||||
Opcode.ROL2_VAR, Opcode.ROR2_VAR,
|
Opcode.ROL_VAR, Opcode.ROL_VAR_W, Opcode.ROR_VAR, Opcode.ROR_VAR_W,
|
||||||
|
Opcode.ROL2_VAR, Opcode.ROL2_VAR_W, Opcode.ROR2_VAR, Opcode.ROR2_VAR_W,
|
||||||
Opcode.POP_VAR, Opcode.POP_VAR_W, Opcode.POP_VAR_F,
|
Opcode.POP_VAR, Opcode.POP_VAR_W, Opcode.POP_VAR_F,
|
||||||
Opcode.PUSH_VAR, Opcode.PUSH_VAR_W, Opcode.PUSH_VAR_F,
|
Opcode.PUSH_VAR, Opcode.PUSH_VAR_W, Opcode.PUSH_VAR_F,
|
||||||
Opcode.READ_INDEXED_VAR, Opcode.READ_INDEXED_VAR_W, Opcode.READ_INDEXED_VAR_F,
|
Opcode.READ_INDEXED_VAR, Opcode.READ_INDEXED_VAR_W, Opcode.READ_INDEXED_VAR_F,
|
||||||
@ -479,56 +512,116 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
}
|
}
|
||||||
Opcode.SHL -> {
|
Opcode.SHL -> {
|
||||||
val v = evalstack.pop()
|
val v = evalstack.pop()
|
||||||
// todo b/w
|
checkDt(v, DataType.BYTE)
|
||||||
|
evalstack.push(v.shl())
|
||||||
|
}
|
||||||
|
Opcode.SHL_W -> {
|
||||||
|
val v = evalstack.pop()
|
||||||
|
checkDt(v, DataType.WORD)
|
||||||
evalstack.push(v.shl())
|
evalstack.push(v.shl())
|
||||||
}
|
}
|
||||||
Opcode.SHR -> {
|
Opcode.SHR -> {
|
||||||
val v = evalstack.pop()
|
val v = evalstack.pop()
|
||||||
// todo b/w
|
checkDt(v, DataType.BYTE)
|
||||||
|
evalstack.push(v.shr())
|
||||||
|
}
|
||||||
|
Opcode.SHR_W -> {
|
||||||
|
val v = evalstack.pop()
|
||||||
|
checkDt(v, DataType.WORD)
|
||||||
evalstack.push(v.shr())
|
evalstack.push(v.shr())
|
||||||
}
|
}
|
||||||
Opcode.ROL -> {
|
Opcode.ROL -> {
|
||||||
val v = evalstack.pop()
|
val v = evalstack.pop()
|
||||||
// todo b/w
|
checkDt(v, DataType.BYTE)
|
||||||
|
val (result, newCarry) = v.rol(P_carry)
|
||||||
|
this.P_carry = newCarry
|
||||||
|
evalstack.push(result)
|
||||||
|
}
|
||||||
|
Opcode.ROL_W -> {
|
||||||
|
val v = evalstack.pop()
|
||||||
|
checkDt(v, DataType.WORD)
|
||||||
val (result, newCarry) = v.rol(P_carry)
|
val (result, newCarry) = v.rol(P_carry)
|
||||||
this.P_carry = newCarry
|
this.P_carry = newCarry
|
||||||
evalstack.push(result)
|
evalstack.push(result)
|
||||||
}
|
}
|
||||||
Opcode.ROL2 -> {
|
Opcode.ROL2 -> {
|
||||||
val v = evalstack.pop()
|
val v = evalstack.pop()
|
||||||
// todo b/w
|
checkDt(v, DataType.BYTE)
|
||||||
|
evalstack.push(v.rol2())
|
||||||
|
}
|
||||||
|
Opcode.ROL2_W -> {
|
||||||
|
val v = evalstack.pop()
|
||||||
|
checkDt(v, DataType.WORD)
|
||||||
evalstack.push(v.rol2())
|
evalstack.push(v.rol2())
|
||||||
}
|
}
|
||||||
Opcode.ROR -> {
|
Opcode.ROR -> {
|
||||||
val v = evalstack.pop()
|
val v = evalstack.pop()
|
||||||
// todo b/w
|
checkDt(v, DataType.BYTE)
|
||||||
|
val (result, newCarry) = v.ror(P_carry)
|
||||||
|
this.P_carry = newCarry
|
||||||
|
evalstack.push(result)
|
||||||
|
}
|
||||||
|
Opcode.ROR_W -> {
|
||||||
|
val v = evalstack.pop()
|
||||||
|
checkDt(v, DataType.WORD)
|
||||||
val (result, newCarry) = v.ror(P_carry)
|
val (result, newCarry) = v.ror(P_carry)
|
||||||
this.P_carry = newCarry
|
this.P_carry = newCarry
|
||||||
evalstack.push(result)
|
evalstack.push(result)
|
||||||
}
|
}
|
||||||
Opcode.ROR2 -> {
|
Opcode.ROR2 -> {
|
||||||
val v = evalstack.pop()
|
val v = evalstack.pop()
|
||||||
// todo b/w
|
checkDt(v, DataType.BYTE)
|
||||||
|
evalstack.push(v.ror2())
|
||||||
|
}
|
||||||
|
Opcode.ROR2_W -> {
|
||||||
|
val v = evalstack.pop()
|
||||||
|
checkDt(v, DataType.WORD)
|
||||||
evalstack.push(v.ror2())
|
evalstack.push(v.ror2())
|
||||||
}
|
}
|
||||||
Opcode.BITAND -> {
|
Opcode.BITAND -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
// todo b/w
|
checkDt(top, DataType.BYTE)
|
||||||
|
checkDt(second, DataType.BYTE)
|
||||||
|
evalstack.push(second.bitand(top))
|
||||||
|
}
|
||||||
|
Opcode.BITAND_W -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.WORD)
|
||||||
|
checkDt(second, DataType.WORD)
|
||||||
evalstack.push(second.bitand(top))
|
evalstack.push(second.bitand(top))
|
||||||
}
|
}
|
||||||
Opcode.BITOR -> {
|
Opcode.BITOR -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
// todo b/w
|
checkDt(top, DataType.BYTE)
|
||||||
|
checkDt(second, DataType.BYTE)
|
||||||
|
evalstack.push(second.bitor(top))
|
||||||
|
}
|
||||||
|
Opcode.BITOR_W -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.WORD)
|
||||||
|
checkDt(second, DataType.WORD)
|
||||||
evalstack.push(second.bitor(top))
|
evalstack.push(second.bitor(top))
|
||||||
}
|
}
|
||||||
Opcode.BITXOR -> {
|
Opcode.BITXOR -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
// todo b/w
|
checkDt(top, DataType.BYTE)
|
||||||
|
checkDt(second, DataType.BYTE)
|
||||||
|
evalstack.push(second.bitxor(top))
|
||||||
|
}
|
||||||
|
Opcode.BITXOR_W -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.WORD)
|
||||||
|
checkDt(second, DataType.WORD)
|
||||||
evalstack.push(second.bitxor(top))
|
evalstack.push(second.bitxor(top))
|
||||||
}
|
}
|
||||||
Opcode.INV -> {
|
Opcode.INV -> {
|
||||||
val v = evalstack.pop()
|
val v = evalstack.pop()
|
||||||
// todo b/w
|
checkDt(v, DataType.BYTE)
|
||||||
|
evalstack.push(v.inv())
|
||||||
|
}
|
||||||
|
Opcode.INV_W -> {
|
||||||
|
val v = evalstack.pop()
|
||||||
|
checkDt(v, DataType.WORD)
|
||||||
evalstack.push(v.inv())
|
evalstack.push(v.inv())
|
||||||
}
|
}
|
||||||
Opcode.INC -> {
|
Opcode.INC -> {
|
||||||
@ -705,36 +798,70 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
}
|
}
|
||||||
Opcode.SHL_VAR -> {
|
Opcode.SHL_VAR -> {
|
||||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||||
// todo b/w
|
checkDt(variable, DataType.BYTE)
|
||||||
|
variables[ins.callLabel!!] = variable.shl()
|
||||||
|
}
|
||||||
|
Opcode.SHL_VAR_W -> {
|
||||||
|
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||||
|
checkDt(variable, DataType.WORD)
|
||||||
variables[ins.callLabel!!] = variable.shl()
|
variables[ins.callLabel!!] = variable.shl()
|
||||||
}
|
}
|
||||||
Opcode.SHR_VAR -> {
|
Opcode.SHR_VAR -> {
|
||||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||||
// todo b/w
|
checkDt(variable, DataType.BYTE)
|
||||||
|
variables[ins.callLabel!!] = variable.shr()
|
||||||
|
}
|
||||||
|
Opcode.SHR_VAR_W -> {
|
||||||
|
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||||
|
checkDt(variable, DataType.WORD)
|
||||||
variables[ins.callLabel!!] = variable.shr()
|
variables[ins.callLabel!!] = variable.shr()
|
||||||
}
|
}
|
||||||
Opcode.ROL_VAR -> {
|
Opcode.ROL_VAR -> {
|
||||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||||
// todo b/w
|
checkDt(variable, DataType.BYTE)
|
||||||
|
val (newValue, newCarry) = variable.rol(P_carry)
|
||||||
|
variables[ins.callLabel!!] = newValue
|
||||||
|
P_carry = newCarry
|
||||||
|
}
|
||||||
|
Opcode.ROL_VAR_W -> {
|
||||||
|
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||||
|
checkDt(variable, DataType.WORD)
|
||||||
val (newValue, newCarry) = variable.rol(P_carry)
|
val (newValue, newCarry) = variable.rol(P_carry)
|
||||||
variables[ins.callLabel!!] = newValue
|
variables[ins.callLabel!!] = newValue
|
||||||
P_carry = newCarry
|
P_carry = newCarry
|
||||||
}
|
}
|
||||||
Opcode.ROR_VAR -> {
|
Opcode.ROR_VAR -> {
|
||||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||||
// todo b/w
|
checkDt(variable, DataType.BYTE)
|
||||||
|
val (newValue, newCarry) = variable.ror(P_carry)
|
||||||
|
variables[ins.callLabel!!] = newValue
|
||||||
|
P_carry = newCarry
|
||||||
|
}
|
||||||
|
Opcode.ROR_VAR_W -> {
|
||||||
|
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||||
|
checkDt(variable, DataType.WORD)
|
||||||
val (newValue, newCarry) = variable.ror(P_carry)
|
val (newValue, newCarry) = variable.ror(P_carry)
|
||||||
variables[ins.callLabel!!] = newValue
|
variables[ins.callLabel!!] = newValue
|
||||||
P_carry = newCarry
|
P_carry = newCarry
|
||||||
}
|
}
|
||||||
Opcode.ROL2_VAR -> {
|
Opcode.ROL2_VAR -> {
|
||||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||||
// todo b/w
|
checkDt(variable, DataType.BYTE)
|
||||||
|
variables[ins.callLabel!!] = variable.rol2()
|
||||||
|
}
|
||||||
|
Opcode.ROL2_VAR_W -> {
|
||||||
|
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||||
|
checkDt(variable, DataType.WORD)
|
||||||
variables[ins.callLabel!!] = variable.rol2()
|
variables[ins.callLabel!!] = variable.rol2()
|
||||||
}
|
}
|
||||||
Opcode.ROR2_VAR -> {
|
Opcode.ROR2_VAR -> {
|
||||||
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||||
// todo b/w
|
checkDt(variable, DataType.BYTE)
|
||||||
|
variables[ins.callLabel!!] = variable.ror2()
|
||||||
|
}
|
||||||
|
Opcode.ROR2_VAR_W -> {
|
||||||
|
val variable = variables[ins.callLabel] ?: throw VmExecutionException("unknown variable: ${ins.callLabel}")
|
||||||
|
checkDt(variable, DataType.WORD)
|
||||||
variables[ins.callLabel!!] = variable.ror2()
|
variables[ins.callLabel!!] = variable.ror2()
|
||||||
}
|
}
|
||||||
Opcode.INC_VAR -> {
|
Opcode.INC_VAR -> {
|
||||||
@ -779,52 +906,156 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
}
|
}
|
||||||
Opcode.AND -> {
|
Opcode.AND -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
// todo b/w
|
checkDt(top, DataType.BYTE)
|
||||||
|
checkDt(second, DataType.BYTE)
|
||||||
|
evalstack.push(second.and(top))
|
||||||
|
}
|
||||||
|
Opcode.AND_W -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.WORD)
|
||||||
|
checkDt(second, DataType.WORD)
|
||||||
evalstack.push(second.and(top))
|
evalstack.push(second.and(top))
|
||||||
}
|
}
|
||||||
Opcode.OR -> {
|
Opcode.OR -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
// todo b/w
|
checkDt(top, DataType.BYTE)
|
||||||
|
checkDt(second, DataType.BYTE)
|
||||||
|
evalstack.push(second.or(top))
|
||||||
|
}
|
||||||
|
Opcode.OR_W -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.WORD)
|
||||||
|
checkDt(second, DataType.WORD)
|
||||||
evalstack.push(second.or(top))
|
evalstack.push(second.or(top))
|
||||||
}
|
}
|
||||||
Opcode.XOR -> {
|
Opcode.XOR -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
// todo b/w
|
checkDt(top, DataType.BYTE)
|
||||||
|
checkDt(second, DataType.BYTE)
|
||||||
|
evalstack.push(second.xor(top))
|
||||||
|
}
|
||||||
|
Opcode.XOR_W -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.WORD)
|
||||||
|
checkDt(second, DataType.WORD)
|
||||||
evalstack.push(second.xor(top))
|
evalstack.push(second.xor(top))
|
||||||
}
|
}
|
||||||
Opcode.NOT -> {
|
Opcode.NOT -> {
|
||||||
val value = evalstack.pop()
|
val value = evalstack.pop()
|
||||||
// todo b/w
|
checkDt(value, DataType.BYTE)
|
||||||
|
evalstack.push(value.not())
|
||||||
|
}
|
||||||
|
Opcode.NOT_W -> {
|
||||||
|
val value = evalstack.pop()
|
||||||
|
checkDt(value, DataType.WORD)
|
||||||
evalstack.push(value.not())
|
evalstack.push(value.not())
|
||||||
}
|
}
|
||||||
Opcode.LESS -> {
|
Opcode.LESS -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
// todo b/w/f?
|
checkDt(top, DataType.BYTE)
|
||||||
|
checkDt(second, DataType.BYTE)
|
||||||
|
evalstack.push(Value(DataType.BYTE, if(second < top) 1 else 0))
|
||||||
|
}
|
||||||
|
Opcode.LESS_W -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.WORD)
|
||||||
|
checkDt(second, DataType.WORD)
|
||||||
|
evalstack.push(Value(DataType.BYTE, if(second < top) 1 else 0))
|
||||||
|
}
|
||||||
|
Opcode.LESS_F -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.FLOAT)
|
||||||
|
checkDt(second, DataType.FLOAT)
|
||||||
evalstack.push(Value(DataType.BYTE, if(second < top) 1 else 0))
|
evalstack.push(Value(DataType.BYTE, if(second < top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.GREATER -> {
|
Opcode.GREATER -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
// todo b/w/f?
|
checkDt(top, DataType.BYTE)
|
||||||
|
checkDt(second, DataType.BYTE)
|
||||||
|
evalstack.push(Value(DataType.BYTE, if(second > top) 1 else 0))
|
||||||
|
}
|
||||||
|
Opcode.GREATER_W -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.WORD)
|
||||||
|
checkDt(second, DataType.WORD)
|
||||||
|
evalstack.push(Value(DataType.BYTE, if(second > top) 1 else 0))
|
||||||
|
}
|
||||||
|
Opcode.GREATER_F -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.FLOAT)
|
||||||
|
checkDt(second, DataType.FLOAT)
|
||||||
evalstack.push(Value(DataType.BYTE, if(second > top) 1 else 0))
|
evalstack.push(Value(DataType.BYTE, if(second > top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.LESSEQ -> {
|
Opcode.LESSEQ -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
// todo b/w/f?
|
checkDt(top, DataType.BYTE)
|
||||||
|
checkDt(second, DataType.BYTE)
|
||||||
|
evalstack.push(Value(DataType.BYTE, if(second <= top) 1 else 0))
|
||||||
|
}
|
||||||
|
Opcode.LESSEQ_W -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.WORD)
|
||||||
|
checkDt(second, DataType.WORD)
|
||||||
|
evalstack.push(Value(DataType.BYTE, if(second <= top) 1 else 0))
|
||||||
|
}
|
||||||
|
Opcode.LESSEQ_F -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.FLOAT)
|
||||||
|
checkDt(second, DataType.FLOAT)
|
||||||
evalstack.push(Value(DataType.BYTE, if(second <= top) 1 else 0))
|
evalstack.push(Value(DataType.BYTE, if(second <= top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.GREATEREQ -> {
|
Opcode.GREATEREQ -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
// todo b/w/f?
|
checkDt(top, DataType.BYTE)
|
||||||
|
checkDt(second, DataType.BYTE)
|
||||||
|
evalstack.push(Value(DataType.BYTE, if(second >= top) 1 else 0))
|
||||||
|
}
|
||||||
|
Opcode.GREATEREQ_W -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.WORD)
|
||||||
|
checkDt(second, DataType.WORD)
|
||||||
|
evalstack.push(Value(DataType.BYTE, if(second >= top) 1 else 0))
|
||||||
|
}
|
||||||
|
Opcode.GREATEREQ_F -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.FLOAT)
|
||||||
|
checkDt(second, DataType.FLOAT)
|
||||||
evalstack.push(Value(DataType.BYTE, if(second >= top) 1 else 0))
|
evalstack.push(Value(DataType.BYTE, if(second >= top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.EQUAL -> {
|
Opcode.EQUAL -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
// todo b/w/f?
|
checkDt(top, DataType.BYTE)
|
||||||
|
checkDt(second, DataType.BYTE)
|
||||||
|
evalstack.push(Value(DataType.BYTE, if(second == top) 1 else 0))
|
||||||
|
}
|
||||||
|
Opcode.EQUAL_W -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.WORD)
|
||||||
|
checkDt(second, DataType.WORD)
|
||||||
|
evalstack.push(Value(DataType.BYTE, if(second == top) 1 else 0))
|
||||||
|
}
|
||||||
|
Opcode.EQUAL_F -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.FLOAT)
|
||||||
|
checkDt(second, DataType.FLOAT)
|
||||||
evalstack.push(Value(DataType.BYTE, if(second == top) 1 else 0))
|
evalstack.push(Value(DataType.BYTE, if(second == top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.NOTEQUAL -> {
|
Opcode.NOTEQUAL -> {
|
||||||
val (top, second) = evalstack.pop2()
|
val (top, second) = evalstack.pop2()
|
||||||
// todo b/w/f?
|
checkDt(top, DataType.BYTE)
|
||||||
|
checkDt(second, DataType.BYTE)
|
||||||
|
evalstack.push(Value(DataType.BYTE, if(second != top) 1 else 0))
|
||||||
|
}
|
||||||
|
Opcode.NOTEQUAL_W -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.WORD)
|
||||||
|
checkDt(second, DataType.WORD)
|
||||||
|
evalstack.push(Value(DataType.BYTE, if(second != top) 1 else 0))
|
||||||
|
}
|
||||||
|
Opcode.NOTEQUAL_F -> {
|
||||||
|
val (top, second) = evalstack.pop2()
|
||||||
|
checkDt(top, DataType.FLOAT)
|
||||||
|
checkDt(second, DataType.FLOAT)
|
||||||
evalstack.push(Value(DataType.BYTE, if(second != top) 1 else 0))
|
evalstack.push(Value(DataType.BYTE, if(second != top) 1 else 0))
|
||||||
}
|
}
|
||||||
Opcode.B2WORD -> {
|
Opcode.B2WORD -> {
|
||||||
|
@ -17,21 +17,27 @@ import kotlin.test.*
|
|||||||
SHL_MEM,
|
SHL_MEM,
|
||||||
SHL_MEM_W,
|
SHL_MEM_W,
|
||||||
SHL_VAR,
|
SHL_VAR,
|
||||||
|
SHL_VAR_W,
|
||||||
SHR_MEM,
|
SHR_MEM,
|
||||||
SHR_MEM_W,
|
SHR_MEM_W,
|
||||||
SHR_VAR,
|
SHR_VAR,
|
||||||
|
SHR_VAR_W,
|
||||||
ROL_MEM,
|
ROL_MEM,
|
||||||
ROL_MEM_W,
|
ROL_MEM_W,
|
||||||
ROL_VAR,
|
ROL_VAR,
|
||||||
|
ROL_VAR_W,
|
||||||
ROR_MEM,
|
ROR_MEM,
|
||||||
ROR_MEM_W,
|
ROR_MEM_W,
|
||||||
ROR_VAR,
|
ROR_VAR,
|
||||||
|
ROR_VAR_W,
|
||||||
ROL2_MEM,
|
ROL2_MEM,
|
||||||
ROL2_MEM_W,
|
ROL2_MEM_W,
|
||||||
ROL2_VAR,
|
ROL2_VAR,
|
||||||
|
ROL2_VAR_W,
|
||||||
ROR2_MEM,
|
ROR2_MEM,
|
||||||
ROR2_MEM_W,
|
ROR2_MEM_W,
|
||||||
ROR2_VAR,
|
ROR2_VAR,
|
||||||
|
ROR2_VAR_W
|
||||||
|
|
||||||
**/
|
**/
|
||||||
|
|
||||||
@ -306,19 +312,19 @@ class TestStackVmOpcodes {
|
|||||||
@Test
|
@Test
|
||||||
fun testBitand() {
|
fun testBitand() {
|
||||||
testBinaryOperator(Value(DataType.BYTE, 0b10011111), Opcode.BITAND, Value(DataType.BYTE, 0b11111101), Value(DataType.BYTE, 0b10011101))
|
testBinaryOperator(Value(DataType.BYTE, 0b10011111), Opcode.BITAND, Value(DataType.BYTE, 0b11111101), Value(DataType.BYTE, 0b10011101))
|
||||||
testBinaryOperator(Value(DataType.WORD, 0b0011001011110001), Opcode.BITAND, Value(DataType.BYTE, 0b10011101), Value(DataType.WORD, 0b0000000010010001))
|
testBinaryOperator(Value(DataType.WORD, 0b0011001011110001), Opcode.BITAND_W, Value(DataType.WORD, 0b1110000010011101), Value(DataType.WORD, 0b0010000010010001))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testBitor() {
|
fun testBitor() {
|
||||||
testBinaryOperator(Value(DataType.BYTE, 0b00011101), Opcode.BITOR, Value(DataType.BYTE, 0b10010001), Value(DataType.BYTE, 0b10011101))
|
testBinaryOperator(Value(DataType.BYTE, 0b00011101), Opcode.BITOR, Value(DataType.BYTE, 0b10010001), Value(DataType.BYTE, 0b10011101))
|
||||||
testBinaryOperator(Value(DataType.WORD, 0b0011001011100000), Opcode.BITOR, Value(DataType.BYTE, 0b10011101), Value(DataType.WORD, 0b0011001011111101))
|
testBinaryOperator(Value(DataType.WORD, 0b0011001011100000), Opcode.BITOR_W, Value(DataType.WORD, 0b1000000010011101), Value(DataType.WORD, 0b1011001011111101))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testBitxor() {
|
fun testBitxor() {
|
||||||
testBinaryOperator(Value(DataType.BYTE, 0b00011101), Opcode.BITXOR, Value(DataType.BYTE, 0b10010001), Value(DataType.BYTE, 0b10001100))
|
testBinaryOperator(Value(DataType.BYTE, 0b00011101), Opcode.BITXOR, Value(DataType.BYTE, 0b10010001), Value(DataType.BYTE, 0b10001100))
|
||||||
testBinaryOperator(Value(DataType.WORD, 0b0011001011100000), Opcode.BITXOR, Value(DataType.BYTE, 0b10001100), Value(DataType.WORD, 0b0011001001101100))
|
testBinaryOperator(Value(DataType.WORD, 0b0011001011100000), Opcode.BITXOR_W, Value(DataType.WORD, 0b1000000010001100), Value(DataType.WORD, 0b1011001001101100))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -326,14 +332,9 @@ class TestStackVmOpcodes {
|
|||||||
testBinaryOperator(Value(DataType.BYTE, 200), Opcode.AND, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1))
|
testBinaryOperator(Value(DataType.BYTE, 200), Opcode.AND, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1))
|
||||||
testBinaryOperator(Value(DataType.BYTE, 200), Opcode.AND, Value(DataType.BYTE, 0), Value(DataType.BYTE, 0))
|
testBinaryOperator(Value(DataType.BYTE, 200), Opcode.AND, Value(DataType.BYTE, 0), Value(DataType.BYTE, 0))
|
||||||
testBinaryOperator(Value(DataType.BYTE, 0), Opcode.AND, Value(DataType.BYTE, 101), Value(DataType.BYTE, 0))
|
testBinaryOperator(Value(DataType.BYTE, 0), Opcode.AND, Value(DataType.BYTE, 101), Value(DataType.BYTE, 0))
|
||||||
testBinaryOperator(Value(DataType.WORD, 200), Opcode.AND, Value(DataType.WORD, 13455), Value(DataType.BYTE, 1))
|
testBinaryOperator(Value(DataType.WORD, 200), Opcode.AND_W, Value(DataType.WORD, 13455), Value(DataType.BYTE, 1))
|
||||||
testBinaryOperator(Value(DataType.WORD, 200), Opcode.AND, Value(DataType.WORD, 0), Value(DataType.BYTE, 0))
|
testBinaryOperator(Value(DataType.WORD, 200), Opcode.AND_W, Value(DataType.WORD, 0), Value(DataType.BYTE, 0))
|
||||||
testBinaryOperator(Value(DataType.WORD, 0), Opcode.AND, Value(DataType.WORD, 101), Value(DataType.BYTE, 0))
|
testBinaryOperator(Value(DataType.WORD, 0), Opcode.AND_W, Value(DataType.WORD, 101), Value(DataType.BYTE, 0))
|
||||||
testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.AND, Value(DataType.FLOAT, 13455.55), Value(DataType.BYTE, 1))
|
|
||||||
testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.AND, Value(DataType.FLOAT, 0.0), Value(DataType.BYTE, 0))
|
|
||||||
testBinaryOperator(Value(DataType.FLOAT, 0.0), Opcode.AND, Value(DataType.FLOAT, 101.11), Value(DataType.BYTE, 0))
|
|
||||||
testBinaryOperator(Value(DataType.STR, 222), Opcode.AND, Value(DataType.STR, 333), Value(DataType.BYTE, 1))
|
|
||||||
testBinaryOperator(Value(DataType.ARRAY, 444), Opcode.AND, Value(DataType.ARRAY, 444), Value(DataType.BYTE, 1))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -341,14 +342,9 @@ class TestStackVmOpcodes {
|
|||||||
testBinaryOperator(Value(DataType.BYTE, 200), Opcode.OR, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1))
|
testBinaryOperator(Value(DataType.BYTE, 200), Opcode.OR, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1))
|
||||||
testBinaryOperator(Value(DataType.BYTE, 200), Opcode.OR, Value(DataType.BYTE, 0), Value(DataType.BYTE, 1))
|
testBinaryOperator(Value(DataType.BYTE, 200), Opcode.OR, Value(DataType.BYTE, 0), Value(DataType.BYTE, 1))
|
||||||
testBinaryOperator(Value(DataType.BYTE, 0), Opcode.OR, Value(DataType.BYTE, 0), Value(DataType.BYTE, 0))
|
testBinaryOperator(Value(DataType.BYTE, 0), Opcode.OR, Value(DataType.BYTE, 0), Value(DataType.BYTE, 0))
|
||||||
testBinaryOperator(Value(DataType.WORD, 200), Opcode.OR, Value(DataType.WORD, 13455), Value(DataType.BYTE, 1))
|
testBinaryOperator(Value(DataType.WORD, 200), Opcode.OR_W, Value(DataType.WORD, 13455), Value(DataType.BYTE, 1))
|
||||||
testBinaryOperator(Value(DataType.WORD, 200), Opcode.OR, Value(DataType.WORD, 0), Value(DataType.BYTE, 1))
|
testBinaryOperator(Value(DataType.WORD, 200), Opcode.OR_W, Value(DataType.WORD, 0), Value(DataType.BYTE, 1))
|
||||||
testBinaryOperator(Value(DataType.WORD, 0), Opcode.OR, Value(DataType.WORD, 0), Value(DataType.BYTE, 0))
|
testBinaryOperator(Value(DataType.WORD, 0), Opcode.OR_W, Value(DataType.WORD, 0), Value(DataType.BYTE, 0))
|
||||||
testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.OR, Value(DataType.FLOAT, 13455.55), Value(DataType.BYTE, 1))
|
|
||||||
testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.OR, Value(DataType.FLOAT, 0.0), Value(DataType.BYTE, 1))
|
|
||||||
testBinaryOperator(Value(DataType.FLOAT, 0.0), Opcode.OR, Value(DataType.FLOAT, 0.0), Value(DataType.BYTE, 0))
|
|
||||||
testBinaryOperator(Value(DataType.STR, 222), Opcode.OR, Value(DataType.STR, 333), Value(DataType.BYTE, 1))
|
|
||||||
testBinaryOperator(Value(DataType.ARRAY, 444), Opcode.OR, Value(DataType.ARRAY, 444), Value(DataType.BYTE, 1))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -356,24 +352,17 @@ class TestStackVmOpcodes {
|
|||||||
testBinaryOperator(Value(DataType.BYTE, 200), Opcode.XOR, Value(DataType.BYTE, 1), Value(DataType.BYTE, 0))
|
testBinaryOperator(Value(DataType.BYTE, 200), Opcode.XOR, Value(DataType.BYTE, 1), Value(DataType.BYTE, 0))
|
||||||
testBinaryOperator(Value(DataType.BYTE, 200), Opcode.XOR, Value(DataType.BYTE, 0), Value(DataType.BYTE, 1))
|
testBinaryOperator(Value(DataType.BYTE, 200), Opcode.XOR, Value(DataType.BYTE, 0), Value(DataType.BYTE, 1))
|
||||||
testBinaryOperator(Value(DataType.BYTE, 0), Opcode.XOR, Value(DataType.BYTE, 0), Value(DataType.BYTE, 0))
|
testBinaryOperator(Value(DataType.BYTE, 0), Opcode.XOR, Value(DataType.BYTE, 0), Value(DataType.BYTE, 0))
|
||||||
testBinaryOperator(Value(DataType.WORD, 200), Opcode.XOR, Value(DataType.WORD, 13455), Value(DataType.BYTE, 0))
|
testBinaryOperator(Value(DataType.WORD, 200), Opcode.XOR_W, Value(DataType.WORD, 13455), Value(DataType.BYTE, 0))
|
||||||
testBinaryOperator(Value(DataType.WORD, 200), Opcode.XOR, Value(DataType.WORD, 0), Value(DataType.BYTE, 1))
|
testBinaryOperator(Value(DataType.WORD, 200), Opcode.XOR_W, Value(DataType.WORD, 0), Value(DataType.BYTE, 1))
|
||||||
testBinaryOperator(Value(DataType.WORD, 0), Opcode.XOR, Value(DataType.WORD, 0), Value(DataType.BYTE, 0))
|
testBinaryOperator(Value(DataType.WORD, 0), Opcode.XOR_W, Value(DataType.WORD, 0), Value(DataType.BYTE, 0))
|
||||||
testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.XOR, Value(DataType.FLOAT, 13455.55), Value(DataType.BYTE, 0))
|
|
||||||
testBinaryOperator(Value(DataType.FLOAT, 200.22), Opcode.XOR, Value(DataType.FLOAT, 0.0), Value(DataType.BYTE, 1))
|
|
||||||
testBinaryOperator(Value(DataType.FLOAT, 0.0), Opcode.XOR, Value(DataType.FLOAT, 0.0), Value(DataType.BYTE, 0))
|
|
||||||
testBinaryOperator(Value(DataType.STR, 222), Opcode.XOR, Value(DataType.STR, 333), Value(DataType.BYTE, 0))
|
|
||||||
testBinaryOperator(Value(DataType.ARRAY, 444), Opcode.XOR, Value(DataType.ARRAY, 444), Value(DataType.BYTE, 0))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testNot() {
|
fun testNot() {
|
||||||
testUnaryOperator(Value(DataType.BYTE, 0), Opcode.NOT, Value(DataType.BYTE, 1))
|
testUnaryOperator(Value(DataType.BYTE, 0), Opcode.NOT, Value(DataType.BYTE, 1))
|
||||||
testUnaryOperator(Value(DataType.BYTE, 20), Opcode.NOT, Value(DataType.BYTE, 0))
|
testUnaryOperator(Value(DataType.BYTE, 20), Opcode.NOT, Value(DataType.BYTE, 0))
|
||||||
testUnaryOperator(Value(DataType.WORD, 0), Opcode.NOT, Value(DataType.BYTE, 1))
|
testUnaryOperator(Value(DataType.WORD, 0), Opcode.NOT_W, Value(DataType.BYTE, 1))
|
||||||
testUnaryOperator(Value(DataType.WORD, 5000), Opcode.NOT, Value(DataType.BYTE, 0))
|
testUnaryOperator(Value(DataType.WORD, 5000), Opcode.NOT_W, Value(DataType.BYTE, 0))
|
||||||
testUnaryOperator(Value(DataType.FLOAT, 0.0), Opcode.NOT, Value(DataType.BYTE, 1))
|
|
||||||
testUnaryOperator(Value(DataType.FLOAT, 5000.0), Opcode.NOT, Value(DataType.BYTE, 0))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -406,7 +395,7 @@ class TestStackVmOpcodes {
|
|||||||
@Test
|
@Test
|
||||||
fun testInv() {
|
fun testInv() {
|
||||||
testUnaryOperator(Value(DataType.BYTE, 123), Opcode.INV, Value(DataType.BYTE, 0x84))
|
testUnaryOperator(Value(DataType.BYTE, 123), Opcode.INV, Value(DataType.BYTE, 0x84))
|
||||||
testUnaryOperator(Value(DataType.WORD, 4044), Opcode.INV, Value(DataType.WORD, 0xf033))
|
testUnaryOperator(Value(DataType.WORD, 4044), Opcode.INV_W, Value(DataType.WORD, 0xf033))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -586,182 +575,74 @@ class TestStackVmOpcodes {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testLess() {
|
fun testLess() {
|
||||||
val values = listOf(
|
testBinaryOperator(Value(DataType.BYTE, 0), Opcode.LESS, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 0),
|
testBinaryOperator(Value(DataType.BYTE, 1), Opcode.LESS, Value(DataType.BYTE, 1), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 1), // 1
|
testBinaryOperator(Value(DataType.WORD, 2), Opcode.LESS_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 1),
|
testBinaryOperator(Value(DataType.WORD, 20), Opcode.LESS_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 1), // 0
|
testBinaryOperator(Value(DataType.WORD, 21), Opcode.LESS_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 2),
|
testBinaryOperator(Value(DataType.WORD, 21), Opcode.LESS_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.WORD, 20), // 1
|
testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.LESS_F, Value(DataType.FLOAT, 21.0), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.WORD, 20),
|
testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.LESS_F, Value(DataType.FLOAT, 21.001), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 21), // 1
|
|
||||||
Value(DataType.WORD, 21),
|
|
||||||
Value(DataType.BYTE, 21), // 0
|
|
||||||
Value(DataType.BYTE, 21),
|
|
||||||
Value(DataType.FLOAT, 21), // 0
|
|
||||||
Value(DataType.BYTE, 21),
|
|
||||||
Value(DataType.FLOAT, 21.0001) // 1
|
|
||||||
)
|
|
||||||
val expected = listOf(1, 0, 1, 1, 0, 0, 1)
|
|
||||||
testComparisonOperator(values, expected, Opcode.LESS)
|
|
||||||
|
|
||||||
val valuesInvalid = listOf(
|
|
||||||
Value(DataType.STR, 333),
|
|
||||||
Value(DataType.STR, 333)
|
|
||||||
)
|
|
||||||
assertFailsWith<VmExecutionException> {
|
|
||||||
testComparisonOperator(valuesInvalid, listOf(0), Opcode.LESS) // can't order strings
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testLessEq() {
|
fun testLessEq() {
|
||||||
val values = listOf(
|
testBinaryOperator(Value(DataType.BYTE, 0), Opcode.LESSEQ, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 0),
|
testBinaryOperator(Value(DataType.BYTE, 1), Opcode.LESSEQ, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 1), // 1
|
testBinaryOperator(Value(DataType.WORD, 2), Opcode.LESSEQ_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 1),
|
testBinaryOperator(Value(DataType.WORD, 20), Opcode.LESSEQ_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 1), // 1
|
testBinaryOperator(Value(DataType.WORD, 21), Opcode.LESSEQ_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 21),
|
testBinaryOperator(Value(DataType.WORD, 21), Opcode.LESSEQ_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.WORD, 20), // 0
|
testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.LESSEQ_F, Value(DataType.FLOAT, 21.0), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.WORD, 20),
|
testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.LESSEQ_F, Value(DataType.FLOAT, 20.999), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 21), // 1
|
|
||||||
Value(DataType.WORD, 21),
|
|
||||||
Value(DataType.BYTE, 22), // 1
|
|
||||||
Value(DataType.BYTE, 21),
|
|
||||||
Value(DataType.FLOAT, 21), // 1
|
|
||||||
Value(DataType.BYTE, 22),
|
|
||||||
Value(DataType.FLOAT, 21.999) // 0
|
|
||||||
)
|
|
||||||
val expected = listOf(1,1,0,1,1,1,0)
|
|
||||||
testComparisonOperator(values, expected, Opcode.LESSEQ)
|
|
||||||
|
|
||||||
val valuesInvalid = listOf(
|
|
||||||
Value(DataType.STR, 333),
|
|
||||||
Value(DataType.STR, 333)
|
|
||||||
)
|
|
||||||
assertFailsWith<VmExecutionException> {
|
|
||||||
testComparisonOperator(valuesInvalid, listOf(0), Opcode.LESSEQ) // can't order strings
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testGreater() {
|
fun testGreater() {
|
||||||
val values = listOf(
|
testBinaryOperator(Value(DataType.BYTE, 0), Opcode.GREATER, Value(DataType.BYTE, 1), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 0),
|
testBinaryOperator(Value(DataType.BYTE, 1), Opcode.GREATER, Value(DataType.BYTE, 1), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 1), // 0
|
testBinaryOperator(Value(DataType.WORD, 2), Opcode.GREATER_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 1),
|
testBinaryOperator(Value(DataType.WORD, 20), Opcode.GREATER_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 1), // 0
|
testBinaryOperator(Value(DataType.WORD, 21), Opcode.GREATER_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 20),
|
testBinaryOperator(Value(DataType.WORD, 21), Opcode.GREATER_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.WORD, 2), // 1
|
testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.GREATER_F, Value(DataType.FLOAT, 21.0), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.WORD, 20),
|
testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.GREATER_F, Value(DataType.FLOAT, 20.999), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 21), // 0
|
|
||||||
Value(DataType.WORD, 21),
|
|
||||||
Value(DataType.BYTE, 20), // 1
|
|
||||||
Value(DataType.BYTE, 21),
|
|
||||||
Value(DataType.FLOAT, 21), // 0
|
|
||||||
Value(DataType.BYTE, 21),
|
|
||||||
Value(DataType.FLOAT, 20.9999) // 1
|
|
||||||
)
|
|
||||||
val expected = listOf(0, 0, 1, 0, 1, 0, 1)
|
|
||||||
testComparisonOperator(values, expected, Opcode.GREATER)
|
|
||||||
|
|
||||||
val valuesInvalid = listOf(
|
|
||||||
Value(DataType.STR, 333),
|
|
||||||
Value(DataType.STR, 333)
|
|
||||||
)
|
|
||||||
assertFailsWith<VmExecutionException> {
|
|
||||||
testComparisonOperator(valuesInvalid, listOf(0), Opcode.GREATER) // can't order strings
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testGreaterEq() {
|
fun testGreaterEq() {
|
||||||
val values = listOf(
|
testBinaryOperator(Value(DataType.BYTE, 0), Opcode.GREATEREQ, Value(DataType.BYTE, 1), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 0),
|
testBinaryOperator(Value(DataType.BYTE, 1), Opcode.GREATEREQ, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 1), // 0
|
testBinaryOperator(Value(DataType.WORD, 2), Opcode.GREATEREQ_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 1),
|
testBinaryOperator(Value(DataType.WORD, 20), Opcode.GREATEREQ_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 1), // 1
|
testBinaryOperator(Value(DataType.WORD, 21), Opcode.GREATEREQ_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 21),
|
testBinaryOperator(Value(DataType.WORD, 21), Opcode.GREATEREQ_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.WORD, 20), // 1
|
testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.GREATEREQ_F, Value(DataType.FLOAT, 21.0), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.WORD, 20),
|
testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.GREATEREQ_F, Value(DataType.FLOAT, 21.001), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 21), // 0
|
|
||||||
Value(DataType.WORD, 21),
|
|
||||||
Value(DataType.BYTE, 22), // 0
|
|
||||||
Value(DataType.BYTE, 21),
|
|
||||||
Value(DataType.FLOAT, 21), // 1
|
|
||||||
Value(DataType.BYTE, 22),
|
|
||||||
Value(DataType.FLOAT, 21.999) // 1
|
|
||||||
)
|
|
||||||
val expected = listOf(0,1,1,0,0,1,1)
|
|
||||||
testComparisonOperator(values, expected, Opcode.GREATEREQ)
|
|
||||||
|
|
||||||
val valuesInvalid = listOf(
|
|
||||||
Value(DataType.STR, 333),
|
|
||||||
Value(DataType.STR, 333)
|
|
||||||
)
|
|
||||||
assertFailsWith<VmExecutionException> {
|
|
||||||
testComparisonOperator(valuesInvalid, listOf(0), Opcode.GREATEREQ) // can't order strings
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testEqual() {
|
fun testEqual() {
|
||||||
val values = listOf(
|
testBinaryOperator(Value(DataType.BYTE, 0), Opcode.EQUAL, Value(DataType.BYTE, 1), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 0),
|
testBinaryOperator(Value(DataType.BYTE, 1), Opcode.EQUAL, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 1), // 0
|
testBinaryOperator(Value(DataType.WORD, 2), Opcode.EQUAL_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 1),
|
testBinaryOperator(Value(DataType.WORD, 20), Opcode.EQUAL_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 1), // 1
|
testBinaryOperator(Value(DataType.WORD, 21), Opcode.EQUAL_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 21),
|
testBinaryOperator(Value(DataType.WORD, 21), Opcode.EQUAL_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.WORD, 20), // 0
|
testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.EQUAL_F, Value(DataType.FLOAT, 21.0), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.WORD, 20),
|
testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.EQUAL_F, Value(DataType.FLOAT, 21.001), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 21), // 0
|
|
||||||
Value(DataType.WORD, 21),
|
|
||||||
Value(DataType.BYTE, 21), // 1
|
|
||||||
Value(DataType.BYTE, 21),
|
|
||||||
Value(DataType.FLOAT, 21), // 1
|
|
||||||
Value(DataType.BYTE, 22),
|
|
||||||
Value(DataType.FLOAT, 21.999) // 0
|
|
||||||
)
|
|
||||||
val expected = listOf(0,1,0,0,1,1,0)
|
|
||||||
testComparisonOperator(values, expected, Opcode.EQUAL)
|
|
||||||
|
|
||||||
val valuesInvalid = listOf(
|
|
||||||
Value(DataType.STR, 111),
|
|
||||||
Value(DataType.STR, 222), // 0
|
|
||||||
Value(DataType.STR, 333),
|
|
||||||
Value(DataType.STR, 333) // 1
|
|
||||||
)
|
|
||||||
testComparisonOperator(valuesInvalid, listOf(0, 1), Opcode.EQUAL)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testNotEqual() {
|
fun testNotEqual() {
|
||||||
val values = listOf(
|
testBinaryOperator(Value(DataType.BYTE, 0), Opcode.NOTEQUAL, Value(DataType.BYTE, 1), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 0),
|
testBinaryOperator(Value(DataType.BYTE, 1), Opcode.NOTEQUAL, Value(DataType.BYTE, 1), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.BYTE, 1), // 1
|
testBinaryOperator(Value(DataType.WORD, 2), Opcode.NOTEQUAL_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 1),
|
testBinaryOperator(Value(DataType.WORD, 20), Opcode.NOTEQUAL_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 1), // 0
|
testBinaryOperator(Value(DataType.WORD, 21), Opcode.NOTEQUAL_W, Value(DataType.WORD, 20), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 21),
|
testBinaryOperator(Value(DataType.WORD, 21), Opcode.NOTEQUAL_W, Value(DataType.WORD, 21), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.WORD, 20), // 1
|
testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.NOTEQUAL_F, Value(DataType.FLOAT, 21.0), Value(DataType.BYTE, 0))
|
||||||
Value(DataType.WORD, 20),
|
testBinaryOperator(Value(DataType.FLOAT, 21.0), Opcode.NOTEQUAL_F, Value(DataType.FLOAT, 21.001), Value(DataType.BYTE, 1))
|
||||||
Value(DataType.BYTE, 21), // 1
|
|
||||||
Value(DataType.WORD, 21),
|
|
||||||
Value(DataType.BYTE, 21), // 0
|
|
||||||
Value(DataType.BYTE, 21),
|
|
||||||
Value(DataType.FLOAT, 21), // 0
|
|
||||||
Value(DataType.BYTE, 22),
|
|
||||||
Value(DataType.FLOAT, 21.999) // 1
|
|
||||||
)
|
|
||||||
val expected = listOf(1,0,1,1,0,0,1)
|
|
||||||
testComparisonOperator(values, expected, Opcode.NOTEQUAL)
|
|
||||||
|
|
||||||
val valuesInvalid = listOf(
|
|
||||||
Value(DataType.STR, 111),
|
|
||||||
Value(DataType.STR, 222), // 1
|
|
||||||
Value(DataType.STR, 333),
|
|
||||||
Value(DataType.STR, 333) // 0
|
|
||||||
)
|
|
||||||
testComparisonOperator(valuesInvalid, listOf(1, 0), Opcode.NOTEQUAL)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -964,11 +845,11 @@ class TestStackVmOpcodes {
|
|||||||
Instruction(Opcode.SHR), // 0
|
Instruction(Opcode.SHR), // 0
|
||||||
Instruction(Opcode.SHR), // 0
|
Instruction(Opcode.SHR), // 0
|
||||||
Instruction(Opcode.DISCARD),
|
Instruction(Opcode.DISCARD),
|
||||||
Instruction(Opcode.SHR), // 30502
|
Instruction(Opcode.SHR_W), // 30502
|
||||||
Instruction(Opcode.DISCARD_W),
|
Instruction(Opcode.DISCARD_W),
|
||||||
Instruction(Opcode.SHR), // 1
|
Instruction(Opcode.SHR_W), // 1
|
||||||
Instruction(Opcode.SHR), // 0
|
Instruction(Opcode.SHR_W), // 0
|
||||||
Instruction(Opcode.SHR), // 0
|
Instruction(Opcode.SHR_W), // 0
|
||||||
Instruction(Opcode.DISCARD_W),
|
Instruction(Opcode.DISCARD_W),
|
||||||
Instruction(Opcode.SHR) // error on float
|
Instruction(Opcode.SHR) // error on float
|
||||||
)
|
)
|
||||||
@ -1004,11 +885,11 @@ class TestStackVmOpcodes {
|
|||||||
Instruction(Opcode.DISCARD),
|
Instruction(Opcode.DISCARD),
|
||||||
Instruction(Opcode.SHL), // 6
|
Instruction(Opcode.SHL), // 6
|
||||||
Instruction(Opcode.DISCARD),
|
Instruction(Opcode.DISCARD),
|
||||||
Instruction(Opcode.SHL), // 56474
|
Instruction(Opcode.SHL_W), // 56474
|
||||||
Instruction(Opcode.DISCARD_W),
|
Instruction(Opcode.DISCARD_W),
|
||||||
Instruction(Opcode.SHL), // 6
|
Instruction(Opcode.SHL_W), // 6
|
||||||
Instruction(Opcode.DISCARD_W),
|
Instruction(Opcode.DISCARD_W),
|
||||||
Instruction(Opcode.SHL) // error on float
|
Instruction(Opcode.SHL_W) // error on float
|
||||||
)
|
)
|
||||||
vm.load(makeProg(ins), null)
|
vm.load(makeProg(ins), null)
|
||||||
vm.step(6)
|
vm.step(6)
|
||||||
@ -1061,23 +942,23 @@ class TestStackVmOpcodes {
|
|||||||
val ins2 = mutableListOf(
|
val ins2 = mutableListOf(
|
||||||
Instruction(Opcode.CLC),
|
Instruction(Opcode.CLC),
|
||||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)),
|
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)),
|
||||||
Instruction(Opcode.ROR), // 0b0100100110000110 c=1
|
Instruction(Opcode.ROR_W), // 0b0100100110000110 c=1
|
||||||
Instruction(Opcode.ROR), // 0b1010010011000011 c=0
|
Instruction(Opcode.ROR_W), // 0b1010010011000011 c=0
|
||||||
Instruction(Opcode.ROR),
|
Instruction(Opcode.ROR_W),
|
||||||
Instruction(Opcode.ROR),
|
Instruction(Opcode.ROR_W),
|
||||||
Instruction(Opcode.ROR),
|
Instruction(Opcode.ROR_W),
|
||||||
Instruction(Opcode.ROR),
|
Instruction(Opcode.ROR_W),
|
||||||
Instruction(Opcode.ROR),
|
Instruction(Opcode.ROR_W),
|
||||||
Instruction(Opcode.ROR),
|
Instruction(Opcode.ROR_W),
|
||||||
Instruction(Opcode.ROR),
|
Instruction(Opcode.ROR_W),
|
||||||
Instruction(Opcode.ROR),
|
Instruction(Opcode.ROR_W),
|
||||||
Instruction(Opcode.ROR),
|
Instruction(Opcode.ROR_W),
|
||||||
Instruction(Opcode.ROR),
|
Instruction(Opcode.ROR_W),
|
||||||
Instruction(Opcode.ROR),
|
Instruction(Opcode.ROR_W),
|
||||||
Instruction(Opcode.ROR),
|
Instruction(Opcode.ROR_W),
|
||||||
Instruction(Opcode.ROR),
|
Instruction(Opcode.ROR_W),
|
||||||
Instruction(Opcode.ROR),
|
Instruction(Opcode.ROR_W),
|
||||||
Instruction(Opcode.ROR) // 0b1001001100001101 c=0 (original value after 17 rors)
|
Instruction(Opcode.ROR_W) // 0b1001001100001101 c=0 (original value after 17 rors)
|
||||||
)
|
)
|
||||||
vm.load(makeProg(ins2), null)
|
vm.load(makeProg(ins2), null)
|
||||||
vm.step(3)
|
vm.step(3)
|
||||||
@ -1126,23 +1007,23 @@ class TestStackVmOpcodes {
|
|||||||
val ins2 = mutableListOf(
|
val ins2 = mutableListOf(
|
||||||
Instruction(Opcode.CLC),
|
Instruction(Opcode.CLC),
|
||||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)),
|
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)),
|
||||||
Instruction(Opcode.ROL), // 0b0010011000011010 c=1
|
Instruction(Opcode.ROL_W), // 0b0010011000011010 c=1
|
||||||
Instruction(Opcode.ROL), // 0b0100110000110101 c=0
|
Instruction(Opcode.ROL_W), // 0b0100110000110101 c=0
|
||||||
Instruction(Opcode.ROL),
|
Instruction(Opcode.ROL_W),
|
||||||
Instruction(Opcode.ROL),
|
Instruction(Opcode.ROL_W),
|
||||||
Instruction(Opcode.ROL),
|
Instruction(Opcode.ROL_W),
|
||||||
Instruction(Opcode.ROL),
|
Instruction(Opcode.ROL_W),
|
||||||
Instruction(Opcode.ROL),
|
Instruction(Opcode.ROL_W),
|
||||||
Instruction(Opcode.ROL),
|
Instruction(Opcode.ROL_W),
|
||||||
Instruction(Opcode.ROL),
|
Instruction(Opcode.ROL_W),
|
||||||
Instruction(Opcode.ROL),
|
Instruction(Opcode.ROL_W),
|
||||||
Instruction(Opcode.ROL),
|
Instruction(Opcode.ROL_W),
|
||||||
Instruction(Opcode.ROL),
|
Instruction(Opcode.ROL_W),
|
||||||
Instruction(Opcode.ROL),
|
Instruction(Opcode.ROL_W),
|
||||||
Instruction(Opcode.ROL),
|
Instruction(Opcode.ROL_W),
|
||||||
Instruction(Opcode.ROL),
|
Instruction(Opcode.ROL_W),
|
||||||
Instruction(Opcode.ROL),
|
Instruction(Opcode.ROL_W),
|
||||||
Instruction(Opcode.ROL) // 0b1001001100001101 c=0 (original value after 17 rors)
|
Instruction(Opcode.ROL_W) // 0b1001001100001101 c=0 (original value after 17 rors)
|
||||||
)
|
)
|
||||||
vm.load(makeProg(ins2), null)
|
vm.load(makeProg(ins2), null)
|
||||||
vm.step(3)
|
vm.step(3)
|
||||||
@ -1183,22 +1064,22 @@ class TestStackVmOpcodes {
|
|||||||
|
|
||||||
val ins2 = mutableListOf(
|
val ins2 = mutableListOf(
|
||||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)),
|
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)),
|
||||||
Instruction(Opcode.ROR2), // 0b1100100110000110
|
Instruction(Opcode.ROR2_W), // 0b1100100110000110
|
||||||
Instruction(Opcode.ROR2), // 0b0110010011000011
|
Instruction(Opcode.ROR2_W), // 0b0110010011000011
|
||||||
Instruction(Opcode.ROR2),
|
Instruction(Opcode.ROR2_W),
|
||||||
Instruction(Opcode.ROR2),
|
Instruction(Opcode.ROR2_W),
|
||||||
Instruction(Opcode.ROR2),
|
Instruction(Opcode.ROR2_W),
|
||||||
Instruction(Opcode.ROR2),
|
Instruction(Opcode.ROR2_W),
|
||||||
Instruction(Opcode.ROR2),
|
Instruction(Opcode.ROR2_W),
|
||||||
Instruction(Opcode.ROR2),
|
Instruction(Opcode.ROR2_W),
|
||||||
Instruction(Opcode.ROR2),
|
Instruction(Opcode.ROR2_W),
|
||||||
Instruction(Opcode.ROR2),
|
Instruction(Opcode.ROR2_W),
|
||||||
Instruction(Opcode.ROR2),
|
Instruction(Opcode.ROR2_W),
|
||||||
Instruction(Opcode.ROR2),
|
Instruction(Opcode.ROR2_W),
|
||||||
Instruction(Opcode.ROR2),
|
Instruction(Opcode.ROR2_W),
|
||||||
Instruction(Opcode.ROR2),
|
Instruction(Opcode.ROR2_W),
|
||||||
Instruction(Opcode.ROR2),
|
Instruction(Opcode.ROR2_W),
|
||||||
Instruction(Opcode.ROR2) // 0b1001001100001101 (original value after 16 rors)
|
Instruction(Opcode.ROR2_W) // 0b1001001100001101 (original value after 16 rors)
|
||||||
)
|
)
|
||||||
vm.load(makeProg(ins2), null)
|
vm.load(makeProg(ins2), null)
|
||||||
vm.step(2)
|
vm.step(2)
|
||||||
@ -1235,22 +1116,22 @@ class TestStackVmOpcodes {
|
|||||||
|
|
||||||
val ins2 = mutableListOf(
|
val ins2 = mutableListOf(
|
||||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)),
|
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)),
|
||||||
Instruction(Opcode.ROL2), // 0b0010011000011011
|
Instruction(Opcode.ROL2_W), // 0b0010011000011011
|
||||||
Instruction(Opcode.ROL2), // 0b0100110000110110
|
Instruction(Opcode.ROL2_W), // 0b0100110000110110
|
||||||
Instruction(Opcode.ROL2),
|
Instruction(Opcode.ROL2_W),
|
||||||
Instruction(Opcode.ROL2),
|
Instruction(Opcode.ROL2_W),
|
||||||
Instruction(Opcode.ROL2),
|
Instruction(Opcode.ROL2_W),
|
||||||
Instruction(Opcode.ROL2),
|
Instruction(Opcode.ROL2_W),
|
||||||
Instruction(Opcode.ROL2),
|
Instruction(Opcode.ROL2_W),
|
||||||
Instruction(Opcode.ROL2),
|
Instruction(Opcode.ROL2_W),
|
||||||
Instruction(Opcode.ROL2),
|
Instruction(Opcode.ROL2_W),
|
||||||
Instruction(Opcode.ROL2),
|
Instruction(Opcode.ROL2_W),
|
||||||
Instruction(Opcode.ROL2),
|
Instruction(Opcode.ROL2_W),
|
||||||
Instruction(Opcode.ROL2),
|
Instruction(Opcode.ROL2_W),
|
||||||
Instruction(Opcode.ROL2),
|
Instruction(Opcode.ROL2_W),
|
||||||
Instruction(Opcode.ROL2),
|
Instruction(Opcode.ROL2_W),
|
||||||
Instruction(Opcode.ROL2),
|
Instruction(Opcode.ROL2_W),
|
||||||
Instruction(Opcode.ROL2) // 0b1001001100001101 (original value after 16 rols)
|
Instruction(Opcode.ROL2_W) // 0b1001001100001101 (original value after 16 rols)
|
||||||
)
|
)
|
||||||
vm.load(makeProg(ins2), null)
|
vm.load(makeProg(ins2), null)
|
||||||
vm.step(2)
|
vm.step(2)
|
||||||
@ -1273,24 +1154,6 @@ class TestStackVmOpcodes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun testComparisonOperator(values: List<Value>, expected: List<Int>, operator: Opcode) {
|
|
||||||
assertEquals(values.size, expected.size*2)
|
|
||||||
val ins = mutableListOf<Instruction>()
|
|
||||||
val vars = values.iterator()
|
|
||||||
while(vars.hasNext()) {
|
|
||||||
var nextvar = vars.next()
|
|
||||||
ins.add(Instruction(pushOpcode(nextvar.type), nextvar))
|
|
||||||
nextvar = vars.next()
|
|
||||||
ins.add(Instruction(pushOpcode(nextvar.type), nextvar))
|
|
||||||
ins.add(Instruction(operator))
|
|
||||||
}
|
|
||||||
vm.load(makeProg(ins), null)
|
|
||||||
for(expectedValue in expected) {
|
|
||||||
vm.step(3)
|
|
||||||
assertEquals(Value(DataType.BYTE, expectedValue), vm.evalstack.pop())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun testBinaryOperator(left: Value, operator: Opcode, right: Value, result: Value) {
|
private fun testBinaryOperator(left: Value, operator: Opcode, right: Value, result: Value) {
|
||||||
val program=makeProg(mutableListOf(
|
val program=makeProg(mutableListOf(
|
||||||
Instruction(pushOpcode(left.type), left),
|
Instruction(pushOpcode(left.type), left),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user