001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.languages;
043:
044: import java.awt.Point;
045: import java.io.InputStream;
046: import java.util.Collections;
047: import java.util.List;
048: import java.util.Set;
049: import java.io.BufferedReader;
050: import java.io.IOException;
051: import java.io.InputStreamReader;
052: import java.util.ArrayList;
053: import java.util.HashMap;
054: import java.util.HashSet;
055: import java.util.Iterator;
056: import java.util.Map;
057: import java.util.Collections;
058: import java.util.Iterator;
059:
060: import org.netbeans.modules.languages.parser.SyntaxError;
061: import org.openide.filesystems.FileObject;
062:
063: import org.netbeans.api.languages.ASTNode;
064: import org.netbeans.api.languages.ASTItem;
065: import org.netbeans.api.languages.ParseException;
066: import org.netbeans.api.languages.CharInput;
067: import org.netbeans.api.languages.TokenInput;
068: import org.netbeans.api.languages.ASTToken;
069:
070: import org.netbeans.modules.languages.Feature.Type;
071: import org.netbeans.modules.languages.lexer.SLexer;
072: import org.netbeans.modules.languages.parser.Pattern;
073: import org.netbeans.modules.languages.parser.StringInput;
074: import org.netbeans.modules.languages.parser.TokenInputUtils;
075: import org.netbeans.modules.languages.parser.LLSyntaxAnalyser;
076:
077: /**
078: *
079: * @author Jan Jancura
080: */
081: public class NBSLanguageReader {
082:
083: public static NBSLanguageReader create(FileObject fo,
084: String mimeType) throws IOException {
085: return create(fo.getInputStream(), fo.getPath(), mimeType);
086: }
087:
088: public static NBSLanguageReader create(InputStream is,
089: String sourceName, String mimeType) {
090: return new NBSLanguageReader(is, sourceName, mimeType);
091: }
092:
093: public static NBSLanguageReader create(String source,
094: String sourceName, String mimeType) {
095: return new NBSLanguageReader(source, sourceName, mimeType);
096: }
097:
098: private String source;
099: private InputStream inputStream;
100: private String sourceName;
101: private String mimeType;
102: private GRNode grammarTree;
103: private List<TokenType> tokenTypes;
104: private boolean containsTokens = false;
105: private Map<String, Integer> tokenTypeToID = new HashMap<String, Integer>();
106: private List<Feature> features;
107: private List<Rule> grammarRules;
108:
109: {
110: tokenTypes = new ArrayList<TokenType>();
111: addToken(null, null, SLexer.ERROR_TOKEN_TYPE_NAME, null, null);
112: addToken(null, null, SLexer.EMBEDDING_TOKEN_TYPE_NAME, null,
113: null);
114: addToken(null, null, LLSyntaxAnalyser.GAP_TOKEN_TYPE_NAME,
115: null, null);
116:
117: //HACK adding new token typed does not work because
118: // token hierarchy is not updated when TokenProvider fires change
119: // so we reserved some default token types at least there
120: addToken(null, null, "string", null, null);
121: addToken(null, null, "character", null, null);
122: addToken(null, null, "identifier", null, null);
123: addToken(null, null, "whitespace", null, null);
124: addToken(null, null, "number", null, null);
125: addToken(null, null, "keyword", null, null);
126: addToken(null, null, "comment", null, null);
127: addToken(null, null, "operator", null, null);
128: containsTokens = false;
129: }
130:
131: private NBSLanguageReader(String source, String sourceName,
132: String mimeType) {
133: this .source = source;
134: this .sourceName = sourceName;
135: this .mimeType = mimeType;
136: }
137:
138: private NBSLanguageReader(InputStream inputStream,
139: String sourceName, String mimeType) {
140: this .inputStream = inputStream;
141: this .sourceName = sourceName;
142: this .mimeType = mimeType;
143: }
144:
145: public List<TokenType> getTokenTypes() throws ParseException,
146: IOException {
147: if (features == null)
148: readNBS();
149: return tokenTypes;
150: }
151:
152: public boolean containsTokens() throws ParseException, IOException {
153: if (features == null)
154: readNBS();
155: return containsTokens;
156: }
157:
158: public List<Feature> getFeatures() throws ParseException,
159: IOException {
160: if (features == null)
161: readNBS();
162: return features;
163: }
164:
165: public List<Rule> getRules(Language language) throws ParseException {
166: if (grammarRules == null)
167: grammarRules = createRules(grammarTree, language);
168: return grammarRules;
169: // Set<Integer> skipTokenIDs = new HashSet<Integer> ();
170: // Iterator<String> it2 = skipTokenTypes.iterator ();
171: // while (it2.hasNext ()) {
172: // String tokenType = it2.next ();
173: // skipTokenIDs.add (language.getTokenID (tokenType));
174: // }
175: // //AnalyserAnalyser.printRules (rules, null);
176: // language.setAnalyser (LLSyntaxAnalyser.create (
177: // language, rules, skipTokenIDs
178: // ));
179: }
180:
181: // private methods .........................................................
182:
183: private void readNBS() throws ParseException, IOException {
184: if (source == null) {
185: BufferedReader reader = null;
186: try {
187: InputStreamReader r = new InputStreamReader(inputStream);
188: reader = new BufferedReader(r);
189: StringBuilder sb = new StringBuilder();
190: String line = reader.readLine();
191: while (line != null) {
192: sb.append(line).append('\n');
193: line = reader.readLine();
194: }
195: source = sb.toString();
196: } finally {
197: if (reader != null)
198: reader.close();
199: }
200: }
201: features = new ArrayList<Feature>();
202: CharInput input = new StringInput(source);
203: ASTNode node = null;
204: TokenInput tokenInput = null;
205: try {
206: Language nbsLanguage = NBSLanguage.getNBSLanguage();
207: tokenInput = TokenInputUtils.create(nbsLanguage,
208: nbsLanguage.getParser(), input);
209: node = nbsLanguage.getAnalyser().read(tokenInput, false,
210: new ArrayList<SyntaxError>(),
211: new boolean[] { false });
212: } catch (ParseException ex) {
213: //ex.printStackTrace ();
214: Point p = Utils
215: .findPosition(source, tokenInput.getOffset());
216: throw new ParseException(sourceName + " " + p.x + "," + p.y
217: + ": " + ex.getMessage());
218: }
219: readBody(node);
220: }
221:
222: private void readBody(ASTNode root) throws ParseException {
223: grammarTree = new GRNode();
224: Set<String> skipTokenTypes = new HashSet<String>();
225: Iterator<ASTItem> it = root.getChildren().iterator();
226: while (it.hasNext()) {
227: ASTItem item = it.next();
228: if (item instanceof ASTToken)
229: continue;
230: ASTNode node = (ASTNode) item;
231: if (node.getNT().equals("token"))
232: readToken(node, null);
233: else if (node.getNT().equals("tokenState"))
234: readTokenState(node);
235: else if (node.getNT().equals("grammarRule"))
236: readGrammarRule(node, grammarTree);
237: else if (node.getNT().equals("command"))
238: readCommand(node, skipTokenTypes);
239: else
240: throw new ParseException("Unknown grammar rule ("
241: + node.getNT() + ").");
242: }
243: //S ystem.out.println(grammarRules);
244: }
245:
246: private void readToken(ASTNode node, String state)
247: throws ParseException {
248: String startState = null;
249: String endState = null;
250: Pattern pattern = null;
251: Feature properties = null;
252: String name = node.getTokenType("identifier").getIdentifier();
253: ASTNode pnode = node.getNode("token2.properties");
254: if (pnode != null) {
255: properties = readProperties(null, null, pnode);
256: // startState = getString (properties, "start_state", false);
257: // endState = getString (properties, "end_state", false);
258: // pattern = (Pattern) properties.get ("pattern");
259: startState = (String) properties.getValue("start_state");
260: endState = (String) properties.getValue("end_state");
261: pattern = properties.getPattern("pattern");
262: if (pattern == null
263: && properties.getType("call") == Type.METHOD_CALL)
264: pattern = Pattern.create(".");
265: } else {
266: ASTNode regularExpressionNode = node
267: .getNode("token2.regularExpression");
268: endState = node
269: .getTokenTypeIdentifier("token2.token3.state.identifier");
270: pattern = readPattern(regularExpressionNode,
271: regularExpressionNode.getOffset());
272: }
273: if (startState != null && state != null)
274: throw new ParseException(
275: "Start state should not be specified inside token group block!");
276: if (startState == null)
277: startState = state;
278: if (endState == null)
279: endState = state;
280: addToken(startState, pattern, name, endState, properties);
281: }
282:
283: private void addToken(String startState, Pattern pattern,
284: String typeName, String endState, Feature properties) {
285: containsTokens = true;
286: int id = tokenTypeToID.size();
287: if (tokenTypeToID.containsKey(typeName))
288: id = tokenTypeToID.get(typeName);
289: else
290: tokenTypeToID.put(typeName, id);
291: tokenTypes.add(new TokenType(startState, pattern, typeName, id,
292: endState, tokenTypes.size(), properties));
293: }
294:
295: private void readGrammarRule(ASTNode node, GRNode grammarRules) {
296: String nt = node.getTokenTypeIdentifier("identifier");
297: ASTNode rightSide = node.getNode("grRightSide");
298: if (rightSide.getChildren().size() == 0) {
299: grammarRules.get(nt).setFinal();
300: } else
301: resolveGrammarRule(nt, rightSide, new Franta(),
302: grammarRules, null);
303: }
304:
305: private static GRNode resolveGrammarRule(String nt,
306: ASTNode rightSide, Franta franta, GRNode ntToMap,
307: GRNode right) {
308: Iterator it = rightSide.getChildren().iterator();
309: while (it.hasNext()) {
310: Object o = it.next();
311: if (o instanceof ASTToken)
312: continue;
313: ASTNode n = (ASTNode) o;
314: if (n.getNT().equals("grRightSide1"))
315: resolveGrammarRule(nt, n, franta, ntToMap, right);
316: else if (n.getNT().equals("grChoice")) {
317: right = resolveGrammarRule(nt, n, franta, ntToMap,
318: ntToMap.get(nt));
319: right.setFinal();
320: } else if (n.getNT().equals("grPart")) {
321: List<ASTItem> ch = n.getChildren();
322: int i = 0;
323: while (i < ch.size() && skip(ch.get(i)))
324: i++;
325: if (ch.get(i) instanceof ASTNode) {
326: String token = readToken((ASTNode) ch.get(i));
327: i++;
328: while (i < ch.size() && skip(ch.get(i)))
329: i++;
330: if (i < ch.size()) {
331: String op = ((ASTNode) ch.get(i))
332: .getTokenTypeIdentifier("operator");
333: if (op != null) {
334: String nt1 = franta.next(nt);
335: right = right.get(nt1);
336: if ("*".equals(op)) {
337: GRNode right1 = ntToMap.get(nt1);
338: right1.setFinal();
339: right1 = right1.get(token);
340: right1 = right1.get(nt1);
341: right1.setFinal();
342: } else if ("+".equals(op)) {
343: GRNode right1 = ntToMap.get(nt1);
344: String nt2 = franta.next(nt);
345: right1 = right1.get(token);
346: right1 = right1.get(nt2);
347: right1.setFinal();
348: GRNode right2 = ntToMap.get(nt2);
349: right2.setFinal();
350: right2 = right2.get(token);
351: right2 = right2.get(nt2);
352: right2.setFinal();
353: }
354: } else
355: right = right.get(token);
356: } else
357: right = right.get(token);
358: continue;
359: }
360: ASTToken t = (ASTToken) ch.get(i);
361: if (t.getIdentifier().equals("(")) {
362: String op = n
363: .getTokenTypeIdentifier("grOperator.operator");
364: String nt1 = franta.next(nt);
365: right = right.get(nt1);
366: ASTNode nn = n.getNode("grRightSide");
367: if ("*".equals(op)) {
368: GRNode right1 = ntToMap.get(nt1);
369: String nt2 = franta.next(nt);
370: right1.setFinal();
371: right1 = right1.get(nt2);
372: right1 = right1.get(nt1);
373: right1.setFinal();
374: GRNode right2 = ntToMap.get(nt2);
375: resolveGrammarRule(nt2, nn, franta, ntToMap,
376: right2);
377: } else if ("+".equals(op)) {
378: GRNode right1 = ntToMap.get(nt1);
379: String nt2 = franta.next(nt);
380: String nt3 = franta.next(nt);
381: //right1.put (null, null);
382: right1 = right1.get(nt2);
383: right1 = right1.get(nt3);
384: right1.setFinal();
385: GRNode right3 = ntToMap.get(nt3);
386: right3.setFinal();
387: right3 = right3.get(nt2);
388: right3 = right3.get(nt3);
389: right3.setFinal();
390: GRNode right2 = ntToMap.get(nt2);
391: resolveGrammarRule(nt2, nn, franta, ntToMap,
392: right2);
393: } else {
394: GRNode right1 = ntToMap.get(nt1);
395: resolveGrammarRule(nt1, nn, franta, ntToMap,
396: right1);
397: }
398: } else if (t.getIdentifier().equals("[")) {
399: String nnt = franta.next(nt);
400: right = right.get(nnt);
401: ASTNode nn = n.getNode("grRightSide");
402: resolveGrammarRule(nnt, nn, franta, ntToMap, null);
403: ntToMap.get(nnt).setFinal();
404: } else {
405: i++;
406: while (i < ch.size() && skip(ch.get(i)))
407: i++;
408: if (i < ch.size()) {
409: String op = ((ASTNode) ch.get(i))
410: .getTokenTypeIdentifier("operator");
411: if (op != null) {
412: String nt1 = franta.next(nt);
413: right = right.get(nt1);
414: if ("*".equals(op)) {
415: GRNode right1 = ntToMap.get(nt1);
416: right1.setFinal();
417: right1 = right1.get(t.getIdentifier());
418: right1 = right1.get(nt1);
419: right1.setFinal();
420: } else if ("+".equals(op)) {
421: GRNode right1 = ntToMap.get(nt1);
422: String nt2 = franta.next(nt);
423: right1 = right1.get(t.getIdentifier());
424: right1 = right1.get(nt2);
425: right1.setFinal();
426: GRNode right2 = ntToMap.get(nt2);
427: right2.setFinal();
428: right2 = right2.get(t.getIdentifier());
429: right2 = right2.get(nt2);
430: right2.setFinal();
431: }
432: } else
433: right = right.get(t.getIdentifier());
434: } else
435: right = right.get(t.getIdentifier());
436: }
437: }
438: }
439: return right;
440: }
441:
442: private static boolean skip(ASTItem item) {
443: if (item instanceof ASTNode)
444: return false;
445: int type = ((ASTToken) item).getTypeID();
446: if (NBSLanguage.WHITESPACE_ID == type)
447: return true;
448: return NBSLanguage.COMMENT_ID == type;
449: }
450:
451: private static String readToken(ASTNode node) {
452: StringBuilder sb = new StringBuilder();
453: String type = node.getTokenTypeIdentifier("identifier");
454: if (type != null)
455: sb.append(type);
456: sb.append('#');
457: String identifier = node
458: .getTokenTypeIdentifier("tokenDef1.string");
459: if (identifier != null)
460: sb.append(identifier);
461: return sb.toString();
462: }
463:
464: private List<Rule> createRules(GRNode grammar, Language language)
465: throws ParseException {
466: List<Rule> rules = new ArrayList<Rule>();
467: Iterator it = grammar.names().iterator();
468: while (it.hasNext()) {
469: String nt = (String) it.next();
470: GRNode right = grammar.get(nt);
471: resolveNT(nt, 0, right, new ArrayList(), rules, language);
472: }
473: return rules;
474: }
475:
476: private void resolveNT(String nt, int id, GRNode grNode,
477: List right, List<Rule> rules, Language language)
478: throws ParseException {
479: do {
480: Set<String> names = grNode.names();
481: if (!grNode.isFinal() && names.isEmpty())
482: throw new IllegalArgumentException();
483: if (grNode.isFinal())
484: addRule(nt, id, new ArrayList(right), rules);
485: if (names.isEmpty())
486: return;
487: if (names.size() > 1)
488: break;
489: String name = names.iterator().next();
490: addItem(right, name, language);
491: grNode = grNode.get(name);
492: } while (true);
493: if (!right.isEmpty()) {
494: right.add(nt + "#" + (id + 1));
495: addRule(nt, id, right, rules);
496: id++;
497: Iterator<String> it = grNode.names().iterator();
498: while (it.hasNext()) {
499: String name = it.next();
500: right = new ArrayList();
501: addItem(right, name, language);
502: resolveNT(nt, id, grNode.get(name), right, rules,
503: language);
504: }
505: } else {
506: Iterator<String> it = grNode.names().iterator();
507: while (it.hasNext()) {
508: String name = it.next();
509: right = new ArrayList();
510: addItem(right, name, language);
511: resolveNT(nt, id, grNode.get(name), right, rules,
512: language);
513: }
514: }
515:
516: // if (grNode.names ().isEmpty ()) {
517: // addRule (nt, id, right, rules);
518: // return;
519: // }
520: // while (grNode.names ().size () == 1 ) {
521: // String n = (String) grNode.names ().iterator ().next ();
522: // addItem (language, right, n);
523: // grNode = grNode.get (n);
524: // }
525: // if (!right.isEmpty ()) {
526: // right.add (nt + "#" + (id + 1));
527: // addRule (nt, id, right, rules);
528: // id ++;
529: // }
530: // Iterator<String> it = grNode.names ().iterator ();
531: // while (it.hasNext ()) {
532: // String n = it.next ();
533: // right = new ArrayList ();
534: // addItem (language, right, n);
535: // resolveNT (language, nt, id, (Map<String,Map>) grNode.get (n), right, rules);
536: // }
537: }
538:
539: private void addItem(List l, String n, Language language)
540: throws ParseException {
541: if (n.startsWith("\"") || n.startsWith("'")) {
542: l.add(ASTToken.create(language, -1, n.substring(1, n
543: .length() - 1), 0));
544: return;
545: }
546: int i = n.indexOf('#');
547: if (i < 0) {
548: l.add(n);
549: return;
550: }
551: String type = n.substring(0, i);
552: int typeID = type.length() > 0 ? language.getTokenID(type) : -1;
553: if (typeID < 0) {
554: throw new ParseException(sourceName + ": Token '" + type
555: + "' not defined!");
556: }
557: i++;
558: String identifier = n.substring(i);
559: if (identifier.length() > 0)
560: identifier = identifier.substring(1,
561: identifier.length() - 1);
562: l.add(ASTToken.create(language, typeID,
563: identifier.length() > 0 ? identifier : null, 0));
564: }
565:
566: private static void addRule(String nt, int id, List right,
567: List<Rule> rules) {
568: if (id > 0)
569: nt += "#" + id;
570: rules.add(Rule.create(nt, right));
571: }
572:
573: private void readTokenState(ASTNode node) throws ParseException {
574: String startState = node
575: .getTokenTypeIdentifier("state.identifier");
576: ASTNode n = node.getNode("tokenState1.token");
577: if (n != null)
578: readToken(n, startState);
579: else
580: readTokenGroup(node.getNode("tokenState1.tokenGroup"),
581: startState);
582: }
583:
584: private void readTokenGroup(ASTNode node, String startState)
585: throws ParseException {
586: Iterator it = node.getNode("tokensInGroup").getChildren()
587: .iterator();
588: while (it.hasNext()) {
589: Object o = it.next();
590: if (o instanceof ASTToken)
591: continue;
592: ASTNode n = (ASTNode) o;
593: readToken(n, startState);
594: }
595: }
596:
597: private void readCommand(ASTNode commandNode,
598: Set<String> skipTokenTypes) throws ParseException {
599: String keyword = commandNode.getTokenTypeIdentifier("keyword");
600: ASTNode command0Node = commandNode.getNode("command0");
601: ASTNode selectorNode = command0Node.getNode("selector");
602: if (selectorNode != null) {
603: //ASTNode classNode = selectorNode.getNode ("class");
604: Iterator<Selector> it = readSelector(selectorNode)
605: .iterator();
606: while (it.hasNext()) {
607: Selector selector = it.next();
608: ASTNode command1Node = command0Node.getNode("command1");
609: ASTNode valueNode = command1Node.getNode("value");
610: if (valueNode != null)
611: features
612: .add(readValue(keyword, selector, valueNode));
613: else {
614: // if (keyword.equals ("SKIP"))
615: // skipTokenTypes.add (selector.getAsString ());
616: // else
617: features.add(Feature.create(keyword, selector));
618: }
619: }
620: } else {
621: ASTNode valueNode = command0Node.getNode("value");
622: features.add(readValue(keyword, null, valueNode));
623: }
624: }
625:
626: private Feature readValue(String keyword, Selector selector,
627: ASTNode valueNode) throws ParseException {
628: ASTNode propertiesNode = valueNode.getNode("properties");
629: if (propertiesNode != null)
630: return readProperties(keyword, selector, propertiesNode);
631: ASTNode classNode = valueNode.getNode("class");
632: if (classNode != null)
633: return Feature.createMethodCallFeature(keyword, selector,
634: readClass(classNode));
635: ASTNode regExprNode = valueNode.getNode("regularExpression");
636: if (regExprNode != null) {
637: Pattern pat = readPattern(regExprNode, regExprNode
638: .getOffset());
639: return Feature.createExpressionFeature(keyword, selector,
640: pat);
641: }
642: String s = valueNode.getTokenTypeIdentifier("string");
643: s = s.substring(1, s.length() - 1);
644: return Feature.createExpressionFeature(keyword, selector, c(s));
645: }
646:
647: private Feature readProperties(String keyword, Selector selector,
648: ASTNode node) throws ParseException {
649: Map<String, String> methods = new HashMap<String, String>();
650: Map<String, String> expressions = new HashMap<String, String>();
651: Map<String, Pattern> patterns = new HashMap<String, Pattern>();
652:
653: Iterator it = node.getChildren().iterator();
654: while (it.hasNext()) {
655: Object o = it.next();
656: if (o instanceof ASTToken)
657: continue;
658: ASTNode n = (ASTNode) o;
659: String key = n.getTokenTypeIdentifier("identifier");
660: String value = n
661: .getTokenTypeIdentifier("propertyValue.string");
662: if (value != null) {
663: value = value.substring(1, value.length() - 1);
664: expressions.put(key, c(value));
665: } else if (n.getNode("propertyValue.class") != null) {
666: value = readClass(n.getNode("propertyValue.class"));
667: methods.put(key, value);
668: } else {
669: ASTNode regularExpressionNode = n
670: .getNode("propertyValue.regularExpression");
671: Pattern pattern = readPattern(regularExpressionNode, n
672: .getOffset());
673: patterns.put(key, pattern);
674: }
675: }
676: return Feature.create(keyword, selector, expressions, methods,
677: patterns);
678: }
679:
680: private static List<Selector> readSelector(ASTNode selectorNode) {
681: return readSelector(selectorNode, new ArrayList<Selector>());
682: }
683:
684: private static List<Selector> readSelector(ASTNode selectorNode,
685: List<Selector> result) {
686: Iterator<ASTItem> it = selectorNode.getChildren().iterator();
687: while (it.hasNext()) {
688: ASTItem item = it.next();
689: if (item instanceof ASTNode) {
690: ASTNode node = (ASTNode) item;
691: if (node.getNT().equals("class"))
692: result.add(Selector.create(readClass(node)));
693: else if (node.getNT().equals("selector1"))
694: readSelector(node, result);
695: }
696: }
697: return result;
698: }
699:
700: private static String readClass(ASTNode cls) {
701: StringBuilder sb = new StringBuilder();
702: sb.append(cls.getTokenTypeIdentifier("identifier"));
703: Iterator<ASTItem> it = cls.getNode("class1").getChildren()
704: .iterator();
705: while (it.hasNext()) {
706: ASTToken token = (ASTToken) it.next();
707: if (token.getIdentifier().equals("."))
708: sb.append('.');
709: else if (token.getTypeID() == NBSLanguage.IDENTIFIER_ID)
710: sb.append(token.getIdentifier());
711: }
712: return sb.toString();
713: }
714:
715: private Pattern readPattern(ASTNode node, int offset)
716: throws ParseException {
717: StringBuilder sb = new StringBuilder();
718: getText(node, sb);
719: String pattern = sb.toString();
720: StringInput input = new StringInput(pattern);
721: try {
722: return Pattern.create(input);
723: } catch (ParseException e) {
724: Point p = Utils.findPosition(source, offset
725: + input.getIndex());
726: throw new ParseException(sourceName + " " + p.x + "," + p.y
727: + ": " + e.getMessage());
728: }
729: }
730:
731: private static void getText(ASTItem item, StringBuilder sb) {
732: Iterator<ASTItem> it = item.getChildren().iterator();
733: while (it.hasNext()) {
734: ASTItem elem = it.next();
735: if (elem instanceof ASTNode)
736: getText(elem, sb);
737: else {
738: ASTToken token = (ASTToken) elem;
739: int typeID = token.getTypeID();
740: if (typeID == NBSLanguage.COMMENT_ID
741: || typeID == NBSLanguage.WHITESPACE_ID)
742: continue;
743: sb.append(token.getIdentifier());
744: }
745: }
746: }
747:
748: private static String c(String s) {
749: s = s.replace("\\n", "\n");
750: s = s.replace("\\r", "\r");
751: s = s.replace("\\t", "\t");
752: s = s.replace("\\\"", "\"");
753: s = s.replace("\\\'", "\'");
754: s = s.replace("\\\\", "\\");
755: return s;
756: }
757:
758: private static class GRNode {
759:
760: private boolean isFinal = false;
761:
762: private Map<String, GRNode> map;
763:
764: GRNode get(String name) {
765: if (map == null)
766: map = new HashMap<String, GRNode>();
767: GRNode result = map.get(name);
768: if (result == null) {
769: result = new GRNode();
770: map.put(name, result);
771: }
772: return result;
773: }
774:
775: Set<String> names() {
776: if (map == null)
777: return Collections.<String> emptySet();
778: return map.keySet();
779: }
780:
781: void setFinal() {
782: isFinal = true;
783: }
784:
785: boolean isFinal() {
786: return isFinal;
787: }
788:
789: void put(String name, GRNode node) {
790: if (map == null)
791: map = new HashMap<String, GRNode>();
792: map.put(name, node);
793: }
794:
795: public String toString() {
796: StringBuilder sb = new StringBuilder();
797: toString(sb, null);
798: return sb.toString();
799: }
800:
801: private void toString(StringBuilder sb, StringBuilder prefix) {
802: if (isFinal)
803: sb.append(prefix).append('\n');
804: if (!isFinal && map == null)
805: sb.append(prefix).append('?').append('\n');
806: if (map == null)
807: return;
808: Iterator<String> it = map.keySet().iterator();
809: while (it.hasNext()) {
810: String name = it.next();
811: if (prefix == null)
812: map.get(name).toString(sb,
813: new StringBuilder(name).append(" ="));
814: else
815: map.get(name).toString(
816: sb,
817: new StringBuilder(prefix).append(' ')
818: .append(name));
819: }
820: }
821: }
822:
823: static class Franta {
824: private int i = 1;
825:
826: String next(String nt) {
827: return nt + '$' + i++;
828: }
829: }
830: }
|