def run_prompt(prompt: str = "lox> ") -> None: while True: global gHadError gHadError = False try: line = input(prompt) except EOFError: break scanner = Scanner(line) tokens = scanner.scan_tokens() parser = Parser(tokens) syntax = parser.parse_repl() # Ignore it if there was a syntax error. if gHadError: continue if isinstance(syntax, list): gInterpreter.interpret(syntax) elif isinstance(syntax, Expr): result = gInterpreter.interpret_repl(syntax) if result is not None: print(f"= {result}")
def test_var(self): line = 'var beverage = "espresso";\nprint beverage;' scanner = Scanner(line) tokens = scanner.scan_tokens() parser = Parser(tokens, "") statements = parser.parse() Interpreter().interpret(statements)
def test_not_equal(self): scanner = Scanner('!=') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 2) self.assertEqual(tokens[0].type, TokenTypes.BANG_EQUAL)
def test_unterminated_string(self): scanner = Scanner('"this string is missing a trailing quote') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 2) self.assertIsInstance(tokens[0], ScannerError) self.assertEqual(tokens[1].type, TokenTypes.EOF)
def test_parens(self): line = "()" scanner = Scanner(line) scanner.scan_tokens() assert scanner.tokens[0].__dict__['lexeme'] == '(' assert scanner.tokens[0].__dict__['type'] == TokenType.LEFT_PAREN assert scanner.tokens[1].__dict__['lexeme'] == ')' assert scanner.tokens[1].__dict__['type'] == TokenType.RIGHT_PAREN
def test_semicolon(self): line = ';' scanner = Scanner(line) scanner.scan_tokens() assert scanner.tokens[0].__dict__['lexeme'] == ';' assert scanner.tokens[0].__dict__['type'] == TokenType.SEMICOLON assert scanner.tokens[1].__dict__['lexeme'] == '' assert scanner.tokens[1].__dict__['type'] == TokenType.EOF
def test_keywords(self): scanner = Scanner("5") tokens = scanner.scan_tokens() expected = [ (TokenType.NUMBER, "5", 5), (TokenType.EOF, "", None), ] self.assertTokens(tokens, expected)
def test_star(self): line = '*' scanner = Scanner(line) scanner.scan_tokens() assert scanner.tokens[0].__dict__['lexeme'] == '*' assert scanner.tokens[0].__dict__['type'] == TokenType.STAR assert scanner.tokens[1].__dict__['lexeme'] == '' assert scanner.tokens[1].__dict__['type'] == TokenType.EOF
def test_slash(self): line = '/' scanner = Scanner(line) scanner.scan_tokens() assert scanner.tokens[0].__dict__['lexeme'] == '/' assert scanner.tokens[0].__dict__['type'] == TokenType.SLASH assert scanner.tokens[1].__dict__['lexeme'] == '' assert scanner.tokens[1].__dict__['type'] == TokenType.EOF
def test_div_equal(self): scanner = Scanner('/=') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 3) self.assertEqual(tokens[0].type, TokenTypes.SLASH) self.assertEqual(tokens[1].type, TokenTypes.EQUAL)
def test_not_equal_greater_equal(self): scanner = Scanner('!=>=') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 3) self.assertEqual(tokens[0].type, TokenTypes.BANG_EQUAL) self.assertEqual(tokens[1].type, TokenTypes.GREATER_EQUAL)
def test_dot(self): line = "." scanner = Scanner(line) scanner.scan_tokens() print(scanner) assert scanner.tokens[0].__dict__['lexeme'] == '.' assert scanner.tokens[0].__dict__['type'] == TokenType.DOT assert scanner.tokens[1].__dict__['lexeme'] == '' assert scanner.tokens[1].__dict__['type'] == TokenType.EOF
def test_minus(self): line = "-" scanner = Scanner(line) scanner.scan_tokens() print(scanner) assert scanner.tokens[0].__dict__['lexeme'] == '-' assert scanner.tokens[0].__dict__['type'] == TokenType.MINUS assert scanner.tokens[1].__dict__['lexeme'] == '' assert scanner.tokens[1].__dict__['type'] == TokenType.EOF
def test_plus(self): line = "+" scanner = Scanner(line) scanner.scan_tokens() print(scanner) assert scanner.tokens[0].__dict__['lexeme'] == '+' assert scanner.tokens[0].__dict__['type'] == TokenType.PLUS assert scanner.tokens[1].__dict__['lexeme'] == '' assert scanner.tokens[1].__dict__['type'] == TokenType.EOF
def test_identifier_made_of_two_keywords(self): scanner = Scanner('orclass') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 2) self.assertEqual(tokens[0].type, TokenTypes.IDENTIFIER) self.assertEqual(tokens[0].lexeme, 'orclass') self.assertEqual(tokens[0].literal, None)
def test_comma(self): line = "," scanner = Scanner(line) scanner.scan_tokens() print(scanner) assert scanner.tokens[0].__dict__['lexeme'] == ',' assert scanner.tokens[0].__dict__['type'] == TokenType.COMMA assert scanner.tokens[1].__dict__['lexeme'] == '' assert scanner.tokens[1].__dict__['type'] == TokenType.EOF
def test_single_invalid_char_should_return_scanner_error(self): scanner = Scanner('@') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 2) self.assertIsInstance(tokens[0], ScannerError) self.assertEqual(tokens[0].line, 1) self.assertEqual(tokens[1].type, TokenTypes.EOF)
def test_multiple_chars_with_underscore(self): scanner = Scanner('a_b') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 2) self.assertEqual(tokens[0].type, TokenTypes.IDENTIFIER) self.assertEqual(tokens[0].lexeme, 'a_b') self.assertEqual(tokens[0].literal, None)
def test_identifier_starting_with_keyword(self): scanner = Scanner('orchid') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 2) self.assertEqual(tokens[0].type, TokenTypes.IDENTIFIER) self.assertEqual(tokens[0].lexeme, 'orchid') self.assertEqual(tokens[0].literal, None)
def test_fractional_number(self): scanner = Scanner('100.12') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 2) self.assertEqual(tokens[0].type, TokenTypes.NUMBER) self.assertEqual(tokens[0].lexeme, '100.12') self.assertEqual(tokens[0].literal, 100.12)
def test_multi_digit(self): scanner = Scanner('234') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 2) self.assertEqual(tokens[0].type, TokenTypes.NUMBER) self.assertEqual(tokens[0].lexeme, '234') self.assertEqual(tokens[0].literal, 234)
def test_braces(self): line = "{}" scanner = Scanner(line) scanner.scan_tokens() print(scanner) assert scanner.tokens[0].__dict__['lexeme'] == '{' assert scanner.tokens[0].__dict__['type'] == TokenType.LEFT_BRACE assert scanner.tokens[1].__dict__['lexeme'] == '}' assert scanner.tokens[1].__dict__['type'] == TokenType.RIGHT_BRACE
def test_two_newlines(self): scanner = Scanner('\n\n') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 3) self.assertEqual(tokens[0].type, TokenTypes.NEWLINE) self.assertEqual(tokens[0].line, 1) self.assertEqual(tokens[1].type, TokenTypes.NEWLINE) self.assertEqual(tokens[1].line, 2)
def test_multiple_single_char_tokens(self): scanner = Scanner('(-*') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 4) self.assertEqual(tokens[0].type, TokenTypes.LEFT_PAREN) self.assertEqual(tokens[1].type, TokenTypes.MINUS) self.assertEqual(tokens[2].type, TokenTypes.STAR) self.assertEqual(tokens[3].type, TokenTypes.EOF)
def test_string_with_newlines(self): scanner = Scanner('"this string is \nover two lines"') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 2) self.assertEqual(tokens[0].type, TokenTypes.STRING) self.assertEqual(tokens[0].lexeme, '"this string is \nover two lines"') self.assertEqual(tokens[0].literal, 'this string is \nover two lines') self.assertEqual(tokens[0].line, 2) self.assertEqual(tokens[1].type, TokenTypes.EOF)
def test_or_keyword(self): scanner = Scanner('or') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 2) self.assertEqual(tokens[0].type, TokenTypes.OR) self.assertEqual(tokens[0].lexeme, 'or') self.assertEqual(tokens[0].literal, None) self.assertEqual(tokens[0].line, 1) self.assertEqual(tokens[1].type, TokenTypes.EOF)
def test_single_char(self): scanner = Scanner('a') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 2) self.assertEqual(tokens[0].type, TokenTypes.IDENTIFIER) self.assertEqual(tokens[0].lexeme, 'a') self.assertEqual(tokens[0].literal, None) self.assertEqual(tokens[0].line, 1) self.assertEqual(tokens[1].type, TokenTypes.EOF)
def test_single_nonempty_string(self): scanner = Scanner('"asdf"') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 2) self.assertEqual(tokens[0].type, TokenTypes.STRING) self.assertEqual(tokens[0].lexeme, '"asdf"') self.assertEqual(tokens[0].literal, 'asdf') self.assertEqual(tokens[0].line, 1) self.assertEqual(tokens[1].type, TokenTypes.EOF)
def test_slash_slash(self): scanner = Scanner('//') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 2) self.assertEqual(tokens[0].type, TokenTypes.COMMENT) self.assertEqual(tokens[0].lexeme, '//') self.assertEqual(tokens[0].literal, '') self.assertEqual(tokens[0].line, 1) self.assertEqual(tokens[1].type, TokenTypes.EOF)
def test_single_digit(self): scanner = Scanner('2') tokens = list(scanner.scan_tokens()) self.assertEqual(len(tokens), 2) self.assertEqual(tokens[0].type, TokenTypes.NUMBER) self.assertEqual(tokens[0].lexeme, '2') self.assertEqual(tokens[0].literal, 2) self.assertEqual(tokens[0].line, 1) self.assertEqual(tokens[1].type, TokenTypes.EOF)