/**
* Copyright 2010 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.drools.ide.common.assistant.engine;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.drools.ide.common.assistant.info.RuleRefactorInfo;
import org.drools.ide.common.assistant.info.drl.DRLContentTypeEnum;
import org.drools.ide.common.assistant.info.drl.DRLRuleRefactorInfo;
import org.drools.ide.common.assistant.info.drl.RuleLineContentInfo;
/**
* A simple DRL parser implemented with regular expressions to get the offset of rule components
*
* @author lucas
*
*/
public class DRLParserEngine extends AbstractParserEngine {
private static final String RULE_DECLARATION = "(rule|RULE)";
private static final String PACKAGE_DECLARATION = "(package|PACKAGE)";
private static final String IMPORT_DECLARATION = "(import|IMPORT)";
private static final String GLOBAL_DECLARATION = "(global|GLOBAL)";
private static final String RULE_WHEN_DECLARATION = "(when|WHEN)";
private static final String RULE_THEN_DECLARATION = "(then|THEN)";
private static final String RULE_END_DECLARATION = "(end|END)";
private static final String OPTIONAL_TAB = "[\t]*";
private static final String FULLY_QUALIFIED_NAME = "[\\w\\.]*";
private static final String ONE_OR_MORE_SPACES = "[\\s]+";
private static final String RULE_NAME = "\"[\\s\\w]*\"";
// Regulars expressions to match DRL Rule
private static final String PACKAGE_PATTERN = PACKAGE_DECLARATION + ONE_OR_MORE_SPACES + FULLY_QUALIFIED_NAME + ";?"; // OK
private static final String IMPORT_PATTERN = IMPORT_DECLARATION + ONE_OR_MORE_SPACES + FULLY_QUALIFIED_NAME + ";"; // OK
private static final String GLOBAL_PATTERN = GLOBAL_DECLARATION + ONE_OR_MORE_SPACES + FULLY_QUALIFIED_NAME + ONE_OR_MORE_SPACES + "[\\w]*" + ONE_OR_MORE_SPACES + ""; // OK
private static final String RULE_NAME_PATTERN = RULE_DECLARATION + ONE_OR_MORE_SPACES + RULE_NAME;
private static final String RULE_LHS_PATTERN = "[\\t\\s]*" + RULE_WHEN_DECLARATION + ONE_OR_MORE_SPACES + OPTIONAL_TAB + "[\\w\\W]*" + "(?=" + RULE_THEN_DECLARATION + ")";
private static final String RULE_RHS_PATTERN = "[\\t\\s]*" + RULE_THEN_DECLARATION + ONE_OR_MORE_SPACES + "[\\w\\W]*" + RULE_END_DECLARATION;
private static final Pattern rulePattern = Pattern.compile("rule.+?end\\s*$", Pattern.MULTILINE | Pattern.DOTALL);
public DRLParserEngine(String rule) {
this.ruleRefactorInfo = new DRLRuleRefactorInfo();
this.rule = rule;
}
public RuleRefactorInfo parse() {
detectPackage(rule);
detectGlobals(rule);
detectImports(rule);
detectRules(rule);
return ruleRefactorInfo;
}
private void detectPackage(CharSequence rule) {
pattern = Pattern.compile(PACKAGE_PATTERN);
matcher = pattern.matcher(rule);
if (matcher.find())
((DRLRuleRefactorInfo) ruleRefactorInfo).addContent(DRLContentTypeEnum.PACKAGE, matcher.start(), matcher.group());
}
private void detectImports(CharSequence rule) {
pattern = Pattern.compile(IMPORT_PATTERN);
matcher = pattern.matcher(rule);
while (matcher.find())
((DRLRuleRefactorInfo) ruleRefactorInfo).addContent(DRLContentTypeEnum.IMPORT, matcher.start(), matcher.group());
}
private void detectGlobals(CharSequence rule) {
pattern = Pattern.compile(GLOBAL_PATTERN);
matcher = pattern.matcher(rule);
while (matcher.find())
((DRLRuleRefactorInfo) ruleRefactorInfo).addContent(DRLContentTypeEnum.GLOBAL, matcher.start(), matcher.group());
}
private void detectRules(CharSequence rule) {
Matcher ruleMatcher = rulePattern.matcher(rule);
while (ruleMatcher.find()) {
for( int position = 0; position < ruleMatcher.groupCount()+1; position++ ){
String value = ruleMatcher.group(position);
int offset = ruleMatcher.start();
String ruleName = detectRuleName(value);
List<RuleLineContentInfo> lhs = detectLHS(value, offset);
List<RuleLineContentInfo> rhs = detectRHS(value, offset);
((DRLRuleRefactorInfo) ruleRefactorInfo).addContent(DRLContentTypeEnum.RULE, offset, value, ruleName, lhs, rhs);
}
}
}
private String detectRuleName(CharSequence rule) {
pattern = Pattern.compile(RULE_NAME_PATTERN);
matcher = pattern.matcher(rule);
if (matcher.find())
return matcher.group();
return null;
}
private List<RuleLineContentInfo> detectLHS(CharSequence rule, int ruleOffset) {
pattern = Pattern.compile(RULE_LHS_PATTERN);
matcher = pattern.matcher(rule);
if (matcher.find()) {
return detectLines(matcher.group(), matcher.start() + ruleOffset, DRLContentTypeEnum.RULE_LHS_LINE);
}
return null;
}
private List<RuleLineContentInfo> detectRHS(CharSequence rule, int ruleOffset) {
pattern = Pattern.compile(RULE_RHS_PATTERN);
matcher = pattern.matcher(rule);
if (matcher.find())
return detectLines(matcher.group(), matcher.start() + ruleOffset, DRLContentTypeEnum.RULE_RHS_LINE);
return null;
}
private List<RuleLineContentInfo> detectLines(CharSequence rule, int lineOffset, DRLContentTypeEnum type) {
List<RuleLineContentInfo> ruleLines = new ArrayList<RuleLineContentInfo>();
pattern = Pattern.compile(".*");
matcher = pattern.matcher(rule);
while (matcher.find()) {
if (matcher.start()!=matcher.end()) {
if (matcher.group().trim().length() > 0) {
ruleLines.add(new RuleLineContentInfo(matcher.start()+lineOffset, matcher.group(), type));
}
}
}
return ruleLines;
}
}