refactored grammar and xtext metamodel

This commit is contained in:
sefftinge 2008-08-15 10:02:37 +00:00
parent 70bcdef81a
commit c9fc5d9a4b
18 changed files with 202 additions and 238 deletions

View file

@ -33,10 +33,10 @@ public class Files {
for (String file : files) {
File copy = new File(target.getAbsolutePath() + File.separatorChar + file);
if (!copy.exists()) {
String uri = sourceDir + "/" + file;
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
InputStream is = contextClassLoader.getResourceAsStream(uri);
try {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
String uri = sourceDir + "/" + file;
InputStream is = contextClassLoader.getResourceAsStream(uri);
copy.createNewFile();
FileOutputStream fwr = new FileOutputStream(copy);
byte[] buff = new byte[1024];
@ -45,9 +45,14 @@ public class Files {
fwr.write(buff, 0, read);
}
log.debug("Copied " + copy);
}
catch (IOException e) {
} catch (IOException e) {
log.error(e);
} finally {
try {
is.close();
} catch (IOException e) {
log.error(e);
}
}
}
}
@ -63,8 +68,7 @@ public class Files {
final File file = contents[j];
if (file.isDirectory()) {
cleanFolder(file);
}
else {
} else {
if (!file.delete()) {
log.error("Couldn't delete " + file.getAbsolutePath());
}

View file

@ -152,7 +152,7 @@ public class GrammarUtil {
String id = getSuperGrammarId(_this);
if (id == null)
return null;
if (!(_this.eResource() != null && _this.eResource().getResourceSet() instanceof XtextResourceSet))
if (!(_this.eResource() != null && _this.eResource().getResourceSet() !=null))
throw new IllegalArgumentException("The passed grammar is not contained in a Resourceset");
ResourceSet resourceSet = _this.eResource().getResourceSet();
URI uri = getClasspathURIForLanguageId(id);
@ -191,51 +191,31 @@ public class GrammarUtil {
public static List<AbstractRule> allRules(Grammar _this) {
List<AbstractRule> result = new ArrayList<AbstractRule>();
result.addAll(allParserRules(_this));
result.addAll(allLexerRules(_this));
Set<String> names = new HashSet<String>();
for (AbstractRule rule : _this.getRules()) {
if (names.add(rule.getName())) {
result.add(rule);
}
}
Grammar superGrammar = getSuperGrammar(_this);
if (superGrammar != null) {
List<AbstractRule> superParserRules = allRules(superGrammar);
for (AbstractRule r : superParserRules) {
if (names.add(r.getName())) {
result.add(r);
}
}
}
return result;
}
public static List<ParserRule> allParserRules(Grammar _this) {
List<ParserRule> result = new ArrayList<ParserRule>();
Set<String> names = new HashSet<String>();
for (ParserRule rule : _this.getParserRules()) {
if (names.add(rule.getName())) {
result.add(rule);
}
}
Grammar superGrammar = getSuperGrammar(_this);
if (superGrammar != null) {
List<ParserRule> superParserRules = allParserRules(superGrammar);
for (ParserRule r : superParserRules) {
if (names.add(r.getName())) {
result.add(r);
}
}
}
return result;
return EcoreUtil2.typeSelect(allRules(_this), ParserRule.class);
}
public static List<LexerRule> allLexerRules(Grammar _this) {
List<LexerRule> result = new ArrayList<LexerRule>();
Set<String> names = new HashSet<String>();
for (LexerRule rule : _this.getLexerRules()) {
if (names.add(rule.getName())) {
result.add(rule);
}
}
Grammar superGrammar = getSuperGrammar(_this);
if (superGrammar != null) {
List<LexerRule> superParserRules = allLexerRules(superGrammar);
for (LexerRule r : superParserRules) {
if (names.add(r.getName())) {
result.add(r);
}
}
}
return result;
return EcoreUtil2.typeSelect(allRules(_this), LexerRule.class);
}
public static List<AbstractMetamodelDeclaration> allMetamodelDeclarations(Grammar _this) {

View file

@ -9,12 +9,10 @@ language org.eclipse.xtext.Xtext
generate xtext "http://www.eclipse.org/2008/Xtext"
Grammar :
Grammar :
(abstract?='abstract language' | 'language') idElements+=ID ('.' idElements+=ID)* ('extends' superGrammarIdElements+=ID ('.' superGrammarIdElements+=ID)*)?
metamodelDeclarations+=AbstractMetamodelDeclaration*
parserRules+=ParserRule*
('lexing' ':'
lexerRules+=LexerRule+)?
(rules+=AbstractRule)+
;
AbstractRule : LexerRule | ParserRule;
@ -29,7 +27,7 @@ ReferencedMetamodel :
'import' uri=STRING ('as' alias=ID)?;
LexerRule :
name=ID ('returns' type=TypeRef)? ':'
('native'|'lexer') name=ID ('returns' type=TypeRef)? ':'
body=STRING ';'
;

View file

@ -14,6 +14,7 @@ import xtext;
import xtextutil;
extension org::eclipse::xtext::Extensions;
extension org::eclipse::xtext::GrammarUtil;
/*
context Action ERROR "Created class " + typeName.name + " cannot be resolved" :
@ -24,8 +25,8 @@ context Action if resolveCreatedType() != null ERROR "Created class does not inh
|| ((EClass) containingParserRule().resolveReturnType().eClassifier).isSuperTypeOf((EClass) resolveCreatedType().eClassifier);
*/
context Assignment ERROR "Assigned token must be a keyword or a rule call" :
Keyword.isInstance(terminal) || RuleCall.isInstance(terminal);
context RuleCall ERROR "Couldn't resolve called rule "+name :
calledRule()!=null;
context GeneratedMetamodel ERROR "Only one generated metamodel can have default alias" :
alias != null
@ -38,8 +39,8 @@ context GeneratedMetamodel ERROR "Duplicate aliases are only allowed for referen
context Group ERROR "Group cannot contain more than one action" :
eAllContents.typeSelect(Action).size <= 1;
context ParserRule ERROR "Name mut be unique" :
grammar().parserRules.select(p | p.name == name).size==1;
context AbstractRule ERROR "Name must be unique" :
grammar().rules.select(p | p.name == name).size==1;
/*
context ParserRule ERROR "Returned class " + getReturnTypeName() + " cannot be resolved" :

View file

@ -68,7 +68,7 @@ private setAbstractFeature(Grammar this, List[MetaModel] x) :
private cached Boolean isAbstract(ComplexType name, Grammar g) :
g.eAllContents.typeSelect(Action).select(e|e.typeName.getQualifiedName() == name.getQualifiedName()).isEmpty &&
g.eAllContents.typeSelect(Assignment).select(e|(e.currentType(g).getQualifiedName()) == (name.getQualifiedName())).isEmpty
g.eAllContents.typeSelect(Assignment).select(e|(if e.currentType(g)==null then info(e)) -> (e.currentType(g).getQualifiedName()) == (name.getQualifiedName())).isEmpty
;

View file

@ -7,14 +7,14 @@
<idElements>builtin</idElements>
<idElements>XtextBuiltin</idElements>
<metamodelDeclarations xsi:type="xtext:ReferencedMetamodel" alias="ecore" uri="http://www.eclipse.org/emf/2002/Ecore"/>
<lexerRules name="ID" body="('^')?('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*"/>
<lexerRules name="INT" body="('0'..'9')+">
<rules xsi:type="xtext:LexerRule" name="ID" body="('^')?('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*"/>
<rules xsi:type="xtext:LexerRule" name="INT" body="('0'..'9')+">
<type alias="ecore" name="EInt"/>
</lexerRules>
<lexerRules name="STRING" body="'&quot;' ( '\\' ('b'|'t'|'n'|'f'|'r'|'\&quot;'|'\''|'\\') | ~('\\'|'&quot;') )* '&quot;' |
</rules>
<rules xsi:type="xtext:LexerRule" name="STRING" body="'&quot;' ( '\\' ('b'|'t'|'n'|'f'|'r'|'\&quot;'|'\''|'\\') | ~('\\'|'&quot;') )* '&quot;' |
'\'' ( '\\' ('b'|'t'|'n'|'f'|'r'|'\&quot;'|'\''|'\\') | ~('\\'|'\'') )* '\''"/>
<lexerRules name="ML_COMMENT" body="'/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}"/>
<lexerRules name="SL_COMMENT" body="'//' ~('\n'|'\r')* ('\r'? '\n')? {$channel=HIDDEN;}"/>
<lexerRules name="WS" body="(' '|'\t'|'\r'|'\n')+ {$channel=HIDDEN;}"/>
<lexerRules name="ANY_OTHER" body="."/>
<rules xsi:type="xtext:LexerRule" name="ML_COMMENT" body="'/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}"/>
<rules xsi:type="xtext:LexerRule" name="SL_COMMENT" body="'//' ~('\n'|'\r')* ('\r'? '\n')? {$channel=HIDDEN;}"/>
<rules xsi:type="xtext:LexerRule" name="WS" body="(' '|'\t'|'\r'|'\n')+ {$channel=HIDDEN;}"/>
<rules xsi:type="xtext:LexerRule" name="ANY_OTHER" body="."/>
</xtext:Grammar>

View file

@ -3,18 +3,17 @@ abstract language org.eclipse.xtext.builtin.XtextBuiltIn_Temp
import "http://www.eclipse.org/emf/2002/Ecore" as ecore;
lexing:
ID : "('^')?('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*";
INT returns ecore::EInt
lexer ID : "('^')?('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*";
lexer INT returns ecore::EInt
: "('0'..'9')+";
STRING : "
lexer STRING : "
'\"' ( '\\\\' ('b'|'t'|'n'|'f'|'r'|'\\\"'|'\\''|'\\\\') | ~('\\\\'|'\"') )* '\"' |
'\\'' ( '\\\\' ('b'|'t'|'n'|'f'|'r'|'\\\"'|'\\''|'\\\\') | ~('\\\\'|'\\'') )* '\\''
";
ML_COMMENT : "'/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}";
SL_COMMENT : "'//' ~('\\n'|'\\r')* '\\r'? '\\n' {$channel=HIDDEN;}";
lexer ML_COMMENT : "'/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}";
lexer SL_COMMENT : "'//' ~('\\n'|'\\r')* '\\r'? '\\n' {$channel=HIDDEN;}";
WS : "(' '|'\\t'|'\\r'|'\\n')+ {$channel=HIDDEN;}";
lexer WS : "(' '|'\\t'|'\\r'|'\\n')+ {$channel=HIDDEN;}";
ANY_OTHER : ".";
lexer ANY_OTHER : ".";

View file

@ -46,9 +46,12 @@ public class GenericEcoreElementFactory implements IAstFactory {
public EObject create(String fullTypeName) {
EClass clazz = getEClass(fullTypeName);
if (clazz != null && !(clazz.isAbstract() || clazz.isInterface()))
return clazz.getEPackage().getEFactoryInstance().create(clazz);
return null;
if (clazz == null)
throw new IllegalArgumentException("Coudln't find EClass for name " + fullTypeName);
if (clazz.isAbstract() || clazz.isInterface())
throw new IllegalArgumentException("Can't create instance of abstract type " + fullTypeName);
return clazz.getEPackage().getEFactoryInstance().create(clazz);
}
@Deprecated
@ -103,10 +106,10 @@ public class GenericEcoreElementFactory implements IAstFactory {
if (decl.getAlias() == null && alias == null || decl.getAlias() != null && decl.getAlias().equals(alias)) {
if (decl instanceof GeneratedMetamodel) {
GeneratedMetamodel mm = (GeneratedMetamodel) decl;
return EcoreUtil2.loadEPackage(mm.getNsURI(),grammarAccess.getClass().getClassLoader());
return EcoreUtil2.loadEPackage(mm.getNsURI(), grammarAccess.getClass().getClassLoader());
} else {
ReferencedMetamodel mm = (ReferencedMetamodel) decl;
return EcoreUtil2.loadEPackage(mm.getUri(),grammarAccess.getClass().getClassLoader());
return EcoreUtil2.loadEPackage(mm.getUri(), grammarAccess.getClass().getClassLoader());
}
}
}

View file

@ -70,13 +70,16 @@ public abstract class AbstractAntlrParser extends Parser {
}
protected void associateNodeWithAstElement(CompositeNode node, EObject astElement) {
if (astElement == null)
throw new NullPointerException("passed astElement was null");
if (node == null)
throw new NullPointerException("passed node was null");
if (node.getElement() != null && node.getElement() != astElement) {
throw new ParseException("Reassignment of astElement in parse tree node");
}
node.setElement(astElement);
if (astElement instanceof EObject) {
EObject eObject = (EObject) astElement;
NodeAdapter adapter = (NodeAdapter) NodeAdapterFactory.INSTANCE.adapt(eObject, AbstractNode.class);
if (node.getElement() != astElement) {
node.setElement(astElement);
NodeAdapter adapter = (NodeAdapter) NodeAdapterFactory.INSTANCE.adapt(astElement, AbstractNode.class);
adapter.setParserNode(node);
}
}
@ -103,7 +106,8 @@ public abstract class AbstractAntlrParser extends Parser {
}
private EObject getGrammarElement(String grammarElementID) {
URI resolved = new ClassloaderClasspathUriResolver().resolve(getClass().getClassLoader(),URI.createURI(grammarElementID));
URI resolved = new ClassloaderClasspathUriResolver().resolve(getClass().getClassLoader(), URI
.createURI(grammarElementID));
return grammar.eResource().getResourceSet().getEObject(resolved, true);
}
@ -111,9 +115,10 @@ public abstract class AbstractAntlrParser extends Parser {
public Map<Integer, String> getTokenTypeMap() {
if (antlrTypeToLexerName == null) {
InputStream tokenFile = getTokenFile();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(tokenFile));
antlrTypeToLexerName = new HashMap<Integer, String>();
BufferedReader br = new BufferedReader(new InputStreamReader(getTokenFile()));
String line = br.readLine();
Pattern pattern = Pattern.compile("(.*)=(\\d+)");
while (line != null) {
@ -129,10 +134,15 @@ public abstract class AbstractAntlrParser extends Parser {
antlrTypeToLexerName.put(Integer.parseInt(tokenTypeId), token.substring(prefix.length()));
line = br.readLine();
}
}
catch (IOException e) {
} catch (IOException e) {
log.error(e);
throw new WrappedException(e);
} finally {
try {
tokenFile.close();
} catch (IOException e) {
throw new WrappedException(e);
}
}
}
return antlrTypeToLexerName;
@ -190,8 +200,7 @@ public abstract class AbstractAntlrParser extends Parser {
EList<LeafNode> leafNodes = currentNode.getLeafNodes();
if (leafNodes.isEmpty()) {
appendError(currentNode);
}
else {
} else {
appendError(leafNodes.get(leafNodes.size() - 1));
}
}
@ -266,8 +275,7 @@ public abstract class AbstractAntlrParser extends Parser {
try {
Method method = this.getClass().getMethod(antlrEntryRuleName);
current = (EObject) method.invoke(this);
}
catch (InvocationTargetException ite) {
} catch (InvocationTargetException ite) {
Throwable targetException = ite.getTargetException();
if (targetException instanceof RecognitionException) {
throw (RecognitionException) targetException;
@ -276,17 +284,14 @@ public abstract class AbstractAntlrParser extends Parser {
throw new WrappedException((Exception) targetException);
}
throw new RuntimeException(targetException);
}
catch (Exception e) {
} catch (Exception e) {
throw new WrappedException(e);
}
appendTrailingHiddenTokens();
}
finally {
} finally {
try {
appendAllTokens();
}
finally {
} finally {
result = new ParseResult(current, currentNode);
}
}
@ -298,12 +303,10 @@ public abstract class AbstractAntlrParser extends Parser {
if (!entryRuleName.startsWith("entryRule")) {
if (!entryRuleName.startsWith("rule")) {
antlrEntryRuleName = "entryRule" + entryRuleName;
}
else {
} else {
antlrEntryRuleName = "entry" + Strings.toFirstUpper(entryRuleName);
}
}
else {
} else {
antlrEntryRuleName = entryRuleName;
}
return antlrEntryRuleName;
@ -331,8 +334,7 @@ public abstract class AbstractAntlrParser extends Parser {
LeafNode leafNode = token2NodeMap.get(lookaheadToken);
if (leafNode == null) {
deferredLookaheadMap.put(lookaheadToken, currentNode);
}
else {
} else {
currentNode.getLookaheadLeafNodes().add(leafNode);
}
}
@ -379,9 +381,7 @@ public abstract class AbstractAntlrParser extends Parser {
}
}
protected InputStream getTokenFile() {
return null;
}
protected abstract InputStream getTokenFile();
/**
* @return

View file

@ -8,24 +8,16 @@
*******************************************************************************/
package org.eclipse.xtext.parsetree;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.Assert;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.Alternatives;
import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.Grammar;
import org.eclipse.xtext.Group;
import org.eclipse.xtext.ParserRule;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.parsetree.AbstractNode;
import org.eclipse.xtext.parsetree.CompositeNode;
import org.eclipse.xtext.parsetree.LeafNode;
/**
*
@ -162,32 +154,32 @@ public final class ParseTreeUtil {
}
}
/**
*
* Returns a list of all assignment to the given rule.
*
* @param parserRule
* the rule of the assignments (ruleCall) to match
* @return a list containing all {@see org.eclipse.xtext.Assignment} to the
* given rule.
*/
public static final List<AbstractElement> getParserRuleAssignments(ParserRule parserRule) {
assertParameterNotNull(parserRule, "parserRule");
List<AbstractElement> list = new ArrayList<AbstractElement>();
Grammar grammar = (Grammar) parserRule.eContainer();
// filter and search
for (ParserRule rule : grammar.getParserRules()) {
// excluded?
if (!parserRule.equals(rule)) {
Assignment ruleAssignment = getParserRuleAssignment(rule.getAlternatives(), parserRule);
if (ruleAssignment != null) {
list.add(ruleAssignment);
}
}
}
return list;
}
//
// /**
// *
// * Returns a list of all assignment to the given rule.
// *
// * @param parserRule
// * the rule of the assignments (ruleCall) to match
// * @return a list containing all {@see org.eclipse.xtext.Assignment} to the
// * given rule.
// */
// public static final List<AbstractElement> getParserRuleAssignments(ParserRule parserRule) {
// assertParameterNotNull(parserRule, "parserRule");
// List<AbstractElement> list = new ArrayList<AbstractElement>();
// Grammar grammar = (Grammar) parserRule.eContainer();
// // filter and search
// for (ParserRule rule : GrammarUtil.allParserRules(grammar)) {
// // excluded?
// if (!parserRule.equals(rule)) {
// Assignment ruleAssignment = getParserRuleAssignment(rule.getAlternatives(), parserRule);
// if (ruleAssignment != null) {
// list.add(ruleAssignment);
// }
// }
// }
// return list;
// }
/**
* asserts if the given parameter object isnt null
@ -225,48 +217,48 @@ public final class ParseTreeUtil {
return abstractElement;
}
/**
*
* @param contextElement
* element searched for assignments to the given rule
* @param parserRule
* the rule of the assignments to search for
* @return an assignment object containing a rulecall to the given
* parserRule or null if not found.
*/
private static final Assignment getParserRuleAssignment(AbstractElement contextElement, ParserRule parserRule) {
assertParameterNotNull(contextElement, "contextElement");
assertParameterNotNull(parserRule, "parserRule");
Assignment assignment = null;
if (contextElement instanceof Group) {
Group group = (Group) contextElement;
for (AbstractElement groupElement : group.getAbstractTokens()) {
assignment = getParserRuleAssignment(groupElement, parserRule);
if (null != assignment) {
break;
}
}
}
else if (contextElement instanceof Alternatives) {
Alternatives alternatives = (Alternatives) contextElement;
for (AbstractElement groupElement : alternatives.getGroups()) {
assignment = getParserRuleAssignment(groupElement, parserRule);
if (null != assignment) {
break;
}
}
}
else if (contextElement instanceof Assignment) {
Assignment assignmentToMatch = (Assignment) contextElement;
if (assignmentToMatch.getTerminal() instanceof RuleCall
&& ((RuleCall) assignmentToMatch.getTerminal()).getName().equalsIgnoreCase(parserRule.getName())) {
assignment = assignmentToMatch;
}
}
return assignment;
}
// /**
// *
// * @param contextElement
// * element searched for assignments to the given rule
// * @param parserRule
// * the rule of the assignments to search for
// * @return an assignment object containing a rulecall to the given
// * parserRule or null if not found.
// */
// private static final Assignment getParserRuleAssignment(AbstractElement contextElement, ParserRule parserRule) {
//
// assertParameterNotNull(contextElement, "contextElement");
// assertParameterNotNull(parserRule, "parserRule");
//
// Assignment assignment = null;
// if (contextElement instanceof Group) {
// Group group = (Group) contextElement;
// for (AbstractElement groupElement : group.getAbstractTokens()) {
// assignment = getParserRuleAssignment(groupElement, parserRule);
// if (null != assignment) {
// break;
// }
// }
// }
// else if (contextElement instanceof Alternatives) {
// Alternatives alternatives = (Alternatives) contextElement;
// for (AbstractElement groupElement : alternatives.getGroups()) {
// assignment = getParserRuleAssignment(groupElement, parserRule);
// if (null != assignment) {
// break;
// }
// }
// }
// else if (contextElement instanceof Assignment) {
// Assignment assignmentToMatch = (Assignment) contextElement;
// if (assignmentToMatch.getTerminal() instanceof RuleCall
// && ((RuleCall) assignmentToMatch.getTerminal()).getName().equalsIgnoreCase(parserRule.getName())) {
// assignment = assignmentToMatch;
// }
// }
// return assignment;
// }
/**
* @param abstractNode

View file

@ -18,23 +18,22 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.conversion.IValueConverterService;
import org.eclipse.xtext.crossref.BrokenLink;
import org.eclipse.xtext.crossref.IFragmentProvider;
import org.eclipse.xtext.crossref.ILinker;
import org.eclipse.xtext.parser.IAstFactory;
import org.eclipse.xtext.parser.IParseResult;
import org.eclipse.xtext.parser.IParser;
import org.eclipse.xtext.parsetree.AbstractNode;
import org.eclipse.xtext.parsetree.CompositeNode;
import org.eclipse.xtext.parsetree.NodeAdapter;
import org.eclipse.xtext.parsetree.NodeContentAdapter;
import org.eclipse.xtext.parsetree.reconstr.IParseTreeConstructor;
import org.eclipse.xtext.parsetree.reconstr.callbacks.WhitespacePreservingCallback;
import org.eclipse.xtext.service.Inject;
/**
@ -54,6 +53,12 @@ public class XtextResource extends ResourceImpl {
@Inject
private IFragmentProvider fragmentProvider;
@Inject
private IParseTreeConstructor parseTreeConstructor;
@Inject
private IValueConverterService valueConverterService;
private Log log = LogFactory.getLog(getClass());
@ -146,23 +151,10 @@ public class XtextResource extends ResourceImpl {
}
if (!contents.isEmpty()) {
EObject rootElement = contents.get(0);
NodeAdapter rootNodeAdapter = getNodeAdapter(rootElement);
if (rootNodeAdapter != null) {
CompositeNode rootNode = rootNodeAdapter.getParserNode();
String serialize = rootNode.serialize();
outputStream.write(serialize.getBytes());
}
WhitespacePreservingCallback cb = new WhitespacePreservingCallback(valueConverterService);
parseTreeConstructor.update(rootElement, cb);
outputStream.write(cb.toString().getBytes());
}
}
private NodeAdapter getNodeAdapter(EObject object) {
EList<Adapter> adapters = object.eAdapters();
for (Adapter adapter : adapters) {
if (adapter.isAdapterForType(AbstractNode.class)) {
return (NodeAdapter) adapter;
}
}
return null;
}
}

View file

@ -26,8 +26,8 @@ public class XtextGrammarTest extends AbstractGeneratorTest {
public void testInstantiate() throws Exception {
EObject grammar = (EObject) getModel("language foo generate foo 'bar' Foo : name=ID;");
assertWithXtend("'Foo'","parserRules.first().name",grammar);
assertWithXtend("'name'","parserRules.first().alternatives.feature",grammar);
assertWithXtend("'Foo'","rules.first().name",grammar);
assertWithXtend("'name'","rules.first().alternatives.feature",grammar);
}
}

View file

@ -11,11 +11,9 @@ language org.eclipse.xtext.XtextGrammarTest
generate XtextTest "http://www.eclipse.org/2008/Test/XtextTest"
Grammar :
((abstract?='abstract language' | 'language') idElements+=ID ('.' idElements+=ID)* ('extends' superGrammarIdElements+=ID ('.' superGrammarIdElements+=ID)*)?)?
(abstract?='abstract language' | 'language') idElements+=ID ('.' idElements+=ID)* ('extends' superGrammarIdElements+=ID ('.' superGrammarIdElements+=ID)*)?
metamodelDeclarations+=AbstractMetamodelDeclaration*
parserRules+=ParserRule*
('lexing' ':'
lexerRules+=LexerRule+)?
(rules+=AbstractRule)+
;
AbstractRule : LexerRule | ParserRule;
@ -29,9 +27,9 @@ GeneratedMetamodel :
ReferencedMetamodel :
'import' uri=STRING ('as' alias=ID)?;
LexerRule :
name=ID ('returns' type=TypeRef)? ':'
body=STRING
LexerRule :
('native'|'lexer') name=ID ('returns' type=TypeRef)? ':'
body=STRING ';'
;
ParserRule :
@ -43,6 +41,7 @@ ParserRule :
TypeRef :
(alias=ID '::')? name=ID
;
Alternatives returns AbstractElement:
Group ({Alternatives.groups+=current} '|' groups+=Group)*
;
@ -54,16 +53,20 @@ Group returns AbstractElement:
AbstractToken returns AbstractElement:
(Assignment |
Action |
AbstractTerminal) cardinality=('?'|'*'|'+')?;
AbstractTerminal) (cardinality=('?'|'*'|'+'))?;
Assignment returns Assignment:
feature=ID operator=('+='|'='|'?=') terminal=AbstractTerminal;
Action returns Action:
'{' ('current' '=')? typeName=TypeRef ('.' feature=ID operator=('='|'+=') 'current')? '}';
'{' ('current' '=')? typeName=TypeRef '.' feature=ID operator=('='|'+=') 'current' '}';//TODO make assignment optional
AbstractTerminal returns AbstractElement:
Keyword | RuleCall | ParenthesizedElement
Keyword | RuleCall | ParenthesizedElement | CrossReference
;
CrossReference :
'[' type=TypeRef ('|' rule=RuleCall)? ']'
;
ParenthesizedElement returns AbstractElement:
@ -76,9 +79,4 @@ Keyword :
RuleCall :
name=ID ;
// lexing:
// Problem: LEXER_BODY kann nicht in xtxt beschrieben werden, da das erste '#>' bereits matcht
// Lösung: built-in lexer token
// LEXER_BODY : <# '<#' ( options {greedy=false;} : . )* '#>' #>

View file

@ -5,8 +5,6 @@ import "classpath:/org/eclipse/xtext/grammarinheritance/ametamodel.ecore" as mm
InheritedParserRule returns mm::AType :
'element' name=ID;
lexing:
lexer REAL returns ecore::EDouble : "RULE_INT '.' RULE_INT";
REAL returns ecore::EDouble : "RULE_INT '.' RULE_INT";
ID : "('^')?('a'..'z'|'A'..'Z'|'ö'|'ä'|'ü'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*";
lexer ID : "('^')?('a'..'z'|'A'..'Z'|'ö'|'ä'|'ü'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*";

View file

@ -27,47 +27,47 @@ public class ParseErrorHandlingTest extends AbstractGeneratorTest {
}
public void testLexError() throws Exception {
EObject root = getModel("import 'holla' % as foo");
EObject root = getModel("language a import 'holla' % as foo");
EList<SyntaxError> errors = NodeUtil.getRootNode(root).allSyntaxErrors();
assertEquals(1,errors.size());
assertEquals("%", ((LeafNode)errors.get(0).getNode()).getText());
assertEquals(1, errors.get(0).getNode().getLine());
assertEquals(15, errors.get(0).getNode().getOffset());
assertEquals(26, errors.get(0).getNode().getOffset());
assertEquals(1, errors.get(0).getNode().getLength());
assertEquals(1, errors.size());
}
public void testParseError1() throws Exception {
EObject root = getModel("import 'holla' foo returns x::y::Z : name=ID;");
EObject root = getModel("language a import 'holla' foo returns x::y::Z : name=ID;");
EList<SyntaxError> errors = NodeUtil.getRootNode(root).allSyntaxErrors();
assertEquals("::", ((LeafNode)errors.get(0).getNode()).getText());
assertEquals(1, errors.get(0).getNode().getLine());
assertEquals(31, errors.get(0).getNode().getOffset());
assertEquals(42, errors.get(0).getNode().getOffset());
assertEquals(2, errors.get(0).getNode().getLength());
assertEquals(1, errors.size());
}
public void testParseError2() throws Exception {
Object object = getModel("import 'holla' foo returns y::Z : name=ID #;");
assertWithXtend("'ID'", "parserRules.first().eAllContents.typeSelect(XtextTest::RuleCall).first().name", object);
Object object = getModel("language a import 'holla' foo returns y::Z : name=ID #;");
assertWithXtend("'ID'", "rules.first().eAllContents.typeSelect(XtextTest::RuleCall).first().name", object);
}
public void testParseError3() throws Exception {
Object object = getModel("import 'holla' foo returns y::Z : name=ID #############");
assertWithXtend("'ID'", "parserRules.first().eAllContents.typeSelect(XtextTest::RuleCall).first().name", object);
Object object = getModel("language a import 'holla' foo returns y::Z : name=ID #############");
assertWithXtend("'ID'", "rules.first().eAllContents.typeSelect(XtextTest::RuleCall).first().name", object);
}
public void testParseError4() throws Exception {
Object object = getModel("import 'holla' foo returns y::Z : name=ID # 'foo'; bar : 'stuff'");
Object object = getModel("language a import 'holla' foo returns y::Z : name=ID # 'foo'; bar : 'stuff'");
//System.out.println(errors);
assertWithXtend("'ID'", "parserRules.first().eAllContents.typeSelect(XtextTest::RuleCall).first().name", object);
assertWithXtend("null", "parserRules.first().eAllContents.typeSelect(XtextTest::Keyword).first().name", object);
assertWithXtend("'stuff'", "parserRules.get(1).eAllContents.typeSelect(XtextTest::Keyword).first().value", object);
assertWithXtend("'ID'", "rules.first().eAllContents.typeSelect(XtextTest::RuleCall).first().name", object);
assertWithXtend("null", "rules.first().eAllContents.typeSelect(XtextTest::Keyword).first().name", object);
assertWithXtend("'stuff'", "rules.get(1).eAllContents.typeSelect(XtextTest::Keyword).first().value", object);
}
public void testname() throws Exception {
String model = "import 'holla' foo returns y::Z : name=ID # 'foo'; bar : 'stuff'";
String model = "language a import 'holla' foo returns y::Z : name=ID # 'foo'; bar : 'stuff'";
for (int i=model.length();0<i;i--) {
getModel(model.substring(0, i));
}

View file

@ -15,5 +15,4 @@ Model :
Element:
name=ID h=STRING;
lexing:
STRING : " '#' ('B')+ ";
lexer STRING : " '#' ('B')+ ";

View file

@ -52,7 +52,7 @@ public class BootstrapModelTest extends AbstractGeneratorTest {
List<MetaModel> result = (List<MetaModel>) facade.call("getAllMetaModels", grammarModel);
MetaModel xtext = (MetaModel) invokeWithXtend("select(e|e.alias()==null).first()", result);
MetaModel ecore = (MetaModel) invokeWithXtend("select(e|e.alias()=='ecore').first()", result);
assertEquals(15,xtext.getTypes().size());
assertEquals(16,xtext.getTypes().size());
assertEquals(3,ecore.getTypes().size());
for(AbstractType t : xtext.getTypes()) {

View file

@ -38,7 +38,7 @@ public class XtextUtilTrafoTest extends AbstractGeneratorTest {
+ "Main : ^import+=Import* types+=Type*;"
+ "Import : 'import' uri=STRING;"
+ "Type : 'type' name=ID 'extends' ^extends=[Type];");
RuleCall rc = (RuleCall) invokeWithXtend("parserRules.first().eAllContents.typeSelect(xtext::RuleCall).first()", model);
RuleCall rc = (RuleCall) invokeWithXtend("rules.first().eAllContents.typeSelect(xtext::RuleCall).first()", model);
assertNotNull(rc);
assertWithXtend("'Main'", "testCurrentType().name", rc);
assertWithXtend("false", "testCurrentType().abstract", rc);