11package org .metaborg .spoofax .shell .core ;
22
33import java .io .IOException ;
4- import java .util . concurrent . Callable ;
4+ import java .lang . reflect . InvocationTargetException ;
55
6+ import org .apache .commons .beanutils .MethodUtils ;
7+ import org .apache .commons .lang3 .ClassUtils ;
8+ import org .apache .commons .lang3 .reflect .ConstructorUtils ;
69import org .metaborg .core .MetaborgException ;
710import org .metaborg .core .context .IContext ;
811import org .metaborg .core .language .ILanguageImpl ;
9- import org .metaborg .meta .lang .dynsem .interpreter .IDynSemLanguageParser ;
12+ import org .metaborg .meta .lang .dynsem .interpreter .nodes . rules . RuleRegistry ;
1013import org .metaborg .meta .lang .dynsem .interpreter .nodes .rules .RuleResult ;
14+ import org .metaborg .meta .lang .dynsem .interpreter .terms .ITerm ;
15+ import org .metaborg .spoofax .core .shell .ShellFacet ;
1116import org .metaborg .spoofax .shell .core .IInterpreterLoader .InterpreterLoadException ;
1217import org .metaborg .spoofax .shell .output .AnalyzeResult ;
1318import org .metaborg .spoofax .shell .output .ParseResult ;
19+ import org .spoofax .interpreter .core .Tools ;
20+ import org .spoofax .interpreter .terms .IStrategoAppl ;
21+ import org .spoofax .interpreter .terms .IStrategoConstructor ;
1422import org .spoofax .interpreter .terms .IStrategoTerm ;
23+ import org .spoofax .jsglr .client .imploder .ImploderAttachment ;
1524import org .spoofax .terms .StrategoString ;
1625import org .spoofax .terms .TermFactory ;
1726
18- import com .oracle . truffle . api . source . Source ;
27+ import com .github . krukow . clj_lang . PersistentHashMap ;
1928import com .oracle .truffle .api .vm .PolyglotEngine ;
2029import com .oracle .truffle .api .vm .PolyglotEngine .Value ;
2130
2231/**
2332 * An {@link IEvaluationStrategy} for DynSem-based languages.
2433 */
2534public class DynSemEvaluationStrategy implements IEvaluationStrategy {
26- private IInterpreterLoader interpLoader ;
35+ private final IInterpreterLoader interpLoader ;
2736 private PolyglotEngine polyglotEngine ;
28- private NonParser nonParser ;
37+ private String shellStartSymbol ;
2938
3039 /**
3140 * Construct a new {@link DynSemEvaluationStrategy}. This does not yet load the interpreter for
3241 * the language. Rather, this is done when first invoking
3342 * {@link #evaluate(AnalyzeResult, IContext)} or {@link #evaluate(ParseResult, IContext)}.
3443 */
3544 public DynSemEvaluationStrategy () {
36- nonParser = new NonParser ();
37- interpLoader = new ClassPathInterpreterLoader (nonParser );
45+ interpLoader = new ClassPathInterpreterLoader ();
3846 }
3947
4048 @ Override
@@ -44,86 +52,82 @@ public String name() {
4452
4553 @ Override
4654 public IStrategoTerm evaluate (ParseResult parsed , IContext context ) throws MetaborgException {
47- return evaluate (parsed .unit (). input (). text (), parsed . ast ().get (), context .language ());
55+ return evaluate (parsed .ast ().get (), context .language ());
4856 }
4957
5058 @ Override
5159 public IStrategoTerm evaluate (AnalyzeResult analyzed , IContext context )
5260 throws MetaborgException {
53- return evaluate (analyzed .unit ().input ().input ().text (), analyzed .ast ().get (),
54- context .language ());
61+ return evaluate (analyzed .ast ().get (), context .language ());
5562 }
5663
57- private IStrategoTerm evaluate (String origSource , IStrategoTerm input , ILanguageImpl langImpl )
64+ private IStrategoTerm evaluate (IStrategoTerm input , ILanguageImpl langImpl )
5865 throws MetaborgException {
5966 if (uninitialized ()) {
6067 initialize (langImpl );
6168 }
62- nonParser . setCurrentTerm ( input );
63- Value eval = null ;
69+
70+ ITerm programTerm = null ;
6471 try {
65- Source source = Source .fromNamedText (origSource , Integer .toHexString (input .hashCode ()))
66- .withMimeType ("application/x-simpl" );
67- eval = polyglotEngine .eval (source );
68- } catch (IOException e ) {
69- // TODO Auto-generated catch block
70- e .printStackTrace ();
72+ programTerm = getProgramTerm (input );
73+ } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
74+ | InvocationTargetException cause ) {
75+ throw new MetaborgException ("Error constructing program term from input." , cause );
7176 }
7277
73- Value prog = polyglotEngine .findGlobalSymbol ("INIT" );
78+ IStrategoConstructor inputCtor = ((IStrategoAppl ) input ).getConstructor ();
79+ String ctorName = inputCtor .getName ();
80+ int arity = inputCtor .getArity ();
81+
82+ if (!Tools .isTermAppl (input )) {
83+ throw new MetaborgException ("Expected a StrategoAppl, but a \" "
84+ + input .getClass ().getName () + "\" was found: "
85+ + input .toString (1 ));
86+ }
87+ Value rule ;
88+ if (getSortForTerm (input ) == shellStartSymbol ) {
89+ // Look up "-shell->" rule.
90+ rule = polyglotEngine .findGlobalSymbol (RuleRegistry .makeKey ("shell" , ctorName , arity ));
91+ } else {
92+ // Look up a "-shell_init->" rule.
93+ rule = polyglotEngine .findGlobalSymbol (RuleRegistry .makeKey ("init" , ctorName , arity ));
94+ }
7495 try {
75- Callable <RuleResult > callable = new Callable <RuleResult >() {
76- @ Override
77- public RuleResult call () throws Exception {
78- return prog .execute ().as (RuleResult .class );
79- }
80- };
81- RuleResult ruleResult = callable .call ();
96+ RuleResult ruleResult = rule .execute (programTerm ).as (RuleResult .class );
8297 return new StrategoString (ruleResult .result .toString (), TermFactory .EMPTY_LIST ,
8398 IStrategoTerm .IMMUTABLE );
84- } catch (Exception e ) {
85- throw new RuntimeException (e );
99+
100+ } catch (IOException e ) {
101+ throw new MetaborgException ("Input/output error while evaluating." , e );
86102 }
87103 }
88104
89- private boolean uninitialized () {
90- return polyglotEngine == null ;
105+ @ SuppressWarnings ("unchecked" )
106+ private ITerm getProgramTerm (IStrategoTerm input ) throws ClassNotFoundException ,
107+ NoSuchMethodException , IllegalAccessException , InvocationTargetException {
108+ String termSort = getSortForTerm (input );
109+ // Get the abstract class for the sort of the term.
110+ Class <? extends ITerm > generatedTermClass = (Class <? extends ITerm >) ClassUtils
111+ .getClass (interpLoader .getTargetPackage () + ".terms.I" + termSort + "Term" );
112+ return (ITerm ) MethodUtils .invokeStaticMethod (generatedTermClass , "create" , input );
91113 }
92114
93- private void initialize (ILanguageImpl langImpl ) throws InterpreterLoadException {
94- polyglotEngine = interpLoader .loadInterpreterForLanguage (langImpl );
115+ private String getSortForTerm (IStrategoTerm input ) {
116+ ImploderAttachment termAttachment = input .getAttachment (ImploderAttachment .TYPE );
117+ if (termAttachment == null ) {
118+ return null ;
119+ }
120+ return termAttachment .getElementSort ();
95121 }
96122
97- /**
98- * An {@link IDynSemLanguageParser} which returns just the {@link IStrategoTerm} which is set by
99- * the evaluation strategy. Since Truffle only supports programs parsed directly from source
100- * code, we need this workaround to avoid having to parse source code to {@link IStrategoTerm
101- * ASTs} again. Hence this class is called a {@link NonParser "non parser"}.
102- */
103- static class NonParser implements IDynSemLanguageParser {
104- private IStrategoTerm currentTerm ;
105-
106- /**
107- * @return the current term.
108- */
109- public IStrategoTerm getCurrentTerm () {
110- return currentTerm ;
111- }
123+ private boolean uninitialized () {
124+ return polyglotEngine == null && shellStartSymbol == null ;
125+ }
112126
113- /**
114- * Sets the term to be returned the next time the parser is called through
115- * {@link PolyglotEngine#eval(Source)}.
116- *
117- * @param currentTerm
118- * the current term to set.
119- */
120- public void setCurrentTerm (IStrategoTerm currentTerm ) {
121- this .currentTerm = currentTerm ;
122- }
127+ private void initialize (ILanguageImpl langImpl ) throws InterpreterLoadException {
128+ polyglotEngine = interpLoader .loadInterpreterForLanguage (langImpl );
123129
124- @ Override
125- public IStrategoTerm parse (Source src ) {
126- return getCurrentTerm ();
127- }
130+ ShellFacet shellFacet = langImpl .facet (ShellFacet .class );
131+ shellStartSymbol = shellFacet .getShellStartSymbol ();
128132 }
129133}
0 commit comments