1
# Copyright (c) Twisted Matrix Laboratories.
2
# See LICENSE for details.
3
import string, sys, linecache
4
from types import ModuleType as module
5
from pymeta.runtime import ParseError
6
from pymeta.grammar import OMetaGrammarMixin, OMeta, OMetaGrammar
7
from pymeta.builder import TreeBuilder, PythonWriter, GeneratedCodeLoader
8
portableOMetaGrammar = """
9
action ::= <spaces> (<actionCall> | <actionNoun> | <actionLiteral>)
10
actionCall ::= <actionNoun>:verb <token "("> <actionArgs>?:args <token ")"> => ActionCall(verb, args)
11
actionArgs ::= <action>:a (<token ','> <action>)*:b => [a] + b
12
actionNoun ::= <name>:n => ActionNoun(n)
13
actionLiteral ::= (<number> | <character> | <bareString>):lit => ActionLiteral(lit)
15
ruleValue ::= <token "=>"> <action>:a => self.result(a)
16
semanticPredicate ::= <token "?("> <action>:a <token ")"> => self.predicate(a)
17
semanticAction ::= <token "!("> <action>:a <token ")"> => self.action(a)
18
applicationArgs ::= (<spaces> <action>)+:args <token ">"> => [self.result(a) for a in args]
19
string ::= <bareString>:s => self.builder.apply("tokenBR", self.name, self.action(ActionLiteral(s)))
21
class ActionNoun(object):
23
A noun in a portable OMeta grammar action.
25
def __init__(self, name):
29
def visit(self, visitor):
30
return visitor.name(self.name)
32
class ActionCall(object):
34
A call action in a portable OMeta grammar.
36
def __init__(self, verb, args):
38
self.args = args or []
41
def visit(self, visitor):
42
return visitor.call(self.verb.visit(visitor),
43
[arg.visit(visitor) for arg in self.args])
46
class ActionLiteral(object):
48
A literal value in a portable OMeta action.
50
def __init__(self, value):
53
def visit(self, visitor):
54
return visitor.literal(self.value)
56
class PortableTreeBuilder(TreeBuilder):
57
def compilePortableAction(self, action):
58
return ["PortableAction", action]
64
def __init__(self, output):
69
Produce a unique name for a variable in generated code.
71
ActionVisitor.gensymCounter += 1
72
return "_A_%s" % (self.gensymCounter)
75
result = self._gensym()
76
self.output.append('%s = self.lookupActionName(%r, _locals)' % (result, name))
79
def call(self, verb, args):
80
result = self._gensym()
81
self.output.append('%s = %s(%s)' % (result, verb, ', '.join(args)))
84
def literal(self, value):
88
class PortablePythonWriter(PythonWriter):
89
def generate_PortableAction(self, action):
91
Generate Python code for an action expression.
93
av = ActionVisitor(self.lines)
94
return action.visit(av)
97
def makePortableGrammar(grammar, bits, name):
98
g = OMetaGrammar(grammar)
99
tree = g.parseGrammar(name, PortableTreeBuilder)
100
return moduleFromGrammar(tree, name, OMetaGrammar, bits)
102
def moduleFromGrammar(tree, className, superclass, globalsDict):
103
pw = PortablePythonWriter(tree)
106
modname = "pymeta_grammar__" + className
107
filename = "/pymeta_generated_code/" + modname + ".py"
108
mod = module(modname)
109
mod.__dict__.update(globalsDict)
110
mod.__name__ = modname
111
mod.__dict__[superclass.__name__] = superclass
112
mod.__dict__["GrammarBase"] = superclass
113
mod.__loader__ = GeneratedCodeLoader(source)
114
code = compile(source, filename, "exec")
115
eval(code, mod.__dict__)
116
fullGlobals = dict(getattr(mod.__dict__[className], "globals", None) or {})
117
fullGlobals.update(globalsDict)
118
mod.__dict__[className].globals = fullGlobals
119
sys.modules[modname] = mod
120
linecache.getlines(filename, mod.__dict__)
121
return mod.__dict__[className]
123
_PortableActionGrammar = makePortableGrammar(portableOMetaGrammar,
124
globals(), "_PortableActionGrammar")
126
class PortableOMetaGrammar(_PortableActionGrammar):
128
An OMeta variant with portable syntax for actions.
131
def result(self, action):
132
return self.builder.compilePortableAction(action)
135
def predicate(self, action):
136
return self.builder.pred(self.builder.compilePortableAction(action))
139
def action(self, action):
140
return self.builder.compilePortableAction(action)
144
class PortableOMeta(OMeta):
145
metagrammarClass = PortableOMetaGrammar
147
def rule_tokenBR(self):
149
Match and return the given string, consuming any preceding or trailing
152
tok, _ = self.input.head()
154
m = self.input = self.input.tail()
159
_, e = self.apply("br")
167
def makeGrammar(cls, grammar, globals, name="Grammar"):
168
g = cls.metagrammarClass(grammar)
169
tree = g.parseGrammar(name, PortableTreeBuilder)
170
return moduleFromGrammar(tree, name, cls, globals)