Source code: com/trapezium/vrml/grammar/BuiltInNodeRule.java
1 /*
2 * @(#)BuiltInNodeRule.java
3 *
4 * Copyright (c) 1998 by Trapezium Development LLC. All Rights Reserved.
5 *
6 * The information in this file is the property of Trapezium Development LLC
7 * and may be used only in accordance with the terms of the license granted
8 * by Trapezium.
9 *
10 */
11 package com.trapezium.vrml.grammar;
12
13 import com.trapezium.parse.TokenEnumerator;
14 import com.trapezium.vrml.Scene;
15 import com.trapezium.vrml.VrmlElement;
16 import com.trapezium.vrml.LeftBrace;
17 import com.trapezium.vrml.RightBrace;
18 import com.trapezium.vrml.node.Node;
19 import com.trapezium.vrml.node.NodeType;
20 import com.trapezium.vrml.node.DEFUSENode;
21 import com.trapezium.vrml.node.PROTO;
22 import com.trapezium.vrml.fields.Field;
23 import com.trapezium.vrml.fields.FieldValue;
24 import com.trapezium.vrml.fields.MFNodeValue;
25
26
27 /**
28 * Creates built in VRML node scene graph components.
29 *
30 * Grammar handled by "Build" method:
31 * <PRE>
32 * builtInNodeTypeId { builtInNodeGuts }
33 * </PRE>
34 * Grammar handled by "BuildNodeGuts" method:
35 * <PRE>
36 * builtInNodeGuts ::=
37 * nodeBodyElement |
38 * nodeBodyElement nodeBody |
39 * empty ;
40 * </PRE>
41 * @author Johannes N. Johannsen
42 * @version 1.12, 24 April 1998, added DEFNameFactory control
43 * @version 1.1, 8 Jan 1998
44 *
45 * @since 1.0
46 */
47 class BuiltInNodeRule {
48 NodeBodyRule nodeBodyRule;
49 DEFNameFactory defNameFactory;
50
51 /** class constructor */
52 BuiltInNodeRule( NodeRule nodeRule ) {
53 nodeBodyRule = new NodeBodyRule( nodeRule );
54 defNameFactory = nodeRule.getDEFNameFactory();
55 }
56
57 /** Set the DEFNameFactory, used when scene factory overrides parser factory */
58 void setDEFNameFactory( DEFNameFactory defNameFactory ) {
59 this.defNameFactory = defNameFactory;
60 }
61
62 /** Create a built in node and add to Scene graph.
63 *
64 * @param nodeType built in node type
65 * @param tokenOffset first token of node
66 * @param v TokenEnumerator containing file text
67 * @param scene Scene containing the resulting node
68 * @param parent immediate parent of resulting node
69 */
70 void Build( String nodeType, int tokenOffset, TokenEnumerator v, Scene scene, VrmlElement parent ) {
71 GrammarRule.Enter( "BuiltInNodeRule.Build" );
72 try {
73 Node node = VRML97.NodeFactory( nodeType );
74 VrmlElement parentElement = parent;
75
76 // three conditions required for auto DEFfing:
77 // 1. defNameFactory non-null
78 // 2. parent not already a DEF
79 // 3. defNameFactory returns non-null
80 if (( defNameFactory != null ) && !( parent instanceof DEFUSENode )) {
81 String defName = defNameFactory.createDEFName( node.getNodeName() );
82 // we assume factory handles details of generating unique name
83 if ( defName != null ) {
84 v.insert( tokenOffset, "DEF", defName );
85 DEFUSENode d = new DEFUSENode( tokenOffset, v, DEFUSENode.DEF );
86 tokenOffset = v.getNextToken();
87 parent.addChild( d );
88 parentElement = d;
89 scene.registerDEF( d );
90 }
91 }
92
93 node.setFirstTokenOffset( tokenOffset );
94 parentElement.addChild( node );
95 BuildNodeGuts( node, tokenOffset, v, scene );
96 if ( parentElement instanceof DEFUSENode ) {
97 parentElement.setLastTokenOffset( node.getLastTokenOffset() );
98 }
99 if ( parent instanceof DEFUSENode ) {
100 parent = parent.getParent();
101 }
102 if ( parent instanceof Scene ) {
103 parent = parent.getParent();
104 if ( !( parent instanceof PROTO ) && NodeType.isBadChild( nodeType )) {
105 node.setError( "Invalid child node" );
106 }
107 }
108 if ( NodeType.isGroupingNode( nodeType )) {
109 Field children = node.getField( "children" );
110 if ( children == null ) {
111 if ( nodeType.compareTo( "Switch" ) == 0 ) {
112 children = node.getField( "choice" );
113 }
114 }
115 if ( children != null ) {
116 FieldValue childnodes = children.getFieldValue();
117 if ( childnodes instanceof MFNodeValue ) {
118 MFNodeValue mfn = (MFNodeValue)childnodes;
119 mfn.validateChildren();
120 }
121 }
122 }
123 } catch ( Exception e ) {
124 System.out.println( "Exception " + e.toString() );
125 e.printStackTrace();
126 }
127 GrammarRule.Exit( "BuiltInNodeRule.Build" );
128 }
129
130 /**
131 * Create node body, and add to node.
132 * <P>
133 * Node body is assumed to be: "{ ..node body.. }"
134 * <P>
135 * If left brace is missing, record the error, then continue parsing
136 * as if it were there.
137 * <P>
138 * If right bracket encountered where right brace might be expected,
139 * report the error, keep token enumerator pointing to right bracket.
140 *
141 * @param node Node that is being created, either a PROTOInstance or built in node
142 * @param tokenOffset first token of the node guts, should be a "{"
143 * @param v TokenEnumerator containing file text
144 * @param scene Scene containing the node
145 */
146 void BuildNodeGuts( Node node, int tokenOffset, TokenEnumerator v, Scene scene ) {
147 int state = v.getState();
148 tokenOffset = v.getNextToken();
149 boolean leftBraceError = false;
150 if ( !LeftBrace.isValid( tokenOffset, v )) {
151 node.addChild( new LeftBrace( tokenOffset, v ));
152 leftBraceError = true;
153 }
154
155 while ( true ) {
156 if ( !leftBraceError ) {
157 state = v.getState();
158 tokenOffset = v.getNextToken();
159 }
160 leftBraceError = false;
161 if ( tokenOffset == -1 ) {
162 node.setError( "Did not find matching right brace" );
163 break;
164 }
165 // If we get "]", add it and report as error, but leave enumerator on it as well
166 if ( v.isRightBracket( tokenOffset )) {
167 v.setState( state );
168 break;
169 }
170 if ( v.isRightBrace( tokenOffset)) {
171 break;
172 }
173 nodeBodyRule.Build( tokenOffset, v, scene, node );
174 }
175 if ( !RightBrace.isValid( tokenOffset, v )) {
176 node.addChild( new RightBrace( tokenOffset, v ));
177 }
178 node.setLastTokenOffset( tokenOffset );
179
180 // have to preserve state of token enumerator, verify may change it
181 int vstate = v.getState();
182 NodeType.verify( node, node.getNodeName(), scene );
183 v.setState( vstate );
184 }
185 }