def test_value_error_on_empty_input(): txt = "// this is a comment\n\n\n // Another comment //\n // " with pytest.raises(ValueError) as e_info: Parser(txt) assert str(e_info.value) == "The input must contain some code"
def test_assembler_with_max_l_file(): code = load_file("MaxL.asm") parser = Parser(code) assembler = Assembler(parser) output = assembler.assemble() expected = load_file("MaxL.hack").splitlines() assert output == expected
def test_assembler_with_add(): code = "// Compute RAM[0] = 2 + 3\n@2\nD = A\n@3\n\nD = A+ D\n@0\nM=d" parser = Parser(code) assembler = Assembler(parser) output = assembler.assemble() expected = [ "0000000000000010", "1110110000010000", "0000000000000011", "1110000010010000", "0000000000000000", "1110001100001000", ] assert output == expected
def test_parser_with_add_asm_file(): code = load_file("Add.asm") parser = Parser(code) expected_commands = ["@2", "D=A", "@3", "D=D+A", "@0", "M=D"] expected_types = [ CommandType.A_COMMAND, CommandType.C_COMMAND, CommandType.A_COMMAND, CommandType.C_COMMAND, CommandType.A_COMMAND, CommandType.C_COMMAND, ] expected_symbols = ["2", None, "3", None, "0", None] expected_dest = [None, "D", None, "D", None, "M"] expected_comp = [None, "A", None, "D+A", None, "D"] zip_obj = zip( expected_commands, expected_types, expected_symbols, expected_dest, expected_comp, ) for i, (command, tp, symbol, dest, comp) in enumerate(zip_obj): assert parser.has_more_commands() assert parser.counter == i comm = parser.current_command assert comm == command assert parser.command_type(comm) == tp if symbol is None: assert parser.dest == dest assert parser.comp == comp assert parser.jmp == "" with pytest.raises(ValueError): _ = parser.symbol else: assert parser.symbol == symbol with pytest.raises(ValueError): _ = parser.dest _ = parser.comp _ = parser.jmp parser.advance() assert parser.counter == 6 assert not parser.has_more_commands()
def assemble( filepth: Path = Argument( ..., exists=True, file_okay=True, dir_okay=True, readable=True, resolve_path=True, ), out: Path = Option(None), ): if filepth.suffix != ".asm": typer.echo("The file name must end with `.asm`") raise typer.Exit(code=1) if out is None: out = filepth.parent.joinpath(f"{filepth.stem}.hack") try: parser = Parser(filepth.read_text()) except ValueError as err: typer.echo(err) raise typer.Exit(1) assembler = Assembler(parser) try: assembly = assembler.assemble() except (InvalidCommandException, InvalidMnemonicError, AddressOutOfRange) as err: typer.echo(err) raise typer.Exit(code=1) typer.echo(f"Writing to {out}") with out.open("w") as f: f.writelines([x + "\n" for x in assembly]) typer.echo("Done")
def test_valid_l_commands(parser: Parser, command: str, symbol: str): assert parser.command_type(command) is CommandType.L_COMMAND assert parser.symbol == symbol
def generate_valid_parser(): txt = "//comment\n\n@23\nA=D\n\n(END)\nM = A + D\n// Another comment \n" parser = Parser(txt) return parser
def test_parser_process_func_with_(txt: str, expected: str): processed = Parser.process(txt) assert processed == expected
def test_parser_with_max_asm_file(): code = load_file("Max.asm") parser = Parser(code) expected_commands = [ "@R0", "D=M", "@R1", "D=D-M", "@OUTPUT_FIRST", "D;JGT", "@R1", "D=M", "@OUTPUT_D", "0;JMP", "(OUTPUT_FIRST)", "@R0", "D=M", "(OUTPUT_D)", "@R2", "M=D", "(INFINITE_LOOP)", "@INFINITE_LOOP", "0;JMP", ] expected_types = [ CommandType.A_COMMAND, CommandType.C_COMMAND, CommandType.A_COMMAND, CommandType.C_COMMAND, CommandType.A_COMMAND, CommandType.C_COMMAND, CommandType.A_COMMAND, CommandType.C_COMMAND, CommandType.A_COMMAND, CommandType.C_COMMAND, CommandType.L_COMMAND, CommandType.A_COMMAND, CommandType.C_COMMAND, CommandType.L_COMMAND, CommandType.A_COMMAND, CommandType.C_COMMAND, CommandType.L_COMMAND, CommandType.A_COMMAND, CommandType.C_COMMAND, ] expected_symbols = [ "R0", None, "R1", None, "OUTPUT_FIRST", None, "R1", None, "OUTPUT_D", None, "OUTPUT_FIRST", "R0", None, "OUTPUT_D", "R2", None, "INFINITE_LOOP", "INFINITE_LOOP", None, ] expected_dest = [ None, "D", None, "D", None, "", None, "D", None, "", None, None, "D", None, None, "M", None, None, "", ] expected_comp = [ None, "M", None, "D-M", None, "D", None, "M", None, "0", None, None, "M", None, None, "D", None, None, "0", ] expected_jmp = [ None, "", None, "", None, "JGT", None, "", None, "JMP", None, None, "", None, None, "", None, None, "JMP", ] zip_obj = zip( expected_commands, expected_types, expected_symbols, expected_dest, expected_comp, expected_jmp, ) for i, (command, tp, symbol, dest, comp, jmp) in enumerate(zip_obj): assert parser.has_more_commands() assert parser.counter == i comm = parser.current_command assert comm == command assert parser.command_type(comm) == tp if symbol is None: assert parser.dest == dest assert parser.comp == comp assert parser.jmp == jmp with pytest.raises(ValueError): _ = parser.symbol else: assert parser.symbol == symbol with pytest.raises(ValueError): _ = parser.dest _ = parser.comp _ = parser.jmp parser.advance() assert parser.counter == 19 assert not parser.has_more_commands()
def test_parser_with_max_L_asm_file(): code = load_file("MaxL.asm") parser = Parser(code) expected_commands = [ "@0", "D=M", "@1", "D=D-M", "@10", "D;JGT", "@1", "D=M", "@12", "0;JMP", "@0", "D=M", "@2", "M=D", "@14", "0;JMP", ] expected_types = [ CommandType.A_COMMAND, CommandType.C_COMMAND, CommandType.A_COMMAND, CommandType.C_COMMAND, CommandType.A_COMMAND, CommandType.C_COMMAND, CommandType.A_COMMAND, CommandType.C_COMMAND, CommandType.A_COMMAND, CommandType.C_COMMAND, CommandType.A_COMMAND, CommandType.C_COMMAND, CommandType.A_COMMAND, CommandType.C_COMMAND, CommandType.A_COMMAND, CommandType.C_COMMAND, ] expected_symbols = [ "0", None, "1", None, "10", None, "1", None, "12", None, "0", None, "2", None, "14", None, ] expected_dest = expected_dest = [ None, "D", None, "D", None, "", None, "D", None, "", None, "D", None, "M", None, "", ] expected_comp = [ None, "M", None, "D-M", None, "D", None, "M", None, "0", None, "M", None, "D", None, "0", ] expected_jmp = [ None, "", None, "", None, "JGT", None, "", None, "JMP", None, "", None, "", None, "JMP", ] zip_obj = zip( expected_commands, expected_types, expected_symbols, expected_dest, expected_comp, expected_jmp, ) for i, (command, tp, symbol, dest, comp, jmp) in enumerate(zip_obj): assert parser.has_more_commands() assert parser.counter == i comm = parser.current_command assert comm == command assert parser.command_type(comm) == tp if symbol is None: assert parser.dest == dest assert parser.comp == comp assert parser.jmp == jmp with pytest.raises(ValueError): _ = parser.symbol else: assert parser.symbol == symbol with pytest.raises(ValueError): _ = parser.dest _ = parser.comp _ = parser.jmp parser.advance() assert parser.counter == 16 assert not parser.has_more_commands()
def test_parser_with_proper_code(): code = ( "// this is a comment\n\n\n // Another comment // \n" " @value // comment\nA = A + D \n(LOOP)\n//comm\n\nD;jle\n" ) parser = Parser(code) # Raise error if we try to access anything right now for attrib in ["symbol", "dest", "comp", "jmp"]: with pytest.raises(ValueError): getattr(parser, attrib) assert parser.counter == 0 assert parser.line_idx == 0 assert parser.has_more_commands() command = parser.current_command assert parser.command_type(command) == CommandType.A_COMMAND assert parser.symbol == "value" with pytest.raises(ValueError): _ = parser.jmp _ = parser.dest _ = parser.comp parser.advance() assert parser.counter == 1 assert parser.line_idx == 1 assert parser.has_more_commands() command = parser.current_command assert parser.command_type(command) == CommandType.C_COMMAND assert parser.dest == "A" assert parser.comp == "A+D" assert parser.jmp == "" with pytest.raises(ValueError): _ = parser.symbol parser.advance() assert parser.counter == 2 assert parser.line_idx == 2 assert parser.has_more_commands() command = parser.current_command assert parser.command_type(command) == CommandType.L_COMMAND assert parser.symbol == "LOOP" with pytest.raises(ValueError): _ = parser.jmp _ = parser.dest _ = parser.comp parser.advance() assert parser.counter == 3 assert parser.line_idx == 2 assert parser.has_more_commands() command = parser.current_command assert parser.command_type(command) == CommandType.C_COMMAND assert parser.dest == "" assert parser.comp == "D" assert parser.jmp == "JLE" with pytest.raises(ValueError): _ = parser.symbol parser.advance() assert parser.counter == 4 assert parser.line_idx == 3 assert not parser.has_more_commands() with pytest.raises(ValueError): _ = parser.current_command
def test_invalid_commands(parser: Parser, command: str): with pytest.raises(InvalidCommandException): parser.command_type(command)
def test_valid_c_commands(parser: Parser): for command, dest, comp, jmp in possible_c_commands: assert parser.command_type(command) is CommandType.C_COMMAND assert parser.comp == comp assert parser.dest == dest assert parser.jmp == jmp
def test_addr_out_of_range(): parser = Parser("@24579") assembler = Assembler(parser) with pytest.raises(AddressOutOfRange): _ = assembler.assemble()