blob: 7d3b411312756560c5ac07b2498e8b096c10da32 [file] [log] [blame]
package org.eclipse.gymnast.generators.ecore.cst;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.gymnast.generator.core.ast.Rule;
import org.eclipse.gymnast.generator.core.ast.TokenRule;
import org.eclipse.gymnast.generators.ecore.errors.Grammar2EcoreInvalidInput.EmptyTokenRule;
import org.eclipse.gymnast.generators.ecore.errors.Grammar2EcoreInvalidInput.EmptyTokenRule.GeneralMessage;
import org.eclipse.gymnast.generators.ecore.errors.Grammar2EcoreInvalidInput.EmptyTokenRule.MalformedTokenRule;
import org.eclipse.gymnast.generators.ecore.errors.Grammar2EcoreInvalidInput.EmptyTokenRule.RuleNameShadowsBuiltInToken;
import org.eclipse.gymnast.runtime.core.parser.ParseContext;
public class TokenRuleCS extends RuleCS {
public TokenRule tr;
public TokenRuleCS(String name, List<String> alts2, List<String> attrs2,
RootCS c, TokenRule tr) {
super(c);
this.name = name;
this.alts = alts2;
this.attrs = attrs2;
this.tr = tr;
}
public List<String> alts;
/**
* Invariant:
*
* (this.enu != null) iff (Grammar2Ecore.convert() has initialized it and
* this.getKindOfAlts() == FIXED_KEYWORDS)
*
* @see AltRuleCS.enu
*
*/
public EEnum enu = null;
public List<String> explodeTerminalAlternatives() {
Set<String> alreadyExploded = new HashSet<String>();
return explTermAlts(this, alreadyExploded);
}
/**
* This method assumes the argument is a FIXED_KEYWORDS token rule.
* Surrounding quotes are removed for the returned items.
*
* @param trCS
* @param alreadyExploded
* @return
*/
private List<String> explTermAlts(TokenRuleCS trCS,
Set<String> alreadyExploded) {
assert innerGetKindOfAlts(trCS) == TokenRuleAltsKind.FIXED_KEYWORDS;
List<String> res = new ArrayList<String>();
for (String alt : trCS.alts) {
if (c.isSurroundedByQuotes(alt)) {
res.add(alt);
} else if (c.isBuiltInToken(alt)) {
res.add(alt);
} else {
TokenRuleCS innerTR = c.findTokenRuleCSByName(alt);
assert innerTR != null;
if (innerTR != null && !alreadyExploded.contains(alt)) {
alreadyExploded.add(alt);
res.addAll(explTermAlts(innerTR, alreadyExploded));
}
}
}
return res;
}
public TokenRuleAltsKind getKindOfAlts() {
return innerGetKindOfAlts(this);
}
private TokenRuleAltsKind innerGetKindOfAlts(TokenRuleCS trCS) {
if (trCS.alts.isEmpty()) {
/*
* calling isEmpty() above on the alts collection instead of
* isEmpty(TokenRuleCS) is intentional, as (1) the checks below will
* catch malformedness due to empty constituents and (2) to allow
* invoking this method from isEmpty(TokenRuleCS) or its invokers.
*/
return TokenRuleAltsKind.MALFORMED;
}
// duplicate alts should be rejected
Set<String> altsAsSet = new HashSet<String>(trCS.alts);
if (altsAsSet.size() != trCS.alts.size()) {
return TokenRuleAltsKind.MALFORMED;
}
/*
* a TokenRule that is to become an EBoolean should have just two
* alternatives
*/
if (trCS.attrs.contains(RootCS.ATTRIBUTE_REGARD_AS_BOOLEAN)
&& !canBeRegardedAsBoolean()) {
return TokenRuleAltsKind.MALFORMED;
}
boolean areThereInts = false;
boolean areThereArbitraryIDs = false;
boolean areThereFixedKeywords = false;
for (String alt : trCS.alts) {
if (alt.equals("ID") || alt.equals("CHAR_LITERAL")
|| alt.equals("STRING_LITERAL")) {
areThereArbitraryIDs = true;
} else if (c.isIntegerLiteral(alt) || alt.equals("INT_LITERAL")) {
areThereInts = true;
} else if ((c.isSurroundedByQuotes(alt) && !c.isIntegerLiteral(alt))
|| c.isBuiltInToken(alt)) {
areThereFixedKeywords = true;
/*
* the default case, if all alts are like this will lead to
* TokenRuleAltsKind.FIXED_KEYWORDS and thus
* canBeConvertedToEnum()
*/
} else {
TokenRuleCS refedTR = c.findTokenRuleCSByName(alt);
if (refedTR == null) {
return TokenRuleAltsKind.MALFORMED;
}
TokenRuleAltsKind refedKind = innerGetKindOfAlts(refedTR);
switch (refedKind) {
case MALFORMED:
return TokenRuleAltsKind.MALFORMED;
case ID_OR_MIXEDSTRINT:
areThereArbitraryIDs = true;
areThereInts = true;
/*
* don't return just yet, let the other alts be checked for
* MALFORMED
*/
break;
case INTS:
areThereInts = true;
break;
case FIXED_KEYWORDS:
areThereFixedKeywords = true;
break;
}
}
}
if (areThereArbitraryIDs || (areThereFixedKeywords && areThereInts)) {
return TokenRuleAltsKind.ID_OR_MIXEDSTRINT;
} else {
if (!areThereFixedKeywords && areThereInts) {
return TokenRuleAltsKind.INTS;
}
return TokenRuleAltsKind.FIXED_KEYWORDS;
}
}
@Override
public Rule getRule() {
return tr;
}
public void addParseMessages(ParseContext parseContext) {
if (c.isBuiltInToken(name)) {
RuleNameShadowsBuiltInToken parseMessage = new RuleNameShadowsBuiltInToken(
this);
parseContext.addParseMessage(parseMessage);
}
// duplicate alts
Set<String> altsAsSet = new HashSet<String>(alts);
if (altsAsSet.size() != alts.size()) {
GeneralMessage parseMessage = new GeneralMessage(
"Duplicate alternatives", name, tr);
parseContext.addParseMessage(parseMessage);
}
/*
* a TokenRule that is to become an EBoolean should have just two
* alternatives
*/
if (attrs.contains(RootCS.ATTRIBUTE_REGARD_AS_BOOLEAN)
&& !canBeRegardedAsBoolean()) {
GeneralMessage parseMessage = new GeneralMessage(
"Marked [boolean] but does not have just two alternatives",
name, tr);
parseContext.addParseMessage(parseMessage);
}
if (getKindOfAlts() == TokenRuleAltsKind.MALFORMED) {
MalformedTokenRule parseMessage = new MalformedTokenRule(this);
parseContext.addParseMessage(parseMessage);
}
if (isEmpty()) {
EmptyTokenRule parseMessage = new EmptyTokenRule(this);
parseContext.addParseMessage(parseMessage);
}
}
public boolean isEmpty() {
boolean res = alts.size() == 0;
return res;
}
public boolean canBeRegardedAsBoolean() {
if (attrs.contains(RootCS.ATTRIBUTE_REGARD_AS_BOOLEAN)
&& alts.size() == 2 && !alts.get(0).equals(alts.get(1))) {
return true;
}
return false;
}
}