30 |
import config |
import config |
31 |
|
|
32 |
import mp, link |
import mp, link |
|
from util.parser import * |
|
33 |
|
|
34 |
|
from util.parser import * |
35 |
|
|
36 |
dbg = config.dbg.shorthand('parser') |
dbg = config.dbg.shorthand('parser') |
37 |
|
|
38 |
class ElementFactor: |
class ElementFactor: |
39 |
""" |
""" |
40 |
Gather available linktypes from modules. |
Factor to build elements imported from 'navidoc.mp' and navidoc.link'. |
41 |
""" |
""" |
42 |
|
|
43 |
top_class = navidoc.Element |
top_class = navidoc.Element # Elements must be inherited from the top_class |
44 |
|
|
45 |
def __init__(self, module_paths): |
def __init__(self, module_paths): |
46 |
self.types = {} |
self.types = {} |
47 |
|
# Gathers elements from modules. |
48 |
for module_path in module_paths: |
for module_path in module_paths: |
49 |
dbg ("Checking module: "+str(module_path)) |
dbg ("Checking module: "+str(module_path)) |
50 |
self.types.update(keys_for_classes(module_path, self.top_class)) |
self.types.update(keys_for_classes(module_path, self.top_class)) |
52 |
if module not in ['os', 're']: module = getattr(module_path, module) |
if module not in ['os', 're']: module = getattr(module_path, module) |
53 |
if type(module) == type(navidoc): |
if type(module) == type(navidoc): |
54 |
dbg ("Checking module: "+str(module)) |
dbg ("Checking module: "+str(module)) |
55 |
# XXX Needs check and exception for conflicting element types |
# XXX Needs check for conflicting element types and raise an exception |
56 |
self.types.update(keys_for_classes(module, self.top_class)) |
self.types.update(keys_for_classes(module, self.top_class)) |
57 |
dbg("Collected: "+str(self.types)) |
dbg("Collected: "+str(self.types)) |
58 |
|
|
60 |
|
|
61 |
def get_type(self, key): |
def get_type(self, key): |
62 |
""" |
""" |
63 |
Return an element type class reference for key. |
get_type(key) |
64 |
|
|
65 |
|
Return a class reference for correct element type referred by |
66 |
|
the key. |
67 |
""" |
""" |
68 |
if self.types.has_key(key): |
if self.types.has_key(key): |
69 |
return self.types[key] |
return self.types[key] |
70 |
else: raise ParserException("Unknown element key: "+key) |
else: raise ParserException("Unknown element key: "+key) |
71 |
|
|
72 |
def create_new(self, key, var, s, list): |
def create_new(self, key, var, s, list): |
73 |
|
""" |
74 |
|
create_new(key, var, s, list) |
75 |
|
|
76 |
|
Create and return a new element of given type. ``Var`` is name |
77 |
|
identifier of the new element, ``s`` parameters for it and |
78 |
|
``list`` contains all its subelements. |
79 |
|
""" |
80 |
type = self.get_type(key) |
type = self.get_type(key) |
81 |
dbg("Found element: "+str(type)) |
dbg("Found element: "+str(type)) |
82 |
new = type(var, s, list) |
new = type(var, s, list) |
84 |
|
|
85 |
class ElementList: |
class ElementList: |
86 |
""" |
""" |
87 |
Container class for parsed elements and collecting all |
Container class for parsed elements. Provide the interface |
88 |
the generated rendering code for them. |
to generate all rendering code for its elements. |
89 |
""" |
""" |
90 |
def __init__(self, list): |
def __init__(self, list): |
91 |
""" |
""" |
101 |
for element in list: |
for element in list: |
102 |
element = self.parse_element(element) |
element = self.parse_element(element) |
103 |
# Borders of linked elements should be drawn before element itself. |
# Borders of linked elements should be drawn before element itself. |
104 |
# Moves link border element from ``extras`` stack into ``elements`` |
# Move link border element from ``extras`` stack into ``elements`` |
105 |
# in front of the linked element. |
# in front of the linked element. |
106 |
if len(self.extras) > 0 and \ |
if len(self.extras) > 0 and \ |
107 |
isinstance(self.extras[0], navidoc.link.Link): |
isinstance(self.extras[0], navidoc.link.Link): |
111 |
|
|
112 |
def add_contained_element(self, super, elements): |
def add_contained_element(self, super, elements): |
113 |
""" |
""" |
114 |
|
add_contained_element(super, elements) |
115 |
|
|
116 |
Add a subelement. |
Add a subelement. |
117 |
""" |
""" |
118 |
toks = elements[0] |
toks = elements[0] |
119 |
key = toks[0] |
key = toks[0] |
120 |
toks.remove(key) |
toks.remove(key) |
121 |
|
|
122 |
# XXX why no explicit var is given? |
# XXX Why no explicit var is given? |
123 |
if super.var != None: toks.insert(0, super.var) |
if super.var != None: toks.insert(0, super.var) |
124 |
else: toks.insert(0, super.name) |
else: toks.insert(0, super.name) |
125 |
element = self.factor.create_new(key, None, toks, elements[1:]) |
element = self.factor.create_new(key, None, toks, elements[1:]) |
126 |
|
|
127 |
if isinstance(element, navidoc.link.Link): |
if isinstance(element, navidoc.link.Link): |
128 |
# mpclass may have different var and name, links should be based on name :/ |
# mpclass may have different var and name, links should be based on name |
129 |
|
# and need special handling :/ |
130 |
if isinstance(element, navidoc.link.Link) and super.var != super.name: |
if isinstance(element, navidoc.link.Link) and super.var != super.name: |
131 |
toks[0] = super.name |
toks[0] = super.name |
132 |
element = self.factor.create_new(key, None, toks, elements[1:]) |
element = self.factor.create_new(key, None, toks, elements[1:]) |
136 |
|
|
137 |
def parse_element(self, element): |
def parse_element(self, element): |
138 |
""" |
""" |
139 |
|
parse_element(element) |
140 |
|
|
141 |
Parse a single element. |
Parse a single element. |
142 |
""" |
""" |
143 |
|
|
144 |
init = element[0] |
init = element[0] |
145 |
name = None |
name = None |
146 |
|
|
147 |
# catching explicit variable name from "element (foo) foo1" |
# Catch explicit variable name from "element (foo) foo1" |
148 |
for tok in init: |
for tok in init: |
149 |
mat = re.match('^\((.*)\)$', tok) |
mat = re.match('^\((.*)\)$', tok) |
150 |
if mat: |
if mat: |
151 |
name = mat.group(1) |
name = mat.group(1) |
152 |
init.remove(tok) |
init.remove(tok) |
153 |
|
|
154 |
# catching explicit variable name from "foo = element foo1" |
# Catch explicit variable name from "foo = element foo1" |
155 |
if init.count('='): |
if init.count('='): |
156 |
if init.index('=') != 1: |
if init.index('=') != 1: |
157 |
raise ParserException('Variable preceding "=" cannot contain any whitespaces in "%s".' % ' '.join(init)) |
raise ParserException('Variable preceding "=" cannot ' \ |
158 |
|
+'contain any whitespaces in "%s".' % ' '.join(init)) |
159 |
if len(init) < 3: |
if len(init) < 3: |
160 |
raise ParserException('Missing element name in "%s".' % ' '.join(init)) |
raise ParserException('Missing element name in "%s".' % ' '.join(init)) |
161 |
name = init[0] |
name = init[0] |
180 |
return element |
return element |
181 |
|
|
182 |
def setup_code(self): |
def setup_code(self): |
183 |
"Return the code to set up the objects for user geometry code" |
""" |
184 |
|
Return the code to set up the objects for user geometry code. |
185 |
|
""" |
186 |
return "\n".join([element.setup_code() for element in self.list]) + "\n" |
return "\n".join([element.setup_code() for element in self.list]) + "\n" |
187 |
|
|
188 |
def draw_code(self): |
def draw_code(self): |
189 |
"Return code to draw the objects after the user code" |
""" |
190 |
|
Return code to draw the objects after the user code. |
191 |
|
""" |
192 |
code = "\n".join([element.draw_code() for element in self.list]) + "\n" |
code = "\n".join([element.draw_code() for element in self.list]) + "\n" |
193 |
return code |
return code |
194 |
|
|