java - 是否可以在运行时从 Java 运行 Xbase 脚本?
问题描述
我想从我的 Java 应用程序在运行时调用一些脚本。但我想对用户隐藏内部模型。所以我的想法是使用 Xtext 编写 DSL。并添加用户在此 DSL 中编写脚本然后在应用程序中执行它的能力。
可能吗?
解决方案
没有通用的教程。这在很大程度上取决于您的规则。在您的环境等
这是一个过于简单的例子
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.xbase.Xbase
generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"
Model:
"model" name=ID "{"
expressions+=NamedExpression*
"}"
;
NamedExpression:
name=ID "=" body=XExpression
;
推断者
/*
* generated by Xtext 2.16.0-SNAPSHOT
*/
package org.xtext.example.mydsl.jvmmodel
import com.google.inject.Inject
import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer
import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor
import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder
import org.xtext.example.mydsl.myDsl.Model
/**
* <p>Infers a JVM model from the source model.</p>
*
* <p>The JVM model should contain all elements that would appear in the Java code
* which is generated from the source model. Other models link against the JVM model rather than the source model.</p>
*/
class MyDslJvmModelInferrer extends AbstractModelInferrer {
/**
* convenience API to build and initialize JVM types and their members.
*/
@Inject extension JvmTypesBuilder
/**
* The dispatch method {@code infer} is called for each instance of the
* given element's type that is contained in a resource.
*
* @param element
* the model to create one or more
* {@link org.eclipse.xtext.common.types.JvmDeclaredType declared
* types} from.
* @param acceptor
* each created
* {@link org.eclipse.xtext.common.types.JvmDeclaredType type}
* without a container should be passed to the acceptor in order
* get attached to the current resource. The acceptor's
* {@link IJvmDeclaredTypeAcceptor#accept(org.eclipse.xtext.common.types.JvmDeclaredType)
* accept(..)} method takes the constructed empty type for the
* pre-indexing phase. This one is further initialized in the
* indexing phase using the lambda you pass as the last argument.
* @param isPreIndexingPhase
* whether the method is called in a pre-indexing phase, i.e.
* when the global index is not yet fully updated. You must not
* rely on linking using the index if isPreIndexingPhase is
* <code>true</code>.
*/
def dispatch void infer(Model element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
// Here you explain how your model is mapped to Java elements, by writing the actual translation code.
// An implementation for the initial hello world example could look like this:
acceptor.accept(element.toClass("my.company.greeting."+ element.name)) [
for (x : element.expressions) {
members += x.toMethod(x.name, inferredType) [
body = x.body
]
}
]
}
}
翻译电话
package org.xtext.example.mydsl
import org.eclipse.emf.common.util.URI
import org.eclipse.emf.ecore.resource.ResourceSet
import org.eclipse.xtext.util.CancelIndicator
import org.eclipse.xtext.util.StringInputStream
import org.eclipse.xtext.xbase.interpreter.impl.DefaultEvaluationContext
import org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter
import org.xtext.example.mydsl.myDsl.Model
class Sample {
def static void main(String[] args) {
val userInput = '''
model x {
a = 1
b = 1 + 2
c = "Hello"
}
'''
val injector = new MyDslStandaloneSetup().createInjectorAndDoEMFRegistration
val resourceSet = injector.getInstance(ResourceSet)
val resource = resourceSet.createResource(URI.createURI("dummy.mydsl"))
resource.load(new StringInputStream(userInput), null)
val model = resource.contents.head as Model
val interpreter = injector.getInstance(XbaseInterpreter)
for (g : model.expressions) {
val ctx = new DefaultEvaluationContext
val result = interpreter.evaluate(g.body, ctx, CancelIndicator.NullImpl)
println(result.result)
}
}
}
您可能必须自定义解释器并另外将内容放入上下文中以使其与您的代码一起运行。
推荐阅读
- azure - LogicApps outlook.com 连接器 GetEmails 触发器 - 获取最旧的电子邮件
- timer - 在 scheduleTimer 中使用 Unresolved Identifer
- c++ - 如何向基类添加另一个初始化函数但不编辑基文件?
- c# - 如何在同一个句子中从 Datatable 中读取多个单元格值?
- python - 如何在小部件上放置文本
- c - Sscanf - 从文件中读取所有数字 - C
- python - TypeError:预期的字符串或类似字节的对象;
- c - 用于探索矩阵的递归函数的最小参数数
- java - 每个 Java 非 void 方法都必须返回值
- c - 计算后从字符串中删除“0”