def __init__(self, debug=False, tracking=False): self.lexer = Lexer() self.debug = debug self.tracking = tracking self.tokens = self.lexer.tokens optionals = ( 'FormalParameterList', 'SourceElements', 'StatementList', 'Elision', 'Expression', 'ExpressionNoIn', 'Identifier', 'Initialiser', 'InitialiserNoIn', 'CaseClauses', ) for rulename in optionals: self._create_opt_rule(rulename) self.yacc = ply.yacc.yacc(module=self, start='Program', optimize=0, tabmodule="tab_yacc")
class Parser(object): """ Grammar for ECMAScript 5 (ECMA-262 Final Draft, 5th edition april 2009) The *NoIn Rules stand for No IN and is required for the IterationStatement The *NoBF Rules stand for No Brace or Function and is required for the ExpressionStatement rule. The grammer contains 1 shift/reduce conflict caused by the if/else clause, which is harmless. """ def __init__(self, debug=False, tracking=False): self.lexer = Lexer() self.debug = debug self.tracking = tracking self.tokens = self.lexer.tokens optionals = ( 'FormalParameterList', 'SourceElements', 'StatementList', 'Elision', 'Expression', 'ExpressionNoIn', 'Identifier', 'Initialiser', 'InitialiserNoIn', 'CaseClauses', ) for rulename in optionals: self._create_opt_rule(rulename) self.yacc = ply.yacc.yacc(module=self, start='Program', optimize=0, tabmodule="tab_yacc") # From plycparser: def _create_opt_rule(self, rulename): """ Given a rule name, creates an optional ply.yacc rule for it. The name of the optional rule is <rulename>_opt """ optname = rulename + '_opt' def optrule(self, p): p[0] = p[1] optrule.__doc__ = '%s : empty\n| %s' % (optname, rulename) optrule.__name__ = 'p_%s' % optname setattr(self.__class__, optrule.__name__, optrule) def parse(self, input): return self.yacc.parse(input, lexer=self.lexer, debug=self.debug, tracking=self.tracking) # Precedence rules precedence = ( ('nonassoc', 'IF_WITHOUT_ELSE'), ('nonassoc', 'ELSE'), ('left', 'LOR'), ('left', 'LAND'), ('left', 'OR'), ('left', 'XOR'), ('left', 'AND'), ('left', 'EQ', 'NE'), ('left', 'GT', 'GE', 'LT', 'LE'), ('left', 'RSHIFT', 'LSHIFT'), ('left', 'PLUS', 'MINUS'), ('left', 'TIMES', 'DIVIDE', 'MOD'), ) def build_list(self, p, base, node, count=None): """Helper function to build a list""" if count is None: count = node if len(p) <= count: return [p[base]] else: p[base].append(p[node]) return p[base] # Internal helpers def p_empty(self, p): """empty :""" def p_auto_semicolon(self, p): """auto_semicolon : error """ def p_error(self, p): if (p and p.type != 'SEMI') or not p: next_token = self.lexer.auto_semicolon(p) if next_token: self.yacc.errok() return next_token raise SyntaxError("%r (%s) unexpected at %d:%d (between %r and %r)" % ( p.value, p.type, p.lineno, p.lexpos, self.lexer.prev_token, self.lexer.token())) # # 7. Lexical Conventions # Only some are implemented currently, see lexer for more # 7.4 Comments (currently ignored by lexer token() method) def p_Comment(self, p): """Comment : SingleLineComment | MultiLineComment """ p[0] = p[1] def p_SingleLineComment(self, p): """SingleLineComment : LINE_COMMENT""" p[0] = ast.LineComment(p[1]) def p_MultiLineComment(self, p): """MultiLineComment : BLOCK_COMMENT""" p[0] = ast.BlockComment(p[1]) def p_IdentifierName(self, p): """IdentifierName : Identifier""" p[0] = p[1] def p_Identifier(self, p): """Identifier : ID""" p[0] = ast.Identifier(p[1]) # TODO: Note that the RegularExpressionLiteral doesn't belong here # according to the ecmascript standard def p_Literal(self, p): """Literal : NullLiteral | BooleanLiteral | NumericLiteral | StringLiteral | RegexStart DIVIDE | RegexStart DIVIDE_EQUALS""" p[0] = p[1] def p_NullLiteral(self, p): """NullLiteral : NULL """ p[0] = ast.Null() def p_BooleanLiteral(self, p): """BooleanLiteral : TRUE | FALSE""" p[0] = ast.Boolean(p[1]) # TODO def p_NumericLiteral(self, p): """NumericLiteral : NUMBER_LITERAL""" p[0] = ast.Number(p[1]) def p_StringLiteral(self, p): """StringLiteral : STRING_LITERAL""" p[0] = ast.String(data=p[1]) def p_RegexStart(self, p): """RegexStart : """ pattern, flags = self.lexer.scan_regexp(start_value='/') p[0] = ast.RegEx(pattern=pattern, flags=flags) # # 11. Expressions # 11.1 Primary Expressions def p_PrimaryExpression(self, p): """PrimaryExpression : PrimaryExpressionNoObj | ObjectLiteral""" p[0] = p[1] def p_PrimaryExpressionNoObj(self, p): """PrimaryExpressionNoObj : THIS | Identifier | Literal | ArrayLiteral | LPAREN Expression RPAREN""" if len(p) == 2: p[0] = p[1] else: p[0] = p[2] # TODO: Elision support is not implemented correctly def p_ArrayLiteral_1(self, p): """ArrayLiteral : LBRACKET Elision_opt RBRACKET""" p[0] = ast.Array(items=None) def p_ArrayLiteral_2(self, p): """ArrayLiteral : LBRACKET ElementList RBRACKET | LBRACKET ElementList COMMA Elision_opt RBRACKET""" p[0] = ast.Array(items=p[2]) def p_ElementList(self, p): """ElementList : Elision_opt AssignmentExpression | ElementList COMMA Elision_opt AssignmentExpression """ if len(p) == 3: p[1] = [p[2]] else: p[1].append(p[4]) p[0] = p[1] # TODO: Implement correctly def p_Elision(self, p): """Elision : COMMA | Elision COMMA""" p[0] = p[1] def p_ObjectLiteral(self, p): """ObjectLiteral : LBRACE RBRACE | LBRACE PropertyNameAndValueList RBRACE | LBRACE PropertyNameAndValueList COMMA RBRACE""" p[0] = ast.Object(properties=p[2] if len(p) > 3 else []) def p_PropertyNameAndValueList(self, p): """PropertyNameAndValueList : PropertyAssignment | PropertyNameAndValueList COMMA PropertyAssignment""" p[0] = self.build_list(p, 1, 3) # TODO: add get / set def p_PropertyAssignment(self, p): """PropertyAssignment : PropertyName COLON AssignmentExpression""" #| GET PropertyName \ # LPAREN RPAREN \ # LBRACE FunctionBody RBRACE #| SET PropertyName \ # LPAREN PropertySetParameterList RPAREN \ # LBRACE FunctionBody RBRACE """ if len(p) == 4: p[0] = ast.Assign(node=p[1], operator=p[2], expression=p[3]) def p_PropertyName(self, p): """PropertyName : IdentifierName | StringLiteral | NumericLiteral""" p[0] = p[1] #def p_PropertySetParameterList(self, p): # """PropertySetParameterList : Identifier """ # p[0] = p[1] # 11.2 Left-Hand-Side Expressions # TODO def p_MemberExpression(self, p): """MemberExpression : PrimaryExpression | FunctionExpression | MemberExpression LBRACKET Expression RBRACKET | MemberExpression PERIOD IdentifierName | NEW MemberExpression Arguments """ if len(p) == 2: p[0] = p[1] elif p[1] == 'new': p[0] = ast.New(identifier=p[2], arguments=p[3]) elif p[2] == '.': p[0] = ast.DotAccessor(node=p[1], element=p[3]) else: p[0] = ast.BracketAccessor(node=p[1], element=p[3]) def p_MemberExpressionNoBF(self, p): """MemberExpressionNoBF : PrimaryExpressionNoObj | MemberExpressionNoBF LBRACKET Expression RBRACKET | MemberExpressionNoBF PERIOD IdentifierName | NEW MemberExpression Arguments """ if len(p) == 2: p[0] = p[1] elif p[1] == 'new': p[0] = ast.New(identifier=p[2], arguments=p[3]) elif p[2] == '.': p[0] = ast.DotAccessor(node=p[1], element=p[3]) else: p[0] = ast.BracketAccessor(node=p[1], element=p[3]) def p_NewExpression(self, p): """NewExpression : MemberExpression | NEW NewExpression """ if len(p) == 2: p[0] = p[1] else: p[0] = ast.New(identifier=p[2]) def p_NewExpressionNoBF(self, p): """NewExpressionNoBF : MemberExpressionNoBF | NEW NewExpression""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.New(identifier=p[2]) def p_CallExpression_1(self, p): """CallExpression : MemberExpression Arguments | CallExpression Arguments""" p[0] = ast.FuncCall(node=p[1], arguments=p[2]) def p_CallExpression_2(self, p): """CallExpression : CallExpression LBRACKET Expression RBRACKET | CallExpression PERIOD IdentifierName""" if len(p) == 4: p[0] = ast.DotAccessor(node=p[1], element=p[3]) else: p[0] = ast.BracketAccessor(node=p[1], element=p[3]) def p_CallExpressionNoBF_1(self, p): """CallExpressionNoBF : MemberExpressionNoBF Arguments | CallExpressionNoBF Arguments""" p[0] = ast.FuncCall(node=p[1], arguments=p[2]) def p_CallExpressionNoBF_2(self, p): """CallExpressionNoBF : CallExpressionNoBF LBRACKET Expression RBRACKET | CallExpressionNoBF PERIOD IdentifierName""" if p[2] == '.': p[0] = ast.DotAccessor(node=p[1], element=p[3]) else: p[0] = ast.BracketAccessor(node=p[1], element=p[3]) def p_Arguments(self, p): """Arguments : LPAREN RPAREN | LPAREN ArgumentList RPAREN""" if len(p) == 4: p[0] = p[2] def p_ArgumentList(self, p): """ArgumentList : AssignmentExpression | ArgumentList COMMA AssignmentExpression""" p[0] = self.build_list(p, 1, 3) def p_LeftHandSideExpression(self, p): """LeftHandSideExpression : NewExpression | CallExpression """ p[0] = p[1] def p_LeftHandSideExpressionNoBF(self, p): """LeftHandSideExpressionNoBF : NewExpressionNoBF | CallExpressionNoBF """ p[0] = p[1] # 11.3 Postfix Expressions def p_PostfixExpression(self, p): """PostfixExpression : LeftHandSideExpression | LeftHandSideExpression INCR | LeftHandSideExpression DECR""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.UnaryOp(operator=p[2], value=p[1], postfix=True) def p_PostfixExpressionNoBF(self, p): """PostfixExpressionNoBF : LeftHandSideExpressionNoBF | LeftHandSideExpressionNoBF INCR | LeftHandSideExpressionNoBF DECR""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.UnaryOp(operator=p[2], value=p[1], postfix=True) # 11.4 Unary Operators def p_UnaryExpressionCommon(self, p): """UnaryExpressionCommon : DELETE UnaryExpression | VOID UnaryExpression | TYPEOF UnaryExpression | INCR UnaryExpression | INCR_NO_LT UnaryExpression | DECR UnaryExpression | DECR_NO_LT UnaryExpression | PLUS UnaryExpression | MINUS UnaryExpression | NOT UnaryExpression | LNOT UnaryExpression """ p[0] = ast.UnaryOp(operator=p[1], value=p[2], postfix=False) def p_UnaryExpression(self, p): """UnaryExpression : PostfixExpression | UnaryExpressionCommon""" p[0] = p[1] def p_UnaryExpressionNoBF(self, p): """UnaryExpressionNoBF : PostfixExpressionNoBF | UnaryExpressionCommon""" p[0] = p[1] # 11.5 Multiplicative Operators def p_MultiplicativeExpression(self, p): """MultiplicativeExpression : UnaryExpression | MultiplicativeExpression TIMES UnaryExpression | MultiplicativeExpression DIVIDE UnaryExpression | MultiplicativeExpression MOD UnaryExpression """ if len(p) == 2: p[0] = p[1] else: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) def p_MultiplicativeExpressionNoBF(self, p): """MultiplicativeExpressionNoBF : UnaryExpressionNoBF | MultiplicativeExpressionNoBF TIMES UnaryExpression | MultiplicativeExpressionNoBF DIVIDE UnaryExpression | MultiplicativeExpressionNoBF MOD UnaryExpression """ if len(p) == 2: p[0] = p[1] else: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) # 11.6 Additive Operators def p_AdditiveExpression(self, p): """AdditiveExpression : MultiplicativeExpression | AdditiveExpression PLUS MultiplicativeExpression | AdditiveExpression MINUS MultiplicativeExpression""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) def p_AdditiveExpressionNoBF(self, p): """AdditiveExpressionNoBF : MultiplicativeExpressionNoBF | AdditiveExpressionNoBF PLUS MultiplicativeExpression | AdditiveExpressionNoBF MINUS MultiplicativeExpression""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) # 11.7 Bitwise Shift Operators def p_ShiftExpression(self, p): """ShiftExpression : AdditiveExpression | ShiftExpression LSHIFT AdditiveExpression | ShiftExpression RSHIFT AdditiveExpression | ShiftExpression URSHIFT AdditiveExpression""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) def p_ShiftExpressionNoBF(self, p): """ShiftExpressionNoBF : AdditiveExpressionNoBF | ShiftExpressionNoBF LSHIFT AdditiveExpression | ShiftExpressionNoBF RSHIFT AdditiveExpression | ShiftExpressionNoBF URSHIFT AdditiveExpression""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) # 11.8 Relational Operators def p_RelationalExpression(self, p): """RelationalExpression : ShiftExpression | RelationalExpression GT ShiftExpression | RelationalExpression LT ShiftExpression | RelationalExpression GE ShiftExpression | RelationalExpression LE ShiftExpression | RelationalExpression INSTANCEOF ShiftExpression | RelationalExpression IN ShiftExpression""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) def p_RelationalExpressionNoIn(self, p): """RelationalExpressionNoIn : ShiftExpression | RelationalExpressionNoIn GT ShiftExpression | RelationalExpressionNoIn LT ShiftExpression | RelationalExpressionNoIn GE ShiftExpression | RelationalExpressionNoIn LE ShiftExpression | RelationalExpressionNoIn INSTANCEOF ShiftExpression""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.BinOp(p[2], left=p[1], right=p[3]) def p_RelationalExpressionNoBF(self, p): """RelationalExpressionNoBF : ShiftExpressionNoBF | RelationalExpressionNoBF GT ShiftExpression | RelationalExpressionNoBF LT ShiftExpression | RelationalExpressionNoBF GE ShiftExpression | RelationalExpressionNoBF LE ShiftExpression | RelationalExpressionNoBF INSTANCEOF ShiftExpression | RelationalExpressionNoBF IN ShiftExpression""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.BinOp(p[2], left=p[1], right=p[3]) # 11.9 Equality Operators def p_EqualityExpression(self, p): """EqualityExpression : RelationalExpression | EqualityExpression EQ RelationalExpression | EqualityExpression NE RelationalExpression | EqualityExpression EQT RelationalExpression | EqualityExpression NET RelationalExpression""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.BinOp(p[2], left=p[1], right=p[3]) def p_EqualityExpressionNoIn(self, p): """EqualityExpressionNoIn : RelationalExpressionNoIn | EqualityExpressionNoIn EQ RelationalExpressionNoIn | EqualityExpressionNoIn NE RelationalExpressionNoIn | EqualityExpressionNoIn EQT RelationalExpressionNoIn | EqualityExpressionNoIn NET RelationalExpressionNoIn""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.BinOp(p[2], left=p[1], right=p[3]) def p_EqualityExpressionNoBF(self, p): """EqualityExpressionNoBF : RelationalExpressionNoBF | EqualityExpressionNoBF EQ RelationalExpressionNoIn | EqualityExpressionNoBF NE RelationalExpressionNoIn | EqualityExpressionNoBF EQT RelationalExpressionNoIn | EqualityExpressionNoBF NET RelationalExpressionNoIn""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.BinOp(p[2], left=p[1], right=p[3]) # 11.10 Binary Bitwise Operators def p_BitwiseANDExpression(self, p): """BitwiseANDExpression : EqualityExpression | BitwiseANDExpression AND EqualityExpression""" if len(p) == 4: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) else: p[0] = p[1] def p_BitwiseANDExpressionNoIn(self, p): """BitwiseANDExpressionNoIn : EqualityExpressionNoIn | BitwiseANDExpressionNoIn AND EqualityExpressionNoIn""" if len(p) == 4: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) else: p[0] = p[1] def p_BitwiseANDExpressionNoBF(self, p): """BitwiseANDExpressionNoBF : EqualityExpressionNoBF | BitwiseANDExpressionNoBF AND EqualityExpressionNoIn""" if len(p) == 4: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) else: p[0] = p[1] def p_BitwiseXORExpression(self, p): """BitwiseXORExpression : BitwiseANDExpression | BitwiseXORExpression XOR BitwiseANDExpression """ if len(p) == 4: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) else: p[0] = p[1] def p_BitwiseXORExpressionNoIn(self, p): """BitwiseXORExpressionNoIn : BitwiseANDExpressionNoIn | BitwiseXORExpressionNoIn XOR BitwiseANDExpressionNoIn """ if len(p) == 4: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) else: p[0] = p[1] def p_BitwiseXORExpressionNoBF(self, p): """BitwiseXORExpressionNoBF : BitwiseANDExpressionNoBF | BitwiseXORExpressionNoBF XOR BitwiseANDExpressionNoIn """ if len(p) == 4: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) else: p[0] = p[1] def p_BitwiseORExpression(self, p): """BitwiseORExpression : BitwiseXORExpression | BitwiseORExpression OR BitwiseXORExpression """ if len(p) == 4: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) else: p[0] = p[1] def p_BitwiseORExpressionNoIn(self, p): """BitwiseORExpressionNoIn : BitwiseXORExpressionNoIn | BitwiseORExpressionNoIn OR BitwiseXORExpressionNoIn""" if len(p) == 4: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) else: p[0] = p[1] def p_BitwiseORExpressionNoBF(self, p): """BitwiseORExpressionNoBF : BitwiseXORExpressionNoBF | BitwiseORExpressionNoBF OR BitwiseXORExpressionNoIn""" if len(p) == 4: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) else: p[0] = p[1] # 11.11 Binary Logical Operators def p_LogicalANDExpression(self, p): """LogicalANDExpression : BitwiseORExpression | LogicalANDExpression LAND BitwiseORExpression""" if len(p) == 4: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) else: p[0] = p[1] def p_LogicalANDExpressionNoIn(self, p): """LogicalANDExpressionNoIn : BitwiseORExpressionNoIn | LogicalANDExpressionNoIn LAND BitwiseORExpressionNoIn """ if len(p) == 4: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) else: p[0] = p[1] def p_LogicalANDExpressionNoBF(self, p): """LogicalANDExpressionNoBF : BitwiseORExpressionNoBF | LogicalANDExpressionNoBF LAND BitwiseORExpressionNoIn """ if len(p) == 4: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) else: p[0] = p[1] def p_LogicalORExpression(self, p): """LogicalORExpression : LogicalANDExpression | LogicalORExpression LOR LogicalANDExpression """ if len(p) == 4: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) else: p[0] = p[1] def p_LogicalORExpressionNoIn(self, p): """LogicalORExpressionNoIn : LogicalANDExpressionNoIn | LogicalORExpressionNoIn LOR LogicalANDExpressionNoIn """ if len(p) == 4: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) else: p[0] = p[1] def p_LogicalORExpressionNoBF(self, p): """LogicalORExpressionNoBF : LogicalANDExpressionNoBF | LogicalORExpressionNoBF LOR LogicalANDExpressionNoIn """ if len(p) == 4: p[0] = ast.BinOp(operator=p[2], left=p[1], right=p[3]) else: p[0] = p[1] # 11.12 Conditional Operator ( ?: ) def p_ConditionalExpression(self, p): """ConditionalExpression : LogicalORExpression | LogicalORExpression CONDOP \ AssignmentExpression COLON \ AssignmentExpression """ if len(p) == 2: p[0] = p[1] else: p[0] = ast.If(expression=p[1], true=[p[3]], false=[p[5]]) def p_ConditionalExpressionNoIn(self, p): """ConditionalExpressionNoIn : LogicalORExpressionNoIn | LogicalORExpressionNoIn CONDOP \ AssignmentExpression COLON \ AssignmentExpressionNoIn""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.If(expression=p[1], true=[p[3]], false=[p[5]]) def p_ConditionalExpressionNoBF(self, p): """ConditionalExpressionNoBF : LogicalORExpressionNoBF | LogicalORExpressionNoBF CONDOP \ AssignmentExpression COLON \ AssignmentExpression """ if len(p) == 2: p[0] = p[1] else: p[0] = ast.If(expression=p[1], true=[p[3]], false=[p[5]]) # 11.13 Assignment Operators def p_AssignmentExpression(self, p): """AssignmentExpression : ConditionalExpression | LeftHandSideExpression AssignmentOperator \ AssignmentExpression""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.Assign(node=p[1], operator=p[2], expression=p[3]) def p_AssignmentExpressionNoIn(self, p): """AssignmentExpressionNoIn : ConditionalExpressionNoIn | LeftHandSideExpression \ AssignmentOperator \ AssignmentExpressionNoIn""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.Assign(node=p[1], operator=p[2], expression=p[3]) def p_AssignmentExpressionNoBF(self, p): """AssignmentExpressionNoBF : ConditionalExpressionNoBF | LeftHandSideExpressionNoBF AssignmentOperator \ AssignmentExpression""" if len(p) == 2: p[0] = p[1] else: p[0] = ast.Assign(node=p[1], operator=p[2], expression=p[3]) def p_AssignmentOperator(self, p): """AssignmentOperator : EQUALS | TIMES_EQUALS | DIVIDE_EQUALS | MOD_EQUALS | PLUS_EQUALS | MINUS_EQUALS | LSHIFT_EQUALS | RSHIFT_EQUALS | URSHIFT_EQUALS | AND_EQUALS | XOR_EQUALS | OR_EQUALS""" p[0] = p[1] # 11.14 Comma Operator ( , ) def p_Expression(self, p): """Expression : AssignmentExpression | Expression COMMA AssignmentExpression""" p[0] = self.build_list(p, 1, 3) def p_ExpressionNoIn(self, p): """ExpressionNoIn : AssignmentExpressionNoIn | ExpressionNoIn COMMA AssignmentExpressionNoIn""" p[0] = self.build_list(p, 1, 3) def p_ExpressionNoBF(self, p): """ExpressionNoBF : AssignmentExpressionNoBF | ExpressionNoBF COMMA AssignmentExpression""" p[0] = self.build_list(p, 1, 3) # 12 Statements # def p_Statement(self, p): """Statement : Block | VariableStatement | EmptyStatement | ExpressionStatement | IfStatement | IterationStatement | ContinueStatement | BreakStatement | ReturnStatement | WithStatement | LabelledStatement | SwitchStatement | ThrowStatement | TryStatement | DebuggerStatement""" p[0] = p[1] # 12.1 Block def p_Block(self, p): """Block : LBRACE StatementList_opt RBRACE""" p[0] = p[2] # Add FunctionDeclaration although it is not in the standard, all the # browsers do support it, and jquery javascript uses it for one function def p_StatementList(self, p): """StatementList : Statement | StatementList Statement | FunctionDeclaration | StatementList FunctionDeclaration""" p[0] = self.build_list(p, 1, 2) # 12.2 Variable Statement def p_VariableStatement(self, p): """VariableStatement : VAR VariableDeclarationList SEMI | VAR VariableDeclarationList auto_semicolon""" p[0] = [] for node, expression in p[2]: p[0].append(ast.VariableDeclaration(node, expression)) def p_VariableDeclarationList(self, p): """VariableDeclarationList : VariableDeclaration | VariableDeclarationList COMMA \ VariableDeclaration""" p[0] = self.build_list(p, 1, 3) def p_VariableDeclarationListNoIn(self, p): """VariableDeclarationListNoIn : VariableDeclarationNoIn | VariableDeclarationListNoIn COMMA \ VariableDeclarationNoIn """ p[0] = self.build_list(p, 1, 3) def p_VariableDeclaration(self, p): """VariableDeclaration : Identifier Initialiser_opt""" p[0] = (p[1], p[2]) def p_VariableDeclarationNoIn(self, p): """VariableDeclarationNoIn : Identifier InitialiserNoIn_opt""" p[0] = (p[1], p[2]) def p_Initialiser(self, p): """Initialiser : EQUALS AssignmentExpression""" p[0] = p[2] def p_InitialiserNoIn(self, p): """InitialiserNoIn : EQUALS AssignmentExpressionNoIn""" p[0] = p[2] # 12.3 Empty Statement def p_EmptyStatement(self, p): """EmptyStatement : SEMI""" # 12.4 Expression Statement def p_ExpressionStatement(self, p): """ExpressionStatement : ExpressionNoBF SEMI | ExpressionNoBF auto_semicolon""" p[0] = p[1] # 12.5 The if Statement def p_IfStatement(self, p): """IfStatement : IF LPAREN Expression RPAREN Statement %prec IF_WITHOUT_ELSE | IF LPAREN Expression RPAREN Statement ELSE Statement""" p[0] = ast.If(expression=p[3], true=p[5], false=p[7] if len(p) > 6 else None) # 12.6 Iteration Statements def p_IterationStatement_1(self, p): """IterationStatement : DO Statement WHILE LPAREN Expression RPAREN \ SEMI | DO Statement WHILE LPAREN Expression RPAREN \ auto_semicolon""" p[0] = ast.DoWhile(condition=p[5], statement=p[2]) def p_IterationStatement_2(self, p): """IterationStatement : WHILE LPAREN Expression RPAREN Statement""" p[0] = ast.While(condition=p[3], statement=p[5]) def p_IterationStatement_3(self, p): """IterationStatement : FOR LPAREN ExpressionNoIn_opt SEMI \ Expression_opt SEMI \ Expression_opt RPAREN Statement | FOR LPAREN VAR VariableDeclarationListNoIn SEMI \ Expression_opt SEMI Expression_opt RPAREN \ Statement""" if len(p) == 10: p[0] = ast.For(initialisers=p[3], conditions=p[5], increments=p[7], statement=p[9]) else: initialisers = [ast.VariableDeclaration(node, expression) for (node, expression) in p[4]] p[0] = ast.For(initialisers=initialisers, conditions=p[6], increments=p[8], statement=p[10]) def p_IterationStatement_4(self, p): """IterationStatement : FOR LPAREN LeftHandSideExpression IN \ Expression RPAREN Statement | FOR LPAREN VAR VariableDeclarationNoIn IN \ Expression RPAREN Statement""" if len(p) == 8: p[0] = ast.ForIn(item=p[3], iterator=p[5], statement=p[7]) else: item = ast.VariableDeclaration(p[4], None) p[0] = ast.ForIn(item=item, iterator=p[6], statement=p[8]) # 12.7 The continue Statement def p_ContinueStatement(self, p): """ContinueStatement : CONTINUE Identifier_opt SEMI""" p[0] = ast.Continue(identifier=p[2]) # 12.8 The break Statement def p_BreakStatement(self, p): """BreakStatement : BREAK Identifier_opt SEMI""" p[0] = ast.Break(identifier=p[2]) # 12.9 The return Statement def p_ReturnStatement(self, p): """ReturnStatement : RETURN Expression_opt SEMI | RETURN Expression_opt auto_semicolon""" p[0] = ast.Return(expression=p[2]) # 12.10 The with Statement def p_WithStatement(self, p): """WithStatement : WITH LPAREN Expression RPAREN Statement""" p[0] = ast.With(expression=p[3], statement=p[5]) # 12.11 The switch Statement def p_SwitchStatement(self, p): """SwitchStatement : SWITCH LPAREN Expression RPAREN CaseBlock""" cases = [] default = None for item in p[5]: if isinstance(item, list): cases.extend(item) elif isinstance(item, ast.DefaultCase): default = item p[0] = ast.Switch(p[3], cases=cases, default=default) def p_CaseBlock(self, p): """CaseBlock : LBRACE CaseClauses_opt RBRACE | LBRACE CaseClauses_opt DefaultClause CaseClauses_opt RBRACE""" p[0] = p[2:-1] def p_CaseClauses(self, p): """CaseClauses : CaseClause | CaseClauses CaseClause""" p[0] = self.build_list(p, 1, 2) def p_CaseClause(self, p): """CaseClause : CASE Expression COLON StatementList_opt""" p[0] = ast.Case(identifier=p[2], statements=p[4]) def p_DefaultClause(self, p): """DefaultClause : DEFAULT COLON StatementList_opt""" p[0] = ast.DefaultCase(statements=p[3]) # 12.12 Labelled Statements def p_LabelledStatement(self, p): """LabelledStatement : Identifier COLON Statement""" p[0] = ast.LabelledStatement(identifier=p[1], statement=p[3]) # 12.13 The throw Statement def p_ThrowStatement(self, p): """ThrowStatement : THROW Expression SEMI""" p[0] = ast.Throw(expression=p[2]) # 12.14 The try Statement def p_TryStatement_1(self, p): """TryStatement : TRY Block Catch""" p[0] = ast.Try(statements=p[2], catch=p[3], finally_=None) def p_TryStatement_2(self, p): """TryStatement : TRY Block Finally | TRY Block Catch Finally""" if len(p) == 4: p[0] = ast.Try(statements=p[2], catch=None, finally_=p[3]) else: p[0] = ast.Try(statements=p[2], catch=p[3], finally_=p[4]) def p_Catch(self, p): """Catch : CATCH LPAREN Identifier RPAREN Block""" p[0] = ast.Catch(identifier=p[3], statements=p[5]) def p_Finally(self, p): """Finally : FINALLY Block""" p[0] = ast.Finally(statements=p[2]) # 12.15 Debugger statement def p_DebuggerStatement(self, p): """DebuggerStatement : DEBUGGER SEMI""" p[0] = ast.Debugger() # # 13. Function Definition def p_FunctionDeclaration(self, p): """FunctionDeclaration : FUNCTION Identifier \ LPAREN FormalParameterList_opt RPAREN \ LBRACE FunctionBody RBRACE""" p[0] = ast.FuncDecl(node=p[2], parameters=p[4], statements=p[7]) def p_FunctionExpression(self, p): """FunctionExpression : FUNCTION Identifier_opt \ LPAREN FormalParameterList_opt RPAREN \ LBRACE FunctionBody RBRACE """ p[0] = ast.FuncDecl(node=p[2], parameters=p[4], statements=p[7]) def p_FormalParameterList(self, p): """FormalParameterList : Identifier | FormalParameterList COMMA Identifier""" p[0] = self.build_list(p, 1, 3) def p_FunctionBody(self, p): """FunctionBody : SourceElements_opt""" p[0] = p[1] # # 14. Program def p_Program(self, p): """Program : SourceElements_opt""" p[0] = ast.Program(p[1]) def p_SourceElements(self, p): """SourceElements : SourceElement | SourceElements SourceElement""" p[0] = self.build_list(p, 1, 2) def p_SourceElement(self, p): """SourceElement : Statement | FunctionDeclaration | Comment """ p[0] = p[1]