Exemple #1
0
 def run(self, source, errors):
     #print("source : \n{}".format(source))
     tokens = []
     statements = []
     scan_tokens(source, {
         'start': 0,
         'current': 0,
         'line': 1
     }, tokens, errors)
     if len(tokens) is 1:
         if tokens[0].type is Tk.EOF:
             LoxError.error(tokens[0], "Source file is empty.")
     parser = Parser(tokens)
     # print("Tokens:\n")
     # for t in tokens:
     #     print(t)
     #print("Lox: ready to parse")
     statements = parser.parse()
     #print("Lox: ready to resolve")
     resolver = Resolver(self.interpreter)
     resolver.resolvelist(statements)
     if LoxError.haderror:
         print("Syntax errors detected during compilation")
         return
     #print("Lox: ready to interpret")
     self.interpreter.interpret(statements)
Exemple #2
0
 def visitclass(self, var_class):
     self.declare(var_class.name)
     self.define(var_class.name)
     if var_class.superclass is not None:
         if var_class.superclass.name.lexeme is var_class.name.lexeme:
             LoxError.error(
                 var_class.name,
                 "Class cannot have the same name as super class.")
         self.resolve(var_class.superclass)
     previous_class = self.current_class
     self.current_class = ClassType.CLASS
     # add the scope for the super keyword
     if var_class.superclass is not None:
         self.current_class = ClassType.SUBCLASS
         self.beginscope()
         self.scopes[-1][Tk.lexeme_from_type[Tk.SUPER]] = True
     # Define the 'this'
     self.beginscope()
     self.scopes[-1][Tk.lexeme_from_type[Tk.THIS]] = True
     for method in var_class.methods:
         self.resolve(method)
     self.endscope()
     if var_class.superclass is not None:
         self.endscope()
     self.current_class = previous_class
Exemple #3
0
 def visitreturn(self, var_return):
     if self.current_function == FunctionType.NONE:
         LoxError.error(var_return.keyword,
                        "Cannot return from top-level code.")
     if var_return.value is not None:
         if self.current_function is FunctionType.INIT:
             LoxError.error(var_return.keyword,
                            "Cannot return value from an initializer.")
         self.resolve(var_return.value)
Exemple #4
0
 def visitsuper(self, var_super):
     if self.current_class is ClassType.NONE:
         LoxError.error(var_super.keyword,
                        "Cannot use 'super' outside of a class.")
     if self.current_class is ClassType.CLASS:
         LoxError.error(
             var_super.keyword,
             "Cannot use 'super' in a class with no superclass.")
     self.resolvelocal(var_super, var_super.keyword)
Exemple #5
0
    def visitvariable(self, variable):
        """Resolve Variable expression.

        Do not allow the variable to initialize with itself."""
        if self.scopes and variable.name.lexeme in self.scopes[-1]:
            if self.scopes[-1][variable.name.lexeme] == False:
                LoxError.error(
                    variable.name,
                    "Cannot use local variable in its own initializer.")
        self.resolvelocal(variable, variable.name)
Exemple #6
0
 def finishcall(self, callee: Expr) -> Expr:
     arguments = []
     if not self.check(Tk.RIGHT_PAREN):
         while "let's parse arguments as long as we have commas":
             arguments.append(self.expression())
             if not self.match(Tk.COMMA):
                 break
     if len(arguments) > LoxConstant.max_param:
         LoxError.error(self.peek(),
                        "function cannot have more than 8 arguments")
     call_left_paren = self.consume(
         Tk.RIGHT_PAREN, "expect a ')' at the end of a function call.")
     return Call(callee, call_left_paren, arguments)
Exemple #7
0
def string(source, positions):
    """Scan strings."""
    while not is_at_end(source, positions) and peek(source, positions) != '"':
        if peek(source, positions) == '\n':
            positions['line'] += 1
        advance(source, positions)
    if is_at_end(source, positions):
        LoxError.error(positions['line'], "String is not ended with quotes.")
        return None
    # Closing quote
    else:
        advance(source, positions)
        # return string without quotes
        return source[positions['start'] + 1:positions['current'] - 1]
Exemple #8
0
 def declare(self, name: LoxToken):
     """Declare a variable in the current scope and mark it non initialized."""
     if not self.scopes:
         return
     # we retrieve the in-work scope
     scope = self.scopes[-1]
     # If the variable is already there, send an error
     if name.lexeme in scope:
         LoxError.error(
             name,
             "A variable with this name has already been declared in the same scope."
         )
         return
     # variable is marked False as it is not initialized yet
     scope[name.lexeme] = False
Exemple #9
0
 def functionbody(self, kind: FunctionType):
     funcid = None
     functiontype = kind
     if kind is FunctionType.FUNCTION:
         funcid = self.consume(Tk.IDENTIFIER,
                               "Expect a function name after 'fun'.")
         self.consume(Tk.LEFT_PAREN, "expect a '(' after function name.")
     elif kind is FunctionType.LAMBDA:
         self.consume(Tk.LEFT_PAREN, "expect a '(' after 'fun' for lambda.")
     elif kind is FunctionType.METHOD:
         funcid = self.consume(Tk.IDENTIFIER, "Expect a method name.")
         if funcid is LoxConstant.init_method:
             functiontype = FunctionType.INIT
         self.consume(Tk.LEFT_PAREN, "expect a '(' after method name.")
     else:
         raise ParserError(self.previous(),
                           "Unexpected function type in parser.")
     parameters = []
     # All parameters should be identifiers
     if not self.check(Tk.RIGHT_PAREN):
         while "we have comma after the parameter":
             parameters.append(
                 self.consume(Tk.IDENTIFIER,
                              "expect identifiers as function parameters."))
             if len(parameters) > LoxConstant.max_param:
                 LoxError.error(
                     self.previous(), "function can take at most " +
                     LoxConstant.max_param + " parameters.")
             if not self.match(Tk.COMMA):
                 break
     self.consume(Tk.RIGHT_PAREN,
                  "expect a ) at the end of the function parameters.")
     # Parse the body of the function
     self.consume(Tk.LEFT_BRACE,
                  "expect a { after function parameters list.")
     body = self.blockstatement()
     return FunctionExp(funcid, parameters, body, functiontype)
Exemple #10
0
 def visitthis(self, this):
     if self.current_class is ClassType.NONE:
         LoxError.error(this.keyword,
                        "Cannot use 'this' outside of a class.")
     self.resolvelocal(this, this.keyword)
Exemple #11
0
 def __init__(self):
     self.interpreter = Interpreter()
     self.error = LoxError()