📄 narcissus.py
字号:
print 'Advancing cursor by',len(match.group(0)) + cursor_advance
self.cursor += len(match.group(0)) + cursor_advance
# # print self.cursor
token.end = self.cursor
# # print token.end
token.lineno = self.lineno
# # print token.lineno
print 'Returning',token.type
return token.type
def unget(self):
self.lookahead += 1
if self.lookahead == 4:
raise NarcissusError("PANIC: too much lookahead!", self)
self.tokenIndex = (self.tokenIndex - 1) & 3
return None
class NarcissusError(Exception):
def __init__(self, msg, tokenizer):
self.msg = msg
self.line = str(tokenizer.lineno)
def __str__(self):
return '\n'.join((self.msg, "on line " + self.line))
class Token(object):
__slots__ = ['type','value','start','end','assignOp','lineno']
def __init__(self):
self.type = None
self.value = None
self.start = None
self.end = None
self.assignOp = None
self.lineno = None
def lower(self):
return self.value.lower()
class CompilerContext(object):
__slots__ = ['inFunction', 'stmtStack','funDecls','varDecls',
'bracketLevel','curlyLevel','parenLevel','hookLevel',
'ecmaStrictMode','inForLoopInit']
def __init__(self, inFunction):
self.inFunction = inFunction
self.stmtStack = []
self.funDecls = []
self.varDecls = []
self.bracketLevel = self.curlyLevel = self.parenLevel = self.hookLevel = 0
self.ecmaStrictMode = self.inForLoopInit = False
CURSOR = 0
IND = 0
# class Node => TODO
class Node(list):
__slots__ = ['type','value','lineno','start','end','tokenizer','initializer',
'name','params','funDecls','varDecls', 'body', 'functionForm',
'assignOp', 'expression', 'condition', 'thenPart', 'elsePart',
'readOnly', 'isLoop', 'setup', 'postfix', 'update', 'exception',
'object', 'iterator', 'varDecl', 'label', 'target', 'tryBlock',
'catchClauses', 'varName', 'guard', 'block', 'discriminant', 'cases',
'defaultIndex', 'caseLabel', 'statements', 'statement','children']
def __init__(self, t, type=None):
# Blanket initialize all params
for var in self.__class__.__slots__:
setattr(self, var, None)
token = t.token()
# # print 'token=>',token
if token:
if type:
self.type = type
else:
self.type = token.type
self.value = token.value
self.lineno = token.lineno
self.start = token.start
self.end = token.end
else:
self.type = type
self.lineno = t.lineno
# T is the Tokenizer instance
self.tokenizer = t
# Always use push$ to add operands to an expression, to update start and end.
def append(self, kid):
# print "Pushing...", kid.__class__, kid.type
if kid.start and self.start:
if kid.start < self.start:
self.start = kid.start
if kid.end and self.end:
if self.end < kid.end:
self.end = kid.end
return super(Node, self).append(kid)
push = append
def __str__(self):
s = ''
attrs = [self.value, self.lineno, self.start, self.end,
self.name, self.params, self.funDecls, self.varDecls,
self.body, self.functionForm, self.assignOp, self.expression,
self.condition, self.thenPart, self.elsePart ]
global IND
IND += 1
for x in range(len(self)):
item = self[x]
if item != self and isinstance(item, Node):
s = s + str(item)
for x in range(len(attrs)):
# Some commented out code here, not adding it
item = attrs[x]
if isinstance(item, Node):
s = s + str(item)
IND -= 1
if IND == 0:
print self.tokenizer.source[CURSOR:],
return ""
def getSource(self):
return self.tokenizer.source[self.start:self.start+self.end]
def filename(self):
return self.tokenizer.filename
def Script(t, x):
n = Statements(t, x)
n.type = consts["SCRIPT"]
n.funDecls = x.funDecls
n.varDecls = x.varDecls
return n
# Statement stack and nested statement handler.
# nb. Narcissus allowed a function reference, here we use Statement explicitly
def nest(t, x, node, end_ = None):
x.stmtStack.append(node)
n = Statement(t, x)
x.stmtStack.pop()
if end_:
t.mustMatch(end_)
return n
def Statements(t, x):
n = Node(t, consts["BLOCK"])
x.stmtStack.append(n)
while (not t.done()) and (t.peek() != consts["RIGHT_CURLY"]):
# print 'Loop'
# # print 'Starting to push'
s = Statement(t, x)
# print 'Type =>',s.type
n.push(s)
# # print "Push ended"
x.stmtStack.pop()
return n
def Block(t, x):
t.mustMatch(consts["LEFT_CURLY"])
n = Statements(t, x)
t.mustMatch(consts["RIGHT_CURLY"])
return n
DECLARED_FORM = 0
EXPRESSED_FORM = 1
STATEMENT_FORM = 2
def Statement(t, x):
# Cases for statements ending in a right curly return early, avoiding the
# common semicolon insertion magic after this switch.
# t is an instance of Tokenizer
tt = t.get()
print 'TT is',tt
if tt == consts["FUNCTION"]:
print 'TT is a function', consts["FUNCTION"]
return FunctionDefinition(t, x, True,
(len(x.stmtStack) > 1) and STATEMENT_FORM or DECLARED_FORM)
elif tt == consts["LEFT_CURLY"]:
n = Statements(t, x)
t.mustMatch(consts["RIGHT_CURLY"])
return n
elif tt == consts["IF"]:
n = Node(t)
n.condition = ParenExpression(t, x)
x.stmtStack.append(n)
n.thenPart = Statement(t, x)
if t.match(consts["ELSE"]):
n.elsePart = Statement(t, x)
else:
n.elsePart = None
x.stmtStack.pop()
return n
elif tt == consts["SWITCH"]:
n = Node(t)
t.mustMatch(consts["LEFT_PAREN"])
n.discriminant = Expression(t, x)
t.mustMatch(consts["RIGHT_PAREN"])
n.cases = []
n.defaultIndex = -1
x.stmtStack.append(n)
t.mustMatch(consts["LEFT_CURLY"])
while True:
tt = t.get()
print 'TT IS',tt
if tt == consts["RIGHT_CURLY"]: break
if tt == consts["DEFAULT"] or tt == consts["CASE"]:
if tt == consts["DEFAULT"] and n.defaultIndex >= 0:
raise NarcissusError("More than one switch default", t)
n2 = Node(t)
if tt == consts["DEFAULT"]:
n.defaultIndex = len(n.cases)
else:
n2.caseLabel = Expression(t, x, consts["COLON"])
else:
raise NarcissusError("Invalid switch case", t)
t.mustMatch(consts["COLON"])
n2.statements = Node(t, consts["BLOCK"])
while True:
tt = t.peek()
if (tt == consts["CASE"]) or \
(tt==consts["DEFAULT"]) or \
(tt==consts["RIGHT_CURLY"]):
break
print 'Yeah dude!'
n2.statements.append(Statement(t, x))
n.cases.append(n2)
# End of while...
x.stmtStack.pop()
return n
elif tt == consts["FOR"]:
n = Node(t)
n.isLoop = True
n2 = None
t.mustMatch(consts["LEFT_PAREN"])
tt = t.peek()
if tt != consts["SEMICOLON"]:
x.inForLoopInit = True
if tt == consts["VAR"] or tt == consts["CONST"]:
print 'Got',t.get()
n2 = Variables(t, x)
else:
n2 = Expression(t, x)
x.inForLoopInit = False
if n2 and t.match(consts["IN"]):
n.type = consts["FOR_IN"]
if n2.type == consts["VAR"]:
if len(n2) != 1:
raise NarcissusError("Invalid for..in left-hand side", t)
n.iterator = n2[0]
n.varDecl = n2
else:
n.iterator = n2
n.varDecl = None
n.object = Expression(t, x)
else:
n.setup = n2 or None
t.mustMatch(consts["SEMICOLON"])
if (t.peek() == consts["SEMICOLON"]):
n.condition = None
else:
n.condition = Expression(t, x)
t.mustMatch(consts["SEMICOLON"])
if (t.peek() == consts["RIGHT_PAREN"]):
n.update = None
else:
n.update = Expression(t, x)
t.mustMatch(consts["RIGHT_PAREN"])
n.body = nest(t, x, n)
return n
elif tt == consts["WHILE"]:
n = Node(t)
n.isLoop = True
n.condition = ParenExpression(t, x)
n.body = nest(t, x, n)
return n
elif tt == consts["DO"]:
n = Node(t)
n.isLoop = True
n.body = nest(t, x, n, consts["WHILE"])
n.condition = ParenExpression(t, x)
if not x.ecmaStrictMode:
# <script language="JavaScript"> (without version hints) may need
# automatic semicolon insertion without a newline after do-while.
# See http://bugzilla.mozilla.org/show_bug.cgi?id=238945.
t.match(consts["SEMICOLON"])
return n
elif (tt == consts["BREAK"]) or (tt == consts["CONTINUE"]):
n = Node(t)
if t.peekOnSameLine() == consts["IDENTIFIER"]:
print 'Gewt',t.get()
n.label = t.token().value
ss = x.stmtStack
i = len(ss)
label = n.label
if label:
while True:
i -= 1
if i < 0:
raise NarcissusError("Label not found", t)
if (ss[i].label != label): break
else:
while True:
i -= 1
if i<0:
if tt == consts["BREAK"]:
raise NarcissusError("Invalid break", t)
else:
raise NarcissusError("Invalid continue", t)
if ss[i].isLoop or (tt==consts["BREAK"] and ss[i].type == consts["SWITCH"]):
break
n.target = ss[i]
elif tt == consts["TRY"]:
n = Node(t)
n.tryBlock = Block(t, x)
n.catchClauses = List2()
while t.match(consts["CATCH"]):
n2 = Node(t)
t.mustMatch(consts["LEFT_PAREN"])
n2.varName = t.mustMatch(consts["IDENTIFIER"]).value
if t.match(consts["IF"]):
if x.ecmaStrictMode:
raise NarcissusError("Illegal catch guard", t)
if len(n.catchClauses) and (not n.catchClauses.last().guard):
raise NarcissusError("Guarded catch after unguarded", t)
n2.guard = Expression(t, x)
else:
n2.guard = None
t.mustMatch(consts["RIGHT_PAREN"])
n2.block = Block(t, x)
n.catchClauses.append(n2)
if t.match(consts["FINALLY"]):
n.finallyBlock = Block(t, x)
if (not len(n.catchClauses)) and (not n.finallyBlock):
raise NarcissusError("Invalid try statement", t)
return n
elif tt == consts["CATCH"]:
pass
elif tt == consts["FINALLY"]:
raise NarcissusError(str(tokens[tt]) + " without preceding try", t)
elif tt == consts["THROW"]:
n = Node(t)
n.exception = Expression(t, x)
elif tt == consts["RETURN"]:
print 'In Return'
if not x.inFunction:
raise NarcissusError("Invalid return", t)
n = Node(t)
tt = t.peekOnSameLine()
if (tt != consts["END"]) and \
(tt != consts["NEWLINE"]) and \
(tt != consts["SEMICOLON"]) and \
(tt != consts["RIGHT_CURLY"]):
print 'Okay!'
n.value = Expression(t, x)
print "Val => " + str(n.value)
elif tt == consts["WITH"]:
n = Node(t)
n.object = ParenExpression(t, x)
n.body = nest(t, x, n)
return n
elif (tt == consts["VAR"]) or (tt==consts["CONST"]):
n = Variables(t, x)
elif tt == consts["DEBUGGER"]:
n = Node(t)
elif (tt==consts["NEWLINE"]) or (tt==consts["SEMICOLON"]):
print 'out here'
n = Node(t, consts["SEMICOLON"])
n.expression = None
return n
else:
# # print 'out there'
if (tt==consts["IDENTIFIER"]) and (t.peek() == consts["COLON"]):
label = t.token().value
ss = x.stmtStack
for x in range(len(ss)-1):
if ss[i].label == label:
raise NarcissusError("Duplicate label", t)
print 'GAWT',t.get()
n = Node(t, consts["LABEL"])
n.label = label
n.statement = nest(t, x, n)
return n
t.unget()
n = Node(t, consts["SEMICOLON"])
n.expression = Expression(t, x)
n.end = n.expression.end
if t.lineno == t.token().lineno:
tt = t.peekOnSameLine()
print 'TT*=>',tt
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -