diff --git a/hy/core/mangles.py b/hy/core/mangles.py index 0290382..e44ab16 100644 --- a/hy/core/mangles.py +++ b/hy/core/mangles.py @@ -26,6 +26,7 @@ import hy.mangle class FunctionMangle(hy.mangle.Mangle): hoistable = ["fn"] + ignore = ["def", "decorate_with"] def __init__(self): self.series = 0 @@ -34,19 +35,29 @@ class FunctionMangle(hy.mangle.Mangle): self.series += 1 return "_hy_hoisted_fn_%s" % (self.series) + def should_hoist(self): + for frame in self.stack: + if frame is self.scope: + return False + + if isinstance(frame, HyExpression) and frame != []: + call = frame[0] + if call in self.ignore: + continue + return True + return False + def visit(self, tree): - if isinstance(tree, HyExpression): + if isinstance(tree, HyExpression) and tree != []: call = tree[0] - if isinstance(call, HyExpression) and len(call) != 0: - what = call[0] - if what in self.hoistable: - name = self.unique_name() - call = HyExpression([HySymbol("def"), name, call]) - self.hoist(call) - tree.pop(0) - entry = HySymbol(name) - entry.replace(tree) - tree.insert(0, entry) - raise self.TreeChanged() + if call == "fn" and self.should_hoist(): + new_name = HySymbol(self.unique_name()) + new_name.replace(tree) + fn_def = HyExpression([HySymbol("def"), + new_name, + tree]) + fn_def.replace(tree) + self.hoist(fn_def) + return new_name hy.mangle.MANGLES.append(FunctionMangle) diff --git a/hy/mangle.py b/hy/mangle.py index d49d3fb..a0f2051 100644 --- a/hy/mangle.py +++ b/hy/mangle.py @@ -45,6 +45,8 @@ class Mangle(object): scopable = ["fn", "if"] scoped = False + self.push_stack(tree) + if isinstance(tree, HyExpression): what = tree[0] if what in scopable: @@ -52,30 +54,31 @@ class Mangle(object): scoped = True if isinstance(tree, list): - for element in tree: - self.visit(element) + for i, element in enumerate(tree): + nel = self.visit(element) + if nel: + tree[i] = nel + self.tree_changed() + self._mangle(element) if scoped: self.pop_scope() + self.pop_stack() def hoist(self, what): - #print "HOIST: " - #print " --> (fro) ", what - #print " --> (to) ", self.scope scope = self.scope - point = 0 - - if isinstance(scope, HyExpression) and len(scope): - if scope[0] == 'fn': - point = 2 - + for point, el in enumerate(scope): + if el in self.stack: + break self.scope.insert(point, what) - #print " --> (aft) ", self.scope def get_scope(self): return self.scopes[0] + def tree_changed(self): + raise self.TreeChanged() + @property def scope(self): return self.get_scope() @@ -83,14 +86,21 @@ class Mangle(object): def push_scope(self, tree): self.scopes.insert(0, tree) + def push_stack(self, tree): + self.stack.insert(0, tree) + def pop_scope(self): return self.scopes.pop(0) + def pop_stack(self): + return self.stack.pop(0) + def mangle(self, tree): unfinished = True while unfinished: self.root = tree self.scopes = [] + self.stack = [] self.push_scope(tree) try: self._mangle(tree)