def atom(self): res = ParseResult() tok = self.current_token if tok.type in (TT_INT, TT_FLOAT): res.register(self.advance()) return res.success(NumberNode(tok)) elif tok.type == TT_LPAREN: res.register(self.advance()) expr = res.register(self.expr()) if res.error: return res if self.current_token.type == TT_RPAREN: res.register(self.advance()) return res.success(expr) else: return res.failure(InvalidSyntaxError( self.current_token.pos_start, self.current_token.pos_end, "Expected ')'" )) return res.failure(InvalidSyntaxError( tok.pos_start, tok.pos_end, "Expected INT, FLOAT, '+', '-' or '('" ))
def atom(self): res = ParseResult() token = self.current_token if token._type in [TokenTypes.TT_INT, TokenTypes.TT_FLOAT]: res.register_advancement() self.advance() return res.success(NumberNode(token)) elif token.get_type() == TokenTypes.TT_IDENTIFIER: res.register_advancement() self.advance() return res.success(VariableAccessNode(token)) elif token._type == TokenTypes.TT_LPAREN: res.register_advancement() self.advance() expr = res.register(self.expression()) if res._error: return res if self.current_token._type == TokenTypes.TT_RPAREN: res.register_advancement() self.advance() return res.success(expr) else: return res.failed( InvalidSyntaxError(self.current_token._start_pos, self.current_token._end_pos, "Expected ')'")) return res.failed( InvalidSyntaxError( self.current_token._start_pos, self.current_token._end_pos, "Expected INT, FLOAT, IDENTIFIER, '+', '-', '*' or '('"))
def if_expr_cases(self, case_keyword): res = ParseResult() cases = [] else_case = None if not self.current_tok.matches(Constants.TOK_KEYWORD, case_keyword): return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, f"Expected '{case_keyword}'" )) res.register_advancement() self.advance() condition = res.register(self.expr()) if res.error: return res if not self.current_tok.matches(Constants.TOK_KEYWORD, 'then'): return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, f"Expected 'then'" )) res.register_advancement() self.advance() if self.current_tok.type == Constants.TOK_NEWLINE: res.register_advancement() self.advance() statements = res.register(self.statements()) if res.error: return res cases.append((condition, statements, True)) if self.current_tok.matches(Constants.TOK_KEYWORD, 'end'): res.register_advancement() self.advance() else: all_cases = res.register(self.if_expr_b_or_c()) if res.error: return res new_cases, else_case = all_cases cases.extend(new_cases) else: expr = res.register(self.statement()) if res.error: return res cases.append((condition, expr, False)) all_cases = res.register(self.if_expr_b_or_c()) if res.error: return res new_cases, else_case = all_cases cases.extend(new_cases) return res.success((cases, else_case))
def factor(self): position_start = self.current_tok.position_start tok = self.current_tok if tok.type == LPAREN: self.advance() result = self.parse_math_expression() if self.current_tok.type != RPAREN: self.errors.register_error( InvalidSyntaxError( "Expected ')'", self.current_tok.position_start, self.current_tok.position_end, )) return None self.advance() return result elif tok.type == INT or tok.type == FLOAT: self.advance() return NumberNode(tok, position_start, self.current_tok.position_end) elif tok.type == STRING: self.advance() return StringNode(tok, position_start, self.current_tok.position_end) elif tok.type == IDENTIFIER: self.advance() return IdentifierNode(tok, position_start, self.current_tok.position_end) elif tok.type in (PLUS, MINUS) or tok.matches(KEYWORD, "nu"): op_tok = self.current_tok self.advance() right = self.factor() return UnaryOperationNode(op_tok, right, position_start, self.current_tok.position_end) elif tok.type == LSQUAREBRACKET: self.advance() result = self.parse_math_expression() if self.current_tok.type != RPAREN: self.errors.register_error( InvalidSyntaxError( "Expected ']'", self.current_tok.position_start, self.current_tok.position_end, )) return None self.advance() return IntCastNode(result) self.errors.register_error( InvalidSyntaxError( "Expected INT, IDENTIFIER, '+', '-', '(', '[', 'if'", self.current_tok.position_start, self.current_tok.position_end, ))
def while_expr(self): res = ParseResult() if not self.current_tok.matches(Constants.TOK_KEYWORD, 'while'): return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected \'while\'' )) res.register_advancement() self.advance() condition = res.register(self.expr()) if res.error: return res if not self.current_tok.matches(Constants.TOK_KEYWORD, 'then'): return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected \'then\'' )) res.register_advancement() self.advance() if self.current_tok.type == Constants.TOK_NEWLINE: res.register_advancement() self.advance() body = res.register(self.statements()) if res.error: return res if not self.current_tok.matches(Constants.TOK_KEYWORD, 'END'): return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, f"Expected 'end'" )) res.register_advancement() self.advance() return res.success(WhileNode(condition, body, True)) body = res.register(self.statement()) if res.error: return res return res.success(WhileNode(condition, body, False))
def if_expr_c(self): res = ParseResult() else_case = None if self.current_tok.matches(Constants.TOK_KEYWORD, 'else'): res.register_advancement() self.advance() if self.current_tok.type == Constants.TOK_NEWLINE: res.register_advancement() self.advance() statements = res.register(self.statements()) if res.error: return res else_case = (statements, True) if self.current_tok.matches(Constants.TOK_KEYWORD, 'end'): res.register_advancement() self.advance() else: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, "Expected 'end'" )) else: expr = res.register(self.statement()) if res.error: return res else_case = (expr, False) return res.success(else_case)
def comp_expr(self): res = ParseResult() if self.current_tok.matches(Constants.TOK_KEYWORD, 'not'): operator = self.current_tok res.register_advancement() self.advance() node = res.register(self.comp_expr()) if res.error: return res return res.success(UnaryOperatorNode(operator, node)) node = res.register(self.binary_operation( self.arith_expr, (Constants.TOK_EE, Constants.TOK_NE, Constants.TOK_LT, Constants.TOK_GT, Constants.TOK_LTE, Constants.TOK_GTE))) if res.error: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected int, float, identifier, operators' )) return res.success(node)
def statement(self): res = ParseResult() pos_start = self.current_tok.pos_start.copy() if self.current_tok.matches(Constants.TOK_KEYWORD, 'return'): res.register_advancement() self.advance() expr = res.try_register(self.expr()) if not expr: self.reverse(res.to_reverse_count) return res.success(ReturnNode(expr, pos_start, self.current_tok.pos_start.copy())) if self.current_tok.matches(Constants.TOK_KEYWORD, 'continue'): res.register_advancement() self.advance() return res.success(ContinueNode(pos_start, self.current_tok.pos_start.copy())) if self.current_tok.matches(Constants.TOK_KEYWORD, 'break'): res.register_advancement() self.advance() return res.success(BreakNode(pos_start, self.current_tok.pos_start.copy())) expr = res.register(self.expr()) if res.error: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, "Expected 'return', 'continue', 'break', 'var', identifier, '+', '-', '(', '[' or 'not'" )) return res.success(expr)
def parse_block_statement(self, end_token_types, end_token_values): position_start = self.current_tok.position_start self.advance() block = Block() while not self.current_tok.matches(end_token_types[0], end_token_values[0]): if len(end_token_types) == 2: if self.current_tok.matches(end_token_types[1], end_token_values[1]): break while self.current_tok.type == NEWLINE: self.advance() if self.current_tok.type == EOF: self.errors.register_error( InvalidSyntaxError( "Unexpected end of file", position_start, self.current_tok.position_end, )) return None stmt = self.parse_statement() if stmt: block.statements.append(stmt) while self.current_tok.type == NEWLINE: self.advance() return block
def list_expr(self): res = ParseResult() element_nodes = [] pos_start = self.current_tok.pos_start.copy() if self.current_tok.type != Constants.TOK_LSQUARE: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, f"Expected '['" )) res.register_advancement() self.advance() if self.current_tok.type == Constants.TOK_RSQUARE: res.register_advancement() self.advance() else: element_nodes.append(res.register(self.expr())) if res.error: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, "Expected ']', 'VAR', 'IF', 'FOR', 'WHILE', 'FUN', int, float, identifier, '+', '-', '(', '[' or 'NOT'" )) while self.current_tok.type == Constants.TOK_COMMA: res.register_advancement() self.advance() element_nodes.append(res.register(self.expr())) if res.error: return res if self.current_tok.type != Constants.TOK_RSQUARE: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, f"Expected ',' or ']'" )) res.register_advancement() self.advance() return res.success(ListNode( element_nodes, pos_start, self.current_tok.pos_end.copy() ))
def parse_declaration_statement(self): position_start = self.current_tok.position_start self.advance() if not self.current_tok.type == COLON: self.errors.register_error( InvalidSyntaxError("Expected ':'", self.current_tok.position_start, self.current_tok.position_end)) return self.advance() elements = [] types = [] element = self.current_tok elements.append(element) self.advance() if self.is_type(): types.append(self.current_tok.value) self.advance() while self.current_tok.type == COMMA: self.advance() element = self.current_tok self.advance() elements.append(element) if self.is_type(): types.append(self.current_tok.value) self.advance() if len(types) == 1: t = types[0] for _ in range(len(elements) - 1): types.append(t) if len(types) != len(elements): self.errors.register_error( InvalidSyntaxError( "The length of elements mismatch the length of types.", position_start, self.current_tok.position_end)) return None return DeclarationNode(elements, types, position_start, self.current_tok.position_end)
def parse(self): res = self.expr() if not res.error and self.current_token.type != TT_EOF: return res.failure(InvalidSyntaxError( self.current_token.pos_start, self.current_token.pos_end, "Expected '+', '-', '*' or '/'" )) return res
def parse(self): res = self.expression() if not res._error and self.current_token._type != TokenTypes.TT_EOF: return res.failed( InvalidSyntaxError(self.current_token._start_pos, self.current_token._end_pos, "Expected '+', '-', '*' or '/'")) return res
def parse(self): res = self.statements() if not res.error and self.current_tok.type!=Constants.TOK_EOF: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected +, -, * or /' )) return res
def expr(self): res = ParseResult() ### New variable declaration if self.current_tok.matches(Constants.TOK_KEYWORD, 'var'): res.register_advancement() self.advance() if self.current_tok.type != Constants.TOK_IDENTIFIER: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected Identifier' )) var_name = self.current_tok res.register_advancement() self.advance() if self.current_tok.type != Constants.TOK_EQUALS: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected \'=\'' )) res.register_advancement() self.advance() expr = res.register(self.expr()) if res.error: return res return res.success(VarAssignNode(var_name, expr)) node = res.register(self.binary_operation(self.comp_expr, ((Constants.TOK_KEYWORD, 'and'), (Constants.TOK_KEYWORD, 'or')))) if res.error: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected \'var\', int, float, identifier or operator or keywords' )) return res.success(node)
def parse_math_expression(self): if self.current_tok.type in (INT, FLOAT, STRING, IDENTIFIER, PLUS, MINUS, LPAREN, LSQUAREBRACKET, KEYWORD): return self.parse_and_or_expression() else: self.errors.register_error( InvalidSyntaxError( "Expected INT, IDENTIFIER, '+', '-', '(', '['", self.current_tok.position_start, self.current_tok.position_end, )) return None
def expression(self): res = ParseResult() if self.current_token.matches(TokenTypes.TT_KEYWORD, "VAR"): res.register_advancement() self.advance() if self.current_token.get_type() != TokenTypes.TT_IDENTIFIER: res.failed( InvalidSyntaxError(self.current_token.get_start_pos(), self.current_token.get_end_pos(), "Expected identifier")) var_name = self.current_token res.register_advancement() self.advance() if self.current_token.get_type() != TokenTypes.TT_EQ: res.failed( InvalidSyntaxError(self.current_token.get_start_pos(), self.current_token.get_end_pos(), "Expected '='")) res.register_advancement() self.advance() expr = res.register(self.expression()) if res._error: return res return res.success(VariableAssignNode(var_name, expr)) node = res.register( self.binary_operation(self.term, [TokenTypes.TT_PLUS, TokenTypes.TT_MINUS])) if res._error: return res.failed( InvalidSyntaxError( self.current_token._start_pos, self.current_token._end_pos, "Expected VAR, int, float, identifier, '+', '-', '*' or '('" )) return res.success(node)
def call(self): res = ParseResult() atom = res.register(self.atom()) if res.error: return res if self.current_tok.type == Constants.TOK_LPAREN: res.register_advancement() self.advance() arg_nodes = [] if self.current_tok.type == Constants.TOK_RPAREN: res.register_advancement() self.advance() else: arg_nodes.append(res.register(self.expr())) if res.error: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, "Expected ')', 'VAR', 'IF', 'FOR', 'WHILE', 'FUN', int, float, identifier, '+', '-', '(' or 'NOT'" )) while self.current_tok.type == Constants.TOK_COMMA: res.register_advancement() self.advance() arg_nodes.append(res.register(self.expr())) if res.error: return res if self.current_tok.type != Constants.TOK_RPAREN: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, f"Expected ',' or ')'" )) res.register_advancement() self.advance() return res.success(CallNode(atom, arg_nodes)) return res.success(atom)
def parse_assign_expression(self): position_start = self.current_tok.position_start left = self.parse_math_expression() if self.current_tok.type == BACKWORD_ARROW: if not isinstance(left, IdentifierNode): self.errors.register_error( InvalidSyntaxError( f"You can't assign a value to {left}", self.current_tok.position_start, self.current_tok.position_end, )) return None self.advance() if self.current_tok.type == LPAREN: self.advance() type_ = self.current_tok.value self.advance() if self.current_tok.type != RPAREN: self.errors.register_error( InvalidSyntaxError( f"Expected ')'", self.current_tok.position_start, self.current_tok.position_end, )) return None self.advance() else: type_ = None right = self.parse_math_expression() return AssignNode(type_, left, right, position_start, self.current_tok.position_end) return left
def term(self): position_start = self.current_tok.position_start left = self.factor() while self.current_tok is not None and self.current_tok.type in (MUL, DIV): if not self.current_tok.type in (MUL, DIV): self.errors.register_error( InvalidSyntaxError( "Expected '*' or '/'", self.current_tok.position_start, self.current_tok.position_end, )) return None operation_tok = self.current_tok self.advance() right = self.factor() left = BinaryOperationNode(left, operation_tok, right, position_start, self.current_tok.position_end) return left
def expression(self): position_start = self.current_tok.position_start left = self.term() while self.current_tok is not None and self.current_tok.type in ( PLUS, MINUS): if not self.current_tok.type in (PLUS, MINUS): self.errors.register_error( InvalidSyntaxError( "Expected '+' or '-'", self.current_tok.position_start, self.current_tok.position_end, )) return None operation_tok = self.current_tok self.advance() right = self.term() left = BinaryOperationNode(left, operation_tok, right, position_start, self.current_tok.position_end) return left
def parse_statement(self): if self.current_tok.matches(KEYWORD, "scrie"): return self.parse_write_statement() elif self.current_tok.matches(KEYWORD, "citeste"): return self.parse_read_statement() elif self.current_tok.matches(KEYWORD, "Di"): return self.parse_declaration_statement() elif self.current_tok.matches(KEYWORD, "Do"): return self.parse_declaration_statement() elif self.current_tok.matches(KEYWORD, "daca"): return self.parse_if_statement() elif self.current_tok.type in (INT, FLOAT, STRING, IDENTIFIER, PLUS, MINUS, LPAREN, LSQUAREBRACKET, KEYWORD): stmt = self.parse_expression_statement() return stmt else: self.errors.register_error( InvalidSyntaxError( "Expected INT, IDENTIFIER, '+', '-', '(', '['", self.current_tok.position_start, self.current_tok.position_end, )) self.advance() return None
def func_def(self): res = ParseResult() if not self.current_tok.matches(Constants.TOK_KEYWORD, 'func'): return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected keyword \'func\'' )) res.register_advancement() self.advance() if self.current_tok.type == Constants.TOK_IDENTIFIER: var_name_tok = self.current_tok res.register_advancement() self.advance() if self.current_tok.type != Constants.TOK_LPAREN: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected parantheses \'(\'' )) else: var_name_tok = None if self.current_tok.type != Constants.TOK_LPAREN: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected parantheses \'(\'' )) res.register_advancement() self.advance() arg_name_toks = [] if self.current_tok.type == Constants.TOK_IDENTIFIER: arg_name_toks.append(self.current_tok) res.register_advancement() self.advance() while self.current_tok.type == Constants.TOK_COMMA: res.register_advancement() self.advance() if self.current_tok.type != Constants.TOK_IDENTIFIER: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected Identifier' )) arg_name_toks.append(self.current_tok) res.register_advancement() self.advance() if self.current_tok.type != Constants.TOK_RPAREN: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected \',\' or \')\'' )) else: if self.current_tok.type != Constants.TOK_RPAREN: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected identifier or \')\'' )) res.register_advancement() self.advance() if self.current_tok.type == Constants.TOK_ARROW: res.register_advancement() self.advance() body = res.register(self.expr()) if res.error: return res return res.success(FuncDefNode(var_name_tok, arg_name_toks, body, True)) if self.current_tok.type != Constants.TOK_NEWLINE: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, f"Expected '->' or NEWLINE" )) res.register_advancement() self.advance() body = res.register(self.statements()) if res.error: return res if not self.current_tok.matches(Constants.TOK_KEYWORD, 'end'): return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, f"Expected 'end'" )) res.register_advancement() self.advance() return res.success(FuncDefNode( var_name_tok, arg_name_toks, body, False ))
def _process_tokens(self, tokens): try: backup_stack = self._stacks.copy() backup_vars = self._variables.copy() valid, tokens = RpnTokens.check_syntax(tokens) if valid: for token in tokens: if RpnTokens.contains_space(token): continue if RpnTokens.is_number(token): num = RpnTokens.get_number(token, self._print.precision) if num is not None: if self._print.mode == 'dec': self._stacks.append(num) else: if isinstance(num, float): raise UnsupportedDecimalError(token) else: self._stacks.append(num) elif RpnTokens.is_keyword(token): if token[1] == RpnTokens.HEX[0]: self._print.change_mode('hex', self._stacks, self._variables) elif token[1] == RpnTokens.DEC[0]: self._print.change_mode('dec', self._stacks, self._variables) elif token[1] == RpnTokens.OCT[0]: self._print.change_mode('oct', self._stacks, self._variables) elif token[1] == RpnTokens.BIN[0]: self._print.change_mode('bin', self._stacks, self._variables) elif token[1] == RpnTokens.HELP[0]: self._print.help() elif token[1] == RpnTokens.EXIT[0]: self._print.bye() return 1 # Limit showing the number of digits after . elif token[1] == RpnTokens.PREC[0]: if len(self._stacks) < 1: raise StackUnderflowError(token) p = self._stacks.pop() if not isinstance(p, int): raise IntegerOperationError(token) if p <= 0 or p > 100: raise DomainError(token, 1, 100) self._print.precision = p # Limit showing the number of items in stack elif token[1] == RpnTokens.LIMIT[0]: if len(self._stacks) < 1: raise StackUnderflowError(token) p = self._stacks.pop() if not isinstance(p, int): raise IntegerOperationError(token) if p <= 0 or p > 100: raise DomainError(token, 1, 100) self._print.precision = p elif token[1] == RpnTokens.STACK[0]: self._print.toggle_display() elif token[1] == RpnTokens.THEME[0]: self._print.toggle_theme() elif RpnTokens.is_literal(token): if token[1] in self._variables: val = self._variables[token[1]] if self._print.mode == 'dec': self._stacks.append(val) else: if isinstance(val, float): raise UnsupportedDecimalError(token) else: self._stacks.append(val) elif token[1] in self._macros: exp = self._macros[token[1]] new_tokens = self._lexer.get_tokens(exp) self._process_tokens(new_tokens) else: raise InvalidSyntaxError(token) else: if token[1].startswith('macro'): cmd_str = token[1].split() if len(cmd_str) <= 2: raise InvalidSyntaxError(token) mc = ' '.join(cmd_str[2:]) self._macros[cmd_str[1]] = mc else: ret = RpnOperations.execute( token, self._stacks, self._variables, self._print.mode) if ret is not None: self._stacks.append(ret) except RpnErrors as e: # Rollback to previous backup data if errors occur self._stacks = backup_stack self._variables = backup_vars self._print.error(e.get_message()) return 0
def atom(self): res= ParseResult() tok = self.current_tok if tok.type == Constants.TOK_IDENTIFIER: res.register_advancement() self.advance() return res.success(VarAccessNode(tok)) elif tok.type in (Constants.TOK_INT, Constants.TOK_FLOAT): res.register_advancement() self.advance() return res.success(NumberNode(tok)) elif tok.type == Constants.TOK_STRING: res.register_advancement() self.advance() return res.success(StringNode(tok)) elif tok.type == Constants.TOK_LPAREN: res.register_advancement() self.advance() expr = res.register(self.expr()) if res.error: return res if self.current_tok.type == Constants.TOK_RPAREN: res.register_advancement() self.advance() return res.success(expr) else: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected \')\'' )) elif tok.type == Constants.TOK_LSQUARE: list_expr = res.register(self.list_expr()) if res.error: return res return res.success(list_expr) elif tok.matches(Constants.TOK_KEYWORD, 'if'): if_expr = res.register(self.if_expr()) if res.error: return res return res.success(if_expr) elif tok.matches(Constants.TOK_KEYWORD, 'for'): for_expr = res.register(self.for_expr()) if res.error: return res return res.success(for_expr) elif tok.matches(Constants.TOK_KEYWORD, 'while'): while_expr = res.register(self.while_expr()) if res.error: return res return res.success(while_expr) elif tok.matches(Constants.TOK_KEYWORD, 'func'): func_def = res.register(self.func_def()) if res.error: return res return res.success(func_def) return res.failure(InvalidSyntaxError( tok.pos_start, tok.pos_end, 'Expected int, float, +, -, *, /. keywords - if, for, while, func etc.' ))
def is_valid(token): if token[0] == Token.Error: raise InvalidSyntaxError(token) return True
def for_expr(self): res = ParseResult() if not self.current_tok.matches(Constants.TOK_KEYWORD, 'for'): return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected \'for\'' )) res.register_advancement() self.advance() if self.current_tok.type != Constants.TOK_IDENTIFIER: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected identifier' )) var_name = self.current_tok res.register_advancement() self.advance() if self.current_tok.type != Constants.TOK_EQUALS: return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected \'=\'' )) res.register_advancement() self.advance() start_value = res.register(self.expr()) if res.error: return res if not self.current_tok.matches(Constants.TOK_KEYWORD, 'to'): return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected \'to\'' )) res.register_advancement() self.advance() end_value = res.register(self.expr()) if res.error: return res if self.current_tok.matches(Constants.TOK_KEYWORD, 'step'): res.register_advancement() self.advance() step_value = res.register(self.expr()) if res.error: return res else: step_value = None if not self.current_tok.matches(Constants.TOK_KEYWORD, 'then'): return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, 'Expected \'then\'' )) res.register_advancement() self.advance() if self.current_tok.type == Constants.TOK_NEWLINE: res.register_advancement() self.advance() body = res.register(self.statements()) if res.error: return res if not self.current_tok.matches(Constants.TOK_KEYWORD, 'end'): return res.failure(InvalidSyntaxError( self.current_tok.pos_start, self.current_tok.pos_end, f"Expected 'end'" )) res.register_advancement() self.advance() return res.success(ForNode(var_name, start_value, end_value, step_value, body, True)) body = res.register(self.statement()) if res.error: return res return res.success(ForNode(var_name, start_value, end_value, step_value, body, False))