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.parser;
043:
044: import org.netbeans.api.languages.CharInput;
045: import org.netbeans.api.languages.ASTToken;
046: import java.util.*;
047: import org.netbeans.api.languages.Language;
048: import org.netbeans.modules.languages.Feature;
049: import org.netbeans.modules.languages.Feature.Type;
050: import org.netbeans.modules.languages.TokenType;
051:
052: /**
053: *
054: * @author Jan Jancura
055: */
056: public class Parser {
057:
058: public static final String DEFAULT_STATE = "DEFAULT";
059:
060: private Parser() {
061: }
062:
063: public static Parser create(List<TokenType> rules) {
064: return new Parser(rules);
065: }
066:
067: private Map<Integer, Pattern> stateToPattern = new HashMap<Integer, Pattern>();
068: private Map<String, Integer> nameToState = new HashMap<String, Integer>();
069: private Map<Integer, String> stateToName = new HashMap<Integer, String>();
070: private List<TokenType> tokenTypes;
071: private int counter = 1;
072: {
073: nameToState.put(DEFAULT_STATE, -1);
074: stateToName.put(-1, DEFAULT_STATE);
075: }
076:
077: private Parser(List<TokenType> tokenTypes) {
078: this .tokenTypes = tokenTypes;
079: Iterator<TokenType> it = tokenTypes.iterator();
080: while (it.hasNext()) {
081: TokenType r = it.next();
082: add(r);
083: }
084: }
085:
086: public List<TokenType> getTokenTypes() {
087: return tokenTypes;
088: }
089:
090: private void add(TokenType tokenType) {
091: if (tokenType.getPattern() == null)
092: return;
093: String startState = tokenType.getStartState();
094: if (startState == null)
095: startState = DEFAULT_STATE;
096: int state = 0;
097: if (nameToState.containsKey(startState))
098: state = nameToState.get(startState);
099: else {
100: state = counter++;
101: nameToState.put(startState, state);
102: stateToName.put(state, startState);
103: }
104: Pattern pattern = tokenType.getPattern();
105: pattern.mark(tokenType.getPriority(), tokenType);
106: if (stateToPattern.containsKey(state))
107: stateToPattern.put(state, stateToPattern.get(state).merge(
108: pattern));
109: else
110: stateToPattern.put(state, pattern);
111: }
112:
113: public ASTToken read(Cookie cookie, CharInput input,
114: Language language) {
115: if (input.eof())
116: return null;
117: int originalIndex = input.getIndex();
118: Pattern pattern = stateToPattern.get(cookie.getState());
119: if (pattern == null)
120: return null;
121: TokenType tokenType = (TokenType) pattern.read(input);
122: if (tokenType == null) {
123: return null;
124: }
125: Feature tokenProperties = tokenType.getProperties();
126: cookie.setProperties(tokenProperties);
127: String endState = tokenType.getEndState();
128: int state = -1;
129: if (endState != null)
130: state = getState(endState);
131: cookie.setState(state);
132: ASTToken token = ASTToken.create(language, tokenType
133: .getTypeID(), input.getString(originalIndex, input
134: .getIndex()), originalIndex);
135: if (tokenProperties != null
136: && tokenProperties.getType("call") != Type.NOT_SET) {
137: input.setIndex(originalIndex);
138: Object[] r = (Object[]) tokenProperties.getValue("call",
139: new Object[] { input });
140: if (r == null)
141: throw new NullPointerException("Method "
142: + tokenProperties.getMethodName("call")
143: + " returns null!\n");
144: token = (ASTToken) r[0];
145: if (r[1] != null)
146: cookie.setState(getState((String) r[1]));
147: }
148: return token;
149: }
150:
151: public int getState(String stateName) {
152: Integer i = nameToState.get(stateName);
153: if (i == null)
154: throw new IllegalArgumentException("Unknown lexer state: "
155: + stateName);
156: return i.intValue();
157: }
158:
159: private Map<String, Pattern> patterns = new HashMap<String, Pattern>();
160:
161: public String toString() {
162: StringBuffer sb = new StringBuffer();
163: Iterator<String> it = patterns.keySet().iterator();
164: while (it.hasNext()) {
165: String state = it.next();
166: sb.append(state).append(":").append(patterns.get(state));
167: }
168: return sb.toString();
169: }
170:
171: // innerclasses ............................................................
172:
173: public interface Cookie {
174: public abstract int getState();
175:
176: public abstract void setState(int state);
177:
178: public abstract void setProperties(Feature tokenProperties);
179: }
180: }
|