def _parse_es_api_call(self): self._publish_event(ParserEventType.ES_METHOD) method_token = self._consume_token(HttpMethod) method_node = NameNode(method_token) if method_token.value.upper() not in HTTP_METHODS: raise PeekSyntaxError( self.text, method_token, title='Invalid HTTP method', message= f'Expect HTTP method of value in {HTTP_METHODS!r}, got {method_token.value!r}' ) if self._peek_token().ttype is Literal: self._publish_event(ParserEventType.ES_URL) path_node = TextNode(self._consume_token(Literal)) elif self._peek_token().ttype is ParenLeft: self._publish_event(ParserEventType.BEFORE_ES_URL_EXPR) path_node = self._parse_expr() self._publish_event(ParserEventType.AFTER_ES_URL_EXPR) else: raise PeekSyntaxError( self.text, self._peek_token(), message= 'HTTP path must be either text literal or an expression enclosed by parenthesis' ) option_nodes = [] while self._peek_token().ttype is OptionName: self._publish_event(ParserEventType.ES_OPTION_NAME) n = NameNode(self._consume_token(OptionName)) self._consume_token(Assign) self._publish_event(ParserEventType.BEFORE_ES_OPTION_VALUE) option_nodes.append(KeyValueNode(n, self._parse_expr())) self._publish_event(ParserEventType.AFTER_ES_OPTION_VALUE) if self._peek_token().ttype is At: self._publish_event(ParserEventType.ES_PAYLOAD_FILE_AT) self._consume_token(At) return EsApiCallFilePayloadNode( method_node, path_node, DictNode(option_nodes), TextNode(self._consume_token(Literal))) else: dict_nodes = [] while self._peek_token().ttype is not EOF: if self._peek_token().ttype is CurlyLeft: self._publish_event( ParserEventType.BEFORE_ES_PAYLOAD_INLINE) dict_nodes.append(self._parse_dict()) self._publish_event( ParserEventType.AFTER_ES_PAYLOAD_INLINE) else: break return EsApiCallInlinePayloadNode(method_node, path_node, DictNode(option_nodes), dict_nodes)
def _parse_func_call_args(self, is_stmt=True): self._publish_event(ParserEventType.BEFORE_FUNC_ARGS) symbol_nodes = [] arg_nodes = [] kwarg_nodes = [] while self._peek_token().ttype is not EOF: if self._peek_token().ttype is BlankLine: self._consume_token(BlankLine) if is_stmt: break elif self._peek_token().ttype is ParenRight: if is_stmt: raise PeekSyntaxError( self.text, self._peek_token(), message= 'Found function expression while parsing for function stmt' ) else: break elif self._peek_token().ttype is Name: self._publish_event(ParserEventType.FUNC_OPTION_NAME_OR_ARG) n = NameNode(self._consume_token(Name)) if self._peek_token().ttype is Assign: self._consume_token(Assign) self._publish_event( ParserEventType.BEFORE_FUNC_OPTION_VALUE) kwarg_nodes.append(KeyValueNode(n, self._parse_expr())) self._publish_event( ParserEventType.AFTER_FUNC_OPTION_VALUE) elif self._peek_token( ).ttype is ParenLeft: # nested function expr self._consume_token(ParenLeft) sub_symbol_nodes, sub_arg_nodes, sub_kwarg_nodes = self._parse_func_call_args( is_stmt=False) arg_nodes.append( FuncCallNode(n, ArrayNode(sub_symbol_nodes), ArrayNode(sub_arg_nodes), DictNode(sub_kwarg_nodes), is_stmt=False)) self._consume_token(ParenRight) else: arg_nodes.append(self._parse_expr_after_left_operand(n)) elif self._peek_token().ttype is At: self._publish_event(ParserEventType.BEFORE_FUNC_SYMBOL_ARG) self._consume_token(At) symbol_nodes.append(SymbolNode(self._consume_token(Literal))) self._publish_event(ParserEventType.AFTER_FUNC_SYMBOL_ARG) else: self._publish_event(ParserEventType.BEFORE_FUNC_REGULAR_ARG) arg_nodes.append(self._parse_expr()) self._publish_event(ParserEventType.AFTER_FUNC_REGULAR_ARG) self._publish_event(ParserEventType.AFTER_FUNC_ARGS) return symbol_nodes, arg_nodes, kwarg_nodes
def _parse_dict(self): kv_nodes = [] self._consume_token(CurlyLeft) while self._peek_token().ttype is not CurlyRight: kv_nodes.append(self._parse_dict_kv()) if self._peek_token().ttype is Comma: self._consume_token(Comma) else: break self._consume_token(CurlyRight) return DictNode(kv_nodes)
def _parse_let_stmt(self): self._publish_event(ParserEventType.LET) self._consume_token(Let) kv_nodes = [] while self._peek_token().ttype is not EOF: if self._peek_token().ttype is BlankLine: self._consume_token(BlankLine) break key_node = self._parse_expr() self._consume_token(Assign) value_node = self._parse_expr() kv_nodes.append(KeyValueNode(key_node, value_node)) return LetNode(DictNode(kv_nodes))
def _parse_expr_after_left_operand(self, n, unary_op_token=None, last_bin_op=None): while True: if self._peek_token().ttype is BinOp: op_token = self._peek_token() if _BIN_OP_ORDERS[last_bin_op] >= _BIN_OP_ORDERS[ op_token.value]: return n if unary_op_token is None else UnaryOpNode( unary_op_token, n) else: self._consume_token(op_token.ttype) right_node = self._parse_expr(last_bin_op=op_token.value) n = n if unary_op_token is None else UnaryOpNode( unary_op_token, n) n = BinOpNode(op_token, n, right_node) elif self._peek_token().ttype is ParenLeft: # func call if last_bin_op == '.': return n if unary_op_token is None else UnaryOpNode( unary_op_token, n) else: self._consume_token(ParenLeft) symbol_nodes, arg_nodes, kwarg_nodes = self._parse_func_call_args( is_stmt=False) self._consume_token(ParenRight) n = FuncCallNode(n, ArrayNode(symbol_nodes), ArrayNode(arg_nodes), DictNode(kwarg_nodes), is_stmt=False) n = n if unary_op_token is None else UnaryOpNode( unary_op_token, n) else: return n if unary_op_token is None else UnaryOpNode( unary_op_token, n) unary_op_token = None
def _parse_func_call(self): self._publish_event(ParserEventType.FUNC_STMT) name_node = NameNode(self._consume_token(FuncName)) symbol_nodes, arg_nodes, kwarg_nodes = self._parse_func_call_args() return FuncCallNode(name_node, ArrayNode(symbol_nodes), ArrayNode(arg_nodes), DictNode(kwarg_nodes))