X-Git-Url: https://git.yukkurigames.com/?p=python-bulletml.git;a=blobdiff_plain;f=bulletml%2Fparser.py;h=10b789ae83a801bc0dc538afc183f8194240f00c;hp=2ad648c20c97eb16e53a08b2c17c7a453b19799a;hb=70d25195d561d8b5d3126c6bbac0ecad2a502f06;hpb=4bb0077fd274237fb81db63460620470b1f6d520 diff --git a/bulletml/parser.py b/bulletml/parser.py index 2ad648c..10b789a 100644 --- a/bulletml/parser.py +++ b/bulletml/parser.py @@ -24,6 +24,7 @@ except ImportError: from bulletml.errors import Error from bulletml.expr import NumberDef, INumberDef + __all_ = ["ParseError", "BulletML"] class ParseError(Error): @@ -66,6 +67,12 @@ class Direction(object): self.type = type self.value = value + def __getstate__(self): + return dict(type=self.type, value=self.value.expr) + + def __setstate__(self, state): + self.__init__(state["type"], NumberDef(state["value"])) + @classmethod def FromElement(cls, doc, element, default="absolute"): """Construct using an ElementTree-style element.""" @@ -85,6 +92,15 @@ class ChangeDirection(object): self.term = term self.direction = direction + def __getstate__(self): + return dict(frames=self.term.expr, + type=self.direction.type, + value=self.direction.value.expr) + + def __setstate__(self, state): + self.__init__(INumberDef(state["frames"]), + Direction(state["type"], NumberDef(state["value"]))) + @classmethod def FromElement(cls, doc, element): """Construct using an ElementTree-style element.""" @@ -117,6 +133,12 @@ class Speed(object): self.type = type self.value = value + def __getstate__(self): + return dict(type=self.type, value=self.value.expr) + + def __setstate__(self, state): + self.__init__(state["type"], NumberDef(state["value"])) + @classmethod def FromElement(cls, doc, element): """Construct using an ElementTree-style element.""" @@ -135,6 +157,15 @@ class ChangeSpeed(object): self.term = term self.speed = speed + def __getstate__(self): + return dict(frames=self.term.expr, + type=self.speed.type, + value=self.speed.value.expr) + + def __setstate__(self, state): + self.__init__(INumberDef(state["frames"]), + Speed(state["type"], NumberDef(state["value"]))) + @classmethod def FromElement(cls, doc, element): """Construct using an ElementTree-style element.""" @@ -162,6 +193,12 @@ class Wait(object): def __init__(self, frames): self.frames = frames + def __getstate__(self): + return dict(frames=self.frames.expr) + + def __setstate__(self, state): + self.__init__(INumberDef(state["frames"])) + @classmethod def FromElement(cls, doc, element): """Construct using an ElementTree-style element.""" @@ -179,6 +216,12 @@ class Tag(object): def __init__(self, tag): self.tag = tag + def __getstate__(self): + return dict(tag=self.tag) + + def __setstate__(self, state): + self.__init__(state["tag"]) + @classmethod def FromElement(cls, doc, element): """Construct using an ElementTree-style element.""" @@ -189,6 +232,12 @@ class Untag(object): def __init__(self, tag): self.tag = tag + + def __getstate__(self): + return dict(tag=self.tag) + + def __setstate__(self, state): + self.__init__(state["tag"]) @classmethod def FromElement(cls, doc, element): @@ -215,6 +264,12 @@ class Repeat(object): def __init__(self, times, action): self.times = times self.action = action + + def __getstate__(self): + return dict(times=self.times.expr, action=self.action) + + def __setstate__(self, state): + self.__init__(INumberDef(state["times"]), state["action"]) @classmethod def FromElement(cls, doc, element): @@ -249,6 +304,18 @@ class Accel(object): self.horizontal = horizontal self.vertical = vertical + def __getstate__(self): + state = dict(frames=self.term.expr) + if self.horizontal: + state["horizontal"] = self.horizontal + if self.vertical: + state["vertical"] = self.vertical + return state + + def __setstate__(self, state): + self.__init__(INumberDef(state["frames"]), state.get("horizontal"), + state.get("vertical")) + @classmethod def FromElement(cls, doc, element): """Construct using an ElementTree-style element.""" @@ -290,6 +357,19 @@ class BulletDef(object): self.speed = speed self.actions = list(actions) + def __getstate__(self): + state = dict() + if self.direction: + state["direction"] = self.direction + if self.speed: + state["speed"] = self.speed + if self.actions: + state["actions"] = self.actions + return state + + def __setstate__(self, state): + self.__init__(**state) + @classmethod def FromElement(cls, doc, element): """Construct using an ElementTree-style element.""" @@ -326,7 +406,18 @@ class BulletRef(object): def __init__(self, bullet, params=None): self.bullet = bullet - self.params = params or ParamList() + self.params = ParamList() if params is None else params + + def __getstate__(self): + state = dict(bullet=self.bullet) + if self.params.params: + state["params"] = [param.expr for param in self.params.params] + return state + + def __setstate__(self, state): + bullet = state["bullet"] + params = [NumberDef(param) for param in state.get("params", [])] + self.__init__(bullet, ParamList(params)) @classmethod def FromElement(cls, doc, element): @@ -357,6 +448,12 @@ class ActionDef(object): def __init__(self, actions): self.actions = list(actions) + def __getstate__(self): + return dict(actions=self.actions) + + def __setstate__(self, state): + self.__init__(state["actions"]) + @classmethod def FromElement(cls, doc, element): """Construct using an ElementTree-style element.""" @@ -386,6 +483,17 @@ class ActionRef(object): self.action = action self.params = params or ParamList() + def __getstate__(self): + state = dict(action=self.action) + if self.params.params: + state["params"] = [param.expr for param in self.params.params] + return state + + def __setstate__(self, state): + action = state["action"] + params = [NumberDef(param) for param in state.get("params", [])] + self.__init__(action, ParamList(params)) + @classmethod def FromElement(cls, doc, element): """Construct using an ElementTree-style element.""" @@ -412,6 +520,17 @@ class Offset(object): self.x = x self.y = y + def __getstate__(self): + state = dict(type=self.type) + if self.x: + state["x"] = self.x.expr + if self.y: + state["y"] = self.y.expr + return state + + def __setstate__(self, state): + self.__init__(state["type"], state.get("x"), state.get("y")) + @classmethod def FromElement(cls, doc, element): """Construct using an ElementTree-style element.""" @@ -439,6 +558,27 @@ class FireDef(object): self.speed = speed self.offset = offset + def __getstate__(self): + try: + params = self.bullet.params + except AttributeError: + state = dict(bullet=self.bullet) + else: + if params.params: + state = dict(bullet=self.bullet) + else: + state = dict(bullet=self.bullet.bullet) + if self.direction: + state["direction"] = self.direction + if self.speed: + state["speed"] = self.speed + if self.offset: + state["offset"] = self.offset + return state + + def __setstate__(self, state): + self.__init__(**state) + @classmethod def FromElement(cls, doc, element): """Construct using an ElementTree-style element.""" @@ -485,6 +625,17 @@ class FireRef(object): self.fire = fire self.params = params or ParamList() + def __getstate__(self): + state = dict(fire=self.fire) + if self.params.params: + state["params"] = [param.expr for param in self.params.params] + return state + + def __setstate__(self, state): + fire = state["fire"] + params = [NumberDef(param) for param in state.get("params", [])] + self.__init__(fire, ParamList(params)) + @classmethod def FromElement(cls, doc, element): """Construct using an ElementTree-style element.""" @@ -524,9 +675,15 @@ class BulletML(object): self.actions = {} if actions is None else actions self.fires = {} if fires is None else fires + def __getstate__(self): + return dict(type=self.type, actions=self.actions) + + def __setstate__(self, state): + self.__init__(state["type"], actions=state.get("actions")) + @classmethod - def FromDocument(cls, source): - """Return a BulletML instance based on a string or file-like.""" + def FromXML(cls, source): + """Return a BulletML instance based on XML.""" if not hasattr(source, 'read'): source = StringIO(source) @@ -564,6 +721,39 @@ class BulletML(object): return self + @classmethod + def FromYAML(cls, source): + """Create a BulletML instance based on YAML.""" + + # Late import to avoid a circular dependency. + try: + import bulletml.bulletyaml + import yaml + except ImportError: + raise ParseError("PyYAML is not available") + else: + try: + return yaml.load(source) + except Exception, exc: + raise ParseError(str(exc)) + + @classmethod + def FromDocument(cls, source): + """Create a BulletML instance based on a seekable file or string. + + This attempts to autodetect if the stream is XML or YAML. + """ + if not hasattr(source, 'read'): + source = StringIO(source) + start = source.read(1) + source.seek(0) + if start == "<": + return cls.FromXML(source) + elif start == "!": + return cls.FromYAML(source) + else: + raise ParseError("unknown initial character %r" % start) + @property def top(self): """Get a list of all top-level actions."""