Get declarations from an external source in Xtext -
i have next grammar:
model: declarations += declaration* statements += statement*; declaration: 'declare' name=id; statement: 'execute' what=[declaration];
with can write simple scripts like:
declare step_forward declare turn_right declare turn_left execute step_forward execute turn_left execute step_forward
now want java programme provides declarations, script contains execute
statements. read iglobalscopeprovider
seems right tool job, have no thought how add together info it, , how create xtext utilize it.
so, how can provide declarations external grammar?
update
my goal unclear, seek create more concrete. want maintain declarations simple java objects, instance:
list<move> declarations = arrays.aslist( new move("step_forward"), new move("turn_right"), new move("turn_left"));
and script should be:
execute step_forward execute turn_left execute step_forward
i'm not sure asking for. after thinking it, cand derive th next possible questions:
1.) want split script 2 files. file contain declarations , file b contain statements. 'what' attribute hold reference declarations of file a.
this works out of box grammar.
2.) have java source code provides class defines, illustration 'declare interface', , want 'what' attribute reference interface or classes implement interface.
updated answer should utilize xbase within language. there can define 'what' attribute references java type using xtypes rule 'jvmtypereference'. modifications have within grammar not difficult, think this:
// grammar inherits xbase grammar // instead of mutual terminals grammar grammar org.xtext.example.mydsl.mydsl org.eclipse.xtext.xbase.xbase generate mydsl "http://www.xtext.org/example/mydsl/mydsl" model: declarator=declarator? statements+=statement*; declarator: 'declare' name=id; statement: 'execute' what=jvmtypereference;
the, can refer java type (java api, linked api, user-defined types) adressing them qualified name. this: referring jvm types in xtext language. (screenshot)
you can validate whether referenced jvm type valid, e.g. implements desired interface define 1 single, optional declarator in model. referenced jvm type checked whether valid type. (screenshot)
with xbase easy infer java interface model element. utilize generated stub '...mydsl.mydsljvmmodelinferrer':
class mydsljvmmodelinferrer extends abstractmodelinferrer { @inject extension jvmtypesbuilder @inject extension typereferences def dispatch void infer(model element, ijvmdeclaredtypeacceptor acceptor, boolean ispreindexingphase) { acceptor.accept( element.declaration.tointerface('declarator.' + element.declaration.name) [ members += it.tomethod("execute", typesfactory.einstance.createjvmvoid.createtyperef)[] ]) } }
it derives single interface, named individually 1 method 'execute()'.
then, implement static checks this, should utilize generated stub '...mydsl.validation.mydslvalidator' in illustration quick , dirty, should thought of it:
class mydslvalidator extends abstractmydslvalidator { @check def checkreferredtype(statement s) { val declarator = (s.econtainer model).declaration.name (st : (s.what.type jvmdeclaredtype).supertypes) { if (st.qualifiedname.equals('declarator.' + declarator)) { homecoming } } (s.what.simplename + " doesn't implement declarator interface " + declarator). warning(mydslpackage.einstance.statement_what) } }
(i used preferred xtend programming language implement static checking!) static check determines if given jvmtypereference (which java class project) implements declared interface. otherwise introduce warning dsl document.
hopefully reply question.
next update: thought not work well! write template xtend without using xbase, cannot imagine how utilize in way. problem is, assume, don't generate hole class 'move' , hole execution process. have played around little bit trying generate usable code , seems hacky! neverthess, here solution:
xtext generated stub '...mydsl.generator.mydslgenerator' method 'void dogenerate'. have fill method. thought following: first, generate abstract , generic executor class 2 generic parameters t , u. executor class has abstract method 'executemoves()' homecoming value t. if should void utilize non-primitive 'void' class. holds list, of generic type u defined subclass of move class.
the move class generated, too, field store string. has derived. 'mydslgenerator' looks that:
class mydslgenerator implements igenerator { static var cnt = 0 override void dogenerate(resource resource, ifilesystemaccess fsa) { cnt = 0 resource.allcontents.filter(typeof(model)).foreach [ m | fsa.generatefile('mydsl/execution/move.java', generatemove) fsa.generatefile('mydsl/execution/executor' + cnt++ + '.java', m.generateexecutor) ] } def generatemove() ''' bundle mydsl.execution; public class move { protected string s; public move(string s) { this.s = s; } } ''' def generateexecutor(model m) ''' bundle mydsl.execution; import java.util.list; import java.util.arrays; /** * class executor abstract because execution has implemented somewhere else. * class executor generic because 1 not know if execution has homecoming * value. if has no homecoming value, utilize not primitive type 'void': * public class myexecutor extends executor_i<void> {...} */ public abstract class executor«cnt - 1»<t, u extends move> { @suppresswarnings("unchecked") private list<u> declarations = arrays.<u>aslist( «for statement s : m.statements» (u) new move("«s.what.name»")«if !m.statements.get(m.statements.size - 1).equals(s)»,«endif» «endfor» ); /** * method homecoming list of moves. */ public list<u> getmoves() { homecoming declarations; } /** * executor class has extended , extending class has implement * method. */ public abstract t executemoves(); }''' }
xtext
No comments:
Post a Comment