001: package org.drools.compiler;
002:
003: /*
004: * Copyright 2005 JBoss Inc
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: import java.io.IOException;
020: import java.io.Reader;
021: import java.util.ArrayList;
022: import java.util.Iterator;
023: import java.util.List;
024:
025: import org.antlr.runtime.ANTLRReaderStream;
026: import org.antlr.runtime.ANTLRStringStream;
027: import org.antlr.runtime.CommonTokenStream;
028: import org.antlr.runtime.RecognitionException;
029: import org.drools.lang.DRLLexer;
030: import org.drools.lang.DRLParser;
031: import org.drools.lang.Expander;
032: import org.drools.lang.ExpanderException;
033: import org.drools.lang.Location;
034: import org.drools.lang.descr.PackageDescr;
035: import org.drools.lang.dsl.DefaultExpanderResolver;
036:
037: /**
038: * This is a low level parser API. This will return textual AST representations
039: * of the DRL source, including with DSL expanders if appropriate.
040: */
041: public class DrlParser {
042:
043: private final List results = new ArrayList();
044: private Location location = null;
045:
046: public DrlParser() {
047:
048: }
049:
050: /** Parse a rule from text */
051: public PackageDescr parse(final String text)
052: throws DroolsParserException {
053: final DRLParser parser = getParser(text);
054: compile(parser);
055: this .location = parser.getLocation();
056: return parser.getPackageDescr();
057:
058: }
059:
060: public PackageDescr parse(final Reader reader)
061: throws DroolsParserException {
062: final DRLParser parser = getParser(reader);
063: compile(parser);
064: this .location = parser.getLocation();
065: return parser.getPackageDescr();
066:
067: }
068:
069: // /** Parse and build a rule package from a DRL source */
070: // public PackageDescr parse(final Reader reader) throws IOException,
071: // DroolsParserException {
072: // DRLParser parser =
073: //
074: // //final StringBuffer text = getDRLText( reader );
075: // //return parse( text.toString() );
076: // }
077:
078: /**
079: * Parse and build a rule package from a DRL source with a
080: * domain specific language.
081: */
082: public PackageDescr parse(final Reader drl, final Reader dsl)
083: throws DroolsParserException, IOException {
084: final StringBuffer text = getDRLText(drl);
085: return parse(text.toString(), dsl);
086: }
087:
088: /**
089: * Parse and build a rule package from a DRL source with a domain specific language.
090: * @param source As Text.
091: * @param dsl
092: * @return
093: * @throws DroolsParserException
094: */
095: public PackageDescr parse(final String source, final Reader dsl)
096: throws DroolsParserException {
097: DefaultExpanderResolver resolver;
098: try {
099: resolver = new DefaultExpanderResolver(dsl);
100: } catch (final IOException e) {
101: throw new DroolsParserException("Error parsing the DSL.", e);
102: }
103: final Expander expander = resolver.get("*", null);
104: final String expanded = expander.expand(source);
105: if (expander.hasErrors()) {
106: this .results.addAll(expander.getErrors());
107: }
108: return this .parse(expanded);
109: }
110:
111: /**
112: * This will expand the DRL.
113: * useful for debugging.
114: * @param source - the source which use a DSL
115: * @param dsl - the DSL itself.
116: * @throws DroolsParserException If unable to expand in any way.
117: */
118: public String getExpandedDRL(final String source, final Reader dsl)
119: throws DroolsParserException {
120: DefaultExpanderResolver resolver;
121: try {
122: resolver = new DefaultExpanderResolver(dsl);
123: } catch (final IOException e) {
124: throw new DroolsParserException("Error parsing the DSL.", e);
125: }
126: final Expander expander = resolver.get("*", null);
127: final String expanded = expander.expand(source);
128:
129: if (expander.hasErrors()) {
130: String err = "";
131: for (Iterator iter = expander.getErrors().iterator(); iter
132: .hasNext();) {
133: ExpanderException ex = (ExpanderException) iter.next();
134: err = err + "\n Line:[" + ex.getLine() + "] "
135: + ex.getMessage();
136:
137: }
138: throw new DroolsParserException(err);
139: }
140: return expanded;
141: }
142:
143: private StringBuffer getDRLText(final Reader reader)
144: throws IOException {
145: final StringBuffer text = new StringBuffer();
146:
147: final char[] buf = new char[1024];
148: int len = 0;
149:
150: while ((len = reader.read(buf)) >= 0) {
151: text.append(buf, 0, len);
152: }
153: return text;
154: }
155:
156: /**
157: * @return true if there were parser errors.
158: */
159: public boolean hasErrors() {
160: return this .results.size() > 0;
161: }
162:
163: /**
164: * @return a list of ParserError's.
165: */
166: public List getErrors() {
167: return this .results;
168: }
169:
170: private void compile(final DRLParser parser)
171: throws DroolsParserException {
172: try {
173: parser.compilation_unit();
174:
175: makeErrorList(parser);
176: } catch (final RecognitionException e) {
177: throw new DroolsParserException(e);
178: } catch (Exception e) {
179: throw new DroolsParserException(
180: "Unknown error while parsing. This is a bug. Please contact the Development team.",
181: e);
182: }
183: }
184:
185: /** Convert the antlr exceptions to drools parser exceptions */
186: private void makeErrorList(final DRLParser parser) {
187: for (final Iterator iter = parser.getErrors().iterator(); iter
188: .hasNext();) {
189: final RecognitionException recogErr = (RecognitionException) iter
190: .next();
191: final ParserError err = new ParserError(parser
192: .createErrorMessage(recogErr), recogErr.line,
193: recogErr.charPositionInLine);
194: this .results.add(err);
195: }
196: }
197:
198: /**
199: * @return An instance of a RuleParser should you need one (most folks will not).
200: */
201: private DRLParser getParser(final String text) {
202: return new DRLParser(new CommonTokenStream(new DRLLexer(
203: new ANTLRStringStream(text))));
204: }
205:
206: private DRLParser getParser(final Reader reader) {
207: try {
208: return new DRLParser(new CommonTokenStream(new DRLLexer(
209: new ANTLRReaderStream(reader))));
210: } catch (final Exception e) {
211: throw new RuntimeException("Unable to parser Reader", e);
212: }
213: }
214:
215: public Location getLocation() {
216: return this.location;
217: }
218: }
|