def _register_global(self, node, name): var = self.vars.get(name) if var: if var.type == Var.TYPE_PARAM: msg = "name '{}' is parameter and global" raise util.ParseError(node, msg.format(name)) if var.type == Var.TYPE_LOCAL: msg = "name '{}' is used prior to global declaration" raise util.ParseError(node, msg.format(name)) else: self.vars[name] = Var(name, Var.TYPE_GLOBAL)
def visit_Break(self, node): if not self.block.loop_stack: raise util.ParseError(node, "'break' not in loop") self._write_py_context(node.lineno) self.writer.write_tmpl(textwrap.dedent("""\ $breakvar = true continue"""), breakvar=self.block.top_loop().breakvar.name)
def _make_future_features(node): """Processes a future import statement, returning set of flags it defines.""" assert isinstance(node, ast.ImportFrom) assert node.module == '__future__' features = FutureFeatures() for alias in node.names: name = alias.name if name in _FUTURE_FEATURES: if name not in _IMPLEMENTED_FUTURE_FEATURES: msg = 'future feature {} not yet implemented by grumpy'.format( name) raise util.ParseError(node, msg) setattr(features, name, True) elif name == 'braces': raise util.ParseError(node, 'not a chance') elif name not in _REDUNDANT_FUTURE_FEATURES: msg = 'future feature {} is not defined'.format(name) raise util.ParseError(node, msg) return features
def visit_Return(self, node): assert isinstance(self.block, block.FunctionBlock) self._write_py_context(node.lineno) if self.block.is_generator and node.value: raise util.ParseError(node, 'returning a value in a generator function') if node.value: with self.visit_expr(node.value) as value: self.writer.write('πR = {}'.format(value.expr)) else: self.writer.write('πR = πg.None') self.writer.write('continue')
def del_var(self, writer, name): var = self.vars.get(name) if not var: raise util.ParseError( None, 'cannot delete nonexistent local: {}'.format(name)) if var.type == Var.TYPE_GLOBAL: return self.root.del_var(writer, name) adjusted_name = util.adjust_local_name(name) # Resolve local first to ensure the variable is already bound. writer.write_checked_call1('πg.CheckLocal(πF, {}, {})', adjusted_name, util.go_str(name)) writer.write('{} = πg.UnboundLocal'.format(adjusted_name))
def visit_BinOp(self, node): result = self.block.alloc_temp() with self.visit(node.left) as lhs, self.visit(node.right) as rhs: op_type = type(node.op) if op_type in ExprVisitor._BIN_OP_TEMPLATES: tmpl = ExprVisitor._BIN_OP_TEMPLATES[op_type] self.writer.write_checked_call2( result, tmpl, lhs=lhs.expr, rhs=rhs.expr) else: msg = 'binary op not implemented: {}'.format(op_type.__name__) raise util.ParseError(node, msg) return result
def visit_Print(self, node): if self.block.root.future_features.print_function: raise util.ParseError(node, 'syntax error (print is not a keyword)') self._write_py_context(node.lineno) with self.block.alloc_temp('[]*πg.Object') as args: self.writer.write('{} = make([]*πg.Object, {})'.format( args.expr, len(node.values))) for i, v in enumerate(node.values): with self.visit_expr(v) as arg: self.writer.write('{}[{}] = {}'.format(args.expr, i, arg.expr)) self.writer.write_checked_call1('πg.Print(πF, {}, {})', args.expr, 'true' if node.nl else 'false')
def visit_AugAssign(self, node): op_type = type(node.op) if op_type not in StatementVisitor._AUG_ASSIGN_TEMPLATES: fmt = 'augmented assignment op not implemented: {}' raise util.ParseError(node, fmt.format(op_type.__name__)) self._write_py_context(node.lineno) with self.visit_expr(node.target) as target,\ self.visit_expr(node.value) as value,\ self.block.alloc_temp() as temp: self.writer.write_checked_call2( temp, StatementVisitor._AUG_ASSIGN_TEMPLATES[op_type], lhs=target.expr, rhs=value.expr) self._assign_target(node.target, temp.expr)
def __init__(self, node): BlockVisitor.__init__(self) self.is_generator = False node_args = node.args args = [a.arg for a in node_args.args] if node_args.vararg: args.append(node_args.vararg.arg) if node_args.kwarg: args.append(node_args.kwarg.arg) for i, name in enumerate(args): if name in self.vars: msg = "duplicate argument '{}' in function definition".format( name) raise util.ParseError(node, msg) self.vars[name] = Var(name, Var.TYPE_PARAM, arg_index=i)
def _assign_target(self, target, value): if isinstance(target, ast.Name): self.block.bind_var(self.writer, target.id, value) elif isinstance(target, ast.Attribute): with self.visit_expr(target.value) as obj: self.writer.write_checked_call1( 'πg.SetAttr(πF, {}, {}, {})', obj.expr, self.block.root.intern(target.attr), value) elif isinstance(target, ast.Subscript): with self.visit_expr(target.value) as mapping,\ self.visit_expr(target.slice) as index: self.writer.write_checked_call1('πg.SetItem(πF, {}, {}, {})', mapping.expr, index.expr, value) else: msg = 'assignment target not yet implemented: ' + type(target).__name__ raise util.ParseError(target, msg)
def visit_Delete(self, node): self._write_py_context(node.lineno) for target in node.targets: if isinstance(target, ast.Attribute): with self.visit_expr(target.value) as t: self.writer.write_checked_call1( 'πg.DelAttr(πF, {}, {})', t.expr, self.block.root.intern(target.attr)) elif isinstance(target, ast.Name): self.block.del_var(self.writer, target.id) elif isinstance(target, ast.Subscript): with self.visit_expr(target.value) as t,\ self.visit_expr(target.slice) as index: self.writer.write_checked_call1('πg.DelItem(πF, {}, {})', t.expr, index.expr) else: msg = 'del target not implemented: {}'.format(type(target).__name__) raise util.ParseError(node, msg)
def visit_UnaryOp(self, node): result = self.block.alloc_temp() with self.visit(node.operand) as operand: op_type = type(node.op) if op_type in ExprVisitor._UNARY_OP_TEMPLATES: self.writer.write_checked_call2( result, ExprVisitor._UNARY_OP_TEMPLATES[op_type], operand=operand.expr) elif isinstance(node.op, ast.Not): with self.block.alloc_temp('bool') as is_true: self.writer.write_checked_call2( is_true, 'πg.IsTrue(πF, {})', operand.expr) self.writer.write('{} = πg.GetBool(!{}).ToObject()'.format( result.name, is_true.expr)) else: msg = 'unary op not implemented: {}'.format(op_type.__name__) raise util.ParseError(node, msg) return result
def _write_except_dispatcher(self, exc, tb, handlers): """Outputs a Go code that jumps to the appropriate except handler. Args: exc: Go variable holding the current exception. tb: Go variable holding the current exception's traceback. handlers: A list of ast.ExceptHandler nodes. Returns: A list of Go labels indexes corresponding to the exception handlers. Raises: ParseError: Except handlers are in an invalid order. """ handler_labels = [] for i, except_node in enumerate(handlers): handler_labels.append(self.block.genlabel()) if except_node.type: with self.visit_expr(except_node.type) as type_,\ self.block.alloc_temp('bool') as is_inst: self.writer.write_checked_call2( is_inst, 'πg.IsInstance(πF, {}.ToObject(), {})', exc, type_.expr) self.writer.write_tmpl(textwrap.dedent("""\ if $is_inst { \tgoto Label$label }"""), is_inst=is_inst.expr, label=handler_labels[-1]) else: # This is a bare except. It should be the last handler. if i != len(handlers) - 1: msg = "default 'except:' must be last" raise util.ParseError(except_node, msg) self.writer.write('goto Label{}'.format(handler_labels[-1])) if handlers[-1].type: # There's no bare except, so the fallback is to re-raise. self.writer.write( 'πE = πF.Raise({}.ToObject(), nil, {}.ToObject())'.format( exc, tb)) self.writer.write('continue') return handler_labels
def visit_Num(self, node): if isinstance(node.n, int): expr_str = 'NewInt({})'.format(node.n) elif isinstance(node.n, long): a = abs(node.n) gobytes = '' while a: gobytes = hex(int(a&255)) + ',' + gobytes a >>= 8 expr_str = 'NewLongFromBytes([]byte{{{}}})'.format(gobytes) if node.n < 0: expr_str = expr_str + '.Neg()' elif isinstance(node.n, float): expr_str = 'NewFloat({})'.format(node.n) elif isinstance(node.n, complex): expr_str = 'NewComplex(complex({}, {}))'.format(node.n.real, node.n.imag) else: msg = 'number type not yet implemented: ' + type(node.n).__name__ raise util.ParseError(node, msg) return expr.GeneratedLiteral('πg.' + expr_str + '.ToObject()')
def _node_not_implemented(self, node): msg = 'node not yet implemented: ' + type(node).__name__ raise util.ParseError(node, msg)
def generic_visit(self, node): msg = 'expression node not yet implemented: ' + type(node).__name__ raise util.ParseError(node, msg)
def _check_duplicate_args(self, name, node): if name in self.vars: msg = "duplicate argument '{}' in function definition".format(name) raise util.ParseError(node, msg)
def visit_Continue(self, node): if not self.block.loop_stack: raise util.ParseError(node, "'continue' not in loop") self._write_py_context(node.lineno) self.writer.write('continue')
def generic_visit(self, node): msg = 'node not yet implemented: {}'.format(type(node).__name__) raise util.ParseError(node, msg)