Mercurial > python-cmd2
changeset 153:5c5c458a6b70
parsing going well
author | catherine@dellzilla |
---|---|
date | Fri, 21 Nov 2008 14:33:15 -0500 |
parents | 693d11072e8e |
children | 606ad25c7f7e |
files | cmd2.py |
diffstat | 1 files changed, 142 insertions(+), 89 deletions(-) [+] |
line wrap: on
line diff
--- a/cmd2.py Fri Nov 21 08:48:38 2008 -0500 +++ b/cmd2.py Fri Nov 21 14:33:15 2008 -0500 @@ -199,114 +199,167 @@ self.stdout.write("Single-key shortcuts for other commands:\n%s\n" % (result)) commentGrammars = pyparsing.Or([pyparsing.pythonStyleComment, pyparsing.cStyleComment]) + commentGrammars.addParseAction(lambda x: '') commentInProgress = pyparsing.Literal('/*') + pyparsing.SkipTo(pyparsing.stringEnd) terminators = [';', '\n\n'] - argSeparatorPattern = pyparsing.Word(pyparsing.printables)('command') \ - + pyparsing.SkipTo(pyparsing.StringEnd())('args') - filenamePattern = pyparsing.Word(pyparsing.alphanums + '#$-_~{},.!:\\/') - integerPattern = pyparsing.Word(pyparsing.nums).setParseAction( lambda s,l,t: [ int(t[0]) ] ) - pipePattern = pyparsing.Literal('|')('pipe') + pyparsing.restOfLine('pipeTo') - redirectOutPattern = (pyparsing.Literal('>>') ^ '>')('output') \ - + pyparsing.Optional(filenamePattern)('outputTo') - redirectInPattern = pyparsing.Literal('<')('input') \ - + pyparsing.Optional(filenamePattern)('inputFrom') - punctuationPattern = pipePattern ^ redirectInPattern ^ redirectOutPattern - + multilineCommands = [] def _init_parser(self): ''' >>> c = Cmd() + >>> c.multilineCommands = ['multiline'] + >>> c.caseInsensitive = True + >>> c._init_parser() >>> print c.parser.parseString('barecommand').dump() - >>> print c.parser.parseString('command with args').dump() + ['barecommand', ''] + - args: + - command: barecommand + - statement: ['barecommand', ''] + - args: + - command: barecommand + >>> print c.parser.parseString('COMmand with args').dump() + ['command', ' with args'] + - args: with args + - command: command + - statement: ['command', ' with args'] + - args: with args + - command: command >>> print c.parser.parseString('command with args and terminator; and suffix').dump() + ['command', 'with args and terminator', ';', ' and suffix'] + - args: with args and terminator + - command: command + - statement: ['command', 'with args and terminator', ';'] + - args: with args and terminator + - command: command + - terminator: ; + - suffix: and suffix + - terminator: ; + >>> print c.parser.parseString('simple | piped').dump() + ['simple', '', '|', ' piped'] + - args: + - command: simple + - pipeDest: piped + - statement: ['simple', ''] + - args: + - command: simple >>> print c.parser.parseString('command with args, terminator;sufx | piped').dump() - >>> print c.parser.parseString('simple | piped').dump() + ['command', 'with args, terminator', ';', 'sufx', '|', ' piped'] + - args: with args, terminator + - command: command + - pipeDest: piped + - statement: ['command', 'with args, terminator', ';'] + - args: with args, terminator + - command: command + - terminator: ; + - suffix: sufx + - terminator: ; >>> print c.parser.parseString('output into > afile.txt').dump() + ['output', ' into', '>', ' afile.txt'] + - args: into + - command: output + - output: > + - outputDest: afile.txt + - statement: ['output', ' into'] + - args: into + - command: output >>> print c.parser.parseString('output into;sufx | pipethrume plz > afile.txt').dump() + ['output', 'into', ';', 'sufx', '|', ' pipethrume plz', '>', ' afile.txt'] + - args: into + - command: output + - output: > + - outputDest: afile.txt + - pipeDest: pipethrume plz + - statement: ['output', 'into', ';'] + - args: into + - command: output + - terminator: ; + - suffix: sufx + - terminator: ; >>> print c.parser.parseString('output to paste buffer >> ').dump() + ['output', ' to paste buffer', '>>', ''] + - args: to paste buffer + - command: output + - output: >> + - outputDest: + - statement: ['output', ' to paste buffer'] + - args: to paste buffer + - command: output >>> print c.parser.parseString('ignore the /* commented | > */ stuff;').dump() - >>> print c.parser.parseString('do not parse > when formally terminated;').dump() - >>> print c.parser.parseString('do not parse > when formally terminated;').dump() - ''' + ['ignore', 'the /* commented | > */ stuff', ';', ''] + - args: the /* commented | > */ stuff + - command: ignore + - statement: ['ignore', 'the /* commented | > */ stuff', ';'] + - args: the /* commented | > */ stuff + - command: ignore + - terminator: ; + - suffix: + - terminator: ; + >>> print c.parser.parseString('has > inside;').dump() + ['has', '> inside', ';', ''] + - args: > inside + - command: has + - statement: ['has', '> inside', ';'] + - args: > inside + - command: has + - terminator: ; + - suffix: + - terminator: ; + >>> print c.parser.parseString('multiline has > inside an unfinished command').dump() + ['multiline', 'has > inside an unfinished command'] + - multilineCommand: multiline + >>> print c.parser.parseString('multiline has > inside;').dump() + ['multiline', 'has > inside', ';', ''] + - args: has > inside + - multilineCommand: multiline + - statement: ['multiline', 'has > inside', ';'] + - args: has > inside + - multilineCommand: multiline + - terminator: ; + - suffix: + - terminator: ; + >>> print c.parser.parseString('multiline command /* with comment in progress;').dump() + ['multiline', 'command /* with comment in progress;'] + - multilineCommand: multiline + >>> print c.parser.parseString('multiline command /* with comment complete */ is done;').dump() + ['multiline', 'command /* with comment complete */ is done', ';', ''] + - args: command /* with comment complete */ is done + - multilineCommand: multiline + - statement: ['multiline', 'command /* with comment complete */ is done', ';'] + - args: command /* with comment complete */ is done + - multilineCommand: multiline + - terminator: ; + - suffix: + - terminator: ; + ''' outputParser = pyparsing.oneOf(['>>','>'])('output') terminatorParser = pyparsing.oneOf(self.terminators)('terminator') stringEnd = pyparsing.stringEnd ^ '\nEOF' - command = pyparsing.Word(pyparsing.printables)('command') + multilineCommand = pyparsing.Or([pyparsing.Keyword(c, caseless=self.caseInsensitive) for c in self.multilineCommands])('multilineCommand') + oneLineCommand = pyparsing.Word(pyparsing.printables)('command') + afterElements = \ + pyparsing.Optional('|' + pyparsing.SkipTo(outputParser ^ stringEnd)('pipeDest')) + \ + pyparsing.Optional(outputParser + pyparsing.SkipTo(stringEnd)('outputDest')) if self.caseInsensitive: - command.setParseAction(lambda x: x[0].lower()) - statementParser = \ - (command + - pyparsing.SkipTo(terminatorParser)('args') + - terminatorParser - )('statement') ^ \ - (command + - pyparsing.SkipTo(terminatorParser ^ '|' ^ outputParser ^ stringEnd)('args') + - pyparsing.Optional(terminatorParser) - )('statement') + multilineCommand.setParseAction(lambda x: x[0].lower()) + oneLineCommand.setParseAction(lambda x: x[0].lower()) + self.parser = ( + (((multilineCommand ^ oneLineCommand) + pyparsing.SkipTo(terminatorParser)('args') + terminatorParser)('statement') + + pyparsing.SkipTo(outputParser ^ '|' ^ stringEnd)('suffix') + afterElements) + ^ + multilineCommand + pyparsing.SkipTo(pyparsing.stringEnd) + ^ + ((oneLineCommand + pyparsing.SkipTo(terminatorParser ^ stringEnd ^ '|' ^ outputParser)('args'))('statement') + + afterElements) + ) self.commentGrammars.ignore(pyparsing.sglQuotedString).ignore(pyparsing.dblQuotedString).setParseAction(lambda x: '') self.commentInProgress.ignore(pyparsing.sglQuotedString).ignore(pyparsing.dblQuotedString).ignore(pyparsing.cStyleComment) - self.parser = statementParser + \ - pyparsing.SkipTo(outputParser ^ '|' ^ stringEnd)('suffix') + \ - pyparsing.Optional('|' + pyparsing.SkipTo(outputParser ^ stringEnd)('pipeDest')) + \ - pyparsing.Optional(outputParser + pyparsing.SkipTo(stringEnd)('outputDest')) self.parser.ignore(pyparsing.sglQuotedString).ignore(pyparsing.dblQuotedString).ignore(self.commentGrammars).ignore(self.commentInProgress) - - def parsed(self, s, assumeComplete=False): - pass - ''' - >>> c = Cmd() - >>> r = c.parsed('quotes "are > ignored" < inp.txt') - >>> r.statement, r.input, r.inputFrom, r.output, r.outputFrom - ('quotes "are > ignored" ', '<', 'inp.txt', '', '') - >>> r = c.parsed('very complex; < from.txt >> to.txt etc.') - >>> r.statement, r.terminator, r.input, r.inputFrom, r.output, r.outputTo - ('very complex;', ';', '<', 'from.txt', '>>', 'to.txt') - >>> c.parsed('nothing to parse').statement - 'nothing to parse' - >>> r = c.parsed('ignore > within a terminated statement; > out.txt') - >>> r.statement, r.terminator, r.input, r.inputFrom, r.output, r.outputTo - ('ignore > within a terminated statement;', ';', '', '', '>', 'out.txt') - >>> r = c.parsed('send it to | sort | wc') - >>> r.statement, r.pipe, r.pipeTo - ('send it to ', '|', ' sort | wc') - >>> r = c.parsed('got from < thisfile.txt plus blah blah') - >>> r.statement, r.input, r.inputFrom - ('got from ', '<', 'thisfile.txt') - ''' - if isinstance(s, pyparsing.ParseResults): - return s - result = (pyparsing.SkipTo(pyparsing.StringEnd()))("fullStatement").parseString(s) - s = self.commentGrammars.transformString(s) - command = s.split()[0] - if self.caseInsensitive: - command = command.lower() - result['command'] = command - if command in self.noSpecialParse: - result['statement'] = s - return result - - if s[0] in self.shortcuts: - s = self.shortcuts[s[0]] + ' ' + s[1:] - result['statement'] = s - result['parseable'] = s - result += parseSearchResults(self.terminatorPattern, s) - if result.terminator: - result['statement'] = result.upToIncluding - result['unterminated'] = result.before - result['parseable'] = result.after - else: - # does not catch output marks - if (not assumeComplete) and (command in self.multilineCommands): - return result # don't bother with the rest, we're still collecting input - result += parseSearchResults(self.punctuationPattern, s) - result['statement'] = result['unterminated'] = result.before - result += parseSearchResults(self.pipePattern, result.parseable) - result += parseSearchResults(self.redirectInPattern, result.parseable) - result += parseSearchResults(self.redirectOutPattern, result.parseable) - result += parseSearchResults(self.argSeparatorPattern, result.statement) - if self.caseInsensitive: - result['command'] = result.command.lower() - result['statement'] = '%s %s' % (result.command, result.args) + + def parsed(self, s): + result = self.parser.parseString(s) + result['command'] = result.multilineCommand or result.command + result['cleanArgs'] = self.commentGrammars.transformString(result.args) + result['statement'] = ' '.join(result.statement) return result def extractCommand(self, statement): @@ -824,4 +877,4 @@ self.outputTrap.tearDown() if __name__ == '__main__': - doctest.testmod() + doctest.testmod(optionflags = doctest.NORMALIZE_WHITESPACE)