Last active
July 6, 2020 14:19
-
-
Save tk0miya/4379646 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sys.path.insert(0, 'lib/') | |
extensions += ['sphinxcontrib_phpautodoc'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* this is bar function! */ | |
function bar() { | |
} | |
/* | |
* Class for foo | |
* | |
* * hello world | |
* * good bye world | |
*/ | |
class Foo { | |
// Hello *Sphinx* world! | |
function buz() { | |
} | |
} | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.. test documentation master file, created by | |
sphinx-quickstart on Wed Dec 26 19:08:50 2012. | |
You can adapt this file completely to your liking, but it should at least | |
contain the root `toctree` directive. | |
Welcome to test's documentation! | |
================================ | |
Contents: | |
.. phpautodoc:: hello.php | |
.. toctree:: | |
:maxdepth: 2 | |
Indices and tables | |
================== | |
* :ref:`genindex` | |
* :ref:`modindex` | |
* :ref:`search` | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ---------------------------------------------------------------------- | |
# phplex.py | |
# | |
# A lexer for PHP. | |
# ---------------------------------------------------------------------- | |
import ply.lex as lex | |
import re | |
# todo: nowdocs | |
# todo: backticks | |
# todo: binary string literals and casts | |
# todo: BAD_CHARACTER | |
# todo: <script> syntax (does anyone use this?) | |
states = ( | |
('php', 'exclusive'), | |
('quoted', 'exclusive'), | |
('quotedvar', 'exclusive'), | |
('varname', 'exclusive'), | |
('offset', 'exclusive'), | |
('property', 'exclusive'), | |
('heredoc', 'exclusive'), | |
('heredocvar', 'exclusive'), | |
) | |
# Reserved words | |
reserved = ( | |
'ARRAY', 'AS', 'BREAK', 'CASE', 'CLASS', 'CONST', 'CONTINUE', 'DECLARE', | |
'DEFAULT', 'DO', 'ECHO', 'ELSE', 'ELSEIF', 'EMPTY', 'ENDDECLARE', | |
'ENDFOR', 'ENDFOREACH', 'ENDIF', 'ENDSWITCH', 'ENDWHILE', 'EVAL', 'EXIT', | |
'EXTENDS', 'FOR', 'FOREACH', 'FUNCTION', 'GLOBAL', 'IF', 'INCLUDE', | |
'INCLUDE_ONCE', 'INSTANCEOF', 'ISSET', 'LIST', 'NEW', 'PRINT', 'REQUIRE', | |
'REQUIRE_ONCE', 'RETURN', 'STATIC', 'SWITCH', 'UNSET', 'USE', 'VAR', | |
'WHILE', 'FINAL', 'INTERFACE', 'IMPLEMENTS', 'PUBLIC', 'PRIVATE', | |
'PROTECTED', 'ABSTRACT', 'CLONE', 'TRY', 'CATCH', 'THROW', 'NAMESPACE', | |
) | |
# Not used by parser | |
unparsed = ( | |
# Invisible characters | |
'WHITESPACE', | |
# Open and close tags | |
'OPEN_TAG', 'OPEN_TAG_WITH_ECHO', 'CLOSE_TAG', | |
) | |
tokens = reserved + unparsed + ( | |
# Operators | |
'PLUS', 'MINUS', 'MUL', 'DIV', 'MOD', 'AND', 'OR', 'NOT', 'XOR', 'SL', | |
'SR', 'BOOLEAN_AND', 'BOOLEAN_OR', 'BOOLEAN_NOT', 'IS_SMALLER', | |
'IS_GREATER', 'IS_SMALLER_OR_EQUAL', 'IS_GREATER_OR_EQUAL', 'IS_EQUAL', | |
'IS_NOT_EQUAL', 'IS_IDENTICAL', 'IS_NOT_IDENTICAL', | |
# Assignment operators | |
'EQUALS', 'MUL_EQUAL', 'DIV_EQUAL', 'MOD_EQUAL', 'PLUS_EQUAL', | |
'MINUS_EQUAL', 'SL_EQUAL', 'SR_EQUAL', 'AND_EQUAL', 'OR_EQUAL', | |
'XOR_EQUAL', 'CONCAT_EQUAL', | |
# Increment/decrement | |
'INC', 'DEC', | |
# Arrows | |
'OBJECT_OPERATOR', 'DOUBLE_ARROW', 'DOUBLE_COLON', | |
# Delimiters | |
'LPAREN', 'RPAREN', 'LBRACKET', 'RBRACKET', 'LBRACE', 'RBRACE', 'DOLLAR', | |
'COMMA', 'CONCAT', 'QUESTION', 'COLON', 'SEMI', 'AT', 'NS_SEPARATOR', | |
# Casts | |
'ARRAY_CAST', 'BOOL_CAST', 'DOUBLE_CAST', 'INT_CAST', 'OBJECT_CAST', | |
'STRING_CAST', 'UNSET_CAST', | |
# Escaping from HTML | |
'INLINE_HTML', | |
# Identifiers and reserved words | |
'DIR', 'FILE', 'LINE', 'FUNC_C', 'CLASS_C', 'METHOD_C', 'NS_C', | |
'LOGICAL_AND', 'LOGICAL_OR', 'LOGICAL_XOR', | |
'HALT_COMPILER', | |
'STRING', 'VARIABLE', | |
'LNUMBER', 'DNUMBER', 'NUM_STRING', | |
'CONSTANT_ENCAPSED_STRING', 'ENCAPSED_AND_WHITESPACE', 'QUOTE', | |
'DOLLAR_OPEN_CURLY_BRACES', 'STRING_VARNAME', 'CURLY_OPEN', | |
# Heredocs | |
'START_HEREDOC', 'END_HEREDOC', | |
# Comments | |
'COMMENT', 'DOC_COMMENT', | |
) | |
# Newlines | |
def t_php_WHITESPACE(t): | |
r'[ \t\r\n]+' | |
t.lexer.lineno += t.value.count("\n") | |
return t | |
# Operators | |
t_php_PLUS = r'\+' | |
t_php_MINUS = r'-' | |
t_php_MUL = r'\*' | |
t_php_DIV = r'/' | |
t_php_MOD = r'%' | |
t_php_AND = r'&' | |
t_php_OR = r'\|' | |
t_php_NOT = r'~' | |
t_php_XOR = r'\^' | |
t_php_SL = r'<<' | |
t_php_SR = r'>>' | |
t_php_BOOLEAN_AND = r'&&' | |
t_php_BOOLEAN_OR = r'\|\|' | |
t_php_BOOLEAN_NOT = r'!' | |
t_php_IS_SMALLER = r'<' | |
t_php_IS_GREATER = r'>' | |
t_php_IS_SMALLER_OR_EQUAL = r'<=' | |
t_php_IS_GREATER_OR_EQUAL = r'>=' | |
t_php_IS_EQUAL = r'==' | |
t_php_IS_NOT_EQUAL = r'(!=(?!=))|(<>)' | |
t_php_IS_IDENTICAL = r'===' | |
t_php_IS_NOT_IDENTICAL = r'!==' | |
# Assignment operators | |
t_php_EQUALS = r'=' | |
t_php_MUL_EQUAL = r'\*=' | |
t_php_DIV_EQUAL = r'/=' | |
t_php_MOD_EQUAL = r'%=' | |
t_php_PLUS_EQUAL = r'\+=' | |
t_php_MINUS_EQUAL = r'-=' | |
t_php_SL_EQUAL = r'<<=' | |
t_php_SR_EQUAL = r'>>=' | |
t_php_AND_EQUAL = r'&=' | |
t_php_OR_EQUAL = r'\|=' | |
t_php_XOR_EQUAL = r'\^=' | |
t_php_CONCAT_EQUAL = r'\.=' | |
# Increment/decrement | |
t_php_INC = r'\+\+' | |
t_php_DEC = r'--' | |
# Arrows | |
t_php_DOUBLE_ARROW = r'=>' | |
t_php_DOUBLE_COLON = r'::' | |
def t_php_OBJECT_OPERATOR(t): | |
r'->' | |
if re.match(r'[A-Za-z_]', peek(t.lexer)): | |
t.lexer.push_state('property') | |
return t | |
# Delimeters | |
t_php_LPAREN = r'\(' | |
t_php_RPAREN = r'\)' | |
t_php_DOLLAR = r'\$' | |
t_php_COMMA = r',' | |
t_php_CONCAT = r'\.(?!\d|=)' | |
t_php_QUESTION = r'\?' | |
t_php_COLON = r':' | |
t_php_SEMI = r';' | |
t_php_AT = r'@' | |
t_php_NS_SEPARATOR = r'\\' | |
def t_php_LBRACKET(t): | |
r'\[' | |
t.lexer.push_state('php') | |
return t | |
def t_php_RBRACKET(t): | |
r'\]' | |
t.lexer.pop_state() | |
return t | |
def t_php_LBRACE(t): | |
r'\{' | |
t.lexer.push_state('php') | |
return t | |
def t_php_RBRACE(t): | |
r'\}' | |
t.lexer.pop_state() | |
return t | |
# Casts | |
t_php_ARRAY_CAST = r'\([ \t]*[Aa][Rr][Rr][Aa][Yy][ \t]*\)' | |
t_php_BOOL_CAST = r'\([ \t]*[Bb][Oo][Oo][Ll]([Ee][Aa][Nn])?[ \t]*\)' | |
t_php_DOUBLE_CAST = r'\([ \t]*([Rr][Ee][Aa][Ll]|[Dd][Oo][Uu][Bb][Ll][Ee]|[Ff][Ll][Oo][Aa][Tt])[ \t]*\)' | |
t_php_INT_CAST = r'\([ \t]*[Ii][Nn][Tt]([Ee][Gg][Ee][Rr])?[ \t]*\)' | |
t_php_OBJECT_CAST = r'\([ \t]*[Oo][Bb][Jj][Ee][Cc][Tt][ \t]*\)' | |
t_php_STRING_CAST = r'\([ \t]*[Ss][Tt][Rr][Ii][Nn][Gg][ \t]*\)' | |
t_php_UNSET_CAST = r'\([ \t]*[Uu][Nn][Ss][Ee][Tt][ \t]*\)' | |
# Comments | |
def t_php_DOC_COMMENT(t): | |
r'/\*\*(.|\n)*?\*/' | |
t.lexer.lineno += t.value.count("\n") | |
return t | |
def t_php_COMMENT(t): | |
r'/\*(.|\n)*?\*/ | //([^?%\n]|[?%](?!>))*\n? | \#([^?%\n]|[?%](?!>))*\n?' | |
t.lexer.lineno += t.value.count("\n") | |
return t | |
# Escaping from HTML | |
def t_OPEN_TAG(t): | |
r'<[?%]((php[ \t\r\n]?)|=)?' | |
if '=' in t.value: t.type = 'OPEN_TAG_WITH_ECHO' | |
t.lexer.lineno += t.value.count("\n") | |
t.lexer.begin('php') | |
return t | |
def t_php_CLOSE_TAG(t): | |
r'[?%]>\r?\n?' | |
t.lexer.lineno += t.value.count("\n") | |
t.lexer.begin('INITIAL') | |
return t | |
def t_INLINE_HTML(t): | |
r'([^<]|<(?![?%]))+' | |
t.lexer.lineno += t.value.count("\n") | |
return t | |
# Identifiers and reserved words | |
reserved_map = { | |
'__DIR__': 'DIR', | |
'__FILE__': 'FILE', | |
'__LINE__': 'LINE', | |
'__FUNCTION__': 'FUNC_C', | |
'__CLASS__': 'CLASS_C', | |
'__METHOD__': 'METHOD_C', | |
'__NAMESPACE__': 'NS_C', | |
'AND': 'LOGICAL_AND', | |
'OR': 'LOGICAL_OR', | |
'XOR': 'LOGICAL_XOR', | |
'DIE': 'EXIT', | |
'__HALT_COMPILER': 'HALT_COMPILER', | |
} | |
for r in reserved: | |
reserved_map[r] = r | |
# Identifier | |
def t_php_STRING(t): | |
r'[A-Za-z_][\w_]*' | |
t.type = reserved_map.get(t.value.upper(), 'STRING') | |
return t | |
# Variable | |
def t_php_VARIABLE(t): | |
r'\$[A-Za-z_][\w_]*' | |
return t | |
# Floating literal | |
def t_php_DNUMBER(t): | |
r'(\d*\.\d+|\d+\.\d*)([Ee][+-]?\d+)? | (\d+[Ee][+-]?\d+)' | |
return t | |
# Integer literal | |
def t_php_LNUMBER(t): | |
r'(0x[0-9A-Fa-f]+)|\d+' | |
return t | |
# String literal | |
def t_php_CONSTANT_ENCAPSED_STRING(t): | |
r"'([^\\']|\\(.|\n))*'" | |
t.lexer.lineno += t.value.count("\n") | |
return t | |
def t_php_QUOTE(t): | |
r'"' | |
t.lexer.push_state('quoted') | |
return t | |
def t_quoted_QUOTE(t): | |
r'"' | |
t.lexer.pop_state() | |
return t | |
def t_quoted_ENCAPSED_AND_WHITESPACE(t): | |
r'( [^"\\${] | \\(.|\n) | \$(?![A-Za-z_{]) | \{(?!\$) )+' | |
t.lexer.lineno += t.value.count("\n") | |
return t | |
def t_quoted_VARIABLE(t): | |
r'\$[A-Za-z_][\w_]*' | |
t.lexer.push_state('quotedvar') | |
return t | |
def t_quoted_CURLY_OPEN(t): | |
r'\{(?=\$)' | |
t.lexer.push_state('php') | |
return t | |
def t_quoted_DOLLAR_OPEN_CURLY_BRACES(t): | |
r'\$\{' | |
if re.match(r'[A-Za-z_]', peek(t.lexer)): | |
t.lexer.push_state('varname') | |
else: | |
t.lexer.push_state('php') | |
return t | |
def t_quotedvar_QUOTE(t): | |
r'"' | |
t.lexer.pop_state() | |
t.lexer.pop_state() | |
return t | |
def t_quotedvar_LBRACKET(t): | |
r'\[' | |
t.lexer.begin('offset') | |
return t | |
def t_quotedvar_OBJECT_OPERATOR(t): | |
r'->(?=[A-Za-z])' | |
t.lexer.begin('property') | |
return t | |
def t_quotedvar_ENCAPSED_AND_WHITESPACE(t): | |
r'( [^"\\${] | \\(.|\n) | \$(?![A-Za-z_{]) | \{(?!\$) )+' | |
t.lexer.lineno += t.value.count("\n") | |
t.lexer.pop_state() | |
return t | |
t_quotedvar_VARIABLE = t_php_VARIABLE | |
def t_quotedvar_CURLY_OPEN(t): | |
r'\{(?=\$)' | |
t.lexer.begin('php') | |
return t | |
def t_quotedvar_DOLLAR_OPEN_CURLY_BRACES(t): | |
r'\$\{' | |
if re.match(r'[A-Za-z_]', peek(t.lexer)): | |
t.lexer.begin('varname') | |
else: | |
t.lexer.begin('php') | |
return t | |
def t_varname_STRING_VARNAME(t): | |
r'[A-Za-z_][\w_]*' | |
return t | |
t_varname_RBRACE = t_php_RBRACE | |
t_varname_LBRACKET = t_php_LBRACKET | |
def t_offset_STRING(t): | |
r'[A-Za-z_][\w_]*' | |
return t | |
def t_offset_NUM_STRING(t): | |
r'\d+' | |
return t | |
t_offset_VARIABLE = t_php_VARIABLE | |
t_offset_RBRACKET = t_php_RBRACKET | |
def t_property_STRING(t): | |
r'[A-Za-z_][\w_]*' | |
t.lexer.pop_state() | |
return t | |
# Heredocs | |
def t_php_START_HEREDOC(t): | |
r'<<<[ \t]*(?P<label>[A-Za-z_][\w_]*)\n' | |
t.lexer.lineno += t.value.count("\n") | |
t.lexer.push_state('heredoc') | |
t.lexer.heredoc_label = t.lexer.lexmatch.group('label') | |
return t | |
def t_heredoc_END_HEREDOC(t): | |
r'(?<=\n)[A-Za-z_][\w_]*' | |
if t.value == t.lexer.heredoc_label: | |
del t.lexer.heredoc_label | |
t.lexer.pop_state() | |
else: | |
t.type = 'ENCAPSED_AND_WHITESPACE' | |
return t | |
def t_heredoc_ENCAPSED_AND_WHITESPACE(t): | |
r'( [^\n\\${] | \\. | \$(?![A-Za-z_{]) | \{(?!\$) )+\n? | \\?\n' | |
t.lexer.lineno += t.value.count("\n") | |
return t | |
def t_heredoc_VARIABLE(t): | |
r'\$[A-Za-z_][\w_]*' | |
t.lexer.push_state('heredocvar') | |
return t | |
t_heredoc_CURLY_OPEN = t_quoted_CURLY_OPEN | |
t_heredoc_DOLLAR_OPEN_CURLY_BRACES = t_quoted_DOLLAR_OPEN_CURLY_BRACES | |
def t_heredocvar_ENCAPSED_AND_WHITESPACE(t): | |
r'( [^\n\\${] | \\. | \$(?![A-Za-z_{]) | \{(?!\$) )+\n? | \\?\n' | |
t.lexer.lineno += t.value.count("\n") | |
t.lexer.pop_state() | |
return t | |
t_heredocvar_LBRACKET = t_quotedvar_LBRACKET | |
t_heredocvar_OBJECT_OPERATOR = t_quotedvar_OBJECT_OPERATOR | |
t_heredocvar_VARIABLE = t_quotedvar_VARIABLE | |
t_heredocvar_CURLY_OPEN = t_quotedvar_CURLY_OPEN | |
t_heredocvar_DOLLAR_OPEN_CURLY_BRACES = t_quotedvar_DOLLAR_OPEN_CURLY_BRACES | |
def t_ANY_error(t): | |
raise SyntaxError('illegal character', (None, t.lineno, None, t.value)) | |
def peek(lexer): | |
try: | |
return lexer.lexdata[lexer.lexpos] | |
except IndexError: | |
return '' | |
class FilteredLexer(object): | |
def __init__(self, lexer): | |
self.lexer = lexer | |
self.last_token = None | |
@property | |
def lineno(self): | |
return self.lexer.lineno | |
@lineno.setter | |
def lineno(self, value): | |
self.lexer.lineno = value | |
@property | |
def lexpos(self): | |
return self.lexer.lexpos | |
@lexpos.setter | |
def lexpos(self, value): | |
self.lexer.lexpos = value | |
def clone(self): | |
return FilteredLexer(self.lexer.clone()) | |
def current_state(self): | |
return self.lexer.current_state() | |
def input(self, input): | |
self.lexer.input(input) | |
def token(self): | |
t = self.lexer.token() | |
# Filter out tokens that the parser is not expecting. | |
while t and t.type in unparsed: | |
# Skip over open tags, but keep track of when we see them. | |
if t.type == 'OPEN_TAG': | |
self.last_token = t | |
t = self.lexer.token() | |
continue | |
# Rewrite <?= to yield an "echo" statement. | |
if t.type == 'OPEN_TAG_WITH_ECHO': | |
t.type = 'ECHO' | |
break | |
# Insert semicolons in place of close tags where necessary. | |
if t.type == 'CLOSE_TAG': | |
if self.last_token and \ | |
self.last_token.type in ('OPEN_TAG', 'SEMI', 'COLON', | |
'LBRACE', 'RBRACE'): | |
# Dont insert semicolons after these tokens. | |
pass | |
else: | |
# Rewrite close tag as a semicolon. | |
t.type = 'SEMI' | |
break | |
t = self.lexer.token() | |
self.last_token = t | |
return t | |
# Iterator interface | |
def __iter__(self): | |
return self | |
def next(self): | |
t = self.token() | |
if t is None: | |
raise StopIteration | |
return t | |
__next__ = next | |
full_lexer = lex.lex() | |
lexer = FilteredLexer(full_lexer) | |
full_tokens = tokens | |
tokens = filter(lambda token: token not in unparsed, tokens) | |
if __name__ == "__main__": | |
lex.runmain(full_lexer) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ----------------------------------------------------------------------------- | |
# phpparse.py | |
# | |
# A parser for PHP. | |
# ----------------------------------------------------------------------------- | |
import os | |
import sys | |
import phplex | |
from phply import phpast as ast | |
import ply.yacc as yacc | |
# Get the token map | |
tokens = phplex.tokens | |
ast.Comment = ast.node('Comment', ['text']) | |
precedence = ( | |
('left', 'INCLUDE', 'INCLUDE_ONCE', 'EVAL', 'REQUIRE', 'REQUIRE_ONCE'), | |
('left', 'COMMA'), | |
('left', 'LOGICAL_OR'), | |
('left', 'LOGICAL_XOR'), | |
('left', 'LOGICAL_AND'), | |
('right', 'PRINT'), | |
('left', 'EQUALS', 'PLUS_EQUAL', 'MINUS_EQUAL', 'MUL_EQUAL', 'DIV_EQUAL', 'CONCAT_EQUAL', 'MOD_EQUAL', 'AND_EQUAL', 'OR_EQUAL', 'XOR_EQUAL', 'SL_EQUAL', 'SR_EQUAL'), | |
('left', 'QUESTION', 'COLON'), | |
('left', 'BOOLEAN_OR'), | |
('left', 'BOOLEAN_AND'), | |
('left', 'OR'), | |
('left', 'XOR'), | |
('left', 'AND'), | |
('nonassoc', 'IS_EQUAL', 'IS_NOT_EQUAL', 'IS_IDENTICAL', 'IS_NOT_IDENTICAL'), | |
('nonassoc', 'IS_SMALLER', 'IS_SMALLER_OR_EQUAL', 'IS_GREATER', 'IS_GREATER_OR_EQUAL'), | |
('left', 'SL', 'SR'), | |
('left', 'PLUS', 'MINUS', 'CONCAT'), | |
('left', 'MUL', 'DIV', 'MOD'), | |
('right', 'BOOLEAN_NOT'), | |
('nonassoc', 'INSTANCEOF'), | |
('right', 'NOT', 'INC', 'DEC', 'INT_CAST', 'DOUBLE_CAST', 'STRING_CAST', 'ARRAY_CAST', 'OBJECT_CAST', 'BOOL_CAST', 'UNSET_CAST', 'AT'), | |
('right', 'LBRACKET'), | |
('nonassoc', 'NEW', 'CLONE'), | |
# ('left', 'ELSEIF'), | |
# ('left', 'ELSE'), | |
('left', 'ENDIF'), | |
('right', 'STATIC', 'ABSTRACT', 'FINAL', 'PRIVATE', 'PROTECTED', 'PUBLIC'), | |
) | |
def p_start(p): | |
'start : top_statement_list' | |
p[0] = p[1] | |
def p_top_statement_list(p): | |
'''top_statement_list : top_statement_list top_statement | |
| empty''' | |
if len(p) == 3: | |
p[0] = p[1] + [p[2]] | |
else: | |
p[0] = [] | |
def p_top_statement(p): | |
'''top_statement : statement | |
| comment | |
| function_declaration_statement | |
| class_declaration_statement | |
| HALT_COMPILER LPAREN RPAREN SEMI''' | |
if len(p) == 2: | |
p[0] = p[1] | |
else: | |
# ??? | |
pass | |
def p_top_statement_namespace(p): | |
'''top_statement : NAMESPACE namespace_name SEMI | |
| NAMESPACE LBRACE top_statement_list RBRACE | |
| NAMESPACE namespace_name LBRACE top_statement_list RBRACE''' | |
if len(p) == 4: | |
p[0] = ast.Namespace(p[2], [], lineno=p.lineno(1)) | |
elif len(p) == 5: | |
p[0] = ast.Namespace(None, p[3], lineno=p.lineno(1)) | |
else: | |
p[0] = ast.Namespace(p[2], p[4], lineno=p.lineno(1)) | |
def p_top_statement_constant(p): | |
'top_statement : CONST constant_declarations SEMI' | |
p[0] = ast.ConstantDeclarations(p[2], lineno=p.lineno(1)) | |
def p_top_statement_use(p): | |
'top_statement : USE use_declarations SEMI' | |
p[0] = ast.UseDeclarations(p[2], lineno=p.lineno(1)) | |
def p_use_declarations(p): | |
'''use_declarations : use_declarations COMMA use_declaration | |
| use_declaration''' | |
if len(p) == 4: | |
p[0] = p[1] + [p[3]] | |
else: | |
p[0] = [p[1]] | |
def p_use_declaration(p): | |
'''use_declaration : namespace_name | |
| NS_SEPARATOR namespace_name | |
| namespace_name AS STRING | |
| NS_SEPARATOR namespace_name AS STRING''' | |
if len(p) == 2: | |
p[0] = ast.UseDeclaration(p[1], None, lineno=p.lineno(1)) | |
elif len(p) == 3: | |
p[0] = ast.UseDeclaration(p[1] + p[2], None, lineno=p.lineno(1)) | |
elif len(p) == 4: | |
p[0] = ast.UseDeclaration(p[1], p[3], lineno=p.lineno(2)) | |
else: | |
p[0] = ast.UseDeclaration(p[1] + p[2], p[4], lineno=p.lineno(1)) | |
def p_constant_declarations(p): | |
'''constant_declarations : constant_declarations COMMA constant_declaration | |
| constant_declaration''' | |
if len(p) == 4: | |
p[0] = p[1] + [p[3]] | |
else: | |
p[0] = [p[1]] | |
def p_constant_declaration(p): | |
'constant_declaration : STRING EQUALS static_scalar' | |
p[0] = ast.ConstantDeclaration(p[1], p[3], lineno=p.lineno(1)) | |
def p_inner_statement_list(p): | |
'''inner_statement_list : inner_statement_list inner_statement | |
| empty''' | |
if len(p) == 3: | |
p[0] = p[1] + [p[2]] | |
else: | |
p[0] = [] | |
def p_inner_statement(p): | |
'''inner_statement : statement | |
| function_declaration_statement | |
| class_declaration_statement | |
| HALT_COMPILER LPAREN RPAREN SEMI''' | |
assert len(p) == 2, "__HALT_COMPILER() can only be used from the outermost scope" | |
p[0] = p[1] | |
def p_statement_block(p): | |
'statement : LBRACE inner_statement_list RBRACE' | |
p[0] = ast.Block(p[2], lineno=p.lineno(1)) | |
def p_statement_if(p): | |
'''statement : IF LPAREN expr RPAREN statement elseif_list else_single | |
| IF LPAREN expr RPAREN COLON inner_statement_list new_elseif_list new_else_single ENDIF SEMI''' | |
if len(p) == 8: | |
p[0] = ast.If(p[3], p[5], p[6], p[7], lineno=p.lineno(1)) | |
else: | |
p[0] = ast.If(p[3], ast.Block(p[6], lineno=p.lineno(5)), | |
p[7], p[8], lineno=p.lineno(1)) | |
def p_statement_while(p): | |
'statement : WHILE LPAREN expr RPAREN while_statement' | |
p[0] = ast.While(p[3], p[5], lineno=p.lineno(1)) | |
def p_statement_do_while(p): | |
'statement : DO statement WHILE LPAREN expr RPAREN SEMI' | |
p[0] = ast.DoWhile(p[2], p[5], lineno=p.lineno(1)) | |
def p_statement_for(p): | |
'statement : FOR LPAREN for_expr SEMI for_expr SEMI for_expr RPAREN for_statement' | |
p[0] = ast.For(p[3], p[5], p[7], p[9], lineno=p.lineno(1)) | |
def p_statement_foreach(p): | |
'statement : FOREACH LPAREN expr AS foreach_variable foreach_optional_arg RPAREN foreach_statement' | |
if p[6] is None: | |
p[0] = ast.Foreach(p[3], None, p[5], p[8], lineno=p.lineno(1)) | |
else: | |
p[0] = ast.Foreach(p[3], p[5], p[6], p[8], lineno=p.lineno(1)) | |
def p_statement_switch(p): | |
'statement : SWITCH LPAREN expr RPAREN switch_case_list' | |
p[0] = ast.Switch(p[3], p[5], lineno=p.lineno(1)) | |
def p_statement_break(p): | |
'''statement : BREAK SEMI | |
| BREAK expr SEMI''' | |
if len(p) == 3: | |
p[0] = ast.Break(None, lineno=p.lineno(1)) | |
else: | |
p[0] = ast.Break(p[2], lineno=p.lineno(1)) | |
def p_statement_continue(p): | |
'''statement : CONTINUE SEMI | |
| CONTINUE expr SEMI''' | |
if len(p) == 3: | |
p[0] = ast.Continue(None, lineno=p.lineno(1)) | |
else: | |
p[0] = ast.Continue(p[2], lineno=p.lineno(1)) | |
def p_statement_return(p): | |
'''statement : RETURN SEMI | |
| RETURN expr SEMI''' | |
if len(p) == 3: | |
p[0] = ast.Return(None, lineno=p.lineno(1)) | |
else: | |
p[0] = ast.Return(p[2], lineno=p.lineno(1)) | |
def p_statement_global(p): | |
'statement : GLOBAL global_var_list SEMI' | |
p[0] = ast.Global(p[2], lineno=p.lineno(1)) | |
def p_statement_static(p): | |
'statement : STATIC static_var_list SEMI' | |
p[0] = ast.Static(p[2], lineno=p.lineno(1)) | |
def p_statement_echo(p): | |
'statement : ECHO echo_expr_list SEMI' | |
p[0] = ast.Echo(p[2], lineno=p.lineno(1)) | |
def p_statement_inline_html(p): | |
'statement : INLINE_HTML' | |
p[0] = ast.InlineHTML(p[1], lineno=p.lineno(1)) | |
def p_statement_expr(p): | |
'statement : expr SEMI' | |
p[0] = p[1] | |
def p_statement_unset(p): | |
'statement : UNSET LPAREN unset_variables RPAREN SEMI' | |
p[0] = ast.Unset(p[3], lineno=p.lineno(1)) | |
def p_statement_empty(p): | |
'statement : SEMI' | |
pass | |
def p_statement_try(p): | |
'statement : TRY LBRACE inner_statement_list RBRACE CATCH LPAREN fully_qualified_class_name VARIABLE RPAREN LBRACE inner_statement_list RBRACE additional_catches' | |
p[0] = ast.Try(p[3], [ast.Catch(p[7], ast.Variable(p[8], lineno=p.lineno(8)), | |
p[11], lineno=p.lineno(5))] + p[13], | |
lineno=p.lineno(1)) | |
def p_additional_catches(p): | |
'''additional_catches : additional_catches CATCH LPAREN fully_qualified_class_name VARIABLE RPAREN LBRACE inner_statement_list RBRACE | |
| empty''' | |
if len(p) == 10: | |
p[0] = p[1] + [ast.Catch(p[4], ast.Variable(p[5], lineno=p.lineno(5)), | |
p[8], lineno=p.lineno(2))] | |
else: | |
p[0] = [] | |
def p_statement_throw(p): | |
'statement : THROW expr SEMI' | |
p[0] = ast.Throw(p[2], lineno=p.lineno(1)) | |
def p_statement_declare(p): | |
'statement : DECLARE LPAREN declare_list RPAREN declare_statement' | |
p[0] = ast.Declare(p[3], p[5], lineno=p.lineno(1)) | |
def p_declare_list(p): | |
'''declare_list : STRING EQUALS static_scalar | |
| declare_list COMMA STRING EQUALS static_scalar''' | |
if len(p) == 4: | |
p[0] = [ast.Directive(p[1], p[3], lineno=p.lineno(1))] | |
else: | |
p[0] = p[1] + [ast.Directive(p[3], p[5], lineno=p.lineno(2))] | |
def p_declare_statement(p): | |
'''declare_statement : statement | |
| COLON inner_statement_list ENDDECLARE SEMI''' | |
if len(p) == 2: | |
p[0] = p[1] | |
else: | |
p[0] = ast.Block(p[2], lineno=p.lineno(1)) | |
def p_elseif_list(p): | |
'''elseif_list : empty | |
| elseif_list ELSEIF LPAREN expr RPAREN statement''' | |
if len(p) == 2: | |
p[0] = [] | |
else: | |
p[0] = p[1] + [ast.ElseIf(p[4], p[6], lineno=p.lineno(2))] | |
def p_else_single(p): | |
'''else_single : empty | |
| ELSE statement''' | |
if len(p) == 3: | |
p[0] = ast.Else(p[2], lineno=p.lineno(1)) | |
def p_new_elseif_list(p): | |
'''new_elseif_list : empty | |
| new_elseif_list ELSEIF LPAREN expr RPAREN COLON inner_statement_list''' | |
if len(p) == 2: | |
p[0] = [] | |
else: | |
p[0] = p[1] + [ast.ElseIf(p[4], ast.Block(p[7], lineo=p.lineno(6)), | |
lineno=p.lineno(2))] | |
def p_new_else_single(p): | |
'''new_else_single : empty | |
| ELSE COLON inner_statement_list''' | |
if len(p) == 4: | |
p[0] = ast.Else(ast.Block(p[3], lineno=p.lineno(2)), | |
lineno=p.lineno(1)) | |
def p_while_statement(p): | |
'''while_statement : statement | |
| COLON inner_statement_list ENDWHILE SEMI''' | |
if len(p) == 2: | |
p[0] = p[1] | |
else: | |
p[0] = ast.Block(p[2], lineno=p.lineno(1)) | |
def p_for_expr(p): | |
'''for_expr : empty | |
| non_empty_for_expr''' | |
p[0] = p[1] | |
def p_non_empty_for_expr(p): | |
'''non_empty_for_expr : non_empty_for_expr COMMA expr | |
| expr''' | |
if len(p) == 4: | |
p[0] = p[1] + [p[3]] | |
else: | |
p[0] = [p[1]] | |
def p_for_statement(p): | |
'''for_statement : statement | |
| COLON inner_statement_list ENDFOR SEMI''' | |
if len(p) == 2: | |
p[0] = p[1] | |
else: | |
p[0] = ast.Block(p[2], lineno=p.lineno(1)) | |
def p_foreach_variable(p): | |
'''foreach_variable : VARIABLE | |
| AND VARIABLE''' | |
if len(p) == 2: | |
p[0] = ast.ForeachVariable(p[1], False, lineno=p.lineno(1)) | |
else: | |
p[0] = ast.ForeachVariable(p[2], True, lineno=p.lineno(1)) | |
def p_foreach_optional_arg(p): | |
'''foreach_optional_arg : empty | |
| DOUBLE_ARROW foreach_variable''' | |
if len(p) == 3: | |
p[0] = p[2] | |
def p_foreach_statement(p): | |
'''foreach_statement : statement | |
| COLON inner_statement_list ENDFOREACH SEMI''' | |
if len(p) == 2: | |
p[0] = p[1] | |
else: | |
p[0] = ast.Block(p[2], lineno=p.lineno(1)) | |
def p_switch_case_list(p): | |
'''switch_case_list : LBRACE case_list RBRACE | |
| LBRACE SEMI case_list RBRACE''' | |
if len(p) == 4: | |
p[0] = p[2] | |
else: | |
p[0] = p[3] | |
def p_switch_case_list_colon(p): | |
'''switch_case_list : COLON case_list ENDSWITCH SEMI | |
| COLON SEMI case_list ENDSWITCH SEMI''' | |
if len(p) == 5: | |
p[0] = p[2] | |
else: | |
p[0] = p[3] | |
def p_case_list(p): | |
'''case_list : empty | |
| case_list CASE expr case_separator inner_statement_list | |
| case_list DEFAULT case_separator inner_statement_list''' | |
if len(p) == 6: | |
p[0] = p[1] + [ast.Case(p[3], p[5], lineno=p.lineno(2))] | |
elif len(p) == 5: | |
p[0] = p[1] + [ast.Default(p[4], lineno=p.lineno(2))] | |
else: | |
p[0] = [] | |
def p_case_separator(p): | |
'''case_separator : COLON | |
| SEMI''' | |
pass | |
def p_global_var_list(p): | |
'''global_var_list : global_var_list COMMA global_var | |
| global_var''' | |
if len(p) == 4: | |
p[0] = p[1] + [p[3]] | |
else: | |
p[0] = [p[1]] | |
def p_global_var(p): | |
'''global_var : VARIABLE | |
| DOLLAR variable | |
| DOLLAR LBRACE expr RBRACE''' | |
if len(p) == 2: | |
p[0] = ast.Variable(p[1], lineno=p.lineno(1)) | |
elif len(p) == 3: | |
p[0] = ast.Variable(p[2], lineno=p.lineno(1)) | |
else: | |
p[0] = ast.Variable(p[3], lineno=p.lineno(1)) | |
def p_static_var_list(p): | |
'''static_var_list : static_var_list COMMA static_var | |
| static_var''' | |
if len(p) == 4: | |
p[0] = p[1] + [p[3]] | |
else: | |
p[0] = [p[1]] | |
def p_static_var(p): | |
'''static_var : VARIABLE EQUALS static_scalar | |
| VARIABLE''' | |
if len(p) == 4: | |
p[0] = ast.StaticVariable(p[1], p[3], lineno=p.lineno(1)) | |
else: | |
p[0] = ast.StaticVariable(p[1], None, lineno=p.lineno(1)) | |
def p_echo_expr_list(p): | |
'''echo_expr_list : echo_expr_list COMMA expr | |
| expr''' | |
if len(p) == 4: | |
p[0] = p[1] + [p[3]] | |
else: | |
p[0] = [p[1]] | |
def p_unset_variables(p): | |
'''unset_variables : unset_variables COMMA unset_variable | |
| unset_variable''' | |
if len(p) == 4: | |
p[0] = p[1] + [p[3]] | |
else: | |
p[0] = [p[1]] | |
def p_unset_variable(p): | |
'unset_variable : variable' | |
p[0] = p[1] | |
def p_function_declaration_statement(p): | |
'function_declaration_statement : FUNCTION is_reference STRING LPAREN parameter_list RPAREN LBRACE inner_statement_list RBRACE' | |
p[0] = ast.Function(p[3], p[5], p[8], p[2], lineno=p.lineno(1)) | |
def p_class_declaration_statement(p): | |
'''class_declaration_statement : class_entry_type STRING extends_from implements_list LBRACE class_statement_list RBRACE | |
| INTERFACE STRING interface_extends_list LBRACE class_statement_list RBRACE''' | |
if len(p) == 8: | |
p[0] = ast.Class(p[2], p[1], p[3], p[4], p[6], lineno=p.lineno(2)) | |
else: | |
p[0] = ast.Interface(p[2], p[3], p[5], lineno=p.lineno(1)) | |
def p_class_entry_type(p): | |
'''class_entry_type : CLASS | |
| ABSTRACT CLASS | |
| FINAL CLASS''' | |
if len(p) == 3: | |
p[0] = p[1].lower() | |
def p_extends_from(p): | |
'''extends_from : empty | |
| EXTENDS fully_qualified_class_name''' | |
if len(p) == 3: | |
p[0] = p[2] | |
def p_fully_qualified_class_name(p): | |
'''fully_qualified_class_name : namespace_name | |
| NS_SEPARATOR namespace_name | |
| NAMESPACE NS_SEPARATOR namespace_name''' | |
if len(p) == 2: | |
p[0] = p[1] | |
elif len(p) == 3: | |
p[0] = p[1] + p[2] | |
else: | |
p[0] = p[1] + p[2] + p[3] | |
def p_implements_list(p): | |
'''implements_list : IMPLEMENTS interface_list | |
| empty''' | |
if len(p) == 3: | |
p[0] = p[2] | |
else: | |
p[0] = [] | |
def p_class_statement_list(p): | |
'''class_statement_list : class_statement_list class_statement | |
| empty''' | |
if len(p) == 3: | |
p[0] = p[1] + [p[2]] | |
else: | |
p[0] = [] | |
def p_class_statement(p): | |
'''class_statement : method_modifiers FUNCTION is_reference STRING LPAREN parameter_list RPAREN method_body | |
| comment | |
| variable_modifiers class_variable_declaration SEMI | |
| class_constant_declaration SEMI''' | |
if len(p) == 9: | |
p[0] = ast.Method(p[4], p[1], p[6], p[8], p[3], lineno=p.lineno(2)) | |
elif len(p) == 4: | |
p[0] = ast.ClassVariables(p[1], p[2], lineno=p.lineno(3)) | |
elif len(p) == 2: | |
p[0] = p[1] | |
else: | |
p[0] = ast.ClassConstants(p[1], lineno=p.lineno(2)) | |
def p_class_variable_declaration_initial(p): | |
'''class_variable_declaration : class_variable_declaration COMMA VARIABLE EQUALS static_scalar | |
| VARIABLE EQUALS static_scalar''' | |
if len(p) == 6: | |
p[0] = p[1] + [ast.ClassVariable(p[3], p[5], lineno=p.lineno(2))] | |
else: | |
p[0] = [ast.ClassVariable(p[1], p[3], lineno=p.lineno(1))] | |
def p_class_variable_declaration_no_initial(p): | |
'''class_variable_declaration : class_variable_declaration COMMA VARIABLE | |
| VARIABLE''' | |
if len(p) == 4: | |
p[0] = p[1] + [ast.ClassVariable(p[3], None, lineno=p.lineno(2))] | |
else: | |
p[0] = [ast.ClassVariable(p[1], None, lineno=p.lineno(1))] | |
def p_class_constant_declaration(p): | |
'''class_constant_declaration : class_constant_declaration COMMA STRING EQUALS static_scalar | |
| CONST STRING EQUALS static_scalar''' | |
if len(p) == 6: | |
p[0] = p[1] + [ast.ClassConstant(p[3], p[5], lineno=p.lineno(2))] | |
else: | |
p[0] = [ast.ClassConstant(p[2], p[4], lineno=p.lineno(1))] | |
def p_interface_list(p): | |
'''interface_list : interface_list COMMA fully_qualified_class_name | |
| fully_qualified_class_name''' | |
if len(p) == 4: | |
p[0] = p[1] + [p[3]] | |
else: | |
p[0] = [p[1]] | |
def p_interface_extends_list(p): | |
'''interface_extends_list : EXTENDS interface_list | |
| empty''' | |
if len(p) == 3: | |
p[0] = p[2] | |
def p_variable_modifiers_non_empty(p): | |
'variable_modifiers : non_empty_member_modifiers' | |
p[0] = p[1] | |
def p_variable_modifiers_var(p): | |
'variable_modifiers : VAR' | |
p[0] = [] | |
def p_method_modifiers_non_empty(p): | |
'method_modifiers : non_empty_member_modifiers' | |
p[0] = p[1] | |
def p_method_modifiers_empty(p): | |
'method_modifiers : empty' | |
p[0] = [] | |
def p_method_body(p): | |
'''method_body : LBRACE inner_statement_list RBRACE | |
| SEMI''' | |
if len(p) == 4: | |
p[0] = p[2] | |
else: | |
p[0] = [] | |
def p_non_empty_member_modifiers(p): | |
'''non_empty_member_modifiers : non_empty_member_modifiers member_modifier | |
| member_modifier''' | |
if len(p) == 3: | |
p[0] = p[1] + [p[2]] | |
else: | |
p[0] = [p[1]] | |
def p_member_modifier(p): | |
'''member_modifier : PUBLIC | |
| PROTECTED | |
| PRIVATE | |
| STATIC | |
| ABSTRACT | |
| FINAL''' | |
p[0] = p[1].lower() | |
def p_is_reference(p): | |
'''is_reference : AND | |
| empty''' | |
p[0] = p[1] is not None | |
def p_parameter_list(p): | |
'''parameter_list : parameter_list COMMA parameter | |
| parameter''' | |
if len(p) == 4: | |
p[0] = p[1] + [p[3]] | |
else: | |
p[0] = [p[1]] | |
def p_parameter_list_empty(p): | |
'parameter_list : empty' | |
p[0] = [] | |
def p_parameter(p): | |
'''parameter : VARIABLE | |
| class_name VARIABLE | |
| AND VARIABLE | |
| class_name AND VARIABLE | |
| VARIABLE EQUALS static_scalar | |
| class_name VARIABLE EQUALS static_scalar | |
| AND VARIABLE EQUALS static_scalar | |
| class_name AND VARIABLE EQUALS static_scalar''' | |
if len(p) == 2: # VARIABLE | |
p[0] = ast.FormalParameter(p[1], None, False, None, lineno=p.lineno(1)) | |
elif len(p) == 3 and p[1] == '&': # AND VARIABLE | |
p[0] = ast.FormalParameter(p[2], None, True, None, lineno=p.lineno(1)) | |
elif len(p) == 3 and p[1] != '&': # STRING VARIABLE | |
p[0] = ast.FormalParameter(p[2], None, False, p[1], lineno=p.lineno(1)) | |
elif len(p) == 4 and p[2] != '&': # VARIABLE EQUALS static_scalar | |
p[0] = ast.FormalParameter(p[1], p[3], False, None, lineno=p.lineno(1)) | |
elif len(p) == 4 and p[2] == '&': # STRING AND VARIABLE | |
p[0] = ast.FormalParameter(p[3], None, True, p[1], lineno=p.lineno(1)) | |
elif len(p) == 5 and p[1] == '&': # AND VARIABLE EQUALS static_scalar | |
p[0] = ast.FormalParameter(p[2], p[4], True, None, lineno=p.lineno(1)) | |
elif len(p) == 5 and p[1] != '&': # class_name VARIABLE EQUALS static_scalar | |
p[0] = ast.FormalParameter(p[2], p[4], False, p[1], lineno=p.lineno(1)) | |
else: # STRING AND VARIABLE EQUALS static_scalar | |
p[0] = ast.FormalParameter(p[3], p[5], True, p[1], lineno=p.lineno(1)) | |
def p_expr_variable(p): | |
'expr : variable' | |
p[0] = p[1] | |
def p_expr_assign(p): | |
'''expr : variable EQUALS expr | |
| variable EQUALS AND expr''' | |
if len(p) == 5: | |
p[0] = ast.Assignment(p[1], p[4], True, lineno=p.lineno(2)) | |
else: | |
p[0] = ast.Assignment(p[1], p[3], False, lineno=p.lineno(2)) | |
def p_expr_new(p): | |
'expr : NEW class_name_reference ctor_arguments' | |
p[0] = ast.New(p[2], p[3], lineno=p.lineno(1)) | |
def p_class_name_reference(p): | |
'''class_name_reference : class_name | |
| dynamic_class_name_reference''' | |
p[0] = p[1] | |
def p_class_name(p): | |
'''class_name : namespace_name | |
| NS_SEPARATOR namespace_name | |
| NAMESPACE NS_SEPARATOR namespace_name''' | |
if len(p) == 2: | |
p[0] = p[1] | |
elif len(p) == 3: | |
p[0] = p[1] + p[2] | |
else: | |
p[0] = p[1] + p[2] + p[3] | |
def p_class_name_static(p): | |
'class_name : STATIC' | |
p[0] = p[1].lower() | |
def p_dynamic_class_name_reference(p): | |
'''dynamic_class_name_reference : base_variable OBJECT_OPERATOR object_property dynamic_class_name_variable_properties | |
| base_variable''' | |
if len(p) == 5: | |
name, dims = p[3] | |
p[0] = ast.ObjectProperty(p[1], name, lineno=p.lineno(2)) | |
for class_, dim, lineno in dims: | |
p[0] = class_(p[0], dim, lineno=lineno) | |
for name, dims in p[4]: | |
p[0] = ast.ObjectProperty(p[0], name, lineno=p.lineno(2)) | |
for class_, dim, lineno in dims: | |
p[0] = class_(p[0], dim, lineno=lineno) | |
else: | |
p[0] = p[1] | |
def p_dynamic_class_name_variable_properties(p): | |
'''dynamic_class_name_variable_properties : dynamic_class_name_variable_properties dynamic_class_name_variable_property | |
| empty''' | |
if len(p) == 3: | |
p[0] = p[1] + [p[2]] | |
else: | |
p[0] = [] | |
def p_dynamic_class_name_variable_property(p): | |
'dynamic_class_name_variable_property : OBJECT_OPERATOR object_property' | |
p[0] = p[2] | |
def p_ctor_arguments(p): | |
'''ctor_arguments : LPAREN function_call_parameter_list RPAREN | |
| empty''' | |
if len(p) == 4: | |
p[0] = p[2] | |
else: | |
p[0] = [] | |
def p_expr_clone(p): | |
'expr : CLONE expr' | |
p[0] = ast.Clone(p[2], lineno=p.lineno(1)) | |
def p_expr_list_assign(p): | |
'expr : LIST LPAREN assignment_list RPAREN EQUALS expr' | |
p[0] = ast.ListAssignment(p[3], p[6], lineno=p.lineno(1)) | |
def p_assignment_list(p): | |
'''assignment_list : assignment_list COMMA assignment_list_element | |
| assignment_list_element''' | |
if len(p) == 4: | |
p[0] = p[1] + [p[3]] | |
else: | |
p[0] = [p[1]] | |
def p_assignment_list_element(p): | |
'''assignment_list_element : variable | |
| empty | |
| LIST LPAREN assignment_list RPAREN''' | |
if len(p) == 2: | |
p[0] = p[1] | |
else: | |
p[0] = p[3] | |
def p_variable(p): | |
'''variable : base_variable_with_function_calls OBJECT_OPERATOR object_property method_or_not variable_properties | |
| base_variable_with_function_calls''' | |
if len(p) == 6: | |
name, dims = p[3] | |
params = p[4] | |
if params is not None: | |
p[0] = ast.MethodCall(p[1], name, params, lineno=p.lineno(2)) | |
else: | |
p[0] = ast.ObjectProperty(p[1], name, lineno=p.lineno(2)) | |
for class_, dim, lineno in dims: | |
p[0] = class_(p[0], dim, lineno=lineno) | |
for (name, dims), params in p[5]: | |
if params is not None: | |
p[0] = ast.MethodCall(p[0], name, params, lineno=p.lineno(2)) | |
else: | |
p[0] = ast.ObjectProperty(p[0], name, lineno=p.lineno(2)) | |
for class_, dim, lineno in dims: | |
p[0] = class_(p[0], dim, lineno=lineno) | |
else: | |
p[0] = p[1] | |
def p_base_variable_with_function_calls(p): | |
'''base_variable_with_function_calls : base_variable | |
| function_call''' | |
p[0] = p[1] | |
def p_function_call(p): | |
'''function_call : namespace_name LPAREN function_call_parameter_list RPAREN | |
| NS_SEPARATOR namespace_name LPAREN function_call_parameter_list RPAREN | |
| NAMESPACE NS_SEPARATOR namespace_name LPAREN function_call_parameter_list RPAREN''' | |
if len(p) == 5: | |
p[0] = ast.FunctionCall(p[1], p[3], lineno=p.lineno(2)) | |
elif len(p) == 6: | |
p[0] = ast.FunctionCall(p[1] + p[2], p[4], lineno=p.lineno(1)) | |
else: | |
p[0] = ast.FunctionCall(p[1] + p[2] + p[3], p[5], lineno=p.lineno(1)) | |
def p_function_call_static(p): | |
'''function_call : class_name DOUBLE_COLON STRING LPAREN function_call_parameter_list RPAREN | |
| class_name DOUBLE_COLON variable_without_objects LPAREN function_call_parameter_list RPAREN | |
| variable_class_name DOUBLE_COLON STRING LPAREN function_call_parameter_list RPAREN | |
| variable_class_name DOUBLE_COLON variable_without_objects LPAREN function_call_parameter_list RPAREN''' | |
p[0] = ast.StaticMethodCall(p[1], p[3], p[5], lineno=p.lineno(2)) | |
def p_function_call_variable(p): | |
'function_call : variable_without_objects LPAREN function_call_parameter_list RPAREN' | |
p[0] = ast.FunctionCall(p[1], p[3], lineno=p.lineno(2)) | |
def p_method_or_not(p): | |
'''method_or_not : LPAREN function_call_parameter_list RPAREN | |
| empty''' | |
if len(p) == 4: | |
p[0] = p[2] | |
def p_variable_properties(p): | |
'''variable_properties : variable_properties variable_property | |
| empty''' | |
if len(p) == 3: | |
p[0] = p[1] + [p[2]] | |
else: | |
p[0] = [] | |
def p_variable_property(p): | |
'variable_property : OBJECT_OPERATOR object_property method_or_not' | |
p[0] = (p[2], p[3]) | |
def p_base_variable(p): | |
'''base_variable : simple_indirect_reference | |
| static_member''' | |
p[0] = p[1] | |
def p_simple_indirect_reference(p): | |
'''simple_indirect_reference : DOLLAR simple_indirect_reference | |
| reference_variable''' | |
if len(p) == 3: | |
p[0] = ast.Variable(p[2], lineno=p.lineno(1)) | |
else: | |
p[0] = p[1] | |
def p_static_member(p): | |
'''static_member : class_name DOUBLE_COLON variable_without_objects | |
| variable_class_name DOUBLE_COLON variable_without_objects''' | |
p[0] = ast.StaticProperty(p[1], p[3], lineno=p.lineno(2)) | |
def p_variable_class_name(p): | |
'variable_class_name : reference_variable' | |
p[0] = p[1] | |
def p_reference_variable_array_offset(p): | |
'reference_variable : reference_variable LBRACKET dim_offset RBRACKET' | |
p[0] = ast.ArrayOffset(p[1], p[3], lineno=p.lineno(2)) | |
def p_reference_variable_string_offset(p): | |
'reference_variable : reference_variable LBRACE expr RBRACE' | |
p[0] = ast.StringOffset(p[1], p[3], lineno=p.lineno(2)) | |
def p_reference_variable_compound_variable(p): | |
'reference_variable : compound_variable' | |
p[0] = p[1] | |
def p_compound_variable(p): | |
'''compound_variable : VARIABLE | |
| DOLLAR LBRACE expr RBRACE''' | |
if len(p) == 2: | |
p[0] = ast.Variable(p[1], lineno=p.lineno(1)) | |
else: | |
p[0] = ast.Variable(p[3], lineno=p.lineno(1)) | |
def p_dim_offset(p): | |
'''dim_offset : expr | |
| empty''' | |
p[0] = p[1] | |
def p_object_property(p): | |
'''object_property : variable_name object_dim_list | |
| variable_without_objects''' | |
if len(p) == 3: | |
p[0] = (p[1], p[2]) | |
else: | |
p[0] = (p[1], []) | |
def p_object_dim_list_empty(p): | |
'object_dim_list : empty' | |
p[0] = [] | |
def p_object_dim_list_array_offset(p): | |
'object_dim_list : object_dim_list LBRACKET dim_offset RBRACKET' | |
p[0] = p[1] + [(ast.ArrayOffset, p[3], p.lineno(2))] | |
def p_object_dim_list_string_offset(p): | |
'object_dim_list : object_dim_list LBRACE expr RBRACE' | |
p[0] = p[1] + [(ast.StringOffset, p[3], p.lineno(2))] | |
def p_variable_name(p): | |
'''variable_name : STRING | |
| LBRACE expr RBRACE''' | |
if len(p) == 2: | |
p[0] = p[1] | |
else: | |
p[0] = p[2] | |
def p_variable_without_objects(p): | |
'variable_without_objects : simple_indirect_reference' | |
p[0] = p[1] | |
def p_expr_scalar(p): | |
'expr : scalar' | |
p[0] = p[1] | |
def p_expr_array(p): | |
'expr : ARRAY LPAREN array_pair_list RPAREN' | |
p[0] = ast.Array(p[3], lineno=p.lineno(1)) | |
def p_array_pair_list(p): | |
'''array_pair_list : empty | |
| non_empty_array_pair_list possible_comma''' | |
if len(p) == 2: | |
p[0] = [] | |
else: | |
p[0] = p[1] | |
def p_non_empty_array_pair_list_item(p): | |
'''non_empty_array_pair_list : non_empty_array_pair_list COMMA AND variable | |
| non_empty_array_pair_list COMMA expr | |
| AND variable | |
| expr''' | |
if len(p) == 5: | |
p[0] = p[1] + [ast.ArrayElement(None, p[4], True, lineno=p.lineno(2))] | |
elif len(p) == 4: | |
p[0] = p[1] + [ast.ArrayElement(None, p[3], False, lineno=p.lineno(2))] | |
elif len(p) == 3: | |
p[0] = [ast.ArrayElement(None, p[2], True, lineno=p.lineno(1))] | |
else: | |
p[0] = [ast.ArrayElement(None, p[1], False, lineno=p.lineno(1))] | |
def p_non_empty_array_pair_list_pair(p): | |
'''non_empty_array_pair_list : non_empty_array_pair_list COMMA expr DOUBLE_ARROW AND variable | |
| non_empty_array_pair_list COMMA expr DOUBLE_ARROW expr | |
| expr DOUBLE_ARROW AND variable | |
| expr DOUBLE_ARROW expr''' | |
if len(p) == 7: | |
p[0] = p[1] + [ast.ArrayElement(p[3], p[6], True, lineno=p.lineno(2))] | |
elif len(p) == 6: | |
p[0] = p[1] + [ast.ArrayElement(p[3], p[5], False, lineno=p.lineno(2))] | |
elif len(p) == 5: | |
p[0] = [ast.ArrayElement(p[1], p[4], True, lineno=p.lineno(2))] | |
else: | |
p[0] = [ast.ArrayElement(p[1], p[3], False, lineno=p.lineno(2))] | |
def p_possible_comma(p): | |
'''possible_comma : empty | |
| COMMA''' | |
pass | |
def p_function_call_parameter_list(p): | |
'''function_call_parameter_list : function_call_parameter_list COMMA function_call_parameter | |
| function_call_parameter''' | |
if len(p) == 4: | |
p[0] = p[1] + [p[3]] | |
else: | |
p[0] = [p[1]] | |
def p_function_call_parameter_list_empty(p): | |
'function_call_parameter_list : empty' | |
p[0] = [] | |
def p_function_call_parameter(p): | |
'''function_call_parameter : expr | |
| AND variable''' | |
if len(p) == 2: | |
p[0] = ast.Parameter(p[1], False, lineno=p.lineno(1)) | |
else: | |
p[0] = ast.Parameter(p[2], True, lineno=p.lineno(1)) | |
def p_expr_function(p): | |
'expr : FUNCTION is_reference LPAREN parameter_list RPAREN lexical_vars LBRACE inner_statement_list RBRACE' | |
p[0] = ast.Closure(p[4], p[6], p[8], p[2], lineno=p.lineno(1)) | |
def p_lexical_vars(p): | |
'''lexical_vars : USE LPAREN lexical_var_list RPAREN | |
| empty''' | |
if len(p) == 5: | |
p[0] = p[3] | |
else: | |
p[0] = [] | |
def p_lexical_var_list(p): | |
'''lexical_var_list : lexical_var_list COMMA AND VARIABLE | |
| lexical_var_list COMMA VARIABLE | |
| AND VARIABLE | |
| VARIABLE''' | |
if len(p) == 5: | |
p[0] = p[1] + [ast.LexicalVariable(p[4], True, lineno=p.lineno(2))] | |
elif len(p) == 4: | |
p[0] = p[1] + [ast.LexicalVariable(p[3], False, lineno=p.lineno(2))] | |
elif len(p) == 3: | |
p[0] = [ast.LexicalVariable(p[2], True, lineno=p.lineno(1))] | |
else: | |
p[0] = [ast.LexicalVariable(p[1], False, lineno=p.lineno(1))] | |
def p_expr_assign_op(p): | |
'''expr : variable PLUS_EQUAL expr | |
| variable MINUS_EQUAL expr | |
| variable MUL_EQUAL expr | |
| variable DIV_EQUAL expr | |
| variable CONCAT_EQUAL expr | |
| variable MOD_EQUAL expr | |
| variable AND_EQUAL expr | |
| variable OR_EQUAL expr | |
| variable XOR_EQUAL expr | |
| variable SL_EQUAL expr | |
| variable SR_EQUAL expr''' | |
p[0] = ast.AssignOp(p[2], p[1], p[3], lineno=p.lineno(2)) | |
def p_expr_binary_op(p): | |
'''expr : expr BOOLEAN_AND expr | |
| expr BOOLEAN_OR expr | |
| expr LOGICAL_AND expr | |
| expr LOGICAL_OR expr | |
| expr LOGICAL_XOR expr | |
| expr AND expr | |
| expr OR expr | |
| expr XOR expr | |
| expr CONCAT expr | |
| expr PLUS expr | |
| expr MINUS expr | |
| expr MUL expr | |
| expr DIV expr | |
| expr SL expr | |
| expr SR expr | |
| expr MOD expr | |
| expr IS_IDENTICAL expr | |
| expr IS_NOT_IDENTICAL expr | |
| expr IS_EQUAL expr | |
| expr IS_NOT_EQUAL expr | |
| expr IS_SMALLER expr | |
| expr IS_SMALLER_OR_EQUAL expr | |
| expr IS_GREATER expr | |
| expr IS_GREATER_OR_EQUAL expr | |
| expr INSTANCEOF expr''' | |
p[0] = ast.BinaryOp(p[2].lower(), p[1], p[3], lineno=p.lineno(2)) | |
def p_expr_unary_op(p): | |
'''expr : PLUS expr | |
| MINUS expr | |
| NOT expr | |
| BOOLEAN_NOT expr''' | |
p[0] = ast.UnaryOp(p[1], p[2], lineno=p.lineno(1)) | |
def p_expr_ternary_op(p): | |
'expr : expr QUESTION expr COLON expr' | |
p[0] = ast.TernaryOp(p[1], p[3], p[5], lineno=p.lineno(2)) | |
def p_expr_pre_incdec(p): | |
'''expr : INC variable | |
| DEC variable''' | |
p[0] = ast.PreIncDecOp(p[1], p[2], lineno=p.lineno(1)) | |
def p_expr_post_incdec(p): | |
'''expr : variable INC | |
| variable DEC''' | |
p[0] = ast.PostIncDecOp(p[2], p[1], lineno=p.lineno(2)) | |
def p_expr_cast_int(p): | |
'expr : INT_CAST expr' | |
p[0] = ast.Cast('int', p[2], lineno=p.lineno(1)) | |
def p_expr_cast_double(p): | |
'expr : DOUBLE_CAST expr' | |
p[0] = ast.Cast('double', p[2], lineno=p.lineno(1)) | |
def p_expr_cast_string(p): | |
'expr : STRING_CAST expr' | |
p[0] = ast.Cast('string', p[2], lineno=p.lineno(1)) | |
def p_expr_cast_array(p): | |
'expr : ARRAY_CAST expr' | |
p[0] = ast.Cast('array', p[2], lineno=p.lineno(1)) | |
def p_expr_cast_object(p): | |
'expr : OBJECT_CAST expr' | |
p[0] = ast.Cast('object', p[2], lineno=p.lineno(1)) | |
def p_expr_cast_bool(p): | |
'expr : BOOL_CAST expr' | |
p[0] = ast.Cast('bool', p[2], lineno=p.lineno(1)) | |
def p_expr_cast_unset(p): | |
'expr : UNSET_CAST expr' | |
p[0] = ast.Cast('unset', p[2], lineno=p.lineno(1)) | |
def p_expr_isset(p): | |
'expr : ISSET LPAREN isset_variables RPAREN' | |
p[0] = ast.IsSet(p[3], lineno=p.lineno(1)) | |
def p_isset_variables(p): | |
'''isset_variables : isset_variables COMMA variable | |
| variable''' | |
if len(p) == 4: | |
p[0] = p[1] + [p[3]] | |
else: | |
p[0] = [p[1]] | |
def p_expr_empty(p): | |
'expr : EMPTY LPAREN expr RPAREN' | |
p[0] = ast.Empty(p[3], lineno=p.lineno(1)) | |
def p_expr_eval(p): | |
'expr : EVAL LPAREN expr RPAREN' | |
p[0] = ast.Eval(p[3], lineno=p.lineno(1)) | |
def p_expr_include(p): | |
'expr : INCLUDE expr' | |
p[0] = ast.Include(p[2], False, lineno=p.lineno(1)) | |
def p_expr_include_once(p): | |
'expr : INCLUDE_ONCE expr' | |
p[0] = ast.Include(p[2], True, lineno=p.lineno(1)) | |
def p_expr_require(p): | |
'expr : REQUIRE expr' | |
p[0] = ast.Require(p[2], False, lineno=p.lineno(1)) | |
def p_expr_require_once(p): | |
'expr : REQUIRE_ONCE expr' | |
p[0] = ast.Require(p[2], True, lineno=p.lineno(1)) | |
def p_expr_exit(p): | |
'''expr : EXIT | |
| EXIT LPAREN RPAREN | |
| EXIT LPAREN expr RPAREN''' | |
if len(p) == 5: | |
p[0] = ast.Exit(p[3], lineno=p.lineno(1)) | |
else: | |
p[0] = ast.Exit(None, lineno=p.lineno(1)) | |
def p_expr_print(p): | |
'expr : PRINT expr' | |
p[0] = ast.Print(p[2], lineno=p.lineno(1)) | |
def p_expr_silence(p): | |
'expr : AT expr' | |
p[0] = ast.Silence(p[2], lineno=p.lineno(1)) | |
def p_expr_group(p): | |
'expr : LPAREN expr RPAREN' | |
p[0] = p[2] | |
def p_scalar(p): | |
'''scalar : class_constant | |
| common_scalar | |
| QUOTE encaps_list QUOTE | |
| START_HEREDOC encaps_list END_HEREDOC''' | |
if len(p) == 4: | |
p[0] = p[2] | |
else: | |
p[0] = p[1] | |
def p_scalar_string_varname(p): | |
'scalar : STRING_VARNAME' | |
p[0] = ast.Variable('$' + p[1], lineno=p.lineno(1)) | |
def p_scalar_namespace_name(p): | |
'''scalar : namespace_name | |
| NS_SEPARATOR namespace_name | |
| NAMESPACE NS_SEPARATOR namespace_name''' | |
if len(p) == 2: | |
p[0] = ast.Constant(p[1], lineno=p.lineno(1)) | |
elif len(p) == 3: | |
p[0] = ast.Constant(p[1] + p[2], lineno=p.lineno(1)) | |
else: | |
p[0] = ast.Constant(p[1] + p[2] + p[3], lineno=p.lineno(1)) | |
def p_class_constant(p): | |
'''class_constant : class_name DOUBLE_COLON STRING | |
| variable_class_name DOUBLE_COLON STRING''' | |
p[0] = ast.StaticProperty(p[1], p[3], lineno=p.lineno(2)) | |
def p_common_scalar_lnumber(p): | |
'common_scalar : LNUMBER' | |
if p[1].startswith('0x'): | |
p[0] = int(p[1], 16) | |
elif p[1].startswith('0'): | |
p[0] = int(p[1], 8) | |
else: | |
p[0] = int(p[1]) | |
def p_common_scalar_dnumber(p): | |
'common_scalar : DNUMBER' | |
p[0] = float(p[1]) | |
def p_common_scalar_string(p): | |
'common_scalar : CONSTANT_ENCAPSED_STRING' | |
p[0] = p[1][1:-1].replace("\\'", "'").replace('\\\\', '\\') | |
def p_common_scalar_magic_line(p): | |
'common_scalar : LINE' | |
p[0] = ast.MagicConstant(p[1].upper(), p.lineno(1), lineno=p.lineno(1)) | |
def p_common_scalar_magic_file(p): | |
'common_scalar : FILE' | |
value = getattr(p.lexer, 'filename', None) | |
p[0] = ast.MagicConstant(p[1].upper(), value, lineno=p.lineno(1)) | |
def p_common_scalar_magic_dir(p): | |
'common_scalar : DIR' | |
value = getattr(p.lexer, 'filename', None) | |
if value is not None: | |
value = os.path.dirname(value) | |
p[0] = ast.MagicConstant(p[1].upper(), value, lineno=p.lineno(1)) | |
def p_common_scalar_magic_class(p): | |
'common_scalar : CLASS_C' | |
p[0] = ast.MagicConstant(p[1].upper(), None, lineno=p.lineno(1)) | |
def p_common_scalar_magic_method(p): | |
'common_scalar : METHOD_C' | |
p[0] = ast.MagicConstant(p[1].upper(), None, lineno=p.lineno(1)) | |
def p_common_scalar_magic_func(p): | |
'common_scalar : FUNC_C' | |
p[0] = ast.MagicConstant(p[1].upper(), None, lineno=p.lineno(1)) | |
def p_common_scalar_magic_ns(p): | |
'common_scalar : NS_C' | |
p[0] = ast.MagicConstant(p[1].upper(), None, lineno=p.lineno(1)) | |
def p_static_scalar(p): | |
'''static_scalar : common_scalar | |
| QUOTE QUOTE | |
| QUOTE ENCAPSED_AND_WHITESPACE QUOTE''' | |
if len(p) == 2: | |
p[0] = p[1] | |
elif len(p) == 3: | |
p[0] = '' | |
else: | |
p[0] = p[2].decode('string_escape') | |
def p_static_scalar_namespace_name(p): | |
'''static_scalar : namespace_name | |
| NS_SEPARATOR namespace_name | |
| NAMESPACE NS_SEPARATOR namespace_name''' | |
if len(p) == 2: | |
p[0] = ast.Constant(p[1], lineno=p.lineno(1)) | |
elif len(p) == 3: | |
p[0] = ast.Constant(p[1] + p[2], lineno=p.lineno(1)) | |
else: | |
p[0] = ast.Constant(p[1] + p[2] + p[3], lineno=p.lineno(1)) | |
def p_static_scalar_unary_op(p): | |
'''static_scalar : PLUS static_scalar | |
| MINUS static_scalar''' | |
p[0] = ast.UnaryOp(p[1], p[2], lineno=p.lineno(1)) | |
def p_static_scalar_array(p): | |
'static_scalar : ARRAY LPAREN static_array_pair_list RPAREN' | |
p[0] = ast.Array(p[3], lineno=p.lineno(1)) | |
def p_static_array_pair_list(p): | |
'''static_array_pair_list : empty | |
| static_non_empty_array_pair_list possible_comma''' | |
if len(p) == 2: | |
p[0] = [] | |
else: | |
p[0] = p[1] | |
def p_static_non_empty_array_pair_list_item(p): | |
'''static_non_empty_array_pair_list : static_non_empty_array_pair_list COMMA static_scalar | |
| static_scalar''' | |
if len(p) == 4: | |
p[0] = p[1] + [ast.ArrayElement(None, p[3], False, lineno=p.lineno(2))] | |
else: | |
p[0] = [ast.ArrayElement(None, p[1], False, lineno=p.lineno(1))] | |
def p_static_non_empty_array_pair_list_pair(p): | |
'''static_non_empty_array_pair_list : static_non_empty_array_pair_list COMMA static_scalar DOUBLE_ARROW static_scalar | |
| static_scalar DOUBLE_ARROW static_scalar''' | |
if len(p) == 6: | |
p[0] = p[1] + [ast.ArrayElement(p[3], p[5], False, lineno=p.lineno(2))] | |
else: | |
p[0] = [ast.ArrayElement(p[1], p[3], False, lineno=p.lineno(2))] | |
def p_namespace_name(p): | |
'''namespace_name : namespace_name NS_SEPARATOR STRING | |
| STRING''' | |
if len(p) == 4: | |
p[0] = p[1] + p[2] + p[3] | |
else: | |
p[0] = p[1] | |
def p_encaps_list(p): | |
'''encaps_list : encaps_list encaps_var | |
| empty''' | |
if len(p) == 3: | |
if p[1] == '': | |
p[0] = p[2] | |
else: | |
p[0] = ast.BinaryOp('.', p[1], p[2], lineno=p.lineno(2)) | |
else: | |
p[0] = '' | |
def p_encaps_list_string(p): | |
'encaps_list : encaps_list ENCAPSED_AND_WHITESPACE' | |
if p[1] == '': | |
p[0] = p[2].decode('string_escape') | |
else: | |
p[0] = ast.BinaryOp('.', p[1], p[2].decode('string_escape'), | |
lineno=p.lineno(2)) | |
def p_encaps_var(p): | |
'encaps_var : VARIABLE' | |
p[0] = ast.Variable(p[1], lineno=p.lineno(1)) | |
def p_encaps_var_array_offset(p): | |
'encaps_var : VARIABLE LBRACKET encaps_var_offset RBRACKET' | |
p[0] = ast.ArrayOffset(ast.Variable(p[1], lineno=p.lineno(1)), p[3], | |
lineno=p.lineno(2)) | |
def p_encaps_var_object_property(p): | |
'encaps_var : VARIABLE OBJECT_OPERATOR STRING' | |
p[0] = ast.ObjectProperty(ast.Variable(p[1], lineno=p.lineno(1)), p[3], | |
lineno=p.lineno(2)) | |
def p_encaps_var_dollar_curly_expr(p): | |
'encaps_var : DOLLAR_OPEN_CURLY_BRACES expr RBRACE' | |
p[0] = p[2] | |
def p_encaps_var_dollar_curly_array_offset(p): | |
'encaps_var : DOLLAR_OPEN_CURLY_BRACES STRING_VARNAME LBRACKET expr RBRACKET RBRACE' | |
p[0] = ast.ArrayOffset(ast.Variable('$' + p[2], lineno=p.lineno(2)), p[4], | |
lineno=p.lineno(3)) | |
def p_encaps_var_curly_variable(p): | |
'encaps_var : CURLY_OPEN variable RBRACE' | |
p[0] = p[2] | |
def p_encaps_var_offset_string(p): | |
'encaps_var_offset : STRING' | |
p[0] = p[1] | |
def p_encaps_var_offset_num_string(p): | |
'encaps_var_offset : NUM_STRING' | |
p[0] = int(p[1]) | |
def p_encaps_var_offset_variable(p): | |
'encaps_var_offset : VARIABLE' | |
p[0] = ast.Variable(p[1], lineno=p.lineno(1)) | |
def p_comment(p): | |
'''comment : COMMENT | |
| DOC_COMMENT''' | |
p[0] = ast.Comment(p[1]) | |
def p_empty(p): | |
'empty : ' | |
pass | |
# Error rule for syntax errors | |
def p_error(t): | |
if t: | |
raise SyntaxError('invalid syntax', (None, t.lineno, None, t.value)) | |
else: | |
raise SyntaxError('unexpected EOF while parsing', (None, None, None, None)) | |
# Build the grammar | |
parser = yacc.yacc() | |
if __name__ == '__main__': | |
import readline | |
import pprint | |
s = '' | |
lexer = phplex.lexer | |
while True: | |
try: | |
if s: | |
prompt = ' ' | |
else: | |
prompt = lexer.current_state() | |
if prompt == 'INITIAL': prompt = 'html' | |
prompt += '> ' | |
s += raw_input(prompt) | |
except EOFError: | |
break | |
if not s: continue | |
s += '\n' | |
try: | |
lexer.lineno = 1 | |
result = parser.parse(s, lexer=lexer) | |
except SyntaxError, e: | |
if e.lineno is not None: | |
print e, 'near', repr(e.text) | |
s = '' | |
continue | |
if result: | |
for item in result: | |
if hasattr(item, 'generic'): | |
item = item.generic() | |
pprint.pprint(item) | |
s = '' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
""" | |
sphinxcontrib_wikitable | |
~~~~~~~~~~~~~~~~~~~~~~~~ | |
:copyright: Copyright 2012 by Takeshi KOMIYA | |
:license: BSD, see LICENSE for details. | |
""" | |
import os | |
import re | |
from docutils import nodes | |
from docutils.parsers.rst import Directive | |
from docutils.statemachine import ViewList | |
class PHPAutodocDirective(Directive): | |
has_content = False | |
optional_arguments = 1 | |
def run(self): | |
self.indent = u'' | |
self.result = ViewList() | |
srcdir = self.state.document.settings.env.srcdir | |
filename = os.path.join(srcdir, self.arguments[0]) | |
self.parse(filename) | |
node = nodes.paragraph() | |
node.document = self.state.document | |
self.state.nested_parse(self.result, 0, node) | |
return node.children | |
def add_line(self, line, *lineno): | |
self.result.append(self.indent + line, '<phpautodoc>', *lineno) | |
def add_directive_header(self, directive, name): | |
domain = getattr(self, 'domain', 'py') | |
self.add_line(u'.. %s:%s:: %s' % (domain, directive, name)) | |
self.add_line('') | |
def add_comment(self, comment): | |
text = comment.text | |
text = re.sub('^//', '', text) | |
text = re.sub('^/\*\s*', '', text) | |
text = re.sub('\s*\*/$', '', text) | |
r = re.compile('^\s*\*[ ]*', re.M) | |
text = re.sub(r, '', text) | |
for line in text.splitlines(): | |
self.add_line(u' ' + line) | |
self.add_line('') | |
def parse(self, filename): | |
from phplex import lexer | |
from phpparse import parser | |
try: | |
with open(filename) as f: | |
tree = parser.parse(f.read(), lexer=lexer) | |
self._parse(tree) | |
except: | |
pass # FIXME: ignore any errors | |
def _parse(self, tree): | |
from phply import phpast as ast | |
last_node = None | |
for node in tree: | |
if isinstance(node, ast.Function): | |
self.add_directive_header('function', node.name) | |
if isinstance(last_node, ast.Comment): | |
self.add_comment(last_node) | |
elif isinstance(node, ast.Class): | |
self.add_directive_header('class', node.name) | |
if isinstance(last_node, ast.Comment): | |
self.add_comment(last_node) | |
self._parse(node.nodes) | |
elif isinstance(node, ast.Method): | |
self.add_directive_header('method', node.name) | |
if isinstance(last_node, ast.Comment): | |
self.add_comment(last_node) | |
last_node = node | |
def setup(app): | |
app.add_directive('phpautodoc', PHPAutodocDirective) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment