def test_assert_eq(): encoded = [0x480680017fff8000, 1] instruction = Instruction( off0=0, off1=-1, off2=1, imm=1, dst_register=Register.AP, op0_register=Register.FP, op1_addr=Instruction.Op1Addr.IMM, res=Instruction.Res.OP1, pc_update=Instruction.PcUpdate.REGULAR, ap_update=Instruction.ApUpdate.ADD1, fp_update=Instruction.FpUpdate.REGULAR, opcode=Instruction.Opcode.ASSERT_EQ, ) assert build_instruction( parse_instruction('[ap] = 1; ap++')) == instruction assert encode_instruction(instruction, prime=PRIME) == encoded assert decode_instruction(*encoded) == instruction # Remove "ap++". instruction = dataclasses.replace(instruction, ap_update=Instruction.ApUpdate.REGULAR) encoded = [0x400680017fff8000, 1] assert encode_instruction(instruction, prime=PRIME) == encoded assert decode_instruction(*encoded) == instruction assert is_call_instruction(*encoded) is False
def test_jmp(): encoded = [0x0129800080027fff] instruction = Instruction( off0=-1, off1=2, off2=0, imm=None, dst_register=Register.FP, op0_register=Register.AP, op1_addr=Instruction.Op1Addr.FP, res=Instruction.Res.ADD, pc_update=Instruction.PcUpdate.JUMP_REL, ap_update=Instruction.ApUpdate.REGULAR, fp_update=Instruction.FpUpdate.REGULAR, opcode=Instruction.Opcode.NOP, ) assert build_instruction( parse_instruction('jmp rel [ap + 2] + [fp]')) == instruction assert encode_instruction(instruction, prime=PRIME) == encoded assert decode_instruction(*encoded) == instruction # Change to jmp abs. instruction = dataclasses.replace(instruction, pc_update=Instruction.PcUpdate.JUMP) encoded = [0x00a9800080027fff] assert encode_instruction(instruction, prime=PRIME) == encoded assert decode_instruction(*encoded) == instruction assert is_call_instruction(encoded[0], None) is False
def test_locations(): code_with_marks = """\ [ap ] = [ fp + 2]; ap ++ ^***********************^ ^***************^ ^***^ ^^ ^*******^ ^****^ ^^ ^ """ lines = code_with_marks.splitlines() code, marks = lines[0], lines[1:] expr = parse_instruction(code) exprs = [ expr, expr.body, expr.body.a, expr.body.a.addr, expr.body.b, expr.body.b.addr, expr.body.b.addr.a, expr.body.b.addr.b, ] assert len(exprs) == len(marks) for expr, mark in zip(exprs, marks): assert get_location_marks(code, expr.location) == code + '\n' + mark
def test_addap(): encoded = [0x40780017fff7fff, 123] instruction = Instruction(off0=-1, off1=-1, off2=1, imm=123, dst_register=Register.FP, op0_register=Register.FP, op1_addr=Instruction.Op1Addr.IMM, res=Instruction.Res.OP1, pc_update=Instruction.PcUpdate.REGULAR, ap_update=Instruction.ApUpdate.ADD, fp_update=Instruction.FpUpdate.REGULAR, opcode=Instruction.Opcode.NOP) assert build_instruction(parse_instruction('ap += 123')) == instruction assert encode_instruction(instruction, prime=PRIME) == encoded assert decode_instruction(*encoded) == instruction assert is_call_instruction(*encoded) is False
def test_call(): encoded = [0x1104800180018000, 1234] instruction = Instruction( off0=0, off1=1, off2=1, imm=1234, dst_register=Register.AP, op0_register=Register.AP, op1_addr=Instruction.Op1Addr.IMM, res=Instruction.Res.OP1, pc_update=Instruction.PcUpdate.JUMP_REL, ap_update=Instruction.ApUpdate.ADD2, fp_update=Instruction.FpUpdate.AP_PLUS2, opcode=Instruction.Opcode.CALL, ) assert build_instruction(parse_instruction('call rel 1234')) == instruction assert encode_instruction(instruction, prime=PRIME) == encoded assert decode_instruction(*encoded) == instruction assert is_call_instruction(*encoded) is True
def test_ret(): encoded = [0x208b7fff7fff7ffe] instruction = Instruction( off0=-2, off1=-1, off2=-1, imm=None, dst_register=Register.FP, op0_register=Register.FP, op1_addr=Instruction.Op1Addr.FP, res=Instruction.Res.OP1, pc_update=Instruction.PcUpdate.JUMP, ap_update=Instruction.ApUpdate.REGULAR, fp_update=Instruction.FpUpdate.DST, opcode=Instruction.Opcode.RET, ) assert build_instruction(parse_instruction('ret')) == instruction assert encode_instruction(instruction, prime=PRIME) == encoded assert decode_instruction(*encoded) == instruction assert is_call_instruction(encoded[0], None) is False
def test_jnz(): encoded = [0x020a7ff07fff8003] instruction = Instruction( off0=3, off1=-1, off2=-16, imm=None, dst_register=Register.AP, op0_register=Register.FP, op1_addr=Instruction.Op1Addr.FP, res=Instruction.Res.UNCONSTRAINED, pc_update=Instruction.PcUpdate.JNZ, ap_update=Instruction.ApUpdate.REGULAR, fp_update=Instruction.FpUpdate.REGULAR, opcode=Instruction.Opcode.NOP, ) assert build_instruction( parse_instruction('jmp rel [fp - 16] if [ap + 3] != 0')) == instruction assert encode_instruction(instruction, prime=PRIME) == encoded assert decode_instruction(*encoded) == instruction assert is_call_instruction(encoded[0], None) is False
def test_instruction(): # AssertEq. expr = parse_instruction('[ap] = [fp]; ap++') assert expr == \ InstructionAst( body=AssertEqInstruction( a=ExprDeref( addr=ExprReg(reg=Register.AP)), b=ExprDeref( addr=ExprReg(reg=Register.FP))), inc_ap=True) assert expr.format() == '[ap] = [fp]; ap++' assert parse_instruction( '[ap+5] = [fp]+[ap] - 5').format() == '[ap + 5] = [fp] + [ap] - 5' assert parse_instruction('[ap+5]+3= [fp]*7;ap ++ ').format() == \ '[ap + 5] + 3 = [fp] * 7; ap++' # Jump. expr = parse_instruction('jmp rel [ap] + x; ap++') assert expr == \ InstructionAst( body=JumpInstruction( val=ExprOperator( a=ExprDeref(addr=ExprReg(reg=Register.AP)), op='+', b=ExprIdentifier(name='x')), relative=True), inc_ap=True) assert expr.format() == 'jmp rel [ap] + x; ap++' assert parse_instruction(' jmp abs[ap]+x').format() == 'jmp abs [ap] + x' # Make sure the following are not OK. with pytest.raises(ParserError): parse_instruction('jmp abs') with pytest.raises(ParserError): parse_instruction('jmpabs[ap]') # JumpToLabel. expr = parse_instruction('jmp label') assert expr == \ InstructionAst( body=JumpToLabelInstruction( label=ExprIdentifier(name='label'), condition=None), inc_ap=False) assert expr.format() == 'jmp label' # Make sure the following are not OK. with pytest.raises(ParserError): parse_instruction('jmp [fp]') with pytest.raises(ParserError): parse_instruction('jmp 7') # Jnz. expr = parse_instruction('jmp rel [ap] + x if [fp + 3] != 0') assert expr == \ InstructionAst( body=JnzInstruction( jump_offset=ExprOperator( a=ExprDeref(addr=ExprReg(reg=Register.AP)), op='+', b=ExprIdentifier(name='x')), condition=ExprDeref( addr=ExprOperator( a=ExprReg(reg=Register.FP), op='+', b=ExprConst(val=3)))), inc_ap=False) assert expr.format() == 'jmp rel [ap] + x if [fp + 3] != 0' assert parse_instruction(' jmp rel 17 if[fp]!=0;ap++').format() == \ 'jmp rel 17 if [fp] != 0; ap++' # Make sure the following are not OK. with pytest.raises(ParserError): parse_instruction('jmprel 17 if x != 0') with pytest.raises(ParserError): parse_instruction('jmp 17 if x') with pytest.raises(ParserError, match='!= 0'): parse_instruction('jmp rel 17 if x != 2') with pytest.raises(ParserError): parse_instruction('jmp rel [fp] ifx != 0') # Jnz to label. expr = parse_instruction('jmp label if [fp] != 0') assert expr == \ InstructionAst( body=JumpToLabelInstruction( label=ExprIdentifier('label'), condition=ExprDeref(addr=ExprReg(reg=Register.FP))), inc_ap=False) assert expr.format() == 'jmp label if [fp] != 0' # Make sure the following are not OK. with pytest.raises(ParserError): parse_instruction('jmp [fp] if [fp] != 0') with pytest.raises(ParserError): parse_instruction('jmp 7 if [fp] != 0') # Call abs. expr = parse_instruction('call abs [fp] + x') assert expr == \ InstructionAst( body=CallInstruction( val=ExprOperator( a=ExprDeref(addr=ExprReg(reg=Register.FP)), op='+', b=ExprIdentifier(name='x')), relative=False), inc_ap=False) assert expr.format() == 'call abs [fp] + x' assert parse_instruction( 'call abs 17;ap++').format() == 'call abs 17; ap++' # Make sure the following are not OK. with pytest.raises(ParserError): parse_instruction('call abs') with pytest.raises(ParserError): parse_instruction('callabs 7') # Call rel. expr = parse_instruction('call rel [ap] + x') assert expr == \ InstructionAst( body=CallInstruction( val=ExprOperator( a=ExprDeref(addr=ExprReg(reg=Register.AP)), op='+', b=ExprIdentifier(name='x')), relative=True), inc_ap=False) assert expr.format() == 'call rel [ap] + x' assert parse_instruction( 'call rel 17;ap++').format() == 'call rel 17; ap++' # Make sure the following are not OK. with pytest.raises(ParserError): parse_instruction('call rel') with pytest.raises(ParserError): parse_instruction('callrel 7') # Call label. expr = parse_instruction('call label') assert expr == \ InstructionAst( body=CallLabelInstruction( label=ExprIdentifier(name='label')), inc_ap=False) assert expr.format() == 'call label' assert parse_instruction( 'call label ;ap++').format() == 'call label; ap++' # Make sure the following are not OK. with pytest.raises(ParserError): parse_instruction('call [fp]') with pytest.raises(ParserError): parse_instruction('call 7') # Ret. expr = parse_instruction('ret') assert expr == \ InstructionAst( body=RetInstruction(), inc_ap=False) assert expr.format() == 'ret' # AddAp. expr = parse_instruction('ap += [fp] + 2') assert expr == \ InstructionAst( body=AddApInstruction( expr=ExprOperator( a=ExprDeref( addr=ExprReg(reg=Register.FP)), op='+', b=ExprConst(val=2))), inc_ap=False) assert expr.format() == 'ap += [fp] + 2' assert parse_instruction('ap +=[ fp]+ 2').format() == 'ap += [fp] + 2' assert parse_instruction( 'ap +=[ fp]+ 2;ap ++').format() == 'ap += [fp] + 2; ap++'
def parse_and_build(inst: str) -> Instruction: """ Parses the given instruction and builds the Instruction instance. """ return build_instruction(parse_instruction(inst))