hy/hy/lex/states.py
2012-12-31 14:32:29 -05:00

193 lines
4.7 KiB
Python

from hy.lang.expression import HYExpression
from hy.lex.errors import LexException
from hy.lang.string import HYString
from hy.lang.symbol import HYSymbol
from hy.lang.number import HYNumber
from hy.lex.machine import Machine
from hy.lang.list import HYList
from hy.lang.bool import HYBool
from hy.lang.map import HYMap
WHITESPACE = [" ", "\t", "\n", "\r"]
def _resolve_atom(value, self):
def _mangle(obj):
obj.line = self.machine.line
obj.column = self.machine.column
return obj
if value == "true":
return _mangle(HYBool(True))
elif value == "false":
return _mangle(HYBool(False))
try:
return _mangle(HYNumber(value))
except ValueError:
pass
# LISP Variants have a tendency to use "-" in symbols n' shit.
value = value.replace("-", "_")
return _mangle(HYSymbol(value))
class State(object):
def __init__(self, machine):
self.machine = machine
self.sub_machine = None
def enter(self):
pass
def exit(self):
pass
def sub(self, machine):
self.sub_machine = Machine(machine)
def process(self, x):
if self.sub_machine:
self.sub_machine.process(x)
idle = type(self.sub_machine.state) == Idle
if idle:
self.nodes += self.sub_machine.nodes
self.sub_machine = None
return
return self.p(x)
class Comment(State):
def p(self, x):
if x == '\n':
return Idle
class Idle(State):
def p(self, x):
if x == ";": return Comment
if x == "(": return Expression
if x in WHITESPACE: return
raise LexException("Unknown char: %s" % (x))
class Expression(State):
def enter(self):
self.nodes = HYExpression([])
self.bulk = ""
def exit(self):
if self.bulk:
self.nodes.append(_resolve_atom(self.bulk, self))
self.machine.add_node(self.nodes)
def commit(self):
if self.bulk.strip() != "":
self.nodes.append(_resolve_atom(self.bulk, self))
self.bulk = ""
def p(self, x):
if x == ")": return Idle
if x in WHITESPACE: self.commit(); return
if x == "\"": self.sub(String); return
if x == "(": self.sub(Expression); return
if x == "[": self.sub(List); return
if x == "{": self.sub(Map); return
if x == ";": self.sub(Comment); return
self.bulk += x
class List(State):
def enter(self):
self.nodes = HYList([])
self.bulk = ""
def exit(self):
if self.bulk:
self.nodes.append(_resolve_atom(self.bulk, self))
self.machine.add_node(self.nodes)
def commit(self):
if self.bulk.strip() != "":
self.nodes.append(_resolve_atom(self.bulk, self))
self.bulk = ""
def p(self, x):
if x == "]": return Idle
if x in WHITESPACE: self.commit(); return
if x == "\"": self.sub(String); return
if x == "[": self.sub(List); return
if x == "(": self.sub(Expression); return
if x == "{": self.sub(Map); return
if x == ";": self.sub(Comment); return
self.bulk += x
class Map(State):
def enter(self):
self.nodes = []
self.bulk = ""
def exit(self):
if self.bulk:
self.nodes.append(_resolve_atom(self.bulk, self))
if (len(self.nodes) % 2) != 0:
raise LexException("Hash map is screwed up")
ret = HYMap({})
i = iter(self.nodes)
hmap = zip(i, i)
for key, val in hmap:
ret[key] = val
self.machine.add_node(ret)
def commit(self):
if self.bulk.strip() != "":
self.nodes.append(_resolve_atom(self.bulk, self))
self.bulk = ""
def p(self, x):
if x == "}": return Idle
if x in WHITESPACE: self.commit(); return
if x == "\"": self.sub(String); return
if x == "[": self.sub(List); return
if x == "{": self.sub(Map); return
if x == "(": self.sub(Expression); return
if x == ";": self.sub(Comment); return
self.bulk += x
class String(State):
magic = { "n": "\n", "t": "\t", "\\": "\\", "\"": "\"" }
def enter(self):
self.buf = ""
self.esc = False
def exit(self):
self.machine.add_node(HYString(self.buf))
def p(self, x):
if x == "\\":
self.esc = True
return
if x == "\"" and not self.esc:
return Idle
if self.esc and x not in self.magic:
raise LexException("Unknown escape: \\%s" % (x))
elif self.esc:
x = self.magic[x]
self.esc = False
self.buf += x