summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul McGuire <ptmcg@austin.rr.com>2019-04-07 07:42:20 -0500
committerPaul McGuire <ptmcg@austin.rr.com>2019-04-07 07:42:20 -0500
commit76b3af7f25d0f25d4eb7f0849a23e22b5b2a0297 (patch)
tree53ae14557c3bbbe7545983ee7414f442f2fe4d07
parenta2439508ba5c94546db98593cfa676de9b59babe (diff)
downloadpyparsing-git-76b3af7f25d0f25d4eb7f0849a23e22b5b2a0297.tar.gz
Improved support for "python setup.py test"
-rw-r--r--CHANGES22
-rw-r--r--examples/antlr_grammar.py442
-rw-r--r--pyparsing.py6
-rw-r--r--setup.py77
-rw-r--r--simple_unit_tests.py30
-rw-r--r--unitTests.py6
6 files changed, 308 insertions, 275 deletions
diff --git a/CHANGES b/CHANGES
index 500682c..e1fa06e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -13,7 +13,12 @@ Version 2.4.0 - April, 2019
future breaking changes.
. Conditionalizes the API-breaking behavior, based on the value
pyparsing.__compat__.collect_all_And_tokens. By default, this value
- will be set to True, reflecting the new bugfixed behavior.
+ will be set to True, reflecting the new bugfixed behavior. To set this
+ value to False, add to your code:
+
+ import pyparsing
+ pyparsing.__compat__.collect_all_And_tokens = False
+
. User code that is dependent on the pre-bugfix behavior can restore
it by setting this value to False.
@@ -21,6 +26,15 @@ Version 2.4.0 - April, 2019
setting the flag to True or False in these later versions will have no
effect.
+- Updated unitTests.py and simple_unit_tests.py to be compatible with
+ "python setup.py test". To run tests using setup, do:
+
+ python setup.py test
+ python setup.py test -s unitTests.suite
+ python setup.py test -s simple_unit_tests.suite
+
+ Prompted by issue #83 and PR submitted by bdragon28, thanks.
+
- Fixed bug in runTests handling '\n' literals in quoted strings.
- Added tag_body attribute to the start tag expressions generated by
@@ -41,7 +55,6 @@ Version 2.4.0 - April, 2019
- Fixed docstring with embedded '\w', which creates SyntaxWarnings in
Py3.8, issue #80.
-
- Examples:
- Added example parser for rosettacode.org tutorial compiler.
@@ -57,6 +70,11 @@ Version 2.4.0 - April, 2019
- Examples using makeHTMLTags use new tag_body expression when
retrieving a tag's body text.
+ - Updated examples that are runnable as unit tests:
+
+ python setup.py test -s examples.antlr_grammar_tests
+ python setup.py test -s examples.test_bibparse
+
Version 2.3.1 - January, 2019
-----------------------------
diff --git a/examples/antlr_grammar.py b/examples/antlr_grammar.py
index e25ff7f..09ef264 100644
--- a/examples/antlr_grammar.py
+++ b/examples/antlr_grammar.py
@@ -1,219 +1,223 @@
-'''
-antlr_grammar.py
-
-Created on 4 sept. 2010
-
-@author: luca
-
-Submitted by Luca DallOlio, September, 2010
-(Minor updates by Paul McGuire, June, 2012)
-'''
-from pyparsing import Word, ZeroOrMore, printables, Suppress, OneOrMore, Group, \
- LineEnd, Optional, White, originalTextFor, hexnums, nums, Combine, Literal, Keyword, \
- cStyleComment, Regex, Forward, MatchFirst, And, oneOf, alphas, alphanums, \
- delimitedList
-
-# http://www.antlr.org/grammar/ANTLR/ANTLRv3.g
-
-# Tokens
-EOL = Suppress(LineEnd()) # $
-singleTextString = originalTextFor(ZeroOrMore(~EOL + (White(" \t") | Word(printables)))).leaveWhitespace()
-XDIGIT = hexnums
-INT = Word(nums)
-ESC = Literal('\\') + (oneOf(list(r'nrtbf\">'+"'")) | ('u' + Word(hexnums, exact=4)) | Word(printables, exact=1))
-LITERAL_CHAR = ESC | ~(Literal("'") | Literal('\\')) + Word(printables, exact=1)
-CHAR_LITERAL = Suppress("'") + LITERAL_CHAR + Suppress("'")
-STRING_LITERAL = Suppress("'") + Combine(OneOrMore(LITERAL_CHAR)) + Suppress("'")
-DOUBLE_QUOTE_STRING_LITERAL = '"' + ZeroOrMore(LITERAL_CHAR) + '"'
-DOUBLE_ANGLE_STRING_LITERAL = '<<' + ZeroOrMore(Word(printables, exact=1)) + '>>'
-TOKEN_REF = Word(alphas.upper(), alphanums+'_')
-RULE_REF = Word(alphas.lower(), alphanums+'_')
-ACTION_ESC = (Suppress("\\") + Suppress("'")) | Suppress('\\"') | Suppress('\\') + (~(Literal("'") | Literal('"')) + Word(printables, exact=1))
-ACTION_CHAR_LITERAL = Suppress("'") + (ACTION_ESC | ~(Literal('\\') | Literal("'")) + Word(printables, exact=1)) + Suppress("'")
-ACTION_STRING_LITERAL = Suppress('"') + ZeroOrMore(ACTION_ESC | ~(Literal('\\') | Literal('"')) + Word(printables, exact=1)) + Suppress('"')
-SRC = Suppress('src') + ACTION_STRING_LITERAL("file") + INT("line")
-id = TOKEN_REF | RULE_REF
-SL_COMMENT = Suppress('//') + Suppress('$ANTLR') + SRC | ZeroOrMore(~EOL + Word(printables)) + EOL
-ML_COMMENT = cStyleComment
-WS = OneOrMore(Suppress(' ') | Suppress('\t') | (Optional(Suppress('\r')) + Literal('\n')))
-WS_LOOP = ZeroOrMore(SL_COMMENT | ML_COMMENT)
-NESTED_ARG_ACTION = Forward()
-NESTED_ARG_ACTION << Suppress('[') + ZeroOrMore(NESTED_ARG_ACTION | ACTION_STRING_LITERAL | ACTION_CHAR_LITERAL) + Suppress(']')
-ARG_ACTION = NESTED_ARG_ACTION
-NESTED_ACTION = Forward()
-NESTED_ACTION << Suppress('{') + ZeroOrMore(NESTED_ACTION | SL_COMMENT | ML_COMMENT | ACTION_STRING_LITERAL | ACTION_CHAR_LITERAL) + Suppress('}')
-ACTION = NESTED_ACTION + Optional('?')
-SCOPE = Suppress('scope')
-OPTIONS = Suppress('options') + Suppress('{') # + WS_LOOP + Suppress('{')
-TOKENS = Suppress('tokens') + Suppress('{') # + WS_LOOP + Suppress('{')
-FRAGMENT = 'fragment';
-TREE_BEGIN = Suppress('^(')
-ROOT = Suppress('^')
-BANG = Suppress('!')
-RANGE = Suppress('..')
-REWRITE = Suppress('->')
-
-# General Parser Definitions
-
-# Grammar heading
-optionValue = id | STRING_LITERAL | CHAR_LITERAL | INT | Literal('*').setName("s")
-
-option = Group(id("id") + Suppress('=') + optionValue("value"))("option")
-optionsSpec = OPTIONS + Group(OneOrMore(option + Suppress(';')))("options") + Suppress('}')
-tokenSpec = Group(TOKEN_REF("token_ref") + (Suppress('=') + (STRING_LITERAL | CHAR_LITERAL)("lit")))("token") + Suppress(';')
-tokensSpec = TOKENS + Group(OneOrMore(tokenSpec))("tokens") + Suppress('}')
-attrScope = Suppress('scope') + id + ACTION
-grammarType = Keyword('lexer') + Keyword('parser') + Keyword('tree')
-actionScopeName = id | Keyword('lexer')("l") | Keyword('parser')("p")
-action = Suppress('@') + Optional(actionScopeName + Suppress('::')) + id + ACTION
-
-grammarHeading = Optional(ML_COMMENT("ML_COMMENT")) + Optional(grammarType) + Suppress('grammar') + id("grammarName") + Suppress(';') + Optional(optionsSpec) + Optional(tokensSpec) + ZeroOrMore(attrScope) + ZeroOrMore(action)
-
-modifier = Keyword('protected') | Keyword('public') | Keyword('private') | Keyword('fragment')
-ruleAction = Suppress('@') + id + ACTION
-throwsSpec = Suppress('throws') + delimitedList(id)
-ruleScopeSpec = (Suppress('scope') + ACTION) | (Suppress('scope') + delimitedList(id) + Suppress(';')) | (Suppress('scope') + ACTION + Suppress('scope') + delimitedList(id) + Suppress(';'))
-unary_op = oneOf("^ !")
-notTerminal = CHAR_LITERAL | TOKEN_REF | STRING_LITERAL
-terminal = (CHAR_LITERAL | TOKEN_REF + Optional(ARG_ACTION) | STRING_LITERAL | '.') + Optional(unary_op)
-block = Forward()
-notSet = Suppress('~') + (notTerminal | block)
-rangeNotPython = CHAR_LITERAL("c1") + RANGE + CHAR_LITERAL("c2")
-atom = Group(rangeNotPython + Optional(unary_op)("op")) | terminal | (notSet + Optional(unary_op)("op")) | (RULE_REF + Optional(ARG_ACTION("arg")) + Optional(unary_op)("op"))
-element = Forward()
-treeSpec = Suppress('^(') + element*(2,) + Suppress(')')
-ebnfSuffix = oneOf("? * +")
-ebnf = block + Optional(ebnfSuffix("op") | '=>')
-elementNoOptionSpec = (id("result_name") + oneOf('= +=')("labelOp") + atom("atom") + Optional(ebnfSuffix)) | (id("result_name") + oneOf('= +=')("labelOp") + block + Optional(ebnfSuffix)) | atom("atom") + Optional(ebnfSuffix) | ebnf | ACTION | (treeSpec + Optional(ebnfSuffix)) # | SEMPRED ( '=>' -> GATED_SEMPRED | -> SEMPRED )
-element << Group(elementNoOptionSpec)("element")
-alternative = Group(Group(OneOrMore(element))("elements")) # Do not ask me why group is needed twice... seems like the xml that you see is not always the real structure?
-rewrite = Optional(Literal('TODO REWRITE RULES TODO'))
-block << Suppress('(') + Optional(Optional(optionsSpec("opts")) + Suppress(':')) + Group(alternative('a1') + rewrite + Group(ZeroOrMore(Suppress('|') + alternative('a2') + rewrite))("alternatives"))("block") + Suppress(')')
-altList = alternative('a1') + rewrite + Group(ZeroOrMore(Suppress('|') + alternative('a2') + rewrite))("alternatives")
-exceptionHandler = Suppress('catch') + ARG_ACTION + ACTION
-finallyClause = Suppress('finally') + ACTION
-exceptionGroup = (OneOrMore(exceptionHandler) + Optional(finallyClause)) | finallyClause
-
-ruleHeading = Optional(ML_COMMENT)("ruleComment") + Optional(modifier)("modifier") + id("ruleName") + Optional("!") + Optional(ARG_ACTION("arg")) + Optional(Suppress('returns') + ARG_ACTION("rt")) + Optional(throwsSpec) + Optional(optionsSpec) + Optional(ruleScopeSpec) + ZeroOrMore(ruleAction)
-rule = Group(ruleHeading + Suppress(':') + altList + Suppress(';') + Optional(exceptionGroup))("rule")
-
-grammarDef = grammarHeading + Group(OneOrMore(rule))("rules")
-
-def grammar():
- return grammarDef
-
-def __antlrAlternativesConverter(pyparsingRules, antlrBlock):
- rule = None
- if hasattr(antlrBlock, 'alternatives') and antlrBlock.alternatives != '' and len(antlrBlock.alternatives) > 0:
- alternatives = []
- alternatives.append(__antlrAlternativeConverter(pyparsingRules, antlrBlock.a1))
- for alternative in antlrBlock.alternatives:
- alternatives.append(__antlrAlternativeConverter(pyparsingRules, alternative))
- rule = MatchFirst(alternatives)("anonymous_or")
- elif hasattr(antlrBlock, 'a1') and antlrBlock.a1 != '':
- rule = __antlrAlternativeConverter(pyparsingRules, antlrBlock.a1)
- else:
- raise Exception('Not yet implemented')
- assert rule != None
- return rule
-
-def __antlrAlternativeConverter(pyparsingRules, antlrAlternative):
- elementList = []
- for element in antlrAlternative.elements:
- rule = None
- if hasattr(element.atom, 'c1') and element.atom.c1 != '':
- regex = r'['+str(element.atom.c1[0])+'-'+str(element.atom.c2[0]+']')
- rule = Regex(regex)("anonymous_regex")
- elif hasattr(element, 'block') and element.block != '':
- rule = __antlrAlternativesConverter(pyparsingRules, element.block)
- else:
- ruleRef = element.atom
- assert ruleRef in pyparsingRules
- rule = pyparsingRules[element.atom](element.atom)
- if hasattr(element, 'op') and element.op != '':
- if element.op == '+':
- rule = Group(OneOrMore(rule))("anonymous_one_or_more")
- elif element.op == '*':
- rule = Group(ZeroOrMore(rule))("anonymous_zero_or_more")
- elif element.op == '?':
- rule = Optional(rule)
- else:
- raise Exception('rule operator not yet implemented : ' + element.op)
- rule = rule
- elementList.append(rule)
- if len(elementList) > 1:
- rule = Group(And(elementList))("anonymous_and")
- else:
- rule = elementList[0]
- assert rule != None
- return rule
-
-def __antlrRuleConverter(pyparsingRules, antlrRule):
- rule = None
- rule = __antlrAlternativesConverter(pyparsingRules, antlrRule)
- assert rule != None
- rule(antlrRule.ruleName)
- return rule
-
-def antlrConverter(antlrGrammarTree):
- pyparsingRules = {}
- antlrTokens = {}
- for antlrToken in antlrGrammarTree.tokens:
- antlrTokens[antlrToken.token_ref] = antlrToken.lit
- for antlrTokenName, antlrToken in list(antlrTokens.items()):
- pyparsingRules[antlrTokenName] = Literal(antlrToken)
- antlrRules = {}
- for antlrRule in antlrGrammarTree.rules:
- antlrRules[antlrRule.ruleName] = antlrRule
- pyparsingRules[antlrRule.ruleName] = Forward() # antlr is a top down grammar
- for antlrRuleName, antlrRule in list(antlrRules.items()):
- pyparsingRule = __antlrRuleConverter(pyparsingRules, antlrRule)
- assert pyparsingRule != None
- pyparsingRules[antlrRuleName] << pyparsingRule
- return pyparsingRules
-
-if __name__ == "__main__":
-
- text = """grammar SimpleCalc;
-
-options {
- language = Python;
-}
-
-tokens {
- PLUS = '+' ;
- MINUS = '-' ;
- MULT = '*' ;
- DIV = '/' ;
-}
-
-/*------------------------------------------------------------------
- * PARSER RULES
- *------------------------------------------------------------------*/
-
-expr : term ( ( PLUS | MINUS ) term )* ;
-
-term : factor ( ( MULT | DIV ) factor )* ;
-
-factor : NUMBER ;
-
-
-/*------------------------------------------------------------------
- * LEXER RULES
- *------------------------------------------------------------------*/
-
-NUMBER : (DIGIT)+ ;
-
-/* WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; } ; */
-
-fragment DIGIT : '0'..'9' ;
-
-"""
-
- grammar().validate()
- antlrGrammarTree = grammar().parseString(text)
- print(antlrGrammarTree.asXML("antlrGrammarTree"))
- pyparsingRules = antlrConverter(antlrGrammarTree)
- pyparsingRule = pyparsingRules["expr"]
- pyparsingTree = pyparsingRule.parseString("2 - 5 * 42 + 7 / 25")
- print(pyparsingTree.asXML("pyparsingTree"))
+'''
+antlr_grammar.py
+
+Created on 4 sept. 2010
+
+@author: luca
+
+Submitted by Luca DallOlio, September, 2010
+(Minor updates by Paul McGuire, June, 2012)
+'''
+from pyparsing import Word, ZeroOrMore, printables, Suppress, OneOrMore, Group, \
+ LineEnd, Optional, White, originalTextFor, hexnums, nums, Combine, Literal, Keyword, \
+ cStyleComment, Regex, Forward, MatchFirst, And, oneOf, alphas, alphanums, \
+ delimitedList, ungroup
+
+# http://www.antlr.org/grammar/ANTLR/ANTLRv3.g
+
+# Tokens
+EOL = Suppress(LineEnd()) # $
+singleTextString = originalTextFor(ZeroOrMore(~EOL + (White(" \t") | Word(printables)))).leaveWhitespace()
+XDIGIT = hexnums
+INT = Word(nums)
+ESC = Literal('\\') + (oneOf(list(r'nrtbf\">'+"'")) | ('u' + Word(hexnums, exact=4)) | Word(printables, exact=1))
+LITERAL_CHAR = ESC | ~(Literal("'") | Literal('\\')) + Word(printables, exact=1)
+CHAR_LITERAL = Suppress("'") + LITERAL_CHAR + Suppress("'")
+STRING_LITERAL = Suppress("'") + Combine(OneOrMore(LITERAL_CHAR)) + Suppress("'")
+DOUBLE_QUOTE_STRING_LITERAL = '"' + ZeroOrMore(LITERAL_CHAR) + '"'
+DOUBLE_ANGLE_STRING_LITERAL = '<<' + ZeroOrMore(Word(printables, exact=1)) + '>>'
+TOKEN_REF = Word(alphas.upper(), alphanums+'_')
+RULE_REF = Word(alphas.lower(), alphanums+'_')
+ACTION_ESC = (Suppress("\\") + Suppress("'")) | Suppress('\\"') | Suppress('\\') + (~(Literal("'") | Literal('"')) + Word(printables, exact=1))
+ACTION_CHAR_LITERAL = Suppress("'") + (ACTION_ESC | ~(Literal('\\') | Literal("'")) + Word(printables, exact=1)) + Suppress("'")
+ACTION_STRING_LITERAL = Suppress('"') + ZeroOrMore(ACTION_ESC | ~(Literal('\\') | Literal('"')) + Word(printables, exact=1)) + Suppress('"')
+SRC = Suppress('src') + ACTION_STRING_LITERAL("file") + INT("line")
+id = TOKEN_REF | RULE_REF
+SL_COMMENT = Suppress('//') + Suppress('$ANTLR') + SRC | ZeroOrMore(~EOL + Word(printables)) + EOL
+ML_COMMENT = cStyleComment
+WS = OneOrMore(Suppress(' ') | Suppress('\t') | (Optional(Suppress('\r')) + Literal('\n')))
+WS_LOOP = ZeroOrMore(SL_COMMENT | ML_COMMENT)
+NESTED_ARG_ACTION = Forward()
+NESTED_ARG_ACTION << Suppress('[') + ZeroOrMore(NESTED_ARG_ACTION | ACTION_STRING_LITERAL | ACTION_CHAR_LITERAL) + Suppress(']')
+ARG_ACTION = NESTED_ARG_ACTION
+NESTED_ACTION = Forward()
+NESTED_ACTION << Suppress('{') + ZeroOrMore(NESTED_ACTION | SL_COMMENT | ML_COMMENT | ACTION_STRING_LITERAL | ACTION_CHAR_LITERAL) + Suppress('}')
+ACTION = NESTED_ACTION + Optional('?')
+SCOPE = Suppress('scope')
+OPTIONS = Suppress('options') + Suppress('{') # + WS_LOOP + Suppress('{')
+TOKENS = Suppress('tokens') + Suppress('{') # + WS_LOOP + Suppress('{')
+FRAGMENT = 'fragment';
+TREE_BEGIN = Suppress('^(')
+ROOT = Suppress('^')
+BANG = Suppress('!')
+RANGE = Suppress('..')
+REWRITE = Suppress('->')
+
+# General Parser Definitions
+
+# Grammar heading
+optionValue = id | STRING_LITERAL | CHAR_LITERAL | INT | Literal('*').setName("s")
+
+option = Group(id("id") + Suppress('=') + optionValue("value"))("option")
+optionsSpec = OPTIONS + Group(OneOrMore(option + Suppress(';')))("options") + Suppress('}')
+tokenSpec = Group(TOKEN_REF("token_ref") + (Suppress('=') + (STRING_LITERAL | CHAR_LITERAL)("lit")))("token") + Suppress(';')
+tokensSpec = TOKENS + Group(OneOrMore(tokenSpec))("tokens") + Suppress('}')
+attrScope = Suppress('scope') + id + ACTION
+grammarType = Keyword('lexer') + Keyword('parser') + Keyword('tree')
+actionScopeName = id | Keyword('lexer')("l") | Keyword('parser')("p")
+action = Suppress('@') + Optional(actionScopeName + Suppress('::')) + id + ACTION
+
+grammarHeading = Optional(ML_COMMENT("ML_COMMENT")) + Optional(grammarType) + Suppress('grammar') + id("grammarName") + Suppress(';') + Optional(optionsSpec) + Optional(tokensSpec) + ZeroOrMore(attrScope) + ZeroOrMore(action)
+
+modifier = Keyword('protected') | Keyword('public') | Keyword('private') | Keyword('fragment')
+ruleAction = Suppress('@') + id + ACTION
+throwsSpec = Suppress('throws') + delimitedList(id)
+ruleScopeSpec = (Suppress('scope') + ACTION) | (Suppress('scope') + delimitedList(id) + Suppress(';')) | (Suppress('scope') + ACTION + Suppress('scope') + delimitedList(id) + Suppress(';'))
+unary_op = oneOf("^ !")
+notTerminal = CHAR_LITERAL | TOKEN_REF | STRING_LITERAL
+terminal = (CHAR_LITERAL | TOKEN_REF + Optional(ARG_ACTION) | STRING_LITERAL | '.') + Optional(unary_op)
+block = Forward()
+notSet = Suppress('~') + (notTerminal | block)
+rangeNotPython = CHAR_LITERAL("c1") + RANGE + CHAR_LITERAL("c2")
+atom = Group((rangeNotPython + Optional(unary_op)("op"))
+ | terminal
+ | (notSet + Optional(unary_op)("op"))
+ | (RULE_REF + Optional(ARG_ACTION("arg")) + Optional(unary_op)("op"))
+ )
+element = Forward()
+treeSpec = Suppress('^(') + element*(2,) + Suppress(')')
+ebnfSuffix = oneOf("? * +")
+ebnf = block + Optional(ebnfSuffix("op") | '=>')
+elementNoOptionSpec = (id("result_name") + oneOf('= +=')("labelOp") + atom("atom") + Optional(ebnfSuffix)) | (id("result_name") + oneOf('= +=')("labelOp") + block + Optional(ebnfSuffix)) | atom("atom") + Optional(ebnfSuffix) | ebnf | ACTION | (treeSpec + Optional(ebnfSuffix)) # | SEMPRED ( '=>' -> GATED_SEMPRED | -> SEMPRED )
+element << Group(elementNoOptionSpec)("element")
+alternative = Group(Group(OneOrMore(element))("elements")) # Do not ask me why group is needed twice... seems like the xml that you see is not always the real structure?
+rewrite = Optional(Literal('TODO REWRITE RULES TODO'))
+block << Suppress('(') + Optional(Optional(optionsSpec("opts")) + Suppress(':')) + Group(alternative('a1') + rewrite + Group(ZeroOrMore(Suppress('|') + alternative('a2') + rewrite))("alternatives"))("block") + Suppress(')')
+altList = alternative('a1') + rewrite + Group(ZeroOrMore(Suppress('|') + alternative('a2') + rewrite))("alternatives")
+exceptionHandler = Suppress('catch') + ARG_ACTION + ACTION
+finallyClause = Suppress('finally') + ACTION
+exceptionGroup = (OneOrMore(exceptionHandler) + Optional(finallyClause)) | finallyClause
+
+ruleHeading = Optional(ML_COMMENT)("ruleComment") + Optional(modifier)("modifier") + id("ruleName") + Optional("!") + Optional(ARG_ACTION("arg")) + Optional(Suppress('returns') + ARG_ACTION("rt")) + Optional(throwsSpec) + Optional(optionsSpec) + Optional(ruleScopeSpec) + ZeroOrMore(ruleAction)
+rule = Group(ruleHeading + Suppress(':') + altList + Suppress(';') + Optional(exceptionGroup))("rule")
+
+grammarDef = grammarHeading + Group(OneOrMore(rule))("rules")
+
+def grammar():
+ return grammarDef
+
+def __antlrAlternativesConverter(pyparsingRules, antlrBlock):
+ rule = None
+ if hasattr(antlrBlock, 'alternatives') and antlrBlock.alternatives != '' and len(antlrBlock.alternatives) > 0:
+ alternatives = []
+ alternatives.append(__antlrAlternativeConverter(pyparsingRules, antlrBlock.a1))
+ for alternative in antlrBlock.alternatives:
+ alternatives.append(__antlrAlternativeConverter(pyparsingRules, alternative))
+ rule = MatchFirst(alternatives)("anonymous_or")
+ elif hasattr(antlrBlock, 'a1') and antlrBlock.a1 != '':
+ rule = __antlrAlternativeConverter(pyparsingRules, antlrBlock.a1)
+ else:
+ raise Exception('Not yet implemented')
+ assert rule != None
+ return rule
+
+def __antlrAlternativeConverter(pyparsingRules, antlrAlternative):
+ elementList = []
+ for element in antlrAlternative.elements:
+ rule = None
+ if hasattr(element.atom, 'c1') and element.atom.c1 != '':
+ regex = r'['+str(element.atom.c1[0])+'-'+str(element.atom.c2[0]+']')
+ rule = Regex(regex)("anonymous_regex")
+ elif hasattr(element, 'block') and element.block != '':
+ rule = __antlrAlternativesConverter(pyparsingRules, element.block)
+ else:
+ ruleRef = element.atom[0]
+ assert ruleRef in pyparsingRules
+ rule = pyparsingRules[ruleRef](ruleRef)
+ if hasattr(element, 'op') and element.op != '':
+ if element.op == '+':
+ rule = Group(OneOrMore(rule))("anonymous_one_or_more")
+ elif element.op == '*':
+ rule = Group(ZeroOrMore(rule))("anonymous_zero_or_more")
+ elif element.op == '?':
+ rule = Optional(rule)
+ else:
+ raise Exception('rule operator not yet implemented : ' + element.op)
+ rule = rule
+ elementList.append(rule)
+ if len(elementList) > 1:
+ rule = Group(And(elementList))("anonymous_and")
+ else:
+ rule = elementList[0]
+ assert rule != None
+ return rule
+
+def __antlrRuleConverter(pyparsingRules, antlrRule):
+ rule = None
+ rule = __antlrAlternativesConverter(pyparsingRules, antlrRule)
+ assert rule != None
+ rule(antlrRule.ruleName)
+ return rule
+
+def antlrConverter(antlrGrammarTree):
+ pyparsingRules = {}
+ antlrTokens = {}
+ for antlrToken in antlrGrammarTree.tokens:
+ antlrTokens[antlrToken.token_ref] = antlrToken.lit
+ for antlrTokenName, antlrToken in list(antlrTokens.items()):
+ pyparsingRules[antlrTokenName] = Literal(antlrToken)
+ antlrRules = {}
+ for antlrRule in antlrGrammarTree.rules:
+ antlrRules[antlrRule.ruleName] = antlrRule
+ pyparsingRules[antlrRule.ruleName] = Forward() # antlr is a top down grammar
+ for antlrRuleName, antlrRule in list(antlrRules.items()):
+ pyparsingRule = __antlrRuleConverter(pyparsingRules, antlrRule)
+ assert pyparsingRule != None
+ pyparsingRules[antlrRuleName] << pyparsingRule
+ return pyparsingRules
+
+if __name__ == "__main__":
+
+ text = """grammar SimpleCalc;
+
+options {
+ language = Python;
+}
+
+tokens {
+ PLUS = '+' ;
+ MINUS = '-' ;
+ MULT = '*' ;
+ DIV = '/' ;
+}
+
+/*------------------------------------------------------------------
+ * PARSER RULES
+ *------------------------------------------------------------------*/
+
+expr : term ( ( PLUS | MINUS ) term )* ;
+
+term : factor ( ( MULT | DIV ) factor )* ;
+
+factor : NUMBER ;
+
+
+/*------------------------------------------------------------------
+ * LEXER RULES
+ *------------------------------------------------------------------*/
+
+NUMBER : (DIGIT)+ ;
+
+/* WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = HIDDEN; } ; */
+
+fragment DIGIT : '0'..'9' ;
+
+"""
+
+ grammar().validate()
+ antlrGrammarTree = grammar().parseString(text)
+ print(antlrGrammarTree.asXML("antlrGrammarTree"))
+ pyparsingRules = antlrConverter(antlrGrammarTree)
+ pyparsingRule = pyparsingRules["expr"]
+ pyparsingTree = pyparsingRule.parseString("2 - 5 * 42 + 7 / 25")
+ print(pyparsingTree.asXML("pyparsingTree"))
diff --git a/pyparsing.py b/pyparsing.py
index 97f3374..093d346 100644
--- a/pyparsing.py
+++ b/pyparsing.py
@@ -94,7 +94,7 @@ classes inherit from. Use the docstrings for examples of how to:
"""
__version__ = "2.4.0"
-__versionTime__ = "07 Apr 2019 04:08 UTC"
+__versionTime__ = "07 Apr 2019 12:40 UTC"
__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
import string
@@ -160,7 +160,7 @@ __compat__.collect_all_And_tokens = True
#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) )
-__all__ = [
+__all__ = [ '__version__', '__versionTime__', '__author__', '__compat__',
'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty',
'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal',
'PrecededBy', 'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or',
@@ -5215,7 +5215,7 @@ def ungroup(expr):
"""Helper to undo pyparsing's default grouping of And expressions,
even if all but one are non-empty.
"""
- return TokenConverter(expr).setParseAction(lambda t:t[0])
+ return TokenConverter(expr).addParseAction(lambda t:t[0])
def locatedExpr(expr):
"""Helper to decorate a returned token with its starting and ending
diff --git a/setup.py b/setup.py
index 89ad68b..9de1761 100644
--- a/setup.py
+++ b/setup.py
@@ -1,38 +1,39 @@
-#!/usr/bin/env python
-
-"""Setup script for the pyparsing module distribution."""
-
-from setuptools import setup
-from pyparsing import __version__ as pyparsing_version
-
-modules = ["pyparsing",]
-
-setup(# Distribution meta-data
- name = "pyparsing",
- version = pyparsing_version,
- description = "Python parsing module",
- author = "Paul McGuire",
- author_email = "ptmcg@users.sourceforge.net",
- url = "https://github.com/pyparsing/pyparsing/",
- download_url = "https://pypi.org/project/pyparsing/",
- license = "MIT License",
- py_modules = modules,
- python_requires='>=2.6, !=3.0.*, !=3.1.*, !=3.2.*',
- classifiers=[
- 'Development Status :: 5 - Production/Stable',
- 'Intended Audience :: Developers',
- 'Intended Audience :: Information Technology',
- 'License :: OSI Approved :: MIT License',
- 'Operating System :: OS Independent',
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.6',
- 'Programming Language :: Python :: 2.7',
- 'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.3',
- 'Programming Language :: Python :: 3.4',
- 'Programming Language :: Python :: 3.5',
- 'Programming Language :: Python :: 3.6',
- 'Programming Language :: Python :: 3.7',
- ]
- )
+#!/usr/bin/env python
+
+"""Setup script for the pyparsing module distribution."""
+
+from setuptools import setup
+from pyparsing import __version__ as pyparsing_version
+
+modules = ["pyparsing",]
+
+setup(# Distribution meta-data
+ name = "pyparsing",
+ version = pyparsing_version,
+ description = "Python parsing module",
+ author = "Paul McGuire",
+ author_email = "ptmcg@users.sourceforge.net",
+ url = "https://github.com/pyparsing/pyparsing/",
+ download_url = "https://pypi.org/project/pyparsing/",
+ license = "MIT License",
+ py_modules = modules,
+ python_requires='>=2.6, !=3.0.*, !=3.1.*, !=3.2.*',
+ test_suite="unitTests.suite",
+ classifiers=[
+ 'Development Status :: 5 - Production/Stable',
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: Information Technology',
+ 'License :: OSI Approved :: MIT License',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.3',
+ 'Programming Language :: Python :: 3.4',
+ 'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
+ 'Programming Language :: Python :: 3.7',
+ ]
+ )
diff --git a/simple_unit_tests.py b/simple_unit_tests.py
index a40795b..7e42003 100644
--- a/simple_unit_tests.py
+++ b/simple_unit_tests.py
@@ -94,7 +94,7 @@ class PyparsingExpressionTestCase(unittest.TestCase):
self.assertTrue(False, "failed to raise expected exception")
-#=========== TEST DEFINITIONS START HERE ==============
+# =========== TEST DEFINITIONS START HERE ==============
class TestLiteral(PyparsingExpressionTestCase):
tests = [
@@ -444,20 +444,26 @@ class TestCommonHelperExpressions(PyparsingExpressionTestCase):
]
-#============ MAIN ================
-
-if __name__ == '__main__':
+def _get_decl_line_no(cls):
import inspect
- def get_decl_line_no(cls):
- return inspect.getsourcelines(cls)[1]
+ return inspect.getsourcelines(cls)[1]
+
- # get all test case classes defined in this module and sort them by decl line no
- test_case_classes = list(PyparsingExpressionTestCase.__subclasses__())
- test_case_classes.sort(key=get_decl_line_no)
+# get all test case classes defined in this module and sort them by decl line no
+test_case_classes = list(PyparsingExpressionTestCase.__subclasses__())
+test_case_classes.sort(key=_get_decl_line_no)
- # make into a suite and run it - this will run the tests in the same order
- # they are declared in this module
- suite = unittest.TestSuite(cls() for cls in test_case_classes)
+# make into a suite and run it - this will run the tests in the same order
+# they are declared in this module
+#
+# runnable from setup.py using "python setup.py test -s simple_unit_tests.suite"
+#
+suite = unittest.TestSuite(cls() for cls in test_case_classes)
+
+
+# ============ MAIN ================
+
+if __name__ == '__main__':
result = unittest.TextTestRunner().run(suite)
exit(0 if result.wasSuccessful() else 1)
diff --git a/unitTests.py b/unitTests.py
index 908266e..5db9ffe 100644
--- a/unitTests.py
+++ b/unitTests.py
@@ -4327,6 +4327,10 @@ def makeTestSuiteTemp(classes):
suite.addTests(cls() for cls in classes)
return suite
+# runnable from setup.py using "python setup.py test -s unitTests.suite"
+suite = makeTestSuite()
+
+
if __name__ == '__main__':
testRunner = TextTestRunner()
@@ -4337,7 +4341,7 @@ if __name__ == '__main__':
]
if not testclasses:
- result = testRunner.run(makeTestSuite())
+ result = testRunner.run(suite)
else:
BUFFER_OUTPUT = False
result = testRunner.run(makeTestSuiteTemp(testclasses))