package com.github.javaparser.ast.expr; import com.github.javaparser.ast.visitor.GenericVisitor; import com.github.javaparser.ast.visitor.VoidVisitor; /** * A template literal is a `tick delimited section of text * in which you can preserve whitespace, * the only escaped sequence is \` * and it ends at the next undelimited tick`. * * If no extra template plugins are installed, * all template literals will act like strings in which you don't have to encode things. * * More advanced features will be embedded as configurable plugins, with features like: * * `text with $scopedReferences or ${inlineCode()} are pending` * prints java code: * "text with " + scopedReferences + " or " + (inlineCode()) + " are pending" * * `js: { dictionary: values.apply(this, []) } :js` * prints java code: * GWT.jso("dictionary", values.run()); * * // GWT.jso is a psuedocode-only method; an XApi json lib / wrapper can be provided * * `{ javaMethod(this, ()->\`an embedded template scope * which is not $resolved when the outer template is\`, $resolved`) }`, * prints java code: * javaMethod(this, ()->"an embedded template scope\n" + * "which is not " + resolved + " when the out template is", resolved) * * // could also use `java: javaMethod(...) :java`, but `{ can(Be.Shorthand,For.Java()) }` * * Element e = `<div class={this::className} />` // creates an element with classname bound to this.className * // Installing a plugin (rebind) for an assigned type of Element, * // we can use the javac compiler diagnostics to find the expected type assignment via magic method injection: * prints java code: * Element e = X_Ui.magicElement("<div class={this::className} />"); * which the javac compiler plugin transforms into: * Element e = element("div") * .className(this::getClassName, this::setClassName) * .build(); // or whatever means you want for creating elements. * * * Because the actual semantics of transforming a template into a type should be dynamic, * this will be done by implementing a TemplateParsingPlugin, * which allows you to define (or override) the handling for a given prefix + suffix of templates, * `go: fmt.Println(stringutil.Reverse("!dlroW ,olleH")) :go` // not for running in java code * or (eventually) for more complex rebinding rules, like "what type am I assigned to?", * "what kind of scope am I running in?", or "what type did you supply as a compile time literal?" * * Toy example for these features might look like: * * // Create a binding rule that templates assigned to MyClass are generated with MyGenerator: * @XApi( * bindRule = { * @BindRule( * assignedTo: MyClass.class, * generator: @Reference(MyGenerator.class) * ) * } * ) * class Test { * static final Class<Test> CLASS = Test.class; * MyClass injected = `some kind of meaningful compile-time value that might want to use $CLASS variable reference`; * } * class MyGenerator implements TemplateValueResolver<MyClass>{ * String generate(Context context, TemplateLiteralExpr template) { * TypeMirror type = context.usefulService().findCompileTimeType(template, "CLASS"); * // finds the compile-time type of Test.class * String sourceName = context.import(type); * return `new MyClass($sourceName.class)`; // why not? :-) * } * } * * // what kind of scope am I running in? * @XApi( * bindRule = { * @BindRule( * assignedTo: MyClass.class, * inScope: GlobalScope.class, * provider: NewInstanceProvider.class * ), * @BindRule( * assignedTo: MyClass.class, * inScope: RequestScope.class, * provider: FromScope.class * ) * } * ) * class Test { * * <Raw, Full extends Raw> void runTest(GlobalScope inGlobalScope, Class<Full> cls) { * MyClass global = `$cls`; // turns into new MyClass(cls) * inGlobalScope.runInScope(RequestScope.class, requestScope->{ * MyClass request = `$cls,$global`; // turns into: * // request = requestScope.newInstance(MyClass.class, new Class[]{ MyClass.class, Class.class }, global, cls); * // which is effectively a cached, request-scope instance that will either be created with these parameters, * // or if there is an onRead() method with matching parameters, then that method will be * // called whenever an existing instance is read from scope. * }); * } * * class MyClass <T> { * MyClass(Class<T> type) { * ... * } * * MyClass(MyClass parent, Class<T> type) { * this(type); * ... * } * * } * } * * * TL;DR: All this class currently does is make `tick delimited strings * valid java strings without any encoding of special characters, except for \` * that is only terminated when a final tick` appears. * * * * @author James X. Nelson (james@wetheinter.net) * Created on 3/19/16. */ public class TemplateLiteralExpr extends UiExpr { private String value; public TemplateLiteralExpr(final int beginLine, final int beginColumn, final int endLine, final int endColumn, final String value) { super(beginLine, beginColumn, endLine, endColumn); this.value = value; } @Override public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) { return v.visit(this, arg); } @Override public <A> void accept(final VoidVisitor<A> v, final A arg) { v.visit(this, arg); } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public String getValueWithoutTicks() { if (value.startsWith("`")) { return value.substring(1, value.length() -1); } return value; } public String getValueWithTicks() { if (!value.startsWith("`")) { return '`' + value + "`"; } return value; } }