def visitStReturn(self, ctx): coord = self._ctx_coord(ctx) if ctx.ret: kid = self.visit(ctx.expr()) else: kid = Ast("VOID", coord=coord) return Ast("RETURN", [kid], coord=coord)
def visitECast(self, ctx): coord = self._ctx_coord(ctx) typeSpec = self.visit(ctx.typeSpec()) tName = typeSpec.name tRank = typeSpec.rank tCoord = typeSpec.coord typeCastTo = Ast("TYPE", type_name=tName, rank=tRank, coord=tCoord) exprToCast = self.visit(ctx.expr()) return Ast("CAST", [typeCastTo, exprToCast], coord=coord)
def visitStIf(self, ctx): coord = self._ctx_coord(ctx) ifExpr = self.visit(ctx.ifExpr) ifStmnt = self.visit(ctx.ifStmnt) if ctx.elseStmnt: elseStmnt = self.visit(ctx.elseStmnt) else: elseStmnt = Ast("BLOCK", coord=coord) kids = [ifExpr] kids.append(ifStmnt) kids.append(elseStmnt) return Ast("IF", kids, coord=coord)
def visitEFnCall(self, ctx): coord = self._ctx_coord(ctx) fnName = self.visit(ctx.expr()) params = self.visit(ctx.actualParams()) kids = [fnName] kids.extend(params) return Ast("APP", kids, coord=coord)
def _make_scope(ast: Ast) -> Environment: global_environment = Environment() ast.env = global_environment def _make_scope_aux(ast: Ast, env: Environment) -> None: if isinstance(ast, VarAst): def _make_scope_aux_var_ast(): nonlocal env scope = env.lookup(ast.name) if scope is None: ast.env = global_environment global_environment.define(ast.name, VarDefine(kind=1)) else: ast.env = scope define: VarDefine = ast.env.get(ast.name) define.refs.append(ast) ast.define = define _make_scope_aux_var_ast() if isinstance(ast, LambdaAst): def _make_scope_aux_lambda_ast(): nonlocal env ast.env = env = env.extend() if ast.name: env.define(ast.name, VarDefine(kind=2)) for _, param in enumerate(ast.params): env.define(param, VarDefine(kind=2)) for param in ast.iife_params: env.define(param, VarDefine(kind=3)) _make_scope_aux(ast.body, env) ast = cast(LambdaAst, ast) _make_scope_aux_lambda_ast() if isinstance(ast, AssignAst): _make_scope_aux(ast.left, env) _make_scope_aux(ast.right, env) if isinstance(ast.left, VarAst): ast.left.define.assigned += 1 ast.left.define.current_value = ast.right if isinstance(ast, BinaryAst): _make_scope_aux(ast.left, env) _make_scope_aux(ast.right, env) if isinstance(ast, IfAst): _make_scope_aux(ast.cond, env) _make_scope_aux(ast.then, env) if ast.else_: _make_scope_aux(ast.else_, env) if isinstance(ast, ProgAst): for prog in ast.prog: _make_scope_aux(prog, env) if isinstance(ast, CallAst): _make_scope_aux(ast.func, env) for arg in ast.args: _make_scope_aux(arg, env) _make_scope_aux(ast, global_environment) return ast.env
def visitStWhile(self, ctx): coord = self._ctx_coord(ctx) expr = self.visit(ctx.expr()) stmnt = self.visit(ctx.statement()) kids = [expr] kids.append(stmnt) return Ast("WHILE", kids, coord=coord)
def defn(self): """Return AST for a defn""" defn_coord = self.lookahead.coord self.match('FN') self.match('PAREN', '(') name = self.lookahead.lexeme self.match('ID') params_coord = self.lookahead.coord params = self.params() params_ast = Ast('PARAMS', params, coord=params_coord, arity=len(params)) self.match('PAREN', ')') expr = self.expr() self.match('SEMI') return Ast('DEFN', [params_ast, expr], name=name, coord=defn_coord)
def visitParams(self, ctx): coord = self._ctx_coord(ctx) if ctx.formals: params = [self.visit(formal) for formal in ctx.formals] else: params = [] params += [self.visit(initFormal) for initFormal in ctx.initFormals] return Ast('PARAMS', params, coord=coord)
def visitFnDefinition(self, ctx): coord = self._ctx_coord(ctx) proto = self.visit(ctx.fnHeader()) body = self.visit(ctx.block()) return Ast('DEFN', [proto.returnType, proto.params, body], kind=proto.kind, isStatic=proto.isStatic, name=proto.name, coord=coord)
def visitClassDefinition(self, ctx): classBody = self._visit_kids(ctx) coord = self._ctx_coord(ctx) return Ast('CLASS', classBody, type_name=ctx.typeName.text, super_name="Object" if ctx.superName == None else ctx.superName.text, coord=coord)
def visitEAddSub(self, ctx): coord = self._ctx_coord(ctx) operator = ctx.operator.text if operator == "+": op = "ADD" if operator == "-": op = "SUB" leftOperand = self.visit(ctx.left) rightOperand = self.visit(ctx.right) return Ast("OP2", [leftOperand, rightOperand], op=op, coord=coord)
def visitConstrProto(self, ctx): coord = self._ctx_coord(ctx) isStatic = True name = ctx.TYPE_ID().getText() params = self.visit(ctx.params()) returnType = Ast('TYPE', type_name='$inferred', rank=0, coord=coord) return WalnutAstBuilder.Proto(kind='constructor', isStatic=True, name=name, returnType=returnType, params=params)
def params(self): """Return list of ASTs for formal parameters""" if self.look('ID'): coord = self.lookahead.coord param_ast = Ast('PARAM', name=self.lookahead.lexeme, coord=coord) self.match('ID') params = self.params() params.insert(0, param_ast) return params else: return []
def visitEMulDivMod(self, ctx): coord = self._ctx_coord(ctx) operator = ctx.operator.text if operator == "*": op = "MUL" if operator == "/": op = "DIV" if operator == "%": op = "REM" leftOperand = self.visit(ctx.left) rightOperand = self.visit(ctx.right) return Ast("OP2", [leftOperand, rightOperand], op=op, coord=coord)
def visitVarDec(self, ctx): isStatic = ctx.isStatic != None kind = ctx.kind.text coord = self._ctx_coord(ctx) type_name = "" rank = 0 if ctx.typeSp: typeInfo = self.visit(ctx.typeSp) type_name = typeInfo.name rank = typeInfo.rank else: type_name = "$inferred" type_ast = Ast("TYPE", type_name=type_name, rank=rank, coord=coord) rest = self._visit_kids(ctx) children = [type_ast] children.extend(rest) return Ast('DECLS', children, isStatic=isStatic, kind=kind, coord=coord)
def expr(self): "Return expr AST" coord = self.lookahead.coord if self.look('INT'): value = int(self.lookahead.lexeme) self.match('INT') return Ast('INT', value=value, coord=coord) elif self.look('ID'): name = self.lookahead.lexeme self.match('ID') return Ast('REF', name=name, coord=coord) elif self.look('PAREN', '('): self.match('PAREN', '(') fn_coord = self.lookahead.coord name = self.lookahead.lexeme if self.look('ID'): self.match('ID') args_coord = self.lookahead.coord args = self.args() args_ast = Ast('ARGS', args, coord=args_coord, arity=len(args)) self.match('PAREN', ')') return Ast('APP', [args_ast], name=name, coord=fn_coord) elif self.look("LET", "let"): self.match('LET') idExp_coord = self.lookahead.coord idExpList = self.idExp(0) idExpList_ast = Ast("LETIDEXPR", idExpList, coord=idExp_coord, arity=(len(idExpList) / 2)) self.match('IN') bodyExp_ast = self.expr() self.match("PAREN", ")") return Ast('LET', [idExpList_ast, bodyExp_ast], coord=fn_coord) elif (self.look('OP') and Parser.BINARY_OPS.get(self.lookahead.lexeme, None)): op = Parser.BINARY_OPS[self.lookahead.lexeme] self.match('OP') return Ast(op, [self.expr(), self.expr()], coord=coord) elif self.look('OP', '?'): self.match('OP') return Ast('IF', [self.expr(), self.expr(), self.expr()], coord=coord) else: raise SyntaxError("Expression expected")
def visitFnProto(self, ctx): isStatic = ctx.isStatic != None name = ctx.ID().getText() typeSpec = self.visit(ctx.typeSpec()) tName = typeSpec.name tRank = typeSpec.rank tCoord = typeSpec.coord returnType = Ast("TYPE", type_name=tName, rank=tRank, coord=tCoord) params = self.visit(ctx.params()) return WalnutAstBuilder.Proto(kind='function', isStatic=isStatic, name=name, returnType=returnType, params=params)
def main(argv=None): if argv is None: argv = sys.argv curWorld.top = Ast(ast.PROGRAM, None) if len(argv) > 1: for p in argv[1:]: if p.endswith(".n"): loadFile(p) else: if loadScript(p) < 0: return 0 nLoop() return 0
def visitArrConstruction(self, ctx): coord = self._ctx_coord(ctx) if ctx.prim: typeName = ctx.primitiveType().getText() else: typeName = ctx.TYPE_ID().getText() rank = 0 if ctx.idxs: idxs = [self.visit(exp) for exp in ctx.idxs] rank = len(ctx.idxs) else: idxs = [] return Ast("NEW_ARRAY", idxs, type_name=typeName, rank=rank, coord=coord)
def visitERelation(self, ctx): coord = self._ctx_coord(ctx) operator = ctx.operator.text if operator == "==": op = "EQ" if operator == "!=": op = "NE" if operator == "<": op = "LT" if operator == ">": op = "GT" if operator == "<=": op = "LE" if operator == ">=": op = "GE" leftOperand = self.visit(ctx.left) rightOperand = self.visit(ctx.right) return Ast("OP2", [leftOperand, rightOperand], op=op, coord=coord)
def __init__(self, symbol = None): ''' Initializes ancestor attributes, and ignore flags. ''' Ast.__init__(self, symbol)