def process_case(self, parent: tl.CollectiveElement, index: int, builder: ab.AstBuilder, lfp: tl.LineFilePos): index += 1 cond_list = tl.CollectiveElement(tl.CE_BRACKET, lfp, None) ele = parent[index] while not (tl.is_brace(ele) or tl.identifier_of(ele, "->")): cond_list.append(ele) index += 1 ele = parent[index] cond = self.parse_as_part(cond_list) if tl.identifier_of(ele, "->"): # case expr index += 1 ele = parent[index] if tl.is_brace(ele): body_block = self.parse_as_block(ele) builder.add_node(ast.CaseExpr(body_block, lfp, cond)) else: body_list = tl.CollectiveElement(tl.CE_BRACKET, lfp, None) while not tl.identifier_of(ele, ";"): body_list.append(ele) index += 1 ele = parent[index] builder.add_node(ast.CaseExpr(self.parse_as_part(body_list), lfp, cond)) else: # case stmt body_block = self.parse_as_block(ele) builder.add_node(ast.CaseStmt(body_block, lfp, cond)) return index
def list_ify_macro_arg(args: tl.CollectiveElement) -> list: res = [] cur = tl.CollectiveElement(tl.CE_BRACE, args.lfp, None) for arg in args: if tl.identifier_of(arg, ","): res.append(cur) cur = tl.CollectiveElement(tl.CE_BRACE, args.lfp, None) else: cur.append(arg) res.append(cur) return res
def process_fn(self, parent: tl.CollectiveElement, index: int, builder: ab.AstBuilder, lfp: tl.LineFilePos): abstract = self.abstract self.abstract = False const = self.var_level == ast.VAR_CONST self.var_level = ast.VAR_VAR permission = self.permission self.permission = ast.PUBLIC inline = self.inline self.inline = False index += 1 name_list = tl.CollectiveElement(tl.CE_BRACKET, lfp, None) next_ele = parent[index] while not tl.is_bracket(next_ele): name_list.append(next_ele) index += 1 next_ele = parent[index] if len(name_list) == 0: fn_name = None else: fn_name = self.parse_as_part(name_list) param_list = next_ele params = self.parse_as_line(param_list) prob_arrow = parent[index + 1] if tl.identifier_of(prob_arrow, "->"): builder.add_node(ast.FunctionTypeExpr(params, lfp)) return index index += 1 rtype_list = tl.CollectiveElement(tl.CE_BRACKET, lfp, None) while not (tl.is_brace(parent[index]) or tl.identifier_of(parent[index], ";")): rtype_list.append(parent[index]) index += 1 rtype = self.parse_as_part(rtype_list) body_list = parent[index] if tl.identifier_of(body_list, ";"): body = None else: body = self.parse_as_block(body_list) if not abstract and body is None: raise errs.TplSyntaxError("Non-abstract method must have body. ", lfp) if abstract and body is not None: raise errs.TplSyntaxError("Abstract method must not have body. ", lfp) fd = ast.FunctionDef(fn_name, params, rtype, abstract, const, permission, body, lfp) fd.inline = inline builder.add_node(fd) return index
def process_block( self, block: tl.CollectiveElement, result_parent: tl.CollectiveElement) -> tl.CollectiveElement: result = tl.CollectiveElement(block.ce_type, block.lfp, result_parent) i = 0 while i < len(block): i = self.process_one(block, i, result) return result
def make_tree(self, cur_active: tl.CollectiveElement, index: int) -> tl.CollectiveElement: tk = self.tokens[index] if isinstance(tk, tl.IdToken): symbol = tk.identifier if symbol == "(": return tl.CollectiveElement(tl.CE_BRACKET, tk.lfp, cur_active) if symbol == "[": return tl.CollectiveElement(tl.CE_SQR_BRACKET, tk.lfp, cur_active) if symbol == "{": return tl.CollectiveElement(tl.CE_BRACE, tk.lfp, cur_active) if symbol == ")": if cur_active.ce_type == tl.CE_BRACKET: cur_active.parent.append(cur_active) return cur_active.parent else: raise errs.TplSyntaxError("Parenthesis does not close. ", tk.lfp) if symbol == "]": if cur_active.ce_type == tl.CE_SQR_BRACKET: cur_active.parent.append(cur_active) return cur_active.parent else: raise errs.TplSyntaxError("Parenthesis does not close. ", tk.lfp) if symbol == "}": if cur_active.ce_type == tl.CE_BRACE: cur_active.parent.append(cur_active) return cur_active.parent else: raise errs.TplSyntaxError("Parenthesis does not close. ", tk.lfp) if symbol == "<": if has_closing_arrow(self.tokens, index): return tl.CollectiveElement(tl.CE_ARROW_BRACKET, tk.lfp, cur_active) if symbol == ">": if tl.is_arrow_bracket(cur_active): cur_active.parent.append(cur_active) return cur_active.parent cur_active.append(tl.AtomicElement(tk, cur_active)) return cur_active
def process_if_expr(self, cond_list: tl.CollectiveElement, parent: tl.CollectiveElement, index: int, builder: ab.AstBuilder, lfp: tl.LineFilePos): cond = self.parse_as_part(cond_list) index += 1 then_list = tl.CollectiveElement(tl.CE_BRACKET, lfp, None) while not tl.identifier_of(parent[index], "else"): then_list.append(parent[index]) index += 1 then_expr = self.parse_as_part(then_list) index += 1 else_list = tl.CollectiveElement(tl.CE_BRACKET, lfp, None) while index < len(parent) and not tl.identifier_of(parent[index], ";"): else_list.append(parent[index]) index += 1 else_expr = self.parse_as_part(else_list) ife = ast.IfExpr(cond, then_expr, else_expr, lfp) builder.add_node(ife) if index < len(parent): # last loop terminated by a ';', add an eol self.process_eol(parent, index, builder, lfp) return index
def process_while_stmt(self, parent: tl.CollectiveElement, index: int, builder: ab.AstBuilder, lfp: tl.LineFilePos): index += 1 item = parent[index] cond_list = tl.CollectiveElement(tl.CE_BRACKET, lfp, None) while not (isinstance(item, tl.CollectiveElement) and item.is_brace()): cond_list.append(item) index += 1 item = parent[index] cond = self.parse_as_part(cond_list) body = self.parse_as_block(item) builder.add_node(ast.WhileStmt(cond, body, lfp)) return index
def process_switch(self, parent: tl.CollectiveElement, index: int, builder: ab.AstBuilder, lfp: tl.LineFilePos): index += 1 cond_list = tl.CollectiveElement(tl.CE_BRACKET, lfp, None) ele = parent[index] while not tl.is_brace(ele): cond_list.append(ele) index += 1 ele = parent[index] cond = self.parse_as_part(cond_list) body_block = self.parse_as_block(ele) res = ab.parse_switch(cond, body_block, lfp) builder.add_node(res) return index
def process_require(self, parent: tl.CollectiveElement, index: int, builder: ab.AstBuilder, lfp: tl.LineFilePos): index += 1 item = parent[index] if isinstance(item, tl.CollectiveElement): content = self.parse_as_block(item) else: bracket = tl.CollectiveElement(tl.CE_BRACKET, lfp, None) bracket.append(item) index += 1 while not tl.identifier_of(parent[index], ";"): bracket.append(parent[index]) index += 1 content = self.parse_as_part(bracket) builder.add_node(ast.RequireStmt(content, lfp)) self.process_eol(parent, index, builder, lfp) return index
def process_lambda(self, parent: tl.CollectiveElement, index: int, builder: ab.AstBuilder, lfp: tl.LineFilePos): index += 1 params_bracket = parent[index] if not tl.is_bracket(params_bracket): raise errs.TplSyntaxError("Invalid syntax for lambda expression. ", lfp) params = self.parse_as_line(params_bracket) body_bracket = tl.CollectiveElement(tl.CE_BRACKET, lfp, None) index += 1 next_tk = parent[index] while not tl.identifier_of(next_tk, ";"): body_bracket.append(next_tk) index += 1 next_tk = parent[index] body = self.parse_as_part(body_bracket) builder.add_node(ast.LambdaExpr(params, body, lfp)) return index
def process_for_stmt(self, parent: tl.CollectiveElement, index: int, builder: ab.AstBuilder, lfp: tl.LineFilePos): index += 1 item = parent[index] cond_list = tl.CollectiveElement(tl.CE_BRACKET, lfp, None) while not (isinstance(item, tl.CollectiveElement) and item.is_brace()): cond_list.append(item) index += 1 item = parent[index] cond = self.parse_as_block(cond_list) body = self.parse_as_block(item) if len(cond) == 3: builder.add_node(ast.ForStmt(cond[0], cond[1], cond[2], body, lfp)) elif len(cond) == 1 and len(cond[0]) == 1 and isinstance(cond[0][0], ast.InStmt): builder.add_node(ast.ForEachStmt(cond[0][0], body, lfp)) else: raise errs.TplCompileError("For loop title must contains 3 parts. ", lfp) return index
def process_if_stmt(self, parent: tl.CollectiveElement, index, builder, lfp): index += 1 condition_list = tl.CollectiveElement(tl.CE_BRACKET, lfp, None) item = parent[index] while not (isinstance(item, tl.CollectiveElement) and item.is_brace()): condition_list.append(item) index += 1 item = parent[index] if tl.identifier_of(item, "then"): # is a if-expr instead of if-stmt return self.process_if_expr(condition_list, parent, index, builder, lfp) cond = self.parse_as_part(condition_list) body = self.parse_as_block(item) if index + 1 < len(parent) and tl.identifier_of(parent[index + 1], "else"): index += 2 else_block = self.parse_as_block(parent[index]) else: else_block = None ifs = ast.IfStmt(cond, body, else_block, lfp) builder.add_node(ifs) return index
def process_default(self, parent: tl.CollectiveElement, index: int, builder: ab.AstBuilder, lfp: tl.LineFilePos): index += 1 ele = parent[index] if tl.is_brace(ele): builder.add_node(ast.CaseStmt(self.parse_as_block(ele), lfp)) elif tl.identifier_of(ele, "->"): index += 1 ele = parent[index] if tl.is_brace(ele): builder.add_node(ast.CaseExpr(self.parse_as_block(ele), lfp)) else: body_list = tl.CollectiveElement(tl.CE_BRACKET, lfp, None) while not tl.identifier_of(ele, ";"): body_list.append(ele) index += 1 ele = parent[index] builder.add_node(ast.CaseExpr(self.parse_as_part(body_list), lfp)) else: raise errs.TplParseError("Invalid syntax of 'default'. ", lfp) return index
def process_one(self, parent: tl.CollectiveElement, index: int, result_parent: tl.CollectiveElement) -> int: ele = parent[index] if isinstance(ele, tl.AtomicElement): if isinstance(ele.atom, tl.IdToken): symbol = ele.atom.identifier lf = ele.atom.lfp if symbol == "macro": index += 1 name_ele = parent[index] if isinstance(name_ele, tl.AtomicElement) and isinstance( name_ele.atom, tl.IdToken): name = name_ele.atom.identifier index += 1 prob_params = parent[index] if isinstance(prob_params, tl.CollectiveElement): if prob_params.is_brace(): # macro name { ... } macro = SimpleMacro(prob_params, lf) self.macros.add_macro(name, macro, lf) return index + 1 elif prob_params.is_bracket( ): # macro name(...) ... index += 1 body = parent[index] if tl.is_brace(body): macro = CallMacro( get_name_list(prob_params), body, lf) self.macros.add_macro(name, macro, lf) return index + 1 raise errs.TplSyntaxError("Invalid macro syntax. ", lf) elif symbol == "exportmacro": index += 1 exports = parent[index] if tl.is_brace(exports): for exp in exports: if isinstance(exp, tl.AtomicElement) and isinstance( exp.atom, tl.IdToken): if exp.atom.identifier != ",": self.macros.add_export(exp.atom.identifier) else: raise errs.TplSyntaxError( "Invalid exportmacro syntax. ", lf) elif isinstance(exports, tl.AtomicElement) and isinstance( exports.atom, tl.IdToken): self.macros.add_export(exports.atom.identifier) else: raise errs.TplSyntaxError( "Invalid exportmacro syntax. ", lf) return index + 1 elif symbol == "import": index += 1 includes = parent[index] if isinstance(includes, tl.AtomicElement): self.import_one(includes.atom, result_parent, lf) elif tl.is_brace(includes): for inc in includes: if isinstance(inc, tl.AtomicElement): self.import_one(inc.atom, result_parent, lf) else: raise errs.TplSyntaxError( "Invalid include. ", lf) else: raise errs.TplSyntaxError("Invalid include. ", lf) return index + 1 elif self.macros.is_macro(symbol): # replace macro macro = self.macros.get_macro(symbol) if isinstance(macro, CallMacro): index += 1 args = parent[index] if not tl.is_bracket(args): raise errs.TplSyntaxError("Invalid macro syntax. ", args.lfp) arg_list = list_ify_macro_arg(args) if len(arg_list) != len(macro.params): raise errs.TplSyntaxError( "Macro syntax arity mismatch. ", args.lfp) body_with_arg = tl.CollectiveElement( tl.CE_BRACE, lf, None) for body_ele in macro.body: if isinstance(body_ele, tl.AtomicElement) and \ isinstance(body_ele.atom, tl.IdToken) and \ body_ele.atom.identifier in macro.params: arg_index = macro.params.index( body_ele.atom.identifier) body_with_arg.extend(arg_list[arg_index]) else: body_with_arg.append(body_ele) macro_res = self.process_block(body_with_arg, None) else: macro_res = self.process_block(macro.body, None) result_parent.extend(macro_res) return index + 1 result_parent.append(ele) elif isinstance(ele, tl.CollectiveElement): res = self.process_block(ele, result_parent) result_parent.append(res) else: raise errs.TplError("Unexpected element. ", parent.lfp) return index + 1
def make_root_tree(self): root = tl.CollectiveElement(tl.CE_BRACE, tl.LF_TOKENIZER, None) cur_active = root for i in range(len(self.tokens)): cur_active = self.make_tree(cur_active, i) return root