blob: df035e4f2fc42d9726975aa47ccfdbaec9b0b417 [file] [log] [blame]
package org.eclipse.gymnast.generators.ecore.walker;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.gymnast.generator.core.ast.AltRule;
import org.eclipse.gymnast.generator.core.ast.Alts;
import org.eclipse.gymnast.generator.core.ast.Attrs;
import org.eclipse.gymnast.generator.core.ast.CompUnit;
import org.eclipse.gymnast.generator.core.ast.Expr;
import org.eclipse.gymnast.generator.core.ast.Grammar;
import org.eclipse.gymnast.generator.core.ast.HeaderSection;
import org.eclipse.gymnast.generator.core.ast.Id;
import org.eclipse.gymnast.generator.core.ast.ListRule;
import org.eclipse.gymnast.generator.core.ast.OptSubSeq;
import org.eclipse.gymnast.generator.core.ast.Option;
import org.eclipse.gymnast.generator.core.ast.Seq;
import org.eclipse.gymnast.generator.core.ast.SeqRule;
import org.eclipse.gymnast.generator.core.ast.SimpleExpr;
import org.eclipse.gymnast.generator.core.ast.TokenRule;
import org.eclipse.gymnast.generator.core.parser.ParserDriver;
import org.eclipse.gymnast.runtime.core.ast.ASTNode;
import org.eclipse.gymnast.runtime.core.parser.ParseContext;
/**
*
* A GymnastWalker navigates the full Abstract Syntax Tree (AST) of a grammar.
* It implements the accept operation of the Visitor pattern for a
* GymnastASTNode object. In this way the accept operation need not be part of
* GymnastASTNode. <br>
* <br>
*
* This walker navigates the grammar AST post-order: for each node children are
* visited, and then those results as well as the current node are given to a
* handler method. <br>
* <br>
*
* Users must subclass GymnastSwitch and call walk(grammarRoot, visitor) where
* grammarRoot is of type org.eclipse.gymnast.generator.core.ast.CompUnit <br>
* <br>
* Example usage: <br>
* <br>
*
* <code>
* class MyVisitor extends GrammarSwitch { .... }<br>
*
* MyVisitor v = new MyVisitor (); <br>
* GymnastWalker w = new GymnastWalker(); <br>
* Object result = w.walk(myGrammar, v);<br>
* </code>
*
* <br>
* <br>
* See Also: GymnastSwitch
*
*
*
* @author <a href="http://www.sts.tu-harburg.de/~mi.garcia/">Miguel Garcia</a>
*
*/
public class GymnastWalker<T> {
public T walk(org.eclipse.gymnast.generator.core.ast.CompUnit root, GymnastSwitch<T> v) {
T resHeader = walkHeader(root.getHeaderSection(), v);
T resGrammar = walkGrammar(root.getGrammar(), v);
T res = v.handleRoot(root, resHeader, resGrammar);
return res;
}
/**
* BufferedReader reader = new BufferedReader(new
* InputStreamReader(context.getASTFile().getContents()));
*/
public T walk(Reader grammar, GymnastSwitch<T> v) {
ParserDriver parser = new ParserDriver();
ParseContext parseContext = parser.parse(grammar);
CompUnit parseRoot = (CompUnit) parseContext.getParseRoot();
if (parseRoot == null) {
return null;
}
return walk(parseRoot, v);
}
public T walkGrammarContents(String grammarContents, GymnastSwitch<T> v) {
StringReader sr = new StringReader(grammarContents);
return walk(sr, v);
}
public T walkFile(String fileLocation, GymnastSwitch<T> v) {
try {
FileReader fr = new FileReader(fileLocation);
return walk(fr, v);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
private T walkGrammar(Grammar grammar, GymnastSwitch<T> v) {
ASTNode[] rules = grammar.getChildren();
List<T> resTokenRules = new ArrayList<T>();
List<T> resSeqRules = new ArrayList<T>();
List<T> resAltRules = new ArrayList<T>();
List<T> resListRules = new ArrayList<T>();
for (ASTNode rule : rules) {
if (rule instanceof TokenRule) {
TokenRule tr = (TokenRule) rule;
resTokenRules.add(walkTokenRule(tr, v));
} else if (rule instanceof SeqRule) {
SeqRule sr = (SeqRule) rule;
resSeqRules.add(walkSeqRule(sr, v));
} else if (rule instanceof AltRule) {
AltRule ar = (AltRule) rule;
resAltRules.add(walkAltRule(ar, v));
} else if (rule instanceof ListRule) {
ListRule lr = (ListRule) rule;
resListRules.add(walkListRule(lr, v));
}
}
return v.handleGrammar(grammar, resTokenRules, resSeqRules, resAltRules, resListRules);
}
private T walkListRule(ListRule lr, GymnastSwitch<T> v) {
String name = lr.getDecl().getName().getText();
List<String> attrs = getAttrsIfAny(lr.getDecl().getAttrs());
SimpleExpr se1 = lr.getBody().getListExpr();
String opt_e1Name = unNullName(se1);
String e1 = se1.getValue().getText();
String separator = "";
if (lr.getBody().getSeparator() != null) {
separator = lr.getBody().getSeparator().getValue().getText();
}
String e2 = "";
SimpleExpr se2 = lr.getBody().getListExpr2();
String opt_e2Name = unNullName(se2);
if (se2 != null) {
e2 = se2.getValue().getText();
}
int lowerBound = lr.getBody().getListMark().getText().equals("+") ? 1 : 0;
return v.handleListRule(lr, attrs, name, e1, separator, e2, lowerBound, opt_e1Name, opt_e2Name);
}
private String unNullName(SimpleExpr se) {
String res = "";
if (se != null && se.getName() != null) {
res = se.getName().getText();
}
return res;
}
private T walkAltRule(AltRule ar, GymnastSwitch<T> v) {
String strKind = ar.getDecl().getKind().getText();
AltRuleKind k = AltRuleKind.ABSTRACT_RK;
if (strKind.equals("container")) {
k = AltRuleKind.CONTAINER_RK;
} else if (strKind.equals("interface")) {
k = AltRuleKind.INTERFACE_RK;
}
String name = ar.getDecl().getName().getText();
List<String> attrs = getAttrsIfAny(ar.getDecl().getAttrs());
List<String> alts = getAlts(ar.getBody().getAlts());
List<T> resPreSeqs = new ArrayList<T>();
List<T> resPostSeqs = new ArrayList<T>();
if (ar.getBody().getPreSeq() != null) {
Seq preSeq = ar.getBody().getPreSeq().getSeq();
for (org.eclipse.gymnast.runtime.core.ast.ASTNode c : preSeq.getChildren()) {
if (c instanceof Expr) {
Expr e = (Expr) c;
resPreSeqs.addAll(walkExprInPreOrPostSeqInAltRule(ar, true, e, v));
}
}
}
if (ar.getBody().getPostSeq() != null) {
Seq postSeq = ar.getBody().getPostSeq().getSeq();
for (org.eclipse.gymnast.runtime.core.ast.ASTNode c : postSeq.getChildren()) {
if (c instanceof Expr) {
Expr e = (Expr) c;
resPreSeqs.addAll(walkExprInPreOrPostSeqInAltRule(ar, true, e, v));
}
}
}
return v.handleAltRule(ar, name, alts, attrs, resPreSeqs, resPostSeqs);
}
private Collection<? extends T> walkExprInPreOrPostSeqInAltRule(AltRule ar, boolean isOptional, Expr e,
GymnastSwitch<T> v) {
isOptional = isOptional || (e instanceof OptSubSeq);
List<T> res = new ArrayList<T>();
if (e instanceof OptSubSeq) {
OptSubSeq optSubSeq = (OptSubSeq) e;
ASTNode[] nodes = optSubSeq.getSeq().getChildren();
for (ASTNode node : nodes) {
if (node instanceof Expr) {
Expr innerE = (Expr) node;
res.addAll(walkExprInPreOrPostSeqInAltRule(ar, isOptional, innerE, v));
}
}
} else {
SimpleExpr se = (SimpleExpr) e;
List<String> attrs = getAttrsIfAny(se.getAttrs());
String optFieldName = unNull(se.getName());
String value = se.getValue().getText();
res.add(v.handleSimpleExprInPreOrPostInAltRule(ar, se, isOptional, optFieldName, value, attrs, res.size()));
}
return res;
}
private T walkSeqRule(SeqRule sr, GymnastSwitch<T> v) {
String name = sr.getDecl().getName().getText();
List<String> attrs = getAttrsIfAny(sr.getDecl().getAttrs());
ASTNode[] exprNodes = sr.getBody().getChildren();
List<T> resSimpleExprs = new ArrayList<T>();
for (ASTNode node : exprNodes) {
if (node instanceof Expr) {
Expr e = (Expr) node;
resSimpleExprs.addAll(walkExprInSeqRule(sr, false, e, v));
}
}
return v.handleSeqRule(sr, name, attrs, resSimpleExprs);
}
private List<T> walkExprInSeqRule(SeqRule sr, boolean isOptional, Expr e, GymnastSwitch<T> v) {
isOptional = isOptional || (e instanceof OptSubSeq);
List<T> res = new ArrayList<T>();
if (e instanceof OptSubSeq) {
OptSubSeq optSubSeq = (OptSubSeq) e;
ASTNode[] nodes = optSubSeq.getSeq().getChildren();
for (ASTNode node : nodes) {
if (node instanceof Expr) {
Expr innerE = (Expr) node;
res.addAll(walkExprInSeqRule(sr, isOptional, innerE, v));
}
}
} else {
SimpleExpr se = (SimpleExpr) e;
List<String> attrs = getAttrsIfAny(se.getAttrs());
String optFieldName = unNull(se.getName());
String value = se.getValue().getText();
res.add(v.handleSimpleExprInRule(sr, se, isOptional, optFieldName, value, attrs, -1));
}
return res;
}
private String unNull(Id name) {
if (name == null) {
return "";
}
return name.getText();
}
private List<String> getAttrsIfAny(Attrs attrs) {
List<String> res = new ArrayList<String>();
if (attrs != null) {
if (attrs.getChild(1) != null) {
ASTNode[] attrNodes = attrs.getChild(1).getChildren();
for (ASTNode attrNode : attrNodes) {
String str = attrNode.getText();
if (str != null && !(",".equals(str)) && !("[".equals(str)) && !("]".equals(str))) {
res.add(attrNode.getText());
}
}
}
}
return res;
}
private T walkTokenRule(TokenRule tr, GymnastSwitch<T> v) {
String tokenRuleName = tr.getDecl().getName().getText();
List<String> attrs = getAttrsIfAny(tr.getDecl().getAttrs());
List<String> alts = getAlts(tr.getBody());
return v.handleTokenRule(tr, tokenRuleName, attrs, alts);
}
private List<String> getAlts(Alts body) {
ASTNode[] altNodes = body.getChildren();
List<String> alts = new ArrayList<String>();
for (ASTNode altNode : altNodes) {
if (altNode instanceof SimpleExpr) {
SimpleExpr alt = (SimpleExpr) altNode;
String str = alt.getValue().getText();
alts.add(str);
}
}
return alts;
}
private T walkHeader(HeaderSection headerSection, GymnastSwitch<T> v) {
String languageName = headerSection.getName().getText();
Map<String, String> resOptions = new HashMap<String, String>();
if (headerSection.getOptionsSection() != null) {
ASTNode[] opts = headerSection.getOptionsSection().getOptionList().getChildren();
for (ASTNode child : opts) {
if (child instanceof Option) {
Option opt = (Option) child;
String optName = opt.getName().getText();
String optValue = opt.getValue().getText();
/*
* FIXME only the last of a set of duplicate options is
* kept, the others are overwritten silently
*/
resOptions.put(optName, optValue);
}
}
}
return v.handleHeader(headerSection, languageName, resOptions);
}
}