Example #1
0
 def scan_token(self):
     c = self.advance()
     if c == "(":
         self.add_token(TokenType.LEFT_PAREN)
     elif c == ")":
         self.add_token(TokenType.RIGHT_PAREN)
     elif c == "{":
         self.add_token(TokenType.LEFT_BRACE)
     elif c == "}":
         self.add_token(TokenType.RIGHT_BRACE)
     elif c == ",":
         self.add_token(TokenType.COMMA)
     elif c == ".":
         self.add_token(TokenType.DOT)
     elif c == "-":
         self.add_token(TokenType.MINUS)
     elif c == "+":
         self.add_token(TokenType.PLUS)
     elif c == ";":
         self.add_token(TokenType.SEMICOLON)
     elif c == "*":
         self.add_token(TokenType.STAR)
     elif c == "!":
         self.add_token(TokenType.BANG_EQUAL if self.match("=") else TokenType.BANG)
     elif c == "=":
         self.add_token(
             TokenType.EQUAL_EQUAL if self.match("=") else TokenType.EQUAL
         )
     elif c == "<":
         self.add_token(TokenType.LESS_EQUAL if self.match("=") else TokenType.LESS)
     elif c == ">":
         self.add_token(
             TokenType.GREATER_EQUAL if self.match("=") else TokenType.GREATER
         )
     elif c == "/":
         if self.match("/"):  # a comment, consume till \n
             while not self.at_end() and self.peek() != "\n":
                 self.advance()
         else:
             self.add_token(TokenType.SLASH)
     elif c == " ":
         pass
     elif c == "\r":
         pass
     elif c == "\t":
         pass
     elif c == "\n":
         self.line += 1
     elif c == '"':
         self.string()
     elif c.isdigit():
         self.number()
     elif self.isalpha(c):
         self.identifier()
     else:
         Lox.error(self.line, f"Unexpected character '{c}'.")
Example #2
0
    def string(self):
        while not self.at_end() and self.peek() != '"':
            if self.peek() == "\n":  # multi line comments
                self.line += 1
            self.advance()

        if self.at_end():
            Lox.error(line, "Unterminated string.")
            return

        self.advance()  # final "
        literal = self.source[self.start + 1 : self.current - 1]
        self.add_token(TokenType.STRING, literal)
Example #3
0
def run_prompt(iptr: lox.Lox, parser: argparse.ArgumentParser):
    """Creates a prompt (REPL) for executing code.

    Args:
        iptr (lox.Lox): Interpreter to pass code into.
        parser (ArgumentParser): ArgumentParser of the executable, used to output
            exec-level errors (e.g. file not found).
    """
    print("pylox version alpha")
    while True:
        try:
            line = input(">>> ")
            iptr.run(line)
        except KeyboardInterrupt:
            sys.exit(0)
Example #4
0
def run_file(filename: str, iptr: lox.Lox, parser: argparse.ArgumentParser):
    """Executes code from a file.

    Args:
        filename (str): Filename of code to execute.
        iptr (Lox): Interpreter to pass code into.
        parser (ArgumentParser): ArgumentParser of the executable, used to output
            exec-level errors (e.g. file not found).
    """
    try:
        with open(filename) as source:
            iptr.run(source.read())
            if iptr.error:
                sys.exit(2)
    except FileNotFoundError:
        parser.error("File not found: {0}".format(filename))
Example #5
0
def run_test(test, verbose=True):
    with open(test, "r", encoding="utf-8") as f:
        source = f.read()

    # get expected output if exists
    expected = "\n".join([
        line.split("// expect: ")[1] for line in source.split("\n")
        if "// expect:" in line
    ])

    # use this to change acceptance conditions
    expected_type = OUTPUT

    # get token error if exists
    if not expected:
        for line in source.split("\n"):
            search = TOKEN_REGEX.search(line)
            if search:
                expected_type = TOKEN_ERROR
                expected += search.group(0).strip() + "\n"

    # get runtime error
    if not expected:
        for line in source.split("\n"):
            search = RUNTIME_REGEX.search(line)
            if search:
                expected_type = RUNTIME_ERROR
                expected += search.group(0).strip() + "\n"

    # actually run the thing
    captured_stdout = io.StringIO()
    with redirect_stdout(captured_stdout):
        Lox(test=True).run(source=source)

    # process + compare output to expected
    actual = captured_stdout.getvalue()[:-1]
    if expected_type == TOKEN_ERROR:
        actual = "\n".join([
            TOKEN_REGEX.search(line).group(0).strip()
            for line in actual.split("\n")
        ])
    if expected_type == RUNTIME_ERROR:
        actual = "\n".join(
            [actual.split("[")[0].strip() for line in actual.split("\n")])

    if actual.strip() == expected.strip():
        return 1
    else:
        print(f"{test} failed")
        if verbose:
            print(f"Expected:\n{expected}\n")
            print(f"Actual:\n{actual}\n\n")
        return 0
Example #6
0
"""Run the interpreter"""

from lox import Lox

if __name__ == "__main__":
    Lox()
Example #7
0
 def _error(self, token, msg):
     from lox import Lox
     Lox.error_token(token, msg)
     return ParseError()
Example #8
0
import argparse

from lox import Lox

parser = argparse.ArgumentParser()
parser.add_argument('path', nargs='?', default=None)
args = parser.parse_args()

lox = Lox()

if args.path is not None:
    lox.run_file(args.path)
else:
    lox.run_prompt()
Example #9
0
 def error(self, token, msg):
     Lox.parsing_error(token, msg)
     return ParseError()
Example #10
0
 def interpret(self, statements):
     try:
         for statement in statements:
             self.execute(statement)
     except RunTimeError as ex:
         Lox.runtime_error(ex)
Example #11
0
 def _Lox_error(self, message):
     from lox import Lox
     Lox.error_line(self.line, message)