mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-16 00:38:56 +00:00
refactored grammar and xtext metamodel
This commit is contained in:
parent
70bcdef81a
commit
c9fc5d9a4b
18 changed files with 202 additions and 238 deletions
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 ';'
|
||||
;
|
||||
|
||||
|
|
|
@ -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" :
|
||||
|
|
|
@ -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
|
||||
;
|
||||
|
||||
|
||||
|
|
|
@ -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="'"' ( '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\') | ~('\\'|'"') )* '"' |
|
||||
</rules>
|
||||
<rules xsi:type="xtext:LexerRule" name="STRING" body="'"' ( '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\') | ~('\\'|'"') )* '"' |
|
||||
'\'' ( '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\') | ~('\\'|'\'') )* '\''"/>
|
||||
<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>
|
||||
|
|
|
@ -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 : ".";
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;} : . )* '#>' #>
|
||||
|
|
|
@ -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')*";
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -15,5 +15,4 @@ Model :
|
|||
Element:
|
||||
name=ID h=STRING;
|
||||
|
||||
lexing:
|
||||
STRING : " '#' ('B')+ ";
|
||||
lexer STRING : " '#' ('B')+ ";
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue