/**
*
*/
package org.korsakow.ide.code.k5;
import java.util.ArrayList;
import java.util.List;
import org.korsakow.domain.Keyword;
import org.korsakow.ide.code.RuleParserException;
import org.korsakow.ide.rules.RuleType;
import org.korsakow.ide.ui.model.RuleModel;
/**
* K5 source code parser. With helper methods to generate K5 Rules.
* @deprecated
* @author d
*
*/
@Deprecated
public class K5RuleParser2
{
List<K5Lexeme> k5Tokens;
public boolean isValidKeyword(String keyword)
{
if (keyword == null)
return false;
return true;
// validation is a pain. it implies:
// 1) complex conversion of k3 projects
// 2) complex handling of the resource-name-as-keyword feature
// 3) complexities related to the use of filenames as resource names / keywords
//return keyword != null && keyword.matches("^(?:\\p{L}|[0-9]|[^+-])+"); // p{L] = any unicode letter
}
public void validateKeyword(String keyword) throws RuleParserException
{
if (!isValidKeyword(keyword))
throw new RuleParserException("invalid keyword:" + keyword);
}
public List<K5Lexeme> tokenize(String code) throws RuleParserException
{
List<K5Lexeme> tokens = new ArrayList<K5Lexeme>();
String[] parts = code.split(String.format("[%s\\s]", K5Symbol.DEFAULT_STATEMENT_SEPARATOR_STRING));
for (String part : parts) {
part = part.trim();
if (part.length() == 0)
continue;
char op = part.charAt(part.length()-1);
String keyword = part.substring(0, part.length()-1);
K5Lexeme lexeme;
if (part.equals(K5Symbol.CLEAR_PREVIOUS_LINKS)) {
lexeme = new K5Lexeme(K5OpType.CLEAR_PREVIOUS_LINKS, part);
} else
if (part.equals(K5Symbol.KEEP_PREVIOUS_LINKS)) {
lexeme = new K5Lexeme(K5OpType.KEEP_PREVIOUS_LINKS, part);
} else {
switch (op)
{
case K5Symbol.EXCLUSION_KEYWORD:
if (K5Symbol.RANDOM_KEYWORD.equals(keyword))
throw new RuleParserException("cannot use '"+keyword+"' in this context");
validateKeyword(keyword);
lexeme = new K5Lexeme(K5OpType.KEYWORD_EXCLUSION, op, keyword);
break;
case K5Symbol.REQUIRED_KEYWORD:
if (K5Symbol.RANDOM_KEYWORD.equals(keyword))
throw new RuleParserException("cannot use '"+keyword+"' in this context");
validateKeyword(keyword);
lexeme = new K5Lexeme(K5OpType.KEYWORD_REQUIRED, op, keyword);
break;
default:
if (isValidKeyword(keyword + op)) {
lexeme = new K5Lexeme(K5OpType.KEYWORD_LOOKUP, keyword + op);
} else
throw new RuleParserException("invalid op: " + op);
}
}
tokens.add(lexeme);
}
return tokens;
}
public List<RuleModel> createRules(List<K5Lexeme> lexemes) throws RuleParserException
{
List<RuleModel> rules = new ArrayList<RuleModel>();
List<String> outboundKeywords = new ArrayList<String>();
List<String> requireKeywords = new ArrayList<String>();
List<String> excludeKeywords = new ArrayList<String>();
boolean clearScores = false;
boolean setendfilm = false;
for (K5Lexeme lexeme : lexemes)
{
switch(lexeme.getOpType())
{
case KEYWORD_LOOKUP:
outboundKeywords.add(lexeme.getToken());
break;
case KEYWORD_REQUIRED:
requireKeywords.add(lexeme.getToken());
break;
case KEYWORD_EXCLUSION:
excludeKeywords.add(lexeme.getToken());
break;
case CLEAR_PREVIOUS_LINKS:
clearScores = true;
break;
case KEEP_PREVIOUS_LINKS:
clearScores = false;
break;
default:
throw new RuleParserException("k5 rule not yet parsable: " + lexeme.getOpType());
}
}
// the order in which we generate most of the rules is important!
// generally: Lookup, Require, Exclude
if (clearScores) {
RuleModel rule = new RuleModel(RuleType.ClearScores);
rules.add(rule);
}
if (setendfilm) { // this rule is order-independant
RuleModel rule = new RuleModel(RuleType.SetEndfilm);
rules.add(rule);
}
{ // scope local vars for clarity
List<String> regularKeywords = new ArrayList<String>();
List<String> randomKeywords = new ArrayList<String>();
List<String> endfilmKeywords = new ArrayList<String>();
for (String keyword : outboundKeywords) {
if (K5Symbol.RANDOM_KEYWORD.equals(keyword)) {
randomKeywords.add(keyword);
} else if (K5Symbol.ENDFILM_KEYWORD.equals(keyword)) {
endfilmKeywords.add(keyword);
} else {
regularKeywords.add(keyword);
}
}
// the order of random/endfilm vs regular is not important
for (String random : randomKeywords) {
RuleModel rule = new RuleModel(RuleType.RandomLookup);
rules.add(rule);
}
for (String endfilm : endfilmKeywords) {
RuleModel rule = new RuleModel(RuleType.EndfilmLookup);
rules.add(rule);
}
if (!regularKeywords.isEmpty()) {
RuleModel rule = new RuleModel(RuleType.KeywordLookup);
rule.setProperty("keywords", Keyword.fromStrings(regularKeywords));
rules.add(rule);
}
}
{ // scope local vars for clarity
// requirekeywords must be after all other keyword lookup rules except exclusion
List<String> regularRequires = new ArrayList<String>();
List<String> endfilmRequires = new ArrayList<String>();
for (String keyword : requireKeywords) {
if (K5Symbol.ENDFILM_KEYWORD.equals(keyword)) {
endfilmRequires.add(keyword);
} else {
regularRequires.add(keyword);
}
}
// the order of endfilm vs regular is not important
for (String endfilm : endfilmRequires) {
RuleModel rule = new RuleModel(RuleType.RequireEndfilm);
rules.add(rule);
}
if (!regularRequires.isEmpty()) {
RuleModel rule = new RuleModel(RuleType.RequireKeywords);
rule.setProperty("keywords", Keyword.fromStrings(regularRequires));
rules.add(rule);
}
}
{ // scope local vars for clarity
// exclude keywords must be after all other keyword lookup rules
List<String> regularExcludes = new ArrayList<String>();
List<String> endfilmExcludes = new ArrayList<String>();
for (String keyword : excludeKeywords) {
if (K5Symbol.ENDFILM_KEYWORD.equals(keyword)) {
endfilmExcludes.add(keyword);
} else {
regularExcludes.add(keyword);
}
}
// the order of endfilm vs regular is not important
for (String endfilm : endfilmExcludes) {
RuleModel rule = new RuleModel(RuleType.ExcludeEndfilm);
rules.add(rule);
}
if (!regularExcludes.isEmpty()) {
RuleModel rule = new RuleModel(RuleType.ExcludeKeywords);
rule.setProperty("keywords", Keyword.fromStrings(regularExcludes));
rules.add(rule);
}
}
return rules;
}
/**
* K5-code and K5 rules are many-to-many. That is any one K5 code might correspond to many K5 rules
* and vice versa.
*
* @param code
* @param triggerTime if null no time is set
* @return
* @throws RuleParserException
*/
public List<RuleModel> parse(String code, Long triggerTime) throws RuleParserException
{
k5Tokens = tokenize(code);
List<RuleModel> rules = createRules(k5Tokens);
if (triggerTime != null) {
for (RuleModel rule : rules)
rule.setProperty("triggerTime", triggerTime);
}
return rules;
}
public List<RuleModel> parse(String code) throws RuleParserException
{
return parse(code, null);
}
}