Skip to content

Commit

Permalink
[BUG #5706] some re-naming for better legibility
Browse files Browse the repository at this point in the history
- inspired by Tom Lynn, http://bit.ly/GDBdG8
  • Loading branch information
thron7 committed Mar 21, 2012
1 parent 489fca7 commit d5e8d29
Showing 1 changed file with 55 additions and 51 deletions.
106 changes: 55 additions & 51 deletions tool/pylib/ecmascript/frontend/treegenerator.py
Expand Up @@ -38,6 +38,10 @@
# Greg Wilson, O'Reilly Media Inc. 2007, which reproduces Douglas' online
# article verbatim, states that readers are free to use the code from the book
# for their own programming without prior permission (p.xx).
#
# For reference with the original algorithm:
# led => ifix
# nud => pfix
##

import sys, os, re, types, string
Expand Down Expand Up @@ -291,10 +295,10 @@ def childappend(self, child):
self.children.append(child)
child.parent = self

def nud(self):
def pfix(self):
raise SyntaxException("Syntax error %r (pos %r)." % (self.id, (self.get("line"), self.get("column"))))

def led(self, left):
def ifix(self, left):
raise SyntaxException("Unknown operator %r (pos %r)." % (self.id, (self.get("line"), self.get("column"))))

def isVar(self):
Expand Down Expand Up @@ -451,7 +455,7 @@ def inForLoop(self):

# -- class factory ------------------

def symbol(id_, lbp=0):
def symbol(id_, bind_left=0):
try:
s = symbol_table[id_]
except KeyError:
Expand All @@ -461,27 +465,27 @@ class s(symbol_base):
s.type = id_ # compat with Node.type
s.id = id_
s.value = None
s.lbp = lbp
s.bind_left = bind_left
symbol_table[id_] = s
globals()[s.__name__] = s # ALERT: this is a devious hack to make Pickle pickle the symbol classes.
# To unpickle, it is necessary to have this module loaded, so the classes
# are ready.
else:
s.lbp = max(lbp, s.lbp)
s.bind_left = max(bind_left, s.bind_left)
return s

# helpers

def infix(id_, bp):
def led(self, left):
def ifix(self, left):
s = symbol("first")(token.get("line"), token.get("column"))
self.childappend(s)
s.childappend(left)
s = symbol("second")(token.get("line"), token.get("column"))
self.childappend(s)
s.childappend(expression(bp))
return self
symbol(id_, bp).led = led
symbol(id_, bp).ifix = ifix

def toJS(self):
r = u''
Expand Down Expand Up @@ -514,26 +518,26 @@ def toJS(self): # adapt the output
def infix_r(id_, bp):
infix(id_, bp)

def led(self, left):
def ifix(self, left):
s = symbol("first")(token.get("line"), token.get("column"))
self.childappend(s)
s.childappend(left)
s = symbol("second")(token.get("line"), token.get("column"))
self.childappend(s)
s.childappend(expression(bp-1))
return self
symbol(id_, bp).led = led
symbol(id_, bp).ifix = ifix


##
# prefix "sigil" operators, like '!', '~', ...
def prefix(id_, bp):
def nud(self):
def pfix(self):
s = symbol("first")(token.get("line"), token.get("column"))
self.childappend(s)
s.childappend(expression(bp-1)) # right-associative
return self
symbol(id_, bp).nud = nud
symbol(id_, bp).pfix = pfix

def toJS(self):
r = u''
Expand All @@ -546,12 +550,12 @@ def toJS(self):
##
# prefix "verb" operators, i.e. that need a space before their operand like 'delete'
def prefix_v(id_, bp):
def nud(self):
def pfix(self):
s = symbol("first")(token.get("line"), token.get("column"))
self.childappend(s)
s.childappend(expression(bp-1)) # right-associative
return self
symbol(id_, bp).nud = nud
symbol(id_, bp).pfix = pfix

def toJS(self):
r = u''
Expand All @@ -566,14 +570,14 @@ def preinfix(id_, bp): # pre-/infix operators (+, -)
infix(id_, bp) # init as infix op

##
# give them a nud() for prefix pos
def nud(self):
# give them a pfix() for prefix pos
def pfix(self):
self.set("left", "true") # mark prefix position
first = symbol("first")(token.get("line"), token.get("column"))
self.childappend(first)
first.childappend(expression(130)) # need to use prefix rbp!
return self
symbol(id_).nud = nud
symbol(id_).pfix = pfix

def toJS(self): # need to handle pre/infix cases
r = []
Expand All @@ -590,21 +594,21 @@ def toJS(self): # need to handle pre/infix cases


def prepostfix(id_, bp): # pre-/post-fix operators (++, --)
def nud(self): # prefix
def pfix(self): # prefix
self.set("left", "true")
s = symbol("first")(token.get("line"), token.get("column"))
self.childappend(s)
s.childappend(expression()) # overgenerating! only lvals allowed
return self
symbol(id_, bp).nud = nud
symbol(id_, bp).pfix = pfix

def led(self, left): # postfix
def ifix(self, left): # postfix
# assert(left, lval)
s = symbol("first")(token.get("line"), token.get("column"))
self.childappend(s)
s.childappend(left)
return self
symbol(id_).led = led
symbol(id_).ifix = ifix

def toJS(self):
r = u''
Expand Down Expand Up @@ -648,7 +652,7 @@ def bind(fn):
prepostfix("++", 140); prepostfix("--", 140) # pre/post increment (unary)

prefix("~", 130); prefix("!", 130)
#prefix("+", 130); prefix("-", 130) # higher than infix position! handled in preinfix.nud()
#prefix("+", 130); prefix("-", 130) # higher than infix position! handled in preinfix.pfix()
prefix_v("delete", 130); prefix_v("typeof", 130); prefix_v("void", 130)

prefix("/", 130) # regexp
Expand All @@ -672,7 +676,7 @@ def bind(fn):
infix("&&", 40)
infix("||", 30)

symbol("?", 20) # ternary operator (.led takes care of ':')
symbol("?", 20) # ternary operator (.ifix takes care of ':')

infix_r("=", 10) # assignment
infix_r("<<=",10); infix_r("-=", 10); infix_r("+=", 10); infix_r("*=", 10)
Expand All @@ -688,12 +692,12 @@ def bind(fn):
symbol("\\", 0) # escape char in strings ("\")


symbol("(unknown)").nud = lambda self: self
symbol("(unknown)").pfix = lambda self: self
symbol("eol")
symbol("eof")


symbol("constant").nud = lambda self: self
symbol("constant").pfix = lambda self: self

@method(symbol("constant"))
def toJS(self):
Expand All @@ -716,7 +720,7 @@ def toJS(self):
symbol("identifier")

@method(symbol("identifier"))
def nud(self):
def pfix(self):
return self

@method(symbol("identifier"))
Expand All @@ -729,8 +733,8 @@ def toJS(self):


@method(symbol("/")) # regexp literals
def nud(self):
# problem: "/".led() and "/".nud() return similar ASTs, e.g. with "/" as root
def pfix(self):
# problem: "/".ifix() and "/".pfix() return similar ASTs, e.g. with "/" as root
# and 2 childs; it is not clear from this AST whether it is division or literal regexp,
# and the types of the childs have to be inspected to decide this.

Expand All @@ -755,7 +759,7 @@ def nud(self):

# ternary op ?:
@method(symbol("?"))
def led(self, left):
def ifix(self, left):
# first
first = symbol("first")(token.get("line"), token.get("column"))
first.childappend(left)
Expand Down Expand Up @@ -799,7 +803,7 @@ def toJS(self):
# Node.isVar() method that returns true for those two node types.

@method(symbol("."))
def led(self, left):
def ifix(self, left):
if token.id != "identifier":
SyntaxException("Expected an attribute name (pos %r)." % ((token.get("line"), token.get("column")),))
#variable = symbol("variable")(token.get("line"), token.get("column"))
Expand All @@ -817,7 +821,7 @@ def led(self, left):
s.childappend(left)
s = symbol("second")(token.get("line"), token.get("column"))
accessor.childappend(s)
s.childappend(expression(symbol(".").lbp))
s.childappend(expression(symbol(".").bind_left))
# i'm providing the rbp to expression() here explicitly, so "foo.bar(baz)" gets parsed
# as (call (dotaccessor ...) (param baz)), and not (dotaccessor foo
# (call bar (param baz))).
Expand Down Expand Up @@ -864,7 +868,7 @@ def getHighestPureDotParent(self):

def constant(id):
@method(symbol(id))
def nud(self):
def pfix(self):
self.id = "constant"
self.value = id
return self
Expand All @@ -878,7 +882,7 @@ def nud(self):
symbol("("), symbol(")")

@method(symbol("(")) # <call>
def led(self, left):
def ifix(self, left):
call = symbol("call")(token.get("line"), token.get("column"))
# operand
operand = symbol("operand")(token.get("line"), token.get("column"))
Expand All @@ -887,7 +891,7 @@ def led(self, left):
# params - parse as group
params = symbol("params")(token.get("line"), token.get("column"))
call.childappend(params)
group = self.nud()
group = self.pfix()
for c in group.children:
params.childappend(c)
return call
Expand All @@ -900,7 +904,7 @@ def toJS(self):


@method(symbol("(")) # <group>
def nud(self):
def pfix(self):
comma = False
group = symbol("group")(token.get("line"), token.get("column"))
if token.id != ")":
Expand Down Expand Up @@ -929,7 +933,7 @@ def toJS(self):
symbol("]")

@method(symbol("[")) # "foo[0]", "foo[bar]", "foo['baz']"
def led(self, left):
def ifix(self, left):
accessor = symbol("accessor")(token.get("line"), token.get("column"))
# identifier
accessor.childappend(left)
Expand All @@ -941,7 +945,7 @@ def led(self, left):
return accessor

@method(symbol("["))
def nud(self):
def pfix(self):
arr = symbol("array")(token.get("line"), token.get("column"))
if token.id != "]":
while True:
Expand Down Expand Up @@ -986,7 +990,7 @@ def toJS(self):
symbol("}")

@method(symbol("{")) # object literals
def nud(self):
def pfix(self):
mmap = symbol("map")(token.get("line"), token.get("column"))
if token.id != "}":
while True:
Expand Down Expand Up @@ -1078,7 +1082,7 @@ def toJS(self):
symbol("function")

@method(symbol("function"))
def nud(self):
def pfix(self):
# optional name
if token.id == "identifier":
#self.childappend(token.get("value"))
Expand Down Expand Up @@ -1161,7 +1165,7 @@ def toJS(self):
#
@method(symbol("var"))
#def std(self):
def nud(self):
def pfix(self):
vardecl = symbol("definitionList")(token.get("line"), token.get("column"))
while True:
var = symbol("definition")(token.get("line"), token.get("column"))
Expand All @@ -1176,7 +1180,7 @@ def nud(self):
if token.id == "=": # initialization
t = token
advance()
defn = t.led(n)
defn = t.ifix(n)
else:
defn = n
var.childappend(defn)
Expand All @@ -1187,11 +1191,11 @@ def nud(self):
return vardecl


# but "var" also needs a nud method, since it can appear in expressions
#symbol("var").nud = symbol("var").std
# but "var" also needs a pfix method, since it can appear in expressions
#symbol("var").pfix = symbol("var").std

#@method(symbol("var"))
#def nud(self):
#def pfix(self):
# while True:
# n = token
# if n.id != "identifier":
Expand Down Expand Up @@ -1316,7 +1320,7 @@ def std(self):
# advance("var")
# defn = symbol("definition")(token.get("line"), token.get("column"))
# var_s.childappend(defn)
# defn.childappend(expression(95)) # lbp higher than "in"
# defn.childappend(expression(95)) # bind_left higher than "in"
# else:
# #ident = symbol("identifier")(token.get("line"), token.get("column"))
# #op_first.childappend(ident)
Expand Down Expand Up @@ -1640,14 +1644,14 @@ def toJS(self):


@method(symbol("new")) # need to treat 'new' explicitly, for the awkward 'new Foo()' "call" syntax
def nud(self):
def pfix(self):
s = symbol("first")(token.get("line"), token.get("column"))
self.childappend(s)
arg = expression(self.lbp-1) # first, parse a normal expression (this excludes '()')
arg = expression(self.bind_left-1) # first, parse a normal expression (this excludes '()')
if token.id == '(': # if the next token indicates a call
t = token
advance("(")
arg = t.led(left=arg) # invoke '('.led, with class name as <left> arg
arg = t.ifix(left=arg) # invoke '('.ifix, with class name as <left> arg
s.childappend(arg)
return self

Expand Down Expand Up @@ -1801,15 +1805,15 @@ def std(self):
self.childappend(block())


def expression(rbp=0):
def expression(bind_right=0):
global token
t = token
token = next()
left = t.nud()
while rbp < token.lbp:
left = t.pfix()
while token.bind_left > bind_right:
t = token
token = next()
left = t.led(left)
left = t.ifix(left)
return left


Expand Down

0 comments on commit d5e8d29

Please sign in to comment.