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.
vrml/olist.py ADDED
@@ -0,0 +1,126 @@
1
+ """Observable list class"""
2
+ from pydispatch.dispatcher import send
3
+ import weakref, types
4
+ try:
5
+ set
6
+ except NameError as err:
7
+ from sets import Set as set
8
+
9
+ class OList( list ):
10
+ """List sub-class which generates pydispatch events on changes
11
+
12
+ Generates 4 types of events:
13
+
14
+ * NEW_CHILD_EVT, from self, with value=child, for each added child
15
+ * NEW_PARENT_EVT, from child, with parent=self, for each added child
16
+ * DEL_CHILD_EVT, from self, with value=child, for each removed child
17
+ * DEL_PARENT_EVT, from child, with parent=self, for each removed child
18
+
19
+ Note that the OList semantics are a little loose currently, as
20
+ it sometimes acts as though adding a new duplicate child is not
21
+ an event and sometimes acts as though it is. This doesn't cause
22
+ problems for the OpenGLContext scenegraph.
23
+
24
+ The OList is intended for situations where slow-write-fast-read
25
+ is the primary requirement, it allows you to hook writing events
26
+ in order to recalculate/cache values.
27
+ """
28
+ NEW_CHILD_EVT = 'new'
29
+ NEW_PARENT_EVT = 'added'
30
+ DEL_CHILD_EVT = 'del'
31
+ DEL_PARENT_EVT = 'removed'
32
+ sender = None
33
+ extraArgs = None
34
+ def setSender( self, sender, **named ):
35
+ """Set the (node) from which messages should be sent"""
36
+ if sender is not None:
37
+ sender = weakref.ref(sender)
38
+ self.sender = sender
39
+ self.extraArgs = named
40
+ def _sender( self ):
41
+ sender = self
42
+ if self.sender is not None:
43
+ sender = self.sender()
44
+ if sender is None:
45
+ sender = self
46
+ return sender
47
+ def _sendAdded( self, value ):
48
+ """Send events for adding value to self"""
49
+ sender = self._sender()
50
+ send( self.NEW_CHILD_EVT, sender, value=value, **(self.extraArgs or {}))
51
+ send( self.NEW_PARENT_EVT, value, parent=sender,**(self.extraArgs or {}))
52
+ def _sendRemoved( self, value ):
53
+ """Send events for removing value from self"""
54
+ sender = self._sender()
55
+ send( self.DEL_CHILD_EVT, sender, value=value,**(self.extraArgs or {}))
56
+ send( self.DEL_PARENT_EVT, value, parent=sender,**(self.extraArgs or {}))
57
+
58
+ def append( self, value ):
59
+ """Append a value and send a message"""
60
+ super( OList,self ).append( value )
61
+ self._sendAdded( value )
62
+ return value
63
+ def insert( self, index, value ):
64
+ """Insert a new item at index"""
65
+ super( OList,self ).insert( index, value )
66
+ self._sendAdded( value )
67
+ return value
68
+ def pop( self, index=None ):
69
+ """Pop a single item out of the list"""
70
+ if index is None:
71
+ index = len(self)-1
72
+ value = super( OList,self ).pop( index )
73
+ self._sendRemoved( value )
74
+ return value
75
+ def remove( self, item ):
76
+ """Remove this instance from the list"""
77
+ super(OList,self).remove( item )
78
+ self._sendRemoved( item )
79
+ return item
80
+ def __delitem__( self, index ):
81
+ """Delete a single item"""
82
+ if isinstance( index, slice ):
83
+ current = self.__getitem__( index )
84
+ for value in current:
85
+ self._sendRemoved( value )
86
+ super( OList,self ).__delitem__( index )
87
+ return current
88
+ else:
89
+ value = self[index]
90
+ self._sendRemoved( value )
91
+ return value
92
+ def __delslice__( self, i,j):
93
+ return self.__delitem__( slice(i,j))
94
+ def __setitem__( self, index, value ):
95
+ """Set a value and send a message"""
96
+ if isinstance( index, slice ):
97
+ values = list(value)
98
+ previous = self.__getitem__( index )
99
+ currents = set( previous )
100
+ super(OList,self).__setitem__( index, values )
101
+ for value in values:
102
+ if value not in currents:
103
+ self._sendAdded( value )
104
+ else:
105
+ try:
106
+ previous.remove( value )
107
+ except ValueError as err:
108
+ pass
109
+ for current in previous:
110
+ self._sendRemoved( current )
111
+ return values
112
+ else:
113
+ current = self[index]
114
+ if current is not value:
115
+ self._sendRemoved( current )
116
+ super( OList,self ).__setitem__( index, value )
117
+ if current is not value:
118
+ self._sendAdded( value )
119
+ return value
120
+ def __setslice__( self, i,j, iterable ):
121
+ return self.__setitem__( slice(i,j), iterable)
122
+ def __iadd__( self, iterable ):
123
+ """Do an in-place add"""
124
+ return self.__setitem__( slice(len(self),len(self)), iterable )
125
+ extend = __iadd__
126
+
vrml/protofunctions.py ADDED
@@ -0,0 +1,233 @@
1
+ """Functions for manipulating prototypes (node classes)
2
+
3
+ Prototypes are implemented as classes, and so are
4
+ available from every instance node, but we often
5
+ want to be able to manipulate the classes themselves
6
+ without needing lots of class-methods
7
+
8
+ The protofunctions module allows us to abstract the
9
+ actual implementation of the prototype away. If we
10
+ at some point want to create a real "prototype" class,
11
+ we could do so with most changes confined to this
12
+ module.
13
+ """
14
+
15
+ from __future__ import unicode_literals
16
+
17
+
18
+ def _getcls(cls):
19
+ """Utility function returns class when passed instance or class"""
20
+ if type(cls) == type:
21
+ return cls
22
+ else:
23
+ return cls.__class__
24
+
25
+
26
+ def getPrototype(cls):
27
+ """Return the prototype for the node or class
28
+ returns either the argument (if it is a proto)
29
+ or the prototype of the argument
30
+ """
31
+ return _getcls(cls)
32
+
33
+
34
+ def protoName(obj, value=None, *args, **named):
35
+ """Get/set the prototype name for the object"""
36
+ obj = _getcls(obj)
37
+ if value is not None:
38
+ return setattr(obj, "PROTO", value)
39
+ elif issubclass(obj, list):
40
+ return '__MFNode__'
41
+ else:
42
+ possible = getattr(obj, "PROTO")
43
+ if not possible:
44
+ return obj.__name__.split(".")[-1]
45
+ return possible
46
+
47
+
48
+ def defName(obj, value=None, *args, **named):
49
+ """Get/set the VRML97 defName for the object"""
50
+ from vrml import node
51
+
52
+ if value is not None:
53
+ return node.Node.DEF.fset(obj, value, *args, **named)
54
+ else:
55
+ return node.Node.DEF.fget(obj, *args, **named)
56
+
57
+
58
+ def name(obj, value=None, *args, **named):
59
+ """Get/set prototype name for prototypes, DEF name for nodes"""
60
+ if type(obj) == type:
61
+ return protoName(obj, value, *args, **named)
62
+ else:
63
+ return defName(obj, value, *args, **named)
64
+
65
+
66
+ def root(obj, value=None, *args, **named):
67
+ """Get/set root-node reference for nodes/protos"""
68
+ from vrml import node
69
+
70
+ if value is not None:
71
+ return node.Node.rootSceneGraph.fset(obj, value, *args, **named)
72
+ else:
73
+ return node.Node.rootSceneGraph.fget(obj, *args, **named)
74
+
75
+
76
+ def builtin(cls):
77
+ """Return whether the class is "built-in" to the system"""
78
+ from vrml import node
79
+
80
+ return not issubclass(_getcls(cls), node.PrototypedNode)
81
+
82
+
83
+ def addField(cls, field):
84
+ """Add a particular field/event to the class/prototype definition
85
+
86
+ At present this just calls setattr(cls,field.name,field)
87
+ """
88
+ setattr(_getcls(cls), field.name, field)
89
+
90
+
91
+ def removeField(cls, field):
92
+ """Remove a particular field/event to the class/prototype definition
93
+
94
+ If field is a string, calls delattr(cls,field) for the class
95
+ otherwise calls delattr( cls, field.name )
96
+ """
97
+ if isinstance(field, str):
98
+ delattr(_getcls(cls), field)
99
+ else:
100
+ delattr(_getcls(cls), field.name)
101
+
102
+
103
+ def getField(cls, field):
104
+ """Get a field/event object for the given name
105
+
106
+ field -- a field-name specifier, which may be any of
107
+ the following, (with the various options checked in
108
+ order, so that earlier options will take
109
+ precedence over later options):
110
+
111
+ * the exact name of the field/demand as specified
112
+ in the class's namespace (fastest and first
113
+ checked)
114
+ * the "storage" name of a field, that is, the "name"
115
+ attribute of a field where that name does not
116
+ match the previous definition (commonly seen in
117
+ non-standard fields on VRML97 standard nodes)
118
+ * the "storage" name of an event
119
+ * a pseudo-event with the prefix "set_" or the
120
+ suffix "_changed", which will return the
121
+ associated field/event as if the suffix were
122
+ not present (does a recursive call with the
123
+ truncated name)
124
+ """
125
+ cls = _getcls(cls)
126
+ try:
127
+ return getattr(cls, field)
128
+ except (AttributeError, KeyError):
129
+ # OK, may be a space-prefixed name...
130
+ for fieldObject in getFields(cls):
131
+ if fieldObject.name == field:
132
+ return field
133
+ # OK, may be an event with space-prefixed name
134
+ for fieldObject in getFields(cls, 1):
135
+ if fieldObject.name == field:
136
+ return field
137
+ # OK, may be one of the "component" events
138
+ # of a field...
139
+ if field.startswith("set_"):
140
+ return getField(cls, field[4:])
141
+ elif field.endswith("_changed"):
142
+ return getField(cls, field[:-8])
143
+ raise AttributeError(
144
+ """The prototype %s does not define a field named %s"""
145
+ % (protoName(cls), field)
146
+ )
147
+
148
+
149
+ def getFields(cls, events=0):
150
+ """Get all fields of the definition/prototype
151
+
152
+ if events is true, then return events
153
+ instead of fields.
154
+ """
155
+ cls = _getcls(cls)
156
+ from vrml import field
157
+
158
+ if events:
159
+ wanted = field.Event
160
+ else:
161
+ wanted = field.Field
162
+ items = {}
163
+ mro = cls.__mro__[:]
164
+ while mro:
165
+ items.update(
166
+ dict(
167
+ [
168
+ (key, value)
169
+ for key, value in mro[-1].__dict__.items()
170
+ if isinstance(value, wanted)
171
+ ]
172
+ )
173
+ )
174
+ mro = mro[:-1]
175
+ return list(items.values())
176
+
177
+
178
+ ##def clonePROTO( cls ):
179
+ ## """Clone the prototype/class
180
+ ##
181
+ ## This allows you to create a new prototype from the
182
+ ## current prototype. The entire prototype is cloned,
183
+ ## including all fields, and the scene graph.
184
+ ## """
185
+ ## cls = _getcls(cls)
186
+ ## fields = [ item.clone() for item in cls.__dict__.values() if isinstance(item, field.Field)]
187
+ ## return prototype(
188
+ ## cls.PROTO,
189
+ ## fields,
190
+ ## cls.sceneGraph.clone(),
191
+ ## )
192
+
193
+
194
+ def setSceneGraph(cls, sg):
195
+ """Set the scenegraph associated with a prototype"""
196
+ from vrml import node
197
+
198
+ return node.PrototypedNode.scenegraph.fset(cls, sg)
199
+
200
+
201
+ def getSceneGraph(cls):
202
+ """Get the scenegraph associated with a prototype (or None)"""
203
+ from vrml import node
204
+
205
+ return node.PrototypedNode.scenegraph.fget(cls)
206
+
207
+
208
+ def delSceneGraph(cls):
209
+ """Delete the scenegraph associated with a prototype"""
210
+ from vrml import node
211
+
212
+ return node.PrototypedNode.scenegraph.fdel(cls)
213
+
214
+
215
+ def setExternalURL(cls, url):
216
+ """Set the externproto URL associated with a prototype"""
217
+ from vrml import node
218
+
219
+ return node.Node.externalURL.fset(cls, url)
220
+
221
+
222
+ def getExternalURL(cls):
223
+ """Get the externproto URL associated with a prototype (or [])"""
224
+ from vrml import node
225
+
226
+ return node.Node.externalURL.fget(cls)
227
+
228
+
229
+ def delExternalURL(cls):
230
+ """Delete the externproto URL associated with a prototype"""
231
+ from vrml import node
232
+
233
+ return node.Node.externalURL.fdel(cls)
vrml/protonamespace.py ADDED
@@ -0,0 +1,13 @@
1
+ """Trivial dict sub-class to hold prototype definitions"""
2
+ class ProtoNamespace( dict ):
3
+ """Simple namespace for holding prototypes"""
4
+ def __getattr__( self, key ):
5
+ """Map attribute access to key access"""
6
+ if key != '__contains__':
7
+ if key in self:
8
+ return self[ key ]
9
+ raise AttributeError( '%r object has no %r attribute'%( self.__class__.__name__, key))
10
+ def __copy__( self ):
11
+ """Produce a ProtoNamespace copy of self"""
12
+ return self.__class__( super(ProtoNamespace,self).__copy__())
13
+
vrml/route.py ADDED
@@ -0,0 +1,167 @@
1
+ """ROUTE and ISRoute Implementations (event-processing)"""
2
+ import traceback
3
+ from vrml import field, fieldtypes, protofunctions, node
4
+ from pydispatch import dispatcher
5
+
6
+ class ROUTE( node.Node ):
7
+ """Representation and implementation of a VRML97 ROUTE
8
+
9
+ This implementation uses the dispatcher module to create
10
+ an approximation of the VRML97 event model. It allows nodes
11
+ to forward events via the ROUTE objects, and watches for
12
+ event cycles.
13
+ """
14
+ PROTO = "ROUTE"
15
+ source = node.SFNode('source',)
16
+ sourceField = fieldtypes.SFString('sourceField',)
17
+ destination = node.SFNode('destination',)
18
+ destinationField = fieldtypes.SFString( 'destinationField',)
19
+ def __init__( self, *arguments, **named ):
20
+ """Initialize the route object
21
+
22
+ Calls self.bind() after normal node.Node
23
+ argument processing.
24
+ """
25
+ if arguments:
26
+ if len(arguments) == 4:
27
+ named['source'] = arguments[0]
28
+ named['sourceField'] = arguments[1]
29
+ named['destination'] = arguments[2]
30
+ named['destinationField'] = arguments[3]
31
+ arguments = ()
32
+ super( ROUTE, self ).__init__( *arguments, **named )
33
+ self.bind()
34
+ def bind( self ):
35
+ """Bind this ROUTE node's source to destination
36
+
37
+ Should also setup notification for changes to our
38
+ values to cause changes to the ROUTING table in
39
+ dispatcher.
40
+ """
41
+ return self._bind( self.source, self.sourceField )
42
+ def _bind( self, source, field ):
43
+ """Low-level binding of the source,field key
44
+
45
+ This method allows sub-classes to do multiple
46
+ bindings when bind() is called.
47
+ """
48
+ if source and field:
49
+ try:
50
+ sf = protofunctions.getField( source, field )
51
+ except (AttributeError, KeyError):
52
+ print("""%s: field %s doesn't exist on %s"""%(protofunctions.protoName(self), field, source))
53
+ else:
54
+ for message in ('set','del','route'):
55
+ dispatcher.connect(
56
+ receiver = self.forward,
57
+ sender = source,
58
+ signal = (message,sf),
59
+ )
60
+ else:
61
+ print("""NULL ROUTE bound""", self)
62
+ def forward(
63
+ self, signal, sender, event=None, value=None, **arguments
64
+ ):
65
+ """Forward a value update to our destination
66
+ """
67
+ return self._forward(
68
+ sender, signal,
69
+ self.destination, self.destinationField,
70
+ event, value, **arguments
71
+ )
72
+ def _forward(
73
+ self,
74
+ sender, signal,
75
+ destination, destinationField,
76
+ event=None, value=None, **arguments
77
+ ):
78
+ """Do the low-level forwarding of the value to a target field"""
79
+ if event is None:
80
+ from vrml import event as eventmodule
81
+ event = eventmodule.Event()
82
+ signal, sourceField = signal
83
+ if signal == 'del':
84
+ value = sourceField.fget( sender )
85
+ if destination and destinationField:
86
+ destinationField = protofunctions.getField( destination, destinationField )
87
+ if event and hasattr(event, "visited"):
88
+ if event.visited((destination, destinationField),):
89
+ ### Short-circuit before a cycle is created...
90
+ return
91
+ event.visited( (destination,destinationField), 1)
92
+ if isinstance( destinationField, field.Field ):
93
+ try:
94
+ value = destinationField.fset( destination, value, notify = 0 )
95
+ except (ValueError, TypeError):
96
+ traceback.print_exc()
97
+ else:
98
+ try:
99
+ value = destinationField.__set__( destination, value )
100
+ except (ValueError, TypeError):
101
+ traceback.print_exc()
102
+ dispatcher.send(
103
+ signal = ('route',destinationField),
104
+ sender = destination,
105
+ value = value,
106
+ event = event,
107
+ )
108
+ def copy( self, copier ):
109
+ """Copy the route for the copier object"""
110
+ source = self.source.copy(copier)
111
+ destination = self.destination.copy( copier )
112
+ return self.__class__(
113
+ source = source,
114
+ destination = destination,
115
+ sourceField = self.sourceField,
116
+ destinationField = self.destinationField,
117
+ )
118
+ def __str__( self ):
119
+ """Get a friendly representation of the Node"""
120
+ return """%s %r.%s TO %r.%s"""%(
121
+ self.__class__.__name__,
122
+ self.source,
123
+ self.sourceField,
124
+ self.destination,
125
+ self.destinationField,
126
+ )
127
+
128
+
129
+ ### Field-type for multi-field route objects...
130
+ class SFRoute( node.SFNode ):
131
+ """Single-field ROUTE value"""
132
+ requiredTypes = (ROUTE,)
133
+
134
+ class MFRoute( node.MFNode ):
135
+ """Multiple-value-field ROUTEs"""
136
+ baseSFNode = SFRoute( "GeneralSFRoute" )
137
+
138
+ class IS( ROUTE ):
139
+ """An is-mapping for a field/event
140
+
141
+ Functionally, an instantiated IS is just a
142
+ multi-directional ROUTE (that is, it's a route
143
+ to and from a given field on the base node to
144
+ the sub-nodes.
145
+ """
146
+ PROTO = "IS"
147
+ def bind( self ):
148
+ """Bind the in and out routes for the IS mapping
149
+ """
150
+ self._bind( self.source, self.sourceField )
151
+ self._bind( self.destination, self.destinationField )
152
+ def forward( self, signal, sender, event=None, value=None, **arguments ):
153
+ """Forward a value update to our destination (or source)
154
+ """
155
+ if sender is self.source:
156
+ return self._forward(
157
+ sender, signal,
158
+ self.destination, self.destinationField,
159
+ event, value, **arguments
160
+ )
161
+ elif sender is self.destination:
162
+ return self._forward(
163
+ sender, signal,
164
+ self.source, self.sourceField,
165
+ event, value, **arguments
166
+ )
167
+
File without changes
@@ -0,0 +1,87 @@
1
+ """VRML200X SimpleParse 2 Parser
2
+
3
+ VRML200x is a fairly minor modification to the VRML97 grammar,
4
+ with almost all of the changes being the more involved header,
5
+ and a few new field-types that are already accepted by the
6
+ VRML97 grammar.
7
+ """
8
+ from simpleparse.parser import Parser
9
+ from simpleparse.common import chartypes
10
+
11
+ #print file
12
+ grammar = r'''
13
+ header := headerStatement,profileStatement,componentStatement*,metaStatement*
14
+ headerStatement := ('#X3D',ts,SFNumber,ts,'utf8',ts,headerComment?,newLine)/('#',headerComment?,newLine)
15
+ headerComment := -newLine+
16
+ profileStatement := 'PROFILE', ts, profileName,newLine
17
+ profileName := name
18
+ <newLine> := ('\r\n'/'\r'/'\n')
19
+
20
+ componentStatement := 'COMPONENT',ts, componentNameId, ts,':', ts, componentSupportLevel
21
+ componentNameId := name
22
+ componentSupportLevel := SFNumber
23
+
24
+ metaStatement := 'META',ts, metakey,ts,metavalue
25
+ metakey := SFString
26
+ metavalue := SFString
27
+
28
+ # not in the grammar, but apparently part of the VRML200x encoding
29
+ importStatement := 'IMPORT',ts,name,ts,'.',ts,name,(ts,asClause)?,ts
30
+ exportStatement := 'EXPORT',ts,name,(ts,asClause)?,ts
31
+ asClause := 'AS',ts,name
32
+
33
+ vrmlFile := header, vrmlScene, !, EOF
34
+ vrmlScene := rootItem*
35
+ rootItem := ts,(Proto/ExternProto/ROUTE/('USE',ts,USE,ts)/Script/Node),ts
36
+
37
+ Proto := 'PROTO',ts,!, nodegi,ts,'[',ts,(fieldDecl/eventDecl)*,']', ts, '{', ts, vrmlScene,ts, '}', ts
38
+ fieldDecl := fieldExposure,ts,!,dataType,ts,name,ts,Field,ts
39
+
40
+ # inputOutput/initializeOnly not in the grammar
41
+ fieldExposure := 'inputOutput'/'initializeOnly'/'field'/'exposedField'
42
+ dataType := ('SF'/'MF')?,name
43
+ eventDecl := eventDirection, ts, !,dataType, ts, name, ts
44
+
45
+ # inputOnly/outputOnly not in the grammar
46
+ eventDirection := 'inputOnly'/'outputOnly'/'eventIn'/'eventOut'
47
+ ExternProto := 'EXTERNPROTO',ts,!,nodegi,ts,'[',ts,(extFieldDecl/eventDecl)*,']', ts, ExtProtoURL
48
+ extFieldDecl := fieldExposure,ts,!,dataType,ts,name,ts
49
+ ExtProtoURL := '['?,(ts,SFString)*, ts, ']'?, ts # just an MFString by another name :)
50
+
51
+ ROUTE := 'ROUTE',ts, !,name,'.',name, ts, 'TO', ts, name,'.',name, ts
52
+
53
+ Node := ('DEF',ts,!,name,ts)?,nodegi,ts,'{',ts,(Proto/ExternProto/ROUTE/Attr)*,ts,!,'}', ts
54
+
55
+ Script := ('DEF',ts,!,name,ts)?,'Script',ts,!,'{',ts,(ScriptFieldDecl/ScriptEventDecl/Proto/ExternProto/ROUTE/Attr)*,ts,'}', ts
56
+ ScriptEventDecl := eventDirection, ts, !,dataType, ts, name, ts, ('IS', ts,!, IS,ts)?
57
+ ScriptFieldDecl := fieldExposure,ts,!,dataType,ts,name,ts,(('IS', ts,!,IS,ts)/Field),ts
58
+
59
+ SFNull := 'NULL', ts
60
+
61
+ # should really have an optimised way of declaring a different reporting name for the same production...
62
+ USE := name
63
+ IS := name
64
+ nodegi := name
65
+ Attr := name, ts, (('IS', ts,IS,ts)/Field), ts
66
+ Field := ( '[',ts,((SFNumber/SFBool/SFString/('USE',ts,USE,ts)/Script/Node),ts)*, ']'!, ts )/((SFNumber/SFBool/SFNull/SFString/('USE',ts,USE,ts)/Script/Node),ts)+
67
+
68
+ name := -[][0-9{}\000-\020"'#,.\\ ], -[][{}\000-\020"'#,.\\ ]*
69
+ SFNumber := [-+]*, ( ('0',[xX],[0-9A-Fa-f]+) / ([0-9.]+,([eE],[-+0-9.]+)?))
70
+ SFBool := 'TRUE'/'FALSE'
71
+ SFString := '"',(CHARNODBLQUOTE/ESCAPEDCHAR/SIMPLEBACKSLASH)*,'"'!
72
+ CHARNODBLQUOTE := -[\134"]+
73
+ SIMPLEBACKSLASH := '\134'
74
+ ESCAPEDCHAR := '\\"'/'\134\134'
75
+ <ts> := ( [ \011-\015,]+ / ('#',-'\012'*,'\n')+ )*
76
+ '''
77
+
78
+ class VRMLParser( Parser ):
79
+ """Simple subclassing of Parser to create proper ParseProcessor"""
80
+ def buildProcessor( self ):
81
+ """Build and return a vrml.vrml97.parseprocessor.ParseProcessor"""
82
+ from vrml.vrml97 import parseprocessor
83
+ return parseprocessor.ParseProcessor()
84
+
85
+ def buildParser( declaration = grammar ):
86
+ """Build a new VRMLParser object"""
87
+ return VRMLParser( declaration, "vrmlFile" )
@@ -0,0 +1,6 @@
1
+ """VRML97-specific customisations and support
2
+
3
+ Includes a full VRML97 parser and lineariser
4
+ for SimpleParse 2.0.x
5
+ """
6
+