Skip to content

Instantly share code, notes, and snippets.

@zvoase
Created October 26, 2008 19:09
Show Gist options
  • Save zvoase/19929 to your computer and use it in GitHub Desktop.
Save zvoase/19929 to your computer and use it in GitHub Desktop.
# Copyright (c) 2008 Zachary Voase
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
class BracketList(list):
def __repr__(self):
return 'BracketList(%s)' % (list.__repr__(self),)
def __str__(self):
return '[%s]' % ' '.join(str(x) for x in self)
class ParenList(list):
def __repr__(self):
return 'ParenList(%s)' % (list.__repr__(self),)
def __str__(self):
return '(%s)' % ' '.join(str(x) for x in self)
class DoubleQuotedString(str):
def __repr__(self):
return 'DoubleQuotedString(%s)' % (str.__repr__(self),)
def __str__(self):
string_repr = str.__repr__(self)
if string_repr.startswith('"'):
return string_repr
return '"' + string_repr[1:-1].replace('"', '\\"') + '"'
class SingleQuotedString(str):
def __repr__(self):
return 'SingleQuotedString(%s)' % (str.__repr__(self),)
def __str__(self):
string_repr = str.__repr__(self)
if string_repr.startswith("'"):
return string_repr
return "'" + string_repr[1:-1].replace("'", "\\'") + "'"
class Symbol(str):
def __repr__(self):
return 'Symbol(%s)' % (str.__repr__(self),)
def __str__(self):
return str.__str__(self)
class ASTGenerator(list):
def __init__(self, tree=[]):
list.__init__(self, tree)
self.__node_stack = [self]
self.__buffer = ''
self.__state = None
self.__escape = False
def __repr__(self):
return 'ASTGenerator(%s)' % (list.__repr__(self),)
def __str__(self):
return ' '.join(str(x) for x in self)
def parse(self, string):
for i, char in enumerate(string):
try:
self.__parse_char(char)
except SyntaxError, exc:
raise SyntaxError(exc.args + (i,))
return self
def backslash(self, char):
if self.__escape:
if self.__state in ('singlequote', 'doublequote', 'symbol'):
self.__buffer += char
elif self.__state == None:
self.__state = 'symbol'
self.__buffer += char
self.__escape = False
return
else:
self.__escape = True
def single_quote(self, char):
if self.__escape:
if self.__state in ('singlequote', 'doublequote', 'symbol'):
self.__buffer += char
else:
self.__state = 'symbol'
self.__buffer += char
self.__escape = False
return
if self.__state == 'singlequote':
self.__node_stack[-1].append(SingleQuotedString(self.__buffer))
self.__buffer = ''
self.__state = None
elif self.__state == 'doublequote':
self.__buffer += char
elif self.__state == 'symbol':
self.__node_stack[-1].append(Symbol(self.__buffer))
self.__buffer = ''
self.__state = 'singlequote'
elif self.__state == None:
self.__state = 'singlequote'
def double_quote(self, char):
if self.__escape:
if self.__state in ('singlequote', 'doublequote', 'symbol'):
self.__buffer += char
else:
self.__state = 'symbol'
self.__buffer += char
self.__escape = False
return
if self.__state == 'doublequote':
self.__node_stack[-1].append(DoubleQuotedString(self.__buffer))
self.__buffer = ''
self.__state = None
elif self.__state == 'singlequote':
self.__buffer += char
elif self.__state == 'symbol':
self.__node_stack[-1].append(Symbol(self.__buffer))
self.__buffer = ''
self.__state = 'doublequote'
elif self.__state == None:
self.__state = 'doublequote'
def open_paren(self, char):
if self.__escape:
if self.__state in ('singlequote', 'doublequote', 'symbol'):
self.__buffer += char
else:
self.__state = 'symbol'
self.__buffer += char
self.__escape = False
return
if self.__state in ('doublequote', 'singlequote'):
self.__buffer += char
elif self.__state == 'symbol':
self.__node_stack[-1].append(Symbol(self.__buffer))
self.__buffer = ''
self.__state = None
plist = ParenList()
self.__node_stack[-1].append(plist)
self.__node_stack.append(plist)
elif self.__state == None:
plist = ParenList()
self.__node_stack[-1].append(plist)
self.__node_stack.append(plist)
def close_paren(self, char):
if self.__escape:
if self.__state in ('singlequote', 'doublequote', 'symbol'):
self.__buffer += char
else:
self.__state = 'symbol'
self.__buffer += char
self.__escape = False
return
if self.__state in ('doublequote', 'singlequote'):
self.__buffer += char
elif self.__state == 'symbol':
self.__node_stack[-1].append(Symbol(self.__buffer))
self.__buffer = ''
self.__state = None
self.__node_stack.pop()
elif self.__state == None:
self.__node_stack.pop()
def open_bracket(self, char):
if self.__escape:
if self.__state in ('singlequote', 'doublequote', 'symbol'):
self.__buffer += char
else:
self.__state = 'symbol'
self.__buffer += char
self.__escape = False
return
if self.__state in ('doublequote', 'singlequote'):
self.__buffer += char
elif self.__state == 'symbol':
self.__node_stack[-1].append(Symbol(self.__buffer))
self.__buffer = ''
self.__state = None
blist = BracketList()
self.__node_stack[-1].append(blist)
self.__node_stack.append(blist)
elif self.__state == None:
blist = BracketList()
self.__node_stack[-1].append(blist)
self.__node_stack.append(blist)
def close_bracket(self, char):
if self.__escape:
if self.__state in ('singlequote', 'doublequote', 'symbol'):
self.__buffer += char
else:
self.__state = 'symbol'
self.__buffer += char
self.__escape = False
return
if self.__state in ('doublequote', 'singlequote'):
self.__buffer += char
elif self.__state == 'symbol':
self.__node_stack[-1].append(Symbol(self.__buffer))
self.__buffer = ''
self.__state = None
self.__node_stack.pop()
elif self.__state == None:
self.__node_stack.pop()
def space_char(self, char):
if self.__escape:
if self.__state in ('singlequote', 'doublequote', 'symbol'):
self.__buffer += char
else:
self.__state = 'symbol'
self.__buffer += char
self.__escape = False
return
if self.__state in ('doublequote', 'singlequote'):
self.__buffer += char
elif self.__state == 'symbol':
self.__node_stack[-1].append(Symbol(self.__buffer))
self.__buffer = ''
self.__state = None
elif self.__state == None:
pass
def otherwise(self, char):
if self.__escape:
self.__buffer += char
if self.__state == None:
self.__state = 'symbol'
self.__escape = False
if self.__state in ('doublequote', 'singlequote', 'symbol'):
self.__buffer += char
elif self.__state == None:
self.__state = 'symbol'
self.__buffer += char
def __get_valid(self):
return not any([self.__state, self.__buffer,
len(self.__node_stack) != 1])
def __parse_char(self, char):
if len(char) > 1:
return self.parse(char)
elif len(char) == 0:
return
for predicate, consequence in self.char_dispatch:
if predicate(char):
consequence(self, char)
return
valid = property(__get_valid)
char_dispatch = (
(lambda char: char.__eq__('\\'), backslash),
(lambda char: char.__eq__("'"), single_quote),
(lambda char: char.__eq__('"'), double_quote),
(lambda char: char.__eq__('('), open_paren),
(lambda char: char.__eq__(')'), close_paren),
(lambda char: char.__eq__('['), open_bracket),
(lambda char: char.__eq__(']'), close_bracket),
(lambda char: char.isspace(), space_char),
(lambda char: True, otherwise))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment