def parse_let_family(tp: ast.Tuple) -> ast.Node: if len(tp.elements) < 3: raise ParseError( f'{tp.elements[0]}: bad syntax, no expression in body') elem = tp.elements[1] if not isinstance(elem, ast.Tuple): raise ParseError( f'{tp.elements[0]}: bad syntax, expected bindings, given: {elem}') bindings: List[Node] = elem.elements patterns: List[ast.Name] = [] exprs: List[Node] = [] for i, binding in enumerate(bindings): if isinstance(binding, ast.Tuple): if len(binding.elements) == 2: if isinstance(binding.elements[0], ast.Name): patterns.append(binding.elements[0]) exprs.append(parse_node(binding.elements[1])) continue raise ParseError( f'{tp.elements[0]}: bad syntax, not an identifer and expression for a binding {binding}' ) body = ast.Block(parse_list(tp.elements[2:])) name = tp.elements[0] if not isinstance(name, ast.Name): raise ParseError(f'expected a Name, given {name}') if name.identifier == constants.LET: return ast.Let(patterns, exprs, body) elif name.identifier == constants.LET_STAR: return ast.LetStar(patterns, exprs, body) elif name.identifier == constants.LET_REC: return ast.LetRec(patterns, exprs, body) else: raise ParseError(f'{tp.elements[0]}: should not be here')
def let(self): self.lexer.match("let") name = self.lexer.match_type(TokenType.Ident) self.lexer.match("=") value = self.expr() return ast.Let(name, value)
def p_inner_lets_initialized(self, parse): ''' nested_lets : ID COLON TYPE ASSIGN expression IN expression | nested_lets COMMA ID COLON TYPE ASSIGN expression ''' parse[0] = AST.Let(instance=parse[1], return_type=parse[3], expression=parse[5], body=parse[7])
def p_inner_lets_simple(self, parse): ''' nested_lets : ID COLON TYPE IN expression | nested_lets COMMA ID COLON TYPE ''' parse[0] = AST.Let(instance=parse[1], return_type=parse[3], expression=None, body=parse[5])
def p_expression_let_initialized(self, parse): ''' let_expression : LET ID COLON TYPE ASSIGN expression IN expression | nested_lets COMMA LET ID COLON TYPE ASSIGN expression ''' parse[0] = AST.Let(instance=parse[2], return_type=parse[4], expression=parse[6], body=parse[8])
def p_expression_let_simple(self, parse): ''' let_expression : LET ID COLON TYPE IN expression | nested_lets COMMA LET ID COLON TYPE ''' parse[0] = AST.Let(instance=parse[2], return_type=parse[4], expression=None, body=parse[6])
def let_stmt(self) -> ast.Let: toks = TokenList() toks.add(self.peek()) # Add 'let' token itself for correct begin var_names, var_types = self.let_lhs() # Writes variable names to symbol table if not toks.add(self.match(token.ASSIGN)): raise ParseException("Empty let statements are not supported. Always assign a value!") expr : typing.Union[ast.ExpressionList, ast.AssignOp] = self.assignment() toks.add(self.match(token.SEMICOLON)) return ast.Let(toks, var_names, var_types, expr, self.symbol_tree.take_snapshot())
def parse_let(self, token, frame): """Parse Let expression""" if len(frame) < 2: _malformed(token) # Resolve first as return val versus args letres = None letargs = None letexpr = None if isinstance(frame[0], ast.Symbol): letres = frame.pop(0) else: sp = token.getsourcepos() lsym = "let_" + str(sp.lineno) + "_" + str(sp.colno) letres = ast.Symbol(lsym, Token("LET_RES", lsym, token.getsourcepos()), self.input) if isinstance(frame[0], ast.CollectionAst): letargs = frame.pop(0) else: _panic( "{}:{} Let expects local argument pair(s) signature [...] {}", token) if letargs.ctype != CollTypes.LIST: _panic( "{}:{} Invalid let argument pair(s) type. Should be [...] {}", token) if len(frame) < 1: _panic("{}:{} Missing Let expression {}", token) letexpr = [frame.pop(0)] letargs = ast.LetPairs(letargs, token, self.input) _check_no_declarations(token, letexpr, self._decl_set) frame.insert(0, ast.Let(letres, letargs, letexpr, token, self.input)) return frame
def p_expression_let_list(self, parse): """ let_expression : LET formal_list IN expression """ parse[0] = AST.Let(declarations=parse[2], body=parse[4])
def statement(self): if self.match("let"): line = self.pop().line ty = self.type() if self.match_val("="): name = ty[1] ty = None #this is where more complete type parsing would happen #for the time being, just error out elif self.match("ident"): name = self.pop().val else: raise ValueError( f"expected type in var declaration on line {line}, saw {self.tl[0].val}" ) self.consume( "=", f"expected '=' in let declaration on line {line}, saw {self.tl[0].val}" ) ex = self.expr() if ty != None: return ast.Let(name, (ty, None), ex) else: return ast.Let(name, None, ex) elif self.match("var"): line = self.pop().line ty = self.type() if self.match_val("="): name = ty[0] ty = None #this is where more complete type parsing would happen #for the time being, just error out elif self.match("ident"): name = self.pop().val else: raise ValueError( f"expected type in var declaration on line {line}, saw {self.tl[0].val}" ) self.consume( "=", f"expected '=' in var declaration on line {line}, saw {self.tl[0].val}" ) ex = self.expr() return ast.Var(name, ty, ex) elif self.match("if"): line = self.pop().line ex = self.expr() thenstmnts = self.statementlist("if statement", line) if not self.match("else"): elsestmnts = None else: line = self.pop().line elsestmnts = self.statementlist("else statement", line) return ast.If(ex, thenstmnts, elsestmnts) elif self.match('return'): self.pop() returning = self.expr() return ast.Return(returning) elif self.match('while'): line = self.pop().line condition = self.expr() body = self.statementlist("while body", line) return ast.While(condition, body) else: lhs = self.expr() if self.match_val('=') or self.match_val('+=') or self.match_val( '-=') or self.match_val('*=') or self.match_val( '/=') or self.match_val('%='): op = self.pop().val rhs = self.expr() if (op[0] != '='): rhs = ast.Binary(lhs, op[0], rhs) return ast.Assign(lhs, rhs) else: return lhs