def __init__(self, code, options={}, delegate=None) : self.ErrorHandler=ErrorHandler() self.Scanner=Scanner(code, self.ErrorHandler) self.Node= Node() #节点创建 self.LookAhead=RawToken(type=2, value='', lineNumber=self.Scanner.LineNumber, lineStart=0, start=0, end=0 ) self.HasLineTerminator=False self.Context = Context(isModule=False, allowAwait=False, allowIn=True, allowStrictDirective=True, allowYield= True, firstCoverInitializedNameError=None, isAssignmentTarget=False, isBindingElement=False, inFunctionBody=False, inIteration=False,inSwitch=False, labelSet= {}, strict=False) self.OperatorPrecedence = { ')': 0, ';': 0, ',': 0, ']': 0, '||': 1, 'OR':1, '&&': 2, 'AND':2, '|': 3, '^': 4, '&': 5, '==': 6, '!=': 6, '<>': 6, '===': 6, '=': 6, '!==': 6, '<': 7, '>': 7, '<=': 7, '>=': 7, '<<': 8, '>>': 8, '>>>': 8, '+': 9, '-': 9, '*': 11, '/': 11, '%': 11, } self.StartMarker = Marker(index=0, line=self.Scanner.LineNumber, column=0) self.LastMarker = Marker(index=0, line=self.Scanner.LineNumber, column=0)
def __init__(self, ast, option=None) : self.AST=ast # 语法树 self.ErrorHandler=ErrorHandler() self.VarTable={} # 变量表 self.OutVarTable=[] # 输出变量 self.Arguments=[] # 脚本自动变量表, 只读 self.ConstVarTable={ # 个股数据 'CLOSE':None, 'VOL':None, 'OPEN':None, 'HIGH':None, 'LOW':None, 'AMOUNT':None, 'C':None, 'V':None, 'O':None, 'H':None, 'L':None, 'VOLR':None, # 日期类 'DATE':None, 'YEAR':None, 'MONTH':None, 'PERIOD':None, 'WEEK':None, # 大盘数据 'INDEXA':None, 'INDEXC':None, 'INDEXH':None, 'INDEXL':None, 'INDEXO':None, 'INDEXV':None, 'INDEXADV':None, 'INDEXDEC':None, # 到最后交易日的周期数 'CURRBARSCOUNT':None, # 流通股本(手) 'CAPITAL':None, # 换手率 'EXCHANGE':None, 'SETCODE':None } if option and option.ProcCreateSymbolData: self.SymbolData=option.ProcCreateSymbolData(ast=ast,option=option, procThrow=self.ThrowUnexpectedNode) else : self.SymbolData=JSSymbolData(ast=ast,option=option, procThrow=self.ThrowUnexpectedNode) self.Algorithm=JSAlgorithm(errorHandler=self.ErrorHandler,symbolData=self.SymbolData) self.Draw=JSDraw(errorHandler=self.ErrorHandler,symbolData=self.SymbolData) self.JobList=[] # 执行的任务队列 if option and option.Arguments: self.Arguments=option.Arguments
class JSExecute: def __init__(self, ast, option=None): self.AST = ast # 语法树 self.ErrorHandler = ErrorHandler() self.VarTable = {} # 变量表 self.OutVarTable = [] # 输出变量 self.Arguments = [] # 脚本自动变量表, 只读 self.ConstVarTable = { # 个股数据 'CLOSE': None, 'VOL': None, 'OPEN': None, 'HIGH': None, 'LOW': None, 'AMOUNT': None, 'C': None, 'V': None, 'O': None, 'H': None, 'L': None, 'VOLR': None, # 日期类 'DATE': None, 'YEAR': None, 'MONTH': None, 'PERIOD': None, 'WEEK': None, # 大盘数据 'INDEXA': None, 'INDEXC': None, 'INDEXH': None, 'INDEXL': None, 'INDEXO': None, 'INDEXV': None, 'INDEXADV': None, 'INDEXDEC': None, # 到最后交易日的周期数 'CURRBARSCOUNT': None, # 流通股本(手) 'CAPITAL': None, # 换手率 'EXCHANGE': None, 'SETCODE': None } self.SymbolData = JSSymbolData(ast=ast, option=option, procThrow=self.ThrowUnexpectedNode) self.Algorithm = JSAlgorithm(errorHandler=self.ErrorHandler, symbolData=self.SymbolData) self.Draw = JSDraw(errorHandler=self.ErrorHandler, symbolData=self.SymbolData) self.JobList = [] # 执行的任务队列 if option and option.Arguments: self.Arguments = option.Arguments def Execute(self): self.SymbolData.RunDownloadJob(self.JobList) # 准备数据 outVar = self.RunAST() return outVar def ReadSymbolData(self, name, node): if name in ('CLOSE', 'C', 'VOL', 'V', 'OPEN', 'O', 'HIGH', 'H', 'LOW', 'L', 'AMOUNT'): return self.SymbolData.GetSymbolCacheData(name) elif name == 'VOLR': # 量比 pass # return self.SymbolData.GetVolRateCacheData(node) elif name in ('INDEXA', 'INDEXC', 'INDEXH', 'INDEXO', 'INDEXV', 'INDEXL', 'INDEXADV', 'INDEXDEC'): # 大盘数据 return self.SymbolData.GetIndexCacheData(name) elif name == 'CURRBARSCOUNT': pass # return self.SymbolData.GetCurrBarsCount() elif name == 'CAPITAL': return self.SymbolData.GetFinanceCacheData( JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_CAPITAL_DATA, node=node) elif name == 'EXCHANGE': return self.SymbolData.GetFinanceCacheData( JS_EXECUTE_JOB_ID.JOB_DOWNLOAD_EXCHANGE_DATA, node=node) elif name == 'SETCODE': return self.SymbolData.SETCODE() elif name == 'DATE': return self.SymbolData.DATE() elif name == 'YEAR': return self.SymbolData.YEAR() elif name == 'MONTH': return self.SymbolData.MONTH() elif name == 'WEEK': return self.SymbolData.WEEK() elif name == 'PERIOD': return self.SymbolData.PERIOD() # 读取变量 def ReadVariable(self, name, node): if name in self.ConstVarTable: data = self.ConstVarTable[name] if not data: # 动态加载,用到再加载 data = self.ReadSymbolData(name, node) self.ConstVarTable[name] = data return data if name in self.VarTable: return self.VarTable[name] self.ThrowUnexpectedNode(node, '变量' + name + '不存在') return None # 单数据转成数组 个数和历史数据一致 def SingleDataToArrayData(self, value): count = len(self.SymbolData.Data.Data) result = [value] * count return result def RunAST(self): # 预定义的变量 for item in self.Arguments: self.VarTable[item.Name] = item.Value if not self.AST or not self.AST.Body: self.ThrowError() for item in self.AST.Body: self.VisitNode(item) if item.Type == Syntax.ExpressionStatement and item.Expression: if item.Expression.Type == Syntax.AssignmentExpression and item.Expression.Operator == ':' and item.Expression.Left: assignmentItem = item.Expression varName = assignmentItem.Left.Name outVar = self.VarTable[varName] if not isinstance(outVar, list): outVar = self.SingleDataToArrayData(outVar) self.OutVarTable.append( OutVariable(name=varName, data=outVar, type=0)) elif (item.Expression.Type == Syntax.CallExpression): callItem = item.Expression if (JSDraw.IsDrawFunction(callItem.Callee.Name)): draw = callItem.Draw draw.Name = callItem.Callee.Name self.OutVarTable.append( OutVariable(name=draw.Name, draw=draw, type=1)) elif (item.Expression.Type == Syntax.SequenceExpression): varName = None draw = None color = None lineWidth = None colorStick = False pointDot = False circleDot = False lineStick = False stick = False volStick = False isShow = True isExData = False for itemExpression in item.Expression.Expression: if (itemExpression.Type == Syntax.AssignmentExpression and itemExpression.Operator == ':' and itemExpression.Left): varName = itemExpression.Left.Name varValue = self.VarTable[varName] if not JSComplierHelper.IsArray(varValue): varValue = self.SingleDataToArrayData(varValue) self.VarTable[ varName] = varValue # 把单数值转化成数组放到变量表里 elif (itemExpression.Type == Syntax.Identifier): value = itemExpression.Name if (value == 'COLORSTICK'): colorStick = True elif (value == 'POINTDOT'): pointDot = True elif (value == 'CIRCLEDOT'): circleDot = True elif (value == 'LINESTICK'): lineStick = True elif (value == 'STICK'): stick = True elif (value == 'VOLSTICK'): volStick = True elif (value.find('COLOR') == 0): color = value elif (value.find('LINETHICK') == 0): lineWidth = value elif (value.find('NODRAW') == 0): isShow = False elif (value.find('EXDATA') == 0): isExData = True # 扩展数据, 不显示再图形里面 elif (itemExpression.Type == Syntax.Literal): #常量 aryValue = self.SingleDataToArrayData( itemExpression.Value) varName = str(itemExpression.Value) self.VarTable[varName, aryValue] # 把常量放到变量表里 elif (itemExpression.Type == Syntax.CallExpression and JSDraw.IsDrawFunction( itemExpression.Callee.Name)): draw = itemExpression.Draw draw.Name = itemExpression.Callee.Name if (pointDot and varName): # 圆点 outVar = self.VarTable[varName] if (not JSComplierHelper.IsArray(outVar)): outVar = self.SingleDataToArrayData(outVar) value = OutVariable(name=varName, data=outVar, type=3) value.Radius = 2 if color: value.Color = color if lineWidth: value.LineWidth = lineWidth self.OutVarTable.append(value) elif (circleDot and varName): # 圆点 outVar = self.VarTable[varName] if not JSComplierHelper.IsArray(outVar): outVar = self.SingleDataToArrayData(outVar) value = OutVariable(name=varName, data=outVar, type=3) value.Radius = 1.3 if color: value.Color = color if lineWidth: value.LineWidth = lineWidth self.OutVarTable.append(value) elif (lineStick and varName): # LINESTICK 同时画出柱状线和指标线 outVar = self.VarTable[varName] value = OutVariable(name=varName, data=outVar, type=4) if color: value.Color = color if lineWidth: value.LineWidth = lineWidth self.OutVarTable.append(value) elif (stick and varName): # STICK 画柱状线 outVar = self.VarTable[varName] value = OutVariable(name=varName, data=outVar, type=5) if color: value.Color = color if lineWidth: value.LineWidth = lineWidth self.OutVarTable.append(value) elif (volStick and varName): # VOLSTICK 画彩色柱状线 outVar = self.VarTable[varName] value = OutVariable(name=varName, data=outVar, type=6) if color: value.Color = color self.OutVarTable.append(value) elif (varName and color): outVar = self.VarTable[varName] if not JSComplierHelper.IsArray(outVar): outVar = self.SingleDataToArrayData(outVar) value = OutVariable(name=varName, data=outVar, type=0) value.Color = color if (lineWidth): value.LineWidth = lineWidth if (isShow == False): value.IsShow = False if (isExData == True): value.IsExData = True self.OutVarTable.append(value) elif (draw and color): value = OutVariable(name=draw.Name, data=draw, type=1) value.Color = color self.OutVarTable.append(value) elif (colorStick and varName ): # CYW: SUM(VAR4,10)/10000, COLORSTICK; 画上下柱子 outVar = self.VarTable[varName] value = OutVariable(name=varName, data=outVar, type=2) value.Color = color self.OutVarTable.append(value) elif (varName): outVar = self.VarTable[varName] value = OutVariable(name=varName, data=outVar, type=0) if color: value.Color = color if lineWidth: value.LineWidth = lineWidth if isShow == False: value.IsShow = False if isExData == True: value.IsExData = True self.OutVarTable.append(value) return self.OutVarTable def VisitNode(self, node): if node.Type == Syntax.SequenceExpression: self.VisitSequenceExpression(node) elif node.Type == Syntax.ExpressionStatement: self.VisitNode(node.Expression) elif node.Type == Syntax.AssignmentExpression: self.VisitAssignmentExpression(node) elif node.Type in (Syntax.BinaryExpression, Syntax.LogicalExpression): self.VisitBinaryExpression(node) elif node.Type == Syntax.CallExpression: self.VisitCallExpression(node) def VisitSequenceExpression(self, node): for item in node.Expression: self.VisitNode(item) # 函数调用 def VisitCallExpression(self, node): funcName = node.Callee.Name args = [] for item in node.Arguments: if item.Type == Syntax.BinaryExpression or item.Type == Syntax.LogicalExpression: value = self.VisitBinaryExpression(item) elif item.Type == Syntax.CallExpression: value = self.VisitCallExpression(item) else: value = self.GetNodeValue(item) args.append(value) # console.log('[JSExecute::VisitCallExpression]' , funcName, '(', args.toString() ,')'); if funcName == 'DYNAINFO': # 行情最新数据 node.Out = self.SymbolData.GetLatestCacheData(int(args[0])) elif funcName == 'STICKLINE': node.Draw = self.Draw.STICKLINE(args[0], args[1], args[2], args[3], args[4]) node.Out = [] elif funcName == 'DRAWTEXT': node.Draw = self.Draw.DRAWTEXT(args[0], args[1], args[2]) node.Out = [] elif funcName == 'SUPERDRAWTEXT': node.Draw = self.Draw.SUPERDRAWTEXT(args[0], args[1], args[2], args[3], args[4]) node.Out = [] elif funcName == 'DRAWICON': node.Draw = self.Draw.DRAWICON(args[0], args[1], int(args[2])) node.Out = [] elif funcName == 'DRAWLINE': node.Draw = self.Draw.DRAWLINE(args[0], args[1], args[2], args[3], int(args[4])) node.Out = node.Draw.DrawData elif funcName == 'DRAWBAND': node.Draw = self.Draw.DRAWBAND(args[0], args[1], args[2], args[3]) node.Out = [] elif funcName == 'DRAWKLINE': node.Draw = self.Draw.DRAWKLINE(args[0], args[1], args[2], args[3]) node.Out = [] elif funcName == 'DRAWKLINE_IF': node.Draw = self.Draw.DRAWKLINE_IF(args[0], args[1], args[2], args[3], args[4]) node.Out = [] elif funcName in ('PLOYLINE', 'POLYLINE'): node.Draw = self.Draw.POLYLINE(args[0], args[1]) node.Out = node.Draw.DrawData elif funcName == 'DRAWNUMBER': node.Draw = self.Draw.DRAWNUMBER(args[0], args[1], args[2]) node.Out = node.Draw.DrawData.Value elif funcName == "DRAWCHANNEL": node.Draw = self.Draw.DRAWCHANNEL(args[0], args[1], args[2], args[3], int(args[4]), args[5], args[6]) node.Out = [] elif funcName == 'CODELIKE': node.Out = self.SymbolData.CODELIKE(args[0]) elif funcName == 'NAMELIKE': node.Out = self.SymbolData.NAMELIKE(args[0]) elif funcName == 'REFDATE': node.Out = self.SymbolData.REFDATE(args[0], args[1]) elif funcName == 'FINANCE': node.Out = self.SymbolData.GetFinanceCacheData(args[0], node) elif funcName == "MARGIN": node.Out = self.SymbolData.GetMarginCacheData(int(args[0]), node) elif funcName == "HK2SHSZ": node.Out = self.SymbolData.GetHKToSHSZCacheData(args[0], node) elif funcName == "NEWS": node.Out = self.SymbolData.GetNewsAnalysisCacheData(args[0], node) elif funcName in ('UPCOUNT', 'DOWNCOUNT'): node.Out = self.SymbolData.GetIndexIncreaseCacheData( funcName, args[0], node) else: node.Out = self.Algorithm.CallFunction(funcName, args, node) return node.Out # 赋值 def VisitAssignmentExpression(self, node): left = node.Left if left.Type != Syntax.Identifier: self.ThrowUnexpectedNode(node) varName = left.Name right = node.Right value = None if right.Type == Syntax.BinaryExpression or right.Type == Syntax.LogicalExpression: value = self.VisitBinaryExpression(right) elif right.Type == Syntax.CallExpression: value = self.VisitCallExpression(right) elif right.Type == Syntax.Literal: value = right.Value elif right.Type == Syntax.Identifier: # 右值是变量 value = self.ReadVariable(right.Name, right) # console.log('[JSExecute::VisitAssignmentExpression]' , varName, ' = ',value); self.VarTable[varName] = value # 逻辑运算 def VisitBinaryExpression(self, node): stack = [] stack.append(node) temp = None while len(stack) != 0: temp = stack[-1] if isinstance( temp, (BinaryExpression, AssignmentExpression )) and temp.Left and node != temp.Left and node != temp.Right: stack.append(temp.Left) elif isinstance( temp, (BinaryExpression, AssignmentExpression)) and temp.Right and node != temp.Right: stack.append(temp.Right) else: value = stack.pop() if value.Type == Syntax.BinaryExpression: # 只遍历操作符就可以 leftValue = self.GetNodeValue(value.Left) rightValue = self.GetNodeValue(value.Right) # console.log('[JSExecute::VisitBinaryExpression] BinaryExpression',value , leftValue, rightValue); value.Out = None # 保存中间值 if value.Operator == '-': value.Out = self.Algorithm.Subtract( leftValue, rightValue) elif value.Operator == '*': value.Out = self.Algorithm.Multiply( leftValue, rightValue) elif value.Operator == '/': value.Out = self.Algorithm.Divide( leftValue, rightValue) elif value.Operator == '+': value.Out = self.Algorithm.Add(leftValue, rightValue) elif value.Operator == '>': value.Out = self.Algorithm.GT(leftValue, rightValue) elif value.Operator == '>=': value.Out = self.Algorithm.GTE(leftValue, rightValue) elif value.Operator == '<': value.Out = self.Algorithm.LT(leftValue, rightValue) elif value.Operator == '<=': value.Out = self.Algorithm.LTE(leftValue, rightValue) elif value.Operator in ('=', '=='): value.Out = self.Algorithm.EQ(leftValue, rightValue) elif value.Operator in ('!=', '<>'): value.Out = self.Algorithm.NEQ(leftValue, rightValue) # console.log('[JSExecute::VisitBinaryExpression] BinaryExpression',value); elif value.Type == Syntax.LogicalExpression: leftValue = self.GetNodeValue(value.Left) rightValue = self.GetNodeValue(value.Right) # console.log('[JSExecute::VisitBinaryExpression] LogicalExpression',value , leftValue, rightValue); value.Out = None # 保存中间值 if value.Operator in ('&&', 'AND'): value.Out = self.Algorithm.And(leftValue, rightValue) elif value.Operator in ('||', 'OR'): value.Out = self.Algorithm.Or(leftValue, rightValue) # console.log('[JSExecute::VisitBinaryExpression] LogicalExpression',value); node = temp return node.Out def GetNodeValue(self, node): if node.Type == Syntax.Literal: #数字 return node.Value elif node.Type == Syntax.UnaryExpression: if node.Operator == '-': value = self.GetNodeValue(node.Argument) return self.Algorithm.Subtract(0, value) return node.Argument.Value elif node.Type == Syntax.Identifier: value = self.ReadVariable(node.Name, node) return value elif node.Type in (Syntax.BinaryExpression, Syntax.LogicalExpression): return node.Out elif node.Type == Syntax.CallExpression: return self.VisitCallExpression(node) else: self.ThrowUnexpectedNode(node) def ThrowUnexpectedNode(self, node, message="执行异常"): marker = node.Marker msg = message return self.ErrorHandler.ThrowError(marker.Index, marker.Line, marker.Column, msg) def ThrowError(self): pass
def __init__(self, code) : self.ErrorHandler=ErrorHandler() #错误信息处理类 self.Scanner=Scanner(code,self.ErrorHandler) self.Buffer=[]
class JSParser: def __init__(self, code, options={}, delegate=None) : self.ErrorHandler=ErrorHandler() self.Scanner=Scanner(code, self.ErrorHandler) self.Node= Node() #节点创建 self.LookAhead=RawToken(type=2, value='', lineNumber=self.Scanner.LineNumber, lineStart=0, start=0, end=0 ) self.HasLineTerminator=False self.Context = Context(isModule=False, allowAwait=False, allowIn=True, allowStrictDirective=True, allowYield= True, firstCoverInitializedNameError=None, isAssignmentTarget=False, isBindingElement=False, inFunctionBody=False, inIteration=False,inSwitch=False, labelSet= {}, strict=False) self.OperatorPrecedence = { ')': 0, ';': 0, ',': 0, ']': 0, '||': 1, 'OR':1, '&&': 2, 'AND':2, '|': 3, '^': 4, '&': 5, '==': 6, '!=': 6, '<>': 6, '===': 6, '=': 6, '!==': 6, '<': 7, '>': 7, '<=': 7, '>=': 7, '<<': 8, '>>': 8, '>>>': 8, '+': 9, '-': 9, '*': 11, '/': 11, '%': 11, } self.StartMarker = Marker(index=0, line=self.Scanner.LineNumber, column=0) self.LastMarker = Marker(index=0, line=self.Scanner.LineNumber, column=0) def Initialize(self) : self.NextToken() self.LastMarker=Marker(index=self.Scanner.Index, line=self.Scanner.LineNumber, column=self.Scanner.Index-self.Scanner.LineStart) def CreateNode(self) : return Marker(index=self.StartMarker.Index, line=self.StartMarker.Line, column=self.StartMarker.Column) def StartNode(self, token, lastLineStart=0): column = token.Start - token.LineStart line = token.LineNumber if column < 0 : column += lastLineStart line-=1 return Marker(index=token.Start, line= line, column=column) def Match(self, value) : return self.LookAhead.Type==7 and self.LookAhead.Value==value # 7=Punctuator def Expect(self, value) : token=self.NextToken() if token.Type!=7 or token.Value!=value : # 7=Punctuator self.ThrowUnexpectedToken(token) # 是否是赋值操作符 def MatchAssign(self) : if self.LookAhead.Type!=7 : return False #7=Punctuator op=self.LookAhead.Value return op in (':', ':=') def GetTokenRaw(self, token) : return self.Scanner.Source[token.Start : token.End] def NextToken(self) : token=self.LookAhead self.LastMarker.Index=self.Scanner.Index self.LastMarker.Line=self.Scanner.LineNumber self.LastMarker.Column=self.Scanner.Index-self.Scanner.LineStart self.CollectComments() # 过滤注释 空格 if self.Scanner.Index != self.StartMarker.Index : self.StartMarker.Index = self.Scanner.Index self.StartMarker.Line = self.Scanner.LineNumber self.StartMarker.Column = self.Scanner.Index - self.Scanner.LineStart next=self.Scanner.Lex() self.HasLineTerminator= token.LineNumber!=next.LineNumber if next and self.Context.Strict and next.Type==3 : #3=Identifier print ('[JSParser::NextToken] not support') self.LookAhead=next return token def CollectComments(self) : self.Scanner.ScanComments() def ParseScript(self) : node=self.CreateNode() body=self.ParseDirectivePrologues() while self.LookAhead.Type!=2: #2=/*EOF*/) body.append(self.ParseStatementListItem()) return self.Finalize(node,self.Node.Script(body)) # https://tc39.github.io/ecma262/#sec-directive-prologues-and-the-use-strict-directive def ParseDirective(self): token=self.LookAhead node=self.CreateNode() expr=self.ParseExpression() return None def ParseDirectivePrologues(self) : firstRestricted=None body=[] while True : token=self.LookAhead if token.Type!=8 : #8=/*StringLiteral* break statement = self.ParseDirective() body.append(statement) return body # https://tc39.github.io/ecma262/#sec-block def ParseStatementListItem(self) : statement=None self.Context.IsAssignmentTarget=True self.Context.IsBindingElement=True if self.LookAhead.Type==4 : # 4=/*Keyword*/ pass else : statement=self.ParseStatement() return statement # https://tc39.github.io/ecma262/#sec-ecmascript-language-statements-and-declarations def ParseStatement(self): statement=None type = self.LookAhead.Type if type in (1,5,6,8,10,9) : # BooleanLiteral, NullLiteral, NumericLiteral, StringLiteral, Template, RegularExpression statement = self.ParseExpressionStatement() elif type==7 : # 7=/* Punctuator */: value = self.LookAhead.Value if value == '(' : statement = self.ParseExpressionStatement() elif value == ';' : statement = self.ParseEmptyStatement() else : statement = self.ParseExpressionStatement() elif type==3 : # 3=/* Identifier */: statement = self.ParseLabelledStatement() elif type==4: # 4= /* Keyword */ print('[JSParser::ParseStatementListItem] not support Keyword') else : statement="error" return statement # https://tc39.github.io/ecma262/#sec-empty-statement def ParseEmptyStatement(self): node=self.CreateNode() self.Expect(';') return self.Finalize(node, self.Node.EmptyStatement()) # https://tc39.github.io/ecma262/#sec-labelled-statements def ParseLabelledStatement(self): node=self.CreateNode() expr=self.ParseExpression() self.ConsumeSemicolon() statement = self.Node.ExpressionStatement(expr) return self.Finalize(node, statement) # https://tc39.github.io/ecma262/#sec-comma-operator def ParseExpression(self) : startToken=self.LookAhead expr=self.IsolateCoverGrammar(self.ParseAssignmentExpression) if self.Match(',') : expressions=[] expressions.append(expr) while self.LookAhead.Type!=2 : #/*EOF*/ if not self.Match(',') : break self.NextToken() expressions.append(self.IsolateCoverGrammar(self.ParseAssignmentExpression)) expr=self.Finalize(self.StartNode(startToken),self.Node.SequenceExpression(expressions)) return expr def ParseAssignmentExpression(self) : expr=None startToken=self.LookAhead token=startToken expr=self.ParseConditionalExpression() if self.MatchAssign() : if not self.Context.IsAssignmentTarget : marker=expr.Marker self.ThrowUnexpectedError(marker.Index,marker.Line,marker.Column,Messages.InvalidLHSInAssignment) if not self.Match('=') and not self.Match(':') : self.Context.IsAssignmentTarget=False self.Context.IsBindingElement=False else : self.ReinterpretExpressionAsPattern(expr) token=self.NextToken() operator=token.Value right=self.IsolateCoverGrammar(self.ParseAssignmentExpression) expr=self.Finalize(self.StartNode(startToken), self.Node.AssignmentExpression(operator, expr, right)) self.Context.FirstCoverInitializedNameError=None return expr def ParseConditionalExpression(self) : startToken=self.LookAhead expr=self.InheritCoverGrammar(self.ParseBinaryExpression) return expr def ParseBinaryExpression(self) : startToken=self.LookAhead expr=self.InheritCoverGrammar(self.ParseExponentiationExpression) token=self.LookAhead prec=self.BinaryPrecedence(token) if prec>0 : self.NextToken() self.Context.IsAssignmentTarget=False self.Context.IsBindingElement=False markers=[startToken,self.LookAhead] left=expr right=self.IsolateCoverGrammar(self.ParseExponentiationExpression) stack=[left,token.Value,right] precedences = [prec] while True : prec=self.BinaryPrecedence(self.LookAhead) if prec<=0 : break while len(stack)>2 and prec<=precedences[-1] : right=stack.pop() operator=stack.pop() precedences.pop() left=stack.pop() markers.pop() node=self.StartNode(markers[-1]) stack.append(self.Finalize(node, self.Node.BinaryExpression(operator, left, right))) # Shift stack.append(self.NextToken().Value) precedences.append(prec) markers.append(self.LookAhead) stack.append(self.IsolateCoverGrammar(self.ParseExponentiationExpression)) i=len(stack)-1 expr=stack[i] lastMarker=markers.pop() while i>1 : marker=markers.pop() lastLineStart=lastMarker and lastMarker.LineStart node=self.StartNode(marker, lastLineStart) operator=stack[i-1] expr=self.Finalize(node, self.Node.BinaryExpression(operator, stack[i - 2], expr)) i-=2 lastMarker=marker return expr def ParseExponentiationExpression(self) : startToken=self.LookAhead expr=self.InheritCoverGrammar(self.ParseUnaryExpression) return expr def ParseUnaryExpression(self) : expr=None if self.Match('+') or self.Match('-') : node=self.StartNode(self.LookAhead) token=self.NextToken() expr=self.InheritCoverGrammar(self.ParseUnaryExpression) expr=self.Finalize(node, self.Node.UnaryExpression(token.Value, expr)) self.Context.IsAssignmentTarget=False self.Context.IsBindingElement=False else : expr=self.ParseUpdateExpression() return expr # https://tc39.github.io/ecma262/#sec-update-expressions def ParseUpdateExpression(self) : startToken=self.LookAhead expr=self.InheritCoverGrammar(self.ParseLeftHandSideExpressionAllowCall) return expr def ParseLeftHandSideExpressionAllowCall(self) : startToken=self.LookAhead expr=self.InheritCoverGrammar(self.ParsePrimaryExpression) while True : if self.Match('(') : self.Context.IsBindingElement=False self.Context.IsAssignmentTarget=False args=self.ParseArguments() # 解析 调用参数 expr=self.Finalize(self.StartNode(startToken), self.Node.CallExpression(expr,args)) else : break return expr # https://tc39.github.io/ecma262/#sec-left-hand-side-expressions def ParseArguments(self) : self.Expect('(') args=[] if not self.Match(')') : while True : expr=self.IsolateCoverGrammar(self.ParseAssignmentExpression) args.append(expr) if self.Match(')') : break self.ExpectCommaSeparator() if self.Match(')'): break self.Expect(')') return args # Quietly expect a comma when in tolerant mode, otherwise delegates to expect(). def ExpectCommaSeparator(self) : self.Expect(',') # https://tc39.github.io/ecma262/#sec-primary-expression def ParsePrimaryExpression(self) : node=self.CreateNode() type=self.LookAhead.Type if type==3 : # Identifier expr=self.Finalize(node, self.Node.Identifier(self.NextToken().Value)) elif type in (6,8) : # 6=NumericLiteral, 8=StringLiteral self.Context.IsAssignmentTarget=False self.Context.IsBindingElement=False token=self.NextToken() raw=self.GetTokenRaw(token) expr=self.Finalize(node, self.Node.Literal(token.Value,raw)) elif type==7 : # 7=Punctuator value=self.LookAhead.Value if value=='(': self.Context.IsBindingElement=False expr=self.InheritCoverGrammar(self.ParseGroupExpression) else : self.ThrowUnexpectedToken(self.NextToken()) else : self.ThrowUnexpectedToken(self.NextToken()) return expr def ParseGroupExpression(self) : self.Expect('(') if self.Match(')') : self.NextToken() else : startToken=self.LookAhead params=[] arrow=False self.Context.IsBindingElement=True expr=self.InheritCoverGrammar(self.ParseAssignmentExpression) if self.Match(',') : expressions=[] self.Context.IsAssignmentTarget=False expressions.append(expr) while self.LookAhead.Type!=2 : # /* EOF */) if not self.Match(',') : break self.NextToken() if not self.Match(')') : self.NextToken() if not arrow : self.Expect(')') self.Context.IsBindingElement=False return expr # https://tc39.github.io/ecma262/#sec-expression-statement def ParseExpressionStatement(self) : node=self.CreateNode() expr=self.ParseExpression() self.ConsumeSemicolon() return self.Finalize(node,self.Node.ExpressionStatement(expr)) def ConsumeSemicolon(self) : if self.Match(';') : self.NextToken() elif not self.HasLineTerminator : # if (this.LookAhead.Type!=2/*EOF*/ && !this.Match('}')) self.LastMarker.Index=self.StartMarker.Index self.LastMarker.Line=self.StartMarker.Line self.LastMarker.Column=self.StartMarker.Column def ReinterpretExpressionAsPattern(self, expr) : if expr.Type in (Syntax.Identifier, Syntax.AssignmentExpression) : pass else : pass def Finalize(self,marker,node) : node.Marker=Marker( line=marker.Line, column=marker.Column, index=marker.Index ) return node def BinaryPrecedence(self, token) : op = token.Value if token.Type == 7 : # /* Punctuator */ precedence = self.OperatorPrecedence.get(op, 0) else : precedence = 0 return precedence def IsolateCoverGrammar(self, parseFunction) : previousIsBindingElement=self.Context.IsBindingElement previousIsAssignmentTarget=self.Context.IsAssignmentTarget previousFirstCoverInitializedNameError=self.Context.FirstCoverInitializedNameError self.Context.IsBindingElement=True self.Context.IsAssignmentTarget=True self.Context.FirstCoverInitializedNameError=None result=parseFunction() if self.Context.FirstCoverInitializedNameError is not None : # 错误 this.throwUnexpectedToken(this.context.firstCoverInitializedNameError); pass self.Context.IsBindingElement=previousIsBindingElement self.Context.IsAssignmentTarget=previousIsAssignmentTarget self.Context.FirstCoverInitializedNameError=previousFirstCoverInitializedNameError return result def InheritCoverGrammar(self,parseFunction) : previousIsBindingElement = self.Context.IsBindingElement previousIsAssignmentTarget = self.Context.IsAssignmentTarget previousFirstCoverInitializedNameError = self.Context.FirstCoverInitializedNameError self.Context.IsBindingElement = True self.Context.IsAssignmentTarget = True self.Context.FirstCoverInitializedNameError = None result = parseFunction() self.Context.IsBindingElement = self.Context.IsBindingElement and previousIsBindingElement self.Context.IsAssignmentTarget = self.Context.IsAssignmentTarget and previousIsAssignmentTarget self.Context.FirstCoverInitializedNameError = previousFirstCoverInitializedNameError or self.Context.FirstCoverInitializedNameError return result def ThrowUnexpectedToken(self, token=None,message=None) : raise self.UnexpectedTokenError(token,message) def ThrowUnexpectedError(self, index,line,column,message=None) : if message is not None : msg=message else : msg="执行异常" return self.ErrorHandler.ThrowError(index,line,column,msg) def UnexpectedTokenError(self,token=None,message=None) : msg=message or Messages.UnexpectedToken value='ILLEGAL' if token : if not message : pass value=token.Value msg=msg.replace("%0",unicode(value),1) if token and isinstance(token.LineNumber, int) : index=token.Start line=token.LineNumber lastMarkerLineStart=self.LastMarker.Index-self.LastMarker.Column column=token.Start-lastMarkerLineStart+1 return self.ErrorHandler.CreateError(index,line,column,msg) else : index=self.LastMarker.Index line=self.LastMarker.Line column=self.LastMarker.Column+1 return self.ErrorHandler.CreateError(index,line,column,msg)