PyVRML97 2.3.4b3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,452 @@
1
+ """SimpleParse post-processor builds node-graph from parse-tree
2
+ """
3
+
4
+ from simpleparse.dispatchprocessor import *
5
+ from vrml import node, field
6
+ from vrml.protofunctions import *
7
+ from vrml.arrays import array
8
+ from .._bytes import as_str
9
+
10
+ try:
11
+ long
12
+ except NameError:
13
+ long = int
14
+ _getString = getString
15
+
16
+
17
+ def getString(*args, **named):
18
+ base = _getString(*args, **named)
19
+ return as_str(base)
20
+
21
+
22
+ class ParseProcessor(DispatchProcessor):
23
+ """Builds in-memory node-graph from VRML97 parse-tree"""
24
+
25
+ def __init__(self, basePrototypes=None, baseURI=""):
26
+ """Initialise the ParseProcessor
27
+
28
+ basePrototypes -- name: constructor mapping for all
29
+ prototypes to be built by the processor. Should
30
+ include at least:
31
+
32
+ * Script
33
+ * PROTO
34
+ * NULL
35
+ * sceneGraph
36
+ * ROUTE
37
+
38
+ as those "node" types are used during the
39
+ building process. You must also include any
40
+ built-in node types which you want recognised
41
+ without needing a prototype declaration.
42
+
43
+ If None, will use:
44
+ vrml.vrml97.basenamespaces.basePrototypes
45
+
46
+ """
47
+ self.position = 0
48
+ if basePrototypes is None:
49
+ from vrml.vrml97 import basenamespaces
50
+
51
+ basePrototypes = basenamespaces.basePrototypes.copy()
52
+ self.basePrototypes = basePrototypes
53
+ self.baseURI = baseURI
54
+ self.sceneGraphStack = []
55
+ self.prototypeStack = []
56
+ self.nodeStack = []
57
+ self.fieldTypeStack = []
58
+
59
+ ### High-level constructs in the grammar
60
+ def header(self, table, buffer):
61
+ """We ignore the header for now"""
62
+
63
+ EOF = header
64
+
65
+ def rootItem(self, table, buffer):
66
+ """A scenegraph root-item"""
67
+ (tag, left, right, children) = table
68
+ # ROUTE and proto are already taken care of, as would be is
69
+ # so we only need to worry about USE, Script and Node types
70
+ items = dispatchList(self, children, buffer)
71
+ result = [item for item in items if isinstance(item, node.Node)]
72
+ self.sceneGraphStack[-1].children.extend(result)
73
+
74
+ def vrmlScene(self, table, buffer):
75
+ """Instantiate a VRML scene object"""
76
+ (tag, left, right, children) = table
77
+ if self.sceneGraphStack:
78
+ root = self.sceneGraphStack[-1]
79
+ protoTypes = None
80
+ else:
81
+ root = None
82
+ protoTypes = self.basePrototypes
83
+ self.sceneGraphStack.append(
84
+ self.basePrototypes.get('sceneGraph')(
85
+ root=root,
86
+ protoTypes=protoTypes,
87
+ baseURI=self.baseURI,
88
+ )
89
+ )
90
+ dispatchList(self, children, buffer)
91
+ node = self.sceneGraphStack.pop()
92
+ return node
93
+
94
+ ### The two prototype sub-types
95
+ def Proto(self, table, buffer):
96
+ """Process a regular Prototype declaration"""
97
+ (tag, left, right, children) = table
98
+ proto = node.prototype(getString(children[0], buffer))
99
+ self.prototypeStack.append(proto)
100
+ try:
101
+ dispatchList(self, children[1:-1], buffer)
102
+ setSceneGraph(proto, dispatch(self, children[-1], buffer))
103
+ self.sceneGraphStack[-1].addProto(proto)
104
+ finally:
105
+ self.prototypeStack.pop()
106
+
107
+ def ExternProto(self, table, buffer):
108
+ """Process an external Prototype declaration"""
109
+ (tag, left, right, children) = table
110
+ proto = node.prototype(getString(children[0], buffer))
111
+ self.prototypeStack.append(proto)
112
+ try:
113
+ dispatchList(self, children[1:-1], buffer)
114
+ setExternalURL(proto, dispatch(self, children[-1], buffer))
115
+ self.sceneGraphStack[-1].addProto(proto)
116
+ finally:
117
+ self.prototypeStack.pop()
118
+
119
+ ### Node instances of the various types
120
+ def Node(self, table, buffer):
121
+ '''Create new node, returning the value to the caller'''
122
+ (tag, start, stop, sublist) = table
123
+ if sublist[0][0] == 'name':
124
+ name = getString(sublist[0], buffer)
125
+ GI = getString(sublist[1], buffer)
126
+ rest = sublist[2:]
127
+ else:
128
+ name = ""
129
+ GI = getString(sublist[0], buffer)
130
+ rest = sublist[1:]
131
+ prototype = self.sceneGraphStack[-1].getProto(GI)
132
+ if prototype is None:
133
+ raise NameError(
134
+ """Prototype %s used without declaration on line %s"""
135
+ % (
136
+ GI,
137
+ lines(end=start, buffer=buffer),
138
+ )
139
+ )
140
+ newNode = prototype()
141
+ root(newNode, self.sceneGraphStack[0])
142
+ if name:
143
+ self.sceneGraphStack[-1].regDefName(name, newNode)
144
+ self.nodeStack.append(newNode)
145
+ dispatchList(self, rest, buffer)
146
+ self.nodeStack.pop()
147
+ return newNode
148
+
149
+ def Script(self, table, buffer):
150
+ '''A script node (can be a root node)'''
151
+ (tag, start, stop, sublist) = table
152
+ # what's the DEF name...
153
+ if sublist and sublist[0][0] == 'name':
154
+ name = getString(sublist[0], buffer)
155
+ rest = sublist[1:]
156
+ else:
157
+ name = ""
158
+ rest = sublist
159
+ # build the node, with dummy fields
160
+ newNode = self.basePrototypes.get('Script')(
161
+ (),
162
+ )
163
+ vProto = newNode.__class__
164
+ # register it
165
+ root(newNode, self.sceneGraphStack[0])
166
+ if name:
167
+ self.sceneGraphStack[-1].regDefName(name, newNode)
168
+ self.nodeStack.append(newNode)
169
+ # now get the field-declarations...
170
+ fields, attributes, isMaps = [], [], []
171
+ for item in rest:
172
+ if item[0] in ("ScriptEventDecl", "ScriptFieldDecl"):
173
+ f, mapName = dispatch(self, item, buffer)
174
+ setattr(vProto, f.name, f)
175
+ if mapName is not None:
176
+ isMaps.append((mapName, f.name))
177
+ elif item[0] == 'Attr':
178
+ attributes.append(item)
179
+ else:
180
+ dispatch(self, item, buffer)
181
+ if isMaps:
182
+ set = node.ismaps(self.prototypeStack[-1])
183
+ for name, field in isMaps:
184
+ set.setdefault(name, []).append((newNode, field))
185
+ dispatchList(self, attributes, buffer)
186
+ self.nodeStack.pop()
187
+ return newNode
188
+
189
+ def SFNull(self, tup, buffer):
190
+ '''Create a reference to the SFNull node'''
191
+ return self.sceneGraphStack[-1].getProto("NULL")
192
+
193
+ def USE(self, tup, buffer):
194
+ """Create a reference to an existing named node"""
195
+ name = getString(tup, buffer)
196
+ node = self.sceneGraphStack[-1].getDEF(name)
197
+ if node is None:
198
+ raise NameError(
199
+ """Use of un-DEF'd name %s on line %s"""
200
+ % (
201
+ name,
202
+ lines(end=tup[1], buffer=buffer),
203
+ )
204
+ )
205
+ return node
206
+
207
+ def ROUTE(self, table, buffer):
208
+ '''Create a new route object/node, add the current sceneGraph'''
209
+ (tag, start, stop, sublist) = table
210
+ (s, sf, d, df) = [getString(item, buffer) for item in sublist]
211
+ (sn, dn) = [self.sceneGraphStack[-1].getDEF(name) for name in (s, d)]
212
+ for node, name in ((sn, s), (dn, d)):
213
+ if node is None:
214
+ raise NameError(
215
+ """ROUTE of un-DEF'd name %s on line %s"""
216
+ % (
217
+ name,
218
+ lines(end=start, buffer=buffer),
219
+ )
220
+ )
221
+ self.sceneGraphStack[-1].addRoute(
222
+ self.basePrototypes.get('ROUTE')(
223
+ source=sn,
224
+ sourceField=sf,
225
+ destination=dn,
226
+ destinationField=df,
227
+ )
228
+ )
229
+
230
+ ### Field and event declarations
231
+ def fieldDecl(self, table, buffer):
232
+ (tag, left, right, (exposure, datatype, name, value)) = table
233
+ datatype = getString(datatype, buffer)
234
+ self.fieldTypeStack.append(datatype)
235
+ try:
236
+ value = dispatch(self, value, buffer)
237
+ addField(
238
+ self.prototypeStack[-1],
239
+ field.newField(
240
+ getString(name, buffer),
241
+ datatype,
242
+ getString(exposure, buffer) == 'exposedField',
243
+ value,
244
+ ),
245
+ )
246
+ finally:
247
+ self.fieldTypeStack.pop()
248
+
249
+ def extFieldDecl(self, table, buffer):
250
+ '''An external field declaration, no default value'''
251
+ (tag, start, stop, (exposure, datatype, name)) = table
252
+ datatype = getString(datatype, buffer)
253
+ addField(
254
+ self.prototypeStack[-1],
255
+ field.newField(
256
+ getString(name, buffer),
257
+ datatype,
258
+ getString(exposure, buffer) == 'exposedField',
259
+ ),
260
+ )
261
+
262
+ def eventDecl(self, table, buffer):
263
+ (tag, left, right, (direction, datatype, name)) = table
264
+ datatype = getString(datatype, buffer)
265
+ addField(
266
+ self.prototypeStack[-1],
267
+ field.newEvent(
268
+ getString(name, buffer),
269
+ datatype,
270
+ getString(direction, buffer) == 'eventOut',
271
+ ),
272
+ )
273
+
274
+ def ScriptEventDecl(self, table, buffer):
275
+ (tag, left, right, sublist) = table
276
+ direction, datatype, name = [getString(item, buffer) for item in sublist[:3]]
277
+ if len(sublist) > 3:
278
+ mapName = dispatch(self, sublist[3], buffer)
279
+ else:
280
+ mapName = None
281
+ return (
282
+ field.newEvent(name, datatype, direction == 'eventOut'),
283
+ mapName,
284
+ )
285
+
286
+ def ScriptFieldDecl(self, table, buffer):
287
+ """Field declaration for a script node"""
288
+ (tag, left, right, (exposure, datatype, name, value)) = table
289
+ datatype = getString(datatype, buffer)
290
+ self.fieldTypeStack.append(datatype)
291
+ try:
292
+ if value[0] == 'IS':
293
+ mapName = self.IS(value, buffer)
294
+ value = None
295
+ fieldObject = field.newField(
296
+ getString(name, buffer),
297
+ datatype,
298
+ getString(exposure, buffer) == 'exposedField',
299
+ )
300
+ else:
301
+ mapName = None
302
+ value = dispatch(self, value, buffer)
303
+ fieldObject = field.newField(
304
+ getString(name, buffer),
305
+ datatype,
306
+ getString(exposure, buffer) == 'exposedField',
307
+ value,
308
+ )
309
+ return (fieldObject, mapName)
310
+ finally:
311
+ self.fieldTypeStack.pop()
312
+
313
+ ### Node attributes and field values
314
+ def Attr(self, table, buffer):
315
+ '''An attribute of a node or script'''
316
+ (tag, start, stop, (name, value)) = table
317
+ name = getString(name, buffer)
318
+ clientNode = self.nodeStack[-1]
319
+ try:
320
+ field = getField(clientNode, name)
321
+ except AttributeError:
322
+ raise AttributeError(
323
+ """Unknown field name %s for node type %s on line %s"""
324
+ % (
325
+ name,
326
+ protoName(clientNode),
327
+ lines(end=start, buffer=buffer),
328
+ )
329
+ )
330
+ if value[0] == 'IS':
331
+ mapName = dispatch(self, value, buffer)
332
+ set = node.ismaps(self.prototypeStack[-1])
333
+ set.setdefault(mapName, []).append((clientNode, name))
334
+ else:
335
+ self.fieldTypeStack.append(field.typeName())
336
+ try:
337
+ value = dispatch(self, value, buffer)
338
+ if isinstance(clientNode, node.PrototypedNode):
339
+ # prototyped nodes get IS-value updates
340
+ field.fset(clientNode, value, notify=1)
341
+ else:
342
+ field.fset(clientNode, value, notify=0)
343
+ finally:
344
+ self.fieldTypeStack.pop()
345
+
346
+ def Field(self, table, buffer):
347
+ '''A field value (of any type)'''
348
+ (tag, start, stop, sublist) = table
349
+ if sublist and sublist[0][0] in ('USE', 'Script', 'Node', 'SFNull'):
350
+ if self.fieldTypeStack[-1] == 'SFNode':
351
+ return dispatch(self, sublist[0], buffer)
352
+ else:
353
+ return dispatchList(self, sublist, buffer)
354
+ elif self.fieldTypeStack[-1] == 'MFNode':
355
+ return []
356
+ else:
357
+ # is a simple data type...
358
+ function = getattr(self, self.fieldTypeStack[-1])
359
+ return function(sublist, buffer)
360
+
361
+ def SFBool(self, table, buffer):
362
+ '''Boolean, in Python tradition is either 0 or 1'''
363
+ (tup,) = table
364
+ return getString(tup, buffer) == 'TRUE'
365
+
366
+ def SFFloat(self, table, buffer):
367
+ (tup,) = table
368
+ return float(getString(tup, buffer))
369
+
370
+ SFTime = SFFloat
371
+
372
+ def SFInt32(self, table, buffer):
373
+ (tup,) = table
374
+ return int(getString(tup, buffer), 0)
375
+
376
+ def SFVec3f(self, table, buffer):
377
+ return [float(getString(item, buffer)) for item in table]
378
+
379
+ def SFVec2f(self, table, buffer):
380
+ return [float(getString(item, buffer)) for item in table]
381
+
382
+ SFColor = SFVec3f
383
+
384
+ def SFRotation(self, table, buffer):
385
+ return [float(getString(item, buffer)) for item in table]
386
+
387
+ def SFArray(self, values, buffer, final=True):
388
+ """Process a vector-of-values data-set"""
389
+ result = []
390
+ for tag, start, stop, children in values:
391
+ if tag == 'vector':
392
+ result.append(self.SFArray(children, buffer, final=False))
393
+ else:
394
+ result.append(float(buffer[start:stop]))
395
+ if final:
396
+ result = array(result, 'f')
397
+ return result
398
+
399
+ def MFInt32(self, tuples, buffer):
400
+ # localisation
401
+ if not tuples:
402
+ return []
403
+ return [int(buffer[start:stop], 0) for (tag, start, stop, children) in tuples]
404
+
405
+ SFImage = MFInt32
406
+
407
+ def MFUInt32(self, tuples, buffer):
408
+ # localisation
409
+ return [long(buffer[start:stop], 0) for (tag, start, stop, children) in tuples]
410
+
411
+ def MFFloat(self, tuples, buffer):
412
+ return [float(buffer[start:stop]) for (tag, start, stop, children) in tuples]
413
+
414
+ MFColor = MFRotation = MFVec2f = MFVec3f = MFTime = MFFloat32 = MFFloat
415
+
416
+ def MFString(self, tuples, buffer):
417
+ bigresult = []
418
+ for tag, start, stop, sublist in tuples:
419
+ result = []
420
+ for element in sublist:
421
+ if element[0] == 'CHARNODBLQUOTE':
422
+ result.append(as_str(buffer[element[1] : element[2]]))
423
+ elif element[0] == 'ESCAPEDCHAR':
424
+ result.append(as_str(buffer[element[1] + 1 : element[2]]))
425
+ elif element[0] == 'SIMPLEBACKSLASH':
426
+ result.append('\\')
427
+ bigresult.append("".join(result))
428
+ return bigresult
429
+
430
+ def SFString(self, table, buffer):
431
+ '''Return the (escaped) string as a simple Python string'''
432
+ ((tag, start, stop, sublist),) = table
433
+ result = []
434
+ for element in sublist:
435
+ if element[0] == 'CHARNODBLQUOTE':
436
+ result.append(as_str(buffer[element[1] : element[2]]))
437
+ elif element[0] == 'ESCAPEDCHAR':
438
+ result.append(as_str(buffer[element[1] + 1 : element[2]]))
439
+ elif element[0] == 'SIMPLEBACKSLASH':
440
+ result.append(as_str('\\'))
441
+ return "".join(result)
442
+
443
+ ### Low-level/trivial constructs which have their own processing functions
444
+ def IS(self, table, buffer):
445
+ '''Create a field reference'''
446
+ (tag, start, stop, (nametuple,)) = table
447
+ return getString(nametuple, buffer)
448
+
449
+ def ExtProtoURL(self, table, buffer):
450
+ '''add the url to the external prototype'''
451
+ (tag, start, stop, sublist) = table
452
+ return self.MFString(sublist, buffer)
vrml/vrml97/parser.py ADDED
@@ -0,0 +1,72 @@
1
+ """VRML97-compliant SimpleParse 2.0 Parser
2
+
3
+ This example is a full VRML97 parser, originally created
4
+ for the mcf.vrml VRML-processing system. It supports all
5
+ VRML97 constructs, and should be correct for any VRML97
6
+ content you can produce. The parser is fairly fast
7
+ (parsing around 280,000 cps on a 1GHz Athlon machine).
8
+
9
+ This is the errorOnFail version of the grammar, otherwise
10
+ identical to the vrml.py module. Note: there is basically
11
+ no speed penalty for the errorOnFail version compared to
12
+ the original version, as the errorOnFail code is not touched
13
+ unless a syntax error is actually found in the input text.
14
+ """
15
+ from simpleparse.parser import Parser
16
+ from simpleparse.common import chartypes
17
+
18
+ #print file
19
+ grammar = r'''
20
+ header := -[\n]*
21
+ vrmlFile := header, vrmlScene, !, EOF
22
+ rootItem := ts,(Proto/ExternProto/ROUTE/('USE',ts,USE,ts)/Script/Node),ts
23
+ vrmlScene := rootItem*
24
+
25
+ Proto := 'PROTO',ts,!, nodegi,ts,'[',ts,(fieldDecl/eventDecl)*,']', ts, '{', ts, vrmlScene,ts, '}', ts
26
+ fieldDecl := fieldExposure,ts,!,dataType,ts,name,ts,Field,ts
27
+ fieldExposure := 'field'/'exposedField'
28
+ dataType := ('SF'/'MF')?,name
29
+ eventDecl := eventDirection, ts, !,dataType, ts, name, ts
30
+ eventDirection := 'eventIn'/'eventOut'
31
+ ExternProto := 'EXTERNPROTO',ts,!,nodegi,ts,'[',ts,(extFieldDecl/eventDecl)*,']', ts, ExtProtoURL
32
+ extFieldDecl := fieldExposure,ts,!,dataType,ts,name,ts
33
+ ExtProtoURL := '['?,(ts,SFString)*, ts, ']'?, ts # just an MFString by another name :)
34
+
35
+ ROUTE := 'ROUTE',ts, !,name,'.',name, ts, 'TO', ts, name,'.',name, ts
36
+
37
+ Node := ('DEF',ts,!,name,ts)?,nodegi,ts,'{',ts,(Proto/ExternProto/ROUTE/Attr)*,ts,!,'}', ts
38
+
39
+ Script := ('DEF',ts,!,name,ts)?,'Script',ts,!,'{',ts,(ScriptFieldDecl/ScriptEventDecl/Proto/ExternProto/ROUTE/Attr)*,ts,'}', ts
40
+ ScriptEventDecl := eventDirection, ts, !,dataType, ts, name, ts, ('IS', ts,!, IS,ts)?
41
+ ScriptFieldDecl := fieldExposure,ts,!,dataType,ts,name,ts,(('IS', ts,!,IS,ts)/Field),ts
42
+
43
+ SFNull := 'NULL', ts
44
+
45
+ # should really have an optimised way of declaring a different reporting name for the same production...
46
+ USE := name
47
+ IS := name
48
+ nodegi := name
49
+ Attr := name, ts, (('IS', ts,IS,ts)/Field), ts
50
+ Field := ( '[',ts,((vector/SFNumber/SFBool/SFString/('USE',ts,USE,ts)/Script/Node),ts)*, ']'!, ts )/((SFNumber/SFBool/SFNull/SFString/('USE',ts,USE,ts)/Script/Node),ts)+
51
+
52
+ vector := '[',ts,((vector/SFNumber),ts)*,']'
53
+ name := -[][0-9{}\000-\020"'#,.\\ ], -[][{}\000-\020"'#,.\\ ]*
54
+ SFNumber := [-+]*, ( ('0',[xX],[0-9A-Fa-f]+) / ([0-9.]+,([eE],[-+0-9.]+)?))
55
+ SFBool := 'TRUE'/'FALSE'
56
+ SFString := '"',(CHARNODBLQUOTE/ESCAPEDCHAR/SIMPLEBACKSLASH)*,'"'!
57
+ CHARNODBLQUOTE := -[\134"]+
58
+ SIMPLEBACKSLASH := '\134'
59
+ ESCAPEDCHAR := '\\"'/'\134\134'
60
+ <ts> := ( [ \011-\015,]+ / ('#',-'\012'*,'\n')+ )*
61
+ '''
62
+
63
+ class VRMLParser( Parser ):
64
+ """Simple subclassing of Parser to create proper ParseProcessor"""
65
+ def buildProcessor( self ):
66
+ """Build and return a vrml.vrml97.parseprocessor.ParseProcessor"""
67
+ from vrml.vrml97 import parseprocessor
68
+ return parseprocessor.ParseProcessor()
69
+
70
+ def buildParser( declaration = grammar ):
71
+ """Build a new VRMLParser object"""
72
+ return VRMLParser( declaration, "vrmlFile" )