Compare commits
8 Commits
04866b4d3a
...
2b935da385
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2b935da385 | ||
![]() |
7a28b0530d | ||
![]() |
45d188d064 | ||
![]() |
bd4dee98fa | ||
![]() |
1a528465f9 | ||
![]() |
5ce934b3fe | ||
![]() |
74c5698d1b | ||
![]() |
525932668f |
9
TODO.md
9
TODO.md
@ -24,9 +24,12 @@ For example:
|
||||
- [ ] Get rid of wvc compiler dependency on di
|
||||
|
||||
## 0.1.3
|
||||
- [ ] refactor tools/gradle start scripts to use dist instead of custom bin script
|
||||
- [ ] have custom bin/* scripts which point to dist(s) for convenience
|
||||
- [ ] di bug: @Singleton toSelf() causes stack overflow
|
||||
- [ ] ~~refactor tools/gradle start scripts to use dist instead of custom bin script~~
|
||||
- [ ] ~~have custom bin/* scripts which point to dist(s) for convenience~~
|
||||
- [x] di bug: @Singleton toSelf() causes stack overflow
|
||||
- [x] wvcc bug: Nested static view classes are not seen by compiler
|
||||
- This required tweaking how the configurations are passed around. Ultimately, we should strive for less complexity
|
||||
in this regard.
|
||||
- [ ] `OutletContainer` trait or interface for components which can contain an `<Outlet />` child.
|
||||
- [ ] `Context` should have methods for simply finding an ancestor of a certain type without the need for a predicate.
|
||||
|
||||
|
@ -3,31 +3,58 @@ package groowt.util.di;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class DefaultRegistry implements Registry {
|
||||
|
||||
protected record ClassKeyBinding<T>(Class<T> key, Binding<T> binding) {}
|
||||
protected static class BindingContainer {
|
||||
|
||||
protected final Collection<ClassKeyBinding<?>> classBindings = new ArrayList<>();
|
||||
private final Map<Class<?>, Binding<?>> bindings = new HashMap<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> @Nullable Binding<T> get(Class<T> key) {
|
||||
for (final var entry : bindings.entrySet()) {
|
||||
if (entry.getKey().isAssignableFrom(key)) {
|
||||
return (Binding<T>) entry.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> void put(Class<T> key, Binding<T> binding) {
|
||||
this.bindings.put(key, binding);
|
||||
}
|
||||
|
||||
public void remove(Class<?> key) {
|
||||
this.bindings.remove(key);
|
||||
}
|
||||
|
||||
public <T> void removeIf(Class<T> key, Predicate<? super Binding<T>> filter) {
|
||||
if (filter.test(this.get(key))) {
|
||||
this.bindings.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.bindings.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected final BindingContainer bindingContainer = new BindingContainer();
|
||||
protected final Collection<RegistryExtension> extensions = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void removeBinding(Class<?> key) {
|
||||
this.classBindings.removeIf(classKeyBinding -> classKeyBinding.key().equals(key));
|
||||
this.bindingContainer.remove(key);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> void removeBindingIf(Class<T> key, Predicate<Binding<T>> filter) {
|
||||
this.classBindings.removeIf(classKeyBinding ->
|
||||
classKeyBinding.key().equals(key) && filter.test((Binding<T>) classKeyBinding.binding())
|
||||
);
|
||||
this.bindingContainer.removeIf(key, filter);
|
||||
}
|
||||
|
||||
private <E extends RegistryExtension> List<E> getAllRegistryExtensions(Class<E> extensionType) {
|
||||
@ -117,18 +144,12 @@ public class DefaultRegistry implements Registry {
|
||||
public <T> void bind(Class<T> key, Consumer<? super BindingConfigurator<T>> configure) {
|
||||
final var configurator = new SimpleBindingConfigurator<>(key);
|
||||
configure.accept(configurator);
|
||||
this.classBindings.add(new ClassKeyBinding<>(key, configurator.getBinding()));
|
||||
this.bindingContainer.put(key, configurator.getBinding());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public @Nullable <T> Binding<T> getBinding(Class<T> key) {
|
||||
for (final var classKeyBinding : this.classBindings) {
|
||||
if (key.isAssignableFrom(classKeyBinding.key())) {
|
||||
return (Binding<T>) classKeyBinding.binding();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
public <T> @Nullable Binding<T> getBinding(Class<T> key) {
|
||||
return this.bindingContainer.get(key);
|
||||
}
|
||||
|
||||
private KeyBinder<?> findKeyBinder(Class<?> keyClass) {
|
||||
@ -189,7 +210,7 @@ public class DefaultRegistry implements Registry {
|
||||
|
||||
@Override
|
||||
public void clearAllBindings() {
|
||||
this.classBindings.clear();
|
||||
this.bindingContainer.clear();
|
||||
for (final var extension : this.extensions) {
|
||||
if (extension instanceof KeyBinder<?> keyBinder) {
|
||||
keyBinder.clearAllBindings();
|
||||
|
@ -1,8 +1,9 @@
|
||||
package groowt.util.di;
|
||||
|
||||
import jakarta.inject.Provider;
|
||||
import jakarta.inject.Singleton;
|
||||
|
||||
import static groowt.util.di.BindingUtil.toSingleton;
|
||||
import static groowt.util.di.BindingUtil.toLazySingleton;
|
||||
|
||||
public final class SingletonScopeHandler implements ScopeHandler<Singleton> {
|
||||
|
||||
@ -19,12 +20,22 @@ public final class SingletonScopeHandler implements ScopeHandler<Singleton> {
|
||||
RegistryObjectFactory objectFactory
|
||||
) {
|
||||
final Binding<T> potentialBinding = this.owner.getBinding(dependencyClass);
|
||||
if (potentialBinding != null) {
|
||||
return potentialBinding;
|
||||
} else {
|
||||
this.owner.bind(dependencyClass, toSingleton(objectFactory.createInstance(dependencyClass)));
|
||||
return this.owner.getBinding(dependencyClass);
|
||||
}
|
||||
return switch (potentialBinding) {
|
||||
case ClassBinding<T>(Class<T> from, Class<? extends T> to) -> {
|
||||
this.owner.bind(from, toLazySingleton(() -> objectFactory.createInstance(to)));
|
||||
yield this.owner.getBinding(from);
|
||||
}
|
||||
case ProviderBinding<T>(Class<T> from, Provider<? extends T> provider) -> {
|
||||
this.owner.bind(from, toLazySingleton(provider::get));
|
||||
yield this.owner.getBinding(from);
|
||||
}
|
||||
case SingletonBinding<T> singletonBinding -> singletonBinding;
|
||||
case LazySingletonBinding<T> lazySingletonBinding -> lazySingletonBinding;
|
||||
case null -> {
|
||||
this.owner.bind(dependencyClass, toLazySingleton(() -> objectFactory.createInstance(dependencyClass)));
|
||||
yield this.owner.getBinding(dependencyClass);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2,6 +2,7 @@ package groowt.util.di;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.inject.Singleton;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static groowt.util.di.BindingUtil.*;
|
||||
@ -250,4 +251,25 @@ public class DefaultRegistryObjectFactoryTests {
|
||||
assertEquals("Given Greeting", g.greet());
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static final class SingletonGreeter implements Greeter {
|
||||
|
||||
@Override
|
||||
public String greet() {
|
||||
return "Hello, World!";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singletonDoesNotOverflow() {
|
||||
final var b = DefaultRegistryObjectFactory.Builder.withDefaults();
|
||||
b.configureRegistry(r -> {
|
||||
r.bind(SingletonGreeter.class, toSelf());
|
||||
});
|
||||
final var f = b.build();
|
||||
final var g = f.get(SingletonGreeter.class);
|
||||
assertEquals("Hello, World!", g.greet());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,41 +10,8 @@ public abstract class CachingComponentTemplateCompiler<U extends ComponentTempla
|
||||
|
||||
private final Map<Class<? extends ViewComponent>, ComponentTemplateCompileResult> cache = new HashMap<>();
|
||||
|
||||
// private ComponentTemplate instantiate(
|
||||
// GroovyClassLoader groovyClassLoader,
|
||||
// CompileResult compileResult
|
||||
// ) {
|
||||
// for (final var groovyClass : compileResult.otherClasses()) {
|
||||
// // Try to find it. If we can't, we need to load it via the groovy loader
|
||||
// try {
|
||||
// Class.forName(groovyClass.getName(), true, groovyClassLoader);
|
||||
// } catch (ClassNotFoundException ignored) {
|
||||
// groovyClassLoader.defineClass(groovyClass.getName(), groovyClass.getBytes());
|
||||
// } catch (LinkageError ignored) {
|
||||
// // no-op, because we already have it
|
||||
// }
|
||||
// }
|
||||
// final GroovyClass templateGroovyClass = compileResult.templateClass();
|
||||
// Class<?> templateClass;
|
||||
// // Try to find it. If we can't, we need to load it via the groovy loader
|
||||
// try {
|
||||
// templateClass = Class.forName(templateGroovyClass.getName(), true, groovyClassLoader);
|
||||
// } catch (ClassNotFoundException ignored) {
|
||||
// templateClass = groovyClassLoader.defineClass(
|
||||
// templateGroovyClass.getName(),
|
||||
// templateGroovyClass.getBytes()
|
||||
// );
|
||||
// }
|
||||
// try {
|
||||
// return (ComponentTemplate) templateClass.getConstructor().newInstance();
|
||||
// } catch (Exception e) {
|
||||
// throw new RuntimeException("Unable to instantiate ComponentTemplate " + templateClass.getName(), e);
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
public final ComponentTemplateCompileResult compile(U compileUnit)
|
||||
throws ComponentTemplateCompileException {
|
||||
public final ComponentTemplateCompileResult compile(U compileUnit) throws ComponentTemplateCompileException {
|
||||
if (this.cache.containsKey(compileUnit.getForClass())) {
|
||||
return this.cache.get(compileUnit.getForClass());
|
||||
} else {
|
||||
|
@ -4,16 +4,9 @@ import groowt.view.component.ViewComponent;
|
||||
import groowt.view.component.compiler.source.ComponentTemplateSource;
|
||||
|
||||
public interface ComponentTemplateCompileUnit {
|
||||
|
||||
String getDescriptiveName();
|
||||
Class<? extends ViewComponent> getForClass();
|
||||
String getDefaultPackageName();
|
||||
ComponentTemplateSource getSource();
|
||||
ComponentTemplateCompileResult compile(ComponentTemplateCompilerConfiguration configuration)
|
||||
throws ComponentTemplateCompileException;
|
||||
|
||||
default ComponentTemplateCompileResult compile() throws ComponentTemplateCompileException {
|
||||
return this.compile(new DefaultComponentTemplateCompilerConfiguration());
|
||||
}
|
||||
|
||||
ComponentTemplateCompileResult compile() throws ComponentTemplateCompileException;
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
package groowt.view.component.compiler;
|
||||
|
||||
import groovy.lang.GroovyClassLoader;
|
||||
import org.codehaus.groovy.control.CompilePhase;
|
||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||
|
||||
public interface ComponentTemplateCompilerConfiguration {
|
||||
GroovyClassLoader getGroovyClassLoader();
|
||||
CompilerConfiguration getGroovyCompilerConfiguration();
|
||||
CompilePhase getToCompilePhase();
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package groowt.view.component.compiler;
|
||||
|
||||
import groovy.lang.GroovyClassLoader;
|
||||
import org.codehaus.groovy.control.CompilePhase;
|
||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class DefaultComponentTemplateCompilerConfiguration implements ComponentTemplateCompilerConfiguration {
|
||||
|
||||
private GroovyClassLoader groovyClassLoader;
|
||||
private CompilerConfiguration groovyCompilerConfiguration;
|
||||
private CompilePhase toCompilePhase;
|
||||
|
||||
public DefaultComponentTemplateCompilerConfiguration() {
|
||||
this.groovyClassLoader = new GroovyClassLoader(Thread.currentThread().getContextClassLoader());
|
||||
this.groovyCompilerConfiguration = new CompilerConfiguration();
|
||||
this.toCompilePhase = CompilePhase.CLASS_GENERATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroovyClassLoader getGroovyClassLoader() {
|
||||
return this.groovyClassLoader;
|
||||
}
|
||||
|
||||
public void setGroovyClassLoader(GroovyClassLoader groovyClassLoader) {
|
||||
this.groovyClassLoader = requireNonNull(groovyClassLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompilerConfiguration getGroovyCompilerConfiguration() {
|
||||
return this.groovyCompilerConfiguration;
|
||||
}
|
||||
|
||||
public void setGroovyCompilerConfiguration(CompilerConfiguration groovyCompilerConfiguration) {
|
||||
this.groovyCompilerConfiguration = requireNonNull(groovyCompilerConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompilePhase getToCompilePhase() {
|
||||
return this.toCompilePhase;
|
||||
}
|
||||
|
||||
public void setToCompilePhase(CompilePhase toCompilePhase) {
|
||||
this.toCompilePhase = requireNonNull(toCompilePhase);
|
||||
}
|
||||
|
||||
}
|
@ -199,7 +199,9 @@ tasks.register('uberJar', Jar) {
|
||||
group 'groovyc'
|
||||
archiveBaseName = 'web-view-components-uber'
|
||||
from sourceSets.main.output
|
||||
from sourceSets.main.runtimeClasspath.filter(File.&exists).collect { it.isDirectory() ? it : zipTree(it) }
|
||||
from sourceSets.main.runtimeClasspath
|
||||
.filter(File.&exists)
|
||||
.collect { it.isDirectory() ? it : zipTree(it) }
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
}
|
||||
|
||||
|
@ -4,14 +4,15 @@ if [ "$1" == "--debug" ]; then
|
||||
shift
|
||||
gradle -q uberJar && \
|
||||
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:8192 \
|
||||
-cp build/libs/web-view-components-uber-0.1.0.jar \
|
||||
-cp build/libs/web-view-components-uber-0.1.2.jar \
|
||||
org.codehaus.groovy.tools.FileSystemCompiler \
|
||||
--configscript src/main/resources/groowt/view/component/web/groovyc/groovycConfigurationScript.groovy \
|
||||
-d groovyc-out \
|
||||
"$@"
|
||||
else
|
||||
gradle -q uberJar && \
|
||||
groovyc -cp build/libs/web-view-components-uber-0.1.0.jar \
|
||||
java -cp build/libs/web-view-components-uber-0.1.2.jar \
|
||||
org.codehaus.groovy.tools.FileSystemCompiler \
|
||||
--configscript src/main/resources/groowt/view/component/web/groovyc/groovycConfigurationScript.groovy \
|
||||
-d groovyc-out \
|
||||
"$@"
|
||||
|
@ -0,0 +1 @@
|
||||
<Echo>Hello, World!</Echo>
|
@ -4,7 +4,6 @@ import groowt.view.component.compiler.*;
|
||||
import groowt.view.component.web.WebViewComponentBugError;
|
||||
import groowt.view.component.web.ast.node.CompilationUnitNode;
|
||||
import groowt.view.component.web.transpile.DefaultGroovyTranspiler;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
import org.codehaus.groovy.control.CompilationFailedException;
|
||||
import org.codehaus.groovy.control.SourceUnit;
|
||||
import org.codehaus.groovy.tools.GroovyClass;
|
||||
@ -16,25 +15,12 @@ public class DefaultWebViewComponentTemplateCompiler
|
||||
extends CachingComponentTemplateCompiler<WebViewComponentTemplateCompileUnit>
|
||||
implements WebViewComponentTemplateCompiler {
|
||||
|
||||
private final ComponentTemplateCompilerConfiguration configuration;
|
||||
private final WebViewComponentTemplateCompilerConfiguration configuration;
|
||||
|
||||
public DefaultWebViewComponentTemplateCompiler(ComponentTemplateCompilerConfiguration configuration) {
|
||||
public DefaultWebViewComponentTemplateCompiler(WebViewComponentTemplateCompilerConfiguration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
protected WebViewComponentTemplateCompileException getException(
|
||||
WebViewComponentTemplateCompileUnit compileUnit,
|
||||
ParserRuleContext parserRuleContext
|
||||
) {
|
||||
final var exception = new WebViewComponentTemplateCompileException(
|
||||
compileUnit,
|
||||
"Parser error: " + parserRuleContext.exception.getMessage(),
|
||||
parserRuleContext.exception
|
||||
);
|
||||
exception.setParserRuleContext(parserRuleContext);
|
||||
return exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ComponentTemplateCompileResult doCompile(WebViewComponentTemplateCompileUnit compileUnit)
|
||||
throws ComponentTemplateCompileException {
|
||||
@ -49,22 +35,12 @@ public class DefaultWebViewComponentTemplateCompiler
|
||||
: "AnonymousWebViewComponent" + System.nanoTime();
|
||||
final var templateClassSimpleName = ownerComponentName + "Template";
|
||||
|
||||
final SourceUnit sourceUnit = transpiler.transpile(
|
||||
this.configuration,
|
||||
compileUnit,
|
||||
cuNode,
|
||||
templateClassSimpleName
|
||||
);
|
||||
final SourceUnit sourceUnit = transpiler.transpile(compileUnit, cuNode, templateClassSimpleName);
|
||||
compileUnit.getGroovyCompilationUnit().addSource(sourceUnit);
|
||||
|
||||
// set the groovy compile unit's class loader to the configuration's classloader.
|
||||
compileUnit.getGroovyCompilationUnit().setClassLoader(
|
||||
this.configuration.getGroovyClassLoader()
|
||||
);
|
||||
|
||||
// compile groovy
|
||||
try {
|
||||
compileUnit.getGroovyCompilationUnit().compile(this.configuration.getToCompilePhase().getPhaseNumber());
|
||||
compileUnit.getGroovyCompilationUnit().compile(this.configuration.getCompilePhase().getPhaseNumber());
|
||||
} catch (CompilationFailedException compilationFailedException) {
|
||||
throw new WebViewComponentTemplateCompileException(
|
||||
compileUnit,
|
||||
|
@ -1,11 +1,9 @@
|
||||
package groowt.view.component.web.compiler;
|
||||
|
||||
import groowt.view.component.compiler.ComponentTemplateCompilerConfiguration;
|
||||
|
||||
public class DefaultWebViewComponentTemplateCompilerFactory implements WebViewComponentTemplateCompilerFactory {
|
||||
|
||||
@Override
|
||||
public WebViewComponentTemplateCompiler create(ComponentTemplateCompilerConfiguration configuration) {
|
||||
public WebViewComponentTemplateCompiler create(WebViewComponentTemplateCompilerConfiguration configuration) {
|
||||
return new DefaultWebViewComponentTemplateCompiler(configuration);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package groowt.view.component.web.groovyc;
|
||||
|
||||
import groowt.view.component.compiler.ComponentTemplateCompileException;
|
||||
import groowt.view.component.compiler.DefaultComponentTemplateCompilerConfiguration;
|
||||
import groowt.view.component.compiler.source.ComponentTemplateSource;
|
||||
import groowt.view.component.web.WebViewComponentBugError;
|
||||
import groowt.view.component.web.ast.node.CompilationUnitNode;
|
||||
@ -80,13 +79,12 @@ public class DelegatingWebViewComponentTemplateParserPlugin implements ParserPlu
|
||||
}
|
||||
|
||||
final var groovyTranspiler = new DefaultGroovyTranspiler();
|
||||
final String teplateClassSimpleName = sourceUnitFileName.substring(0, sourceUnitFileName.length() - 4);
|
||||
final String templateClassName = sourceUnitFileName.substring(0, sourceUnitFileName.length() - 4);
|
||||
try {
|
||||
final SourceUnit transpiledSourceUnit = groovyTranspiler.transpile(
|
||||
new DefaultComponentTemplateCompilerConfiguration(),
|
||||
compileUnit,
|
||||
cuNode,
|
||||
teplateClassSimpleName
|
||||
templateClassName
|
||||
);
|
||||
return transpiledSourceUnit.getAST();
|
||||
} catch (ComponentTemplateCompileException e) {
|
||||
|
@ -6,7 +6,6 @@ import groowt.view.component.web.WebViewComponentBugError;
|
||||
import groowt.view.component.web.ast.node.*;
|
||||
import groowt.view.component.web.transpile.groovy.GroovyUtil;
|
||||
import groowt.view.component.web.transpile.groovy.GroovyUtil.ConvertResult;
|
||||
import groowt.view.component.web.transpile.resolve.ComponentClassNodeResolver;
|
||||
import groowt.view.component.web.util.SourcePosition;
|
||||
import org.codehaus.groovy.ast.*;
|
||||
import org.codehaus.groovy.ast.expr.*;
|
||||
@ -15,7 +14,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static groowt.view.component.web.transpile.TranspilerUtil.*;
|
||||
|
||||
@ -25,13 +23,9 @@ public class DefaultComponentTranspiler implements ComponentTranspiler {
|
||||
private static final ClassNode COMPONENT_RESOLVE_EXCEPTION_TYPE = ClassHelper.make(ComponentResolveException.class);
|
||||
private static final ClassNode COMPONENT_CREATE_EXCEPTION_TYPE = ClassHelper.make(ComponentCreateException.class);
|
||||
|
||||
private static final Pattern isFqn = Pattern.compile("^(\\p{Ll}.+\\.)+\\p{Lu}.+$");
|
||||
private static final Pattern isWithPackage = Pattern.compile("^\\p{Ll}.+\\.");
|
||||
|
||||
private LeftShiftFactory leftShiftFactory;
|
||||
private ValueNodeTranspiler valueNodeTranspiler;
|
||||
private BodyTranspiler bodyTranspiler;
|
||||
private ComponentClassNodeResolver componentClassNodeResolver;
|
||||
|
||||
public void setLeftShiftFactory(LeftShiftFactory leftShiftFactory) {
|
||||
this.leftShiftFactory = leftShiftFactory;
|
||||
@ -45,10 +39,6 @@ public class DefaultComponentTranspiler implements ComponentTranspiler {
|
||||
this.bodyTranspiler = bodyTranspiler;
|
||||
}
|
||||
|
||||
public void setComponentClassNodeResolver(ComponentClassNodeResolver componentClassNodeResolver) {
|
||||
this.componentClassNodeResolver = componentClassNodeResolver;
|
||||
}
|
||||
|
||||
/* UTIL */
|
||||
|
||||
protected String getComponentName(int componentNumber) {
|
||||
@ -74,49 +64,14 @@ public class DefaultComponentTranspiler implements ComponentTranspiler {
|
||||
|
||||
/* RESOLVE */
|
||||
|
||||
protected List<Expression> getArgsAsList(
|
||||
TypedComponentNode componentNode,
|
||||
TranspilerState state
|
||||
) {
|
||||
protected List<Expression> getArgsAsList(TypedComponentNode componentNode) {
|
||||
return switch (componentNode.getArgs().getType()) {
|
||||
case ClassComponentTypeNode classComponentTypeNode -> {
|
||||
final String identifier = classComponentTypeNode.getIdentifier();
|
||||
final ConstantExpression alias = getStringLiteral(identifier);
|
||||
final var matcher = isFqn.matcher(identifier);
|
||||
if (matcher.matches()) {
|
||||
final ClassNode classNode = ClassHelper.make(identifier);
|
||||
final ClassExpression classExpression = new ClassExpression(classNode);
|
||||
yield List.of(alias, classExpression);
|
||||
} else {
|
||||
// we need to resolve it
|
||||
final var isWithPackageMatcher = isWithPackage.matcher(identifier);
|
||||
if (isWithPackageMatcher.matches()) {
|
||||
final var resolveResult = this.componentClassNodeResolver.getClassForFqn(identifier);
|
||||
if (resolveResult.isLeft()) {
|
||||
final var error = resolveResult.getLeft();
|
||||
error.setNode(componentNode.getArgs().getType());
|
||||
state.addError(error);
|
||||
yield List.of();
|
||||
} else {
|
||||
final ClassNode classNode = resolveResult.getRight();
|
||||
final ClassExpression classExpression = new ClassExpression(classNode); // TODO: pos
|
||||
yield List.of(alias, classExpression);
|
||||
}
|
||||
} else {
|
||||
final var resolveResult =
|
||||
this.componentClassNodeResolver.getClassForNameWithoutPackage(identifier);
|
||||
if (resolveResult.isLeft()) {
|
||||
final var error = resolveResult.getLeft();
|
||||
error.setNode(componentNode.getArgs().getType());
|
||||
state.addError(error);
|
||||
yield List.of();
|
||||
} else {
|
||||
final ClassNode classNode = resolveResult.getRight();
|
||||
final ClassExpression classExpression = new ClassExpression(classNode); // TODO: pos
|
||||
yield List.of(alias, classExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
final ClassNode classNode = ClassHelper.make(identifier);
|
||||
final var classExpression = new ClassExpression(classNode);
|
||||
yield List.of(alias, classExpression);
|
||||
}
|
||||
case StringComponentTypeNode stringComponentTypeNode -> {
|
||||
final String identifier = stringComponentTypeNode.getIdentifier();
|
||||
@ -127,8 +82,8 @@ public class DefaultComponentTranspiler implements ComponentTranspiler {
|
||||
}
|
||||
|
||||
// 'h1' | 'MyComponent', MyComponent(.class)
|
||||
protected ArgumentListExpression getResolveArgs(TypedComponentNode componentNode, TranspilerState state) {
|
||||
final List<Expression> args = this.getArgsAsList(componentNode, state);
|
||||
protected ArgumentListExpression getResolveArgs(TypedComponentNode componentNode) {
|
||||
final List<Expression> args = this.getArgsAsList(componentNode);
|
||||
final ArgumentListExpression argsListExpr = new ArgumentListExpression();
|
||||
args.forEach(argsListExpr::addExpression);
|
||||
return argsListExpr;
|
||||
@ -142,7 +97,7 @@ public class DefaultComponentTranspiler implements ComponentTranspiler {
|
||||
return new MethodCallExpression(
|
||||
new VariableExpression(state.getRenderContext()),
|
||||
"resolve",
|
||||
this.getResolveArgs(componentNode, state)
|
||||
this.getResolveArgs(componentNode)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package groowt.view.component.web.transpile;
|
||||
|
||||
import groowt.view.component.compiler.ComponentTemplateCompileException;
|
||||
import groowt.view.component.compiler.ComponentTemplateCompileUnit;
|
||||
import groowt.view.component.compiler.ComponentTemplateCompilerConfiguration;
|
||||
import groowt.view.component.web.ast.node.BodyNode;
|
||||
import groowt.view.component.web.ast.node.CompilationUnitNode;
|
||||
import groowt.view.component.web.ast.node.PreambleNode;
|
||||
@ -10,7 +9,6 @@ import groowt.view.component.web.compiler.MultipleWebViewComponentCompileErrorsE
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileException;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit;
|
||||
import groowt.view.component.web.transpile.groovy.GroovyUtil;
|
||||
import groowt.view.component.web.transpile.resolve.ClassLoaderComponentClassNodeResolver;
|
||||
import org.codehaus.groovy.ast.*;
|
||||
import org.codehaus.groovy.ast.expr.*;
|
||||
import org.codehaus.groovy.ast.stmt.BlockStatement;
|
||||
@ -31,25 +29,13 @@ public class DefaultGroovyTranspiler implements GroovyTranspiler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultGroovyTranspiler.class);
|
||||
|
||||
protected TranspilerConfiguration getConfiguration(
|
||||
ClassLoaderComponentClassNodeResolver classLoaderComponentClassNodeResolver
|
||||
) {
|
||||
return SimpleTranspilerConfiguration.withDefaults(classLoaderComponentClassNodeResolver);
|
||||
}
|
||||
|
||||
protected void addAutomaticImports(WebViewComponentModuleNode moduleNode, TranspilerConfiguration configuration) {
|
||||
configuration.getImports().forEach(moduleNode::addImport);
|
||||
configuration.getStaticImports().forEach(staticImport -> moduleNode.addStaticImport(
|
||||
staticImport.getV1(), staticImport.getV2(), staticImport.getV3()
|
||||
));
|
||||
configuration.getStarImports().forEach(moduleNode::addStarImport);
|
||||
configuration.getStaticStarImports().forEach(moduleNode::addStaticStarImport);
|
||||
protected TranspilerConfiguration getConfiguration() {
|
||||
return SimpleTranspilerConfiguration.withDefaults();
|
||||
}
|
||||
|
||||
protected WebViewComponentModuleNode initModuleNode(
|
||||
ComponentTemplateCompileUnit compileUnit,
|
||||
WebViewComponentSourceUnit sourceUnit,
|
||||
TranspilerConfiguration configuration
|
||||
WebViewComponentSourceUnit sourceUnit
|
||||
) {
|
||||
final var moduleNode = new WebViewComponentModuleNode(sourceUnit);
|
||||
sourceUnit.setModuleNode(moduleNode);
|
||||
@ -59,22 +45,16 @@ public class DefaultGroovyTranspiler implements GroovyTranspiler {
|
||||
moduleNode.setPackageName(defaultPackageName);
|
||||
}
|
||||
|
||||
this.addAutomaticImports(moduleNode, configuration);
|
||||
return moduleNode;
|
||||
}
|
||||
|
||||
protected ClassNode initMainClassNode(
|
||||
ComponentTemplateCompileUnit compileUnit,
|
||||
String templateClassName,
|
||||
WebViewComponentModuleNode moduleNode
|
||||
) {
|
||||
protected ClassNode initMainClassNode(ComponentTemplateCompileUnit compileUnit, String templateClassName) {
|
||||
final ClassNode mainClassNode = new ClassNode(
|
||||
compileUnit.getDefaultPackageName() + templateClassName,
|
||||
ACC_PUBLIC,
|
||||
ClassHelper.OBJECT_TYPE
|
||||
);
|
||||
mainClassNode.addInterface(TranspilerUtil.COMPONENT_TEMPLATE);
|
||||
moduleNode.addClass(mainClassNode);
|
||||
return mainClassNode;
|
||||
}
|
||||
|
||||
@ -216,40 +196,32 @@ public class DefaultGroovyTranspiler implements GroovyTranspiler {
|
||||
|
||||
@Override
|
||||
public WebViewComponentSourceUnit transpile(
|
||||
ComponentTemplateCompilerConfiguration compilerConfiguration,
|
||||
WebViewComponentTemplateCompileUnit compileUnit,
|
||||
CompilationUnitNode compilationUnitNode,
|
||||
String templateClassSimpleName
|
||||
) throws ComponentTemplateCompileException {
|
||||
// resolver, transpilerConfiguration, and positionSetter
|
||||
final ClassLoaderComponentClassNodeResolver resolver = new ClassLoaderComponentClassNodeResolver(
|
||||
compileUnit,
|
||||
compilerConfiguration.getGroovyClassLoader()
|
||||
);
|
||||
final var transpilerConfiguration = this.getConfiguration(resolver);
|
||||
// transpilerConfiguration, and positionSetter
|
||||
final var transpilerConfiguration = this.getConfiguration();
|
||||
final PositionSetter positionSetter = transpilerConfiguration.getPositionSetter();
|
||||
|
||||
// prepare sourceUnit
|
||||
final CompilerConfiguration groovyCompilerConfiguration =
|
||||
compilerConfiguration.getGroovyCompilerConfiguration();
|
||||
final CompilerConfiguration groovyCompilerConfiguration = compileUnit.getGroovyCompilationUnit()
|
||||
.getConfiguration();
|
||||
final WebViewComponentSourceUnit sourceUnit = new WebViewComponentSourceUnit(
|
||||
compileUnit.getDescriptiveName(),
|
||||
compileUnit.getGroovyReaderSource(),
|
||||
groovyCompilerConfiguration,
|
||||
compilerConfiguration.getGroovyClassLoader(),
|
||||
compileUnit.getGroovyCompilationUnit().getClassLoader(),
|
||||
new ErrorCollector(groovyCompilerConfiguration)
|
||||
);
|
||||
|
||||
// prepare moduleNode
|
||||
final WebViewComponentModuleNode moduleNode = this.initModuleNode(
|
||||
compileUnit, sourceUnit, transpilerConfiguration
|
||||
compileUnit, sourceUnit
|
||||
);
|
||||
|
||||
// set resolver's moduleNode
|
||||
resolver.setModuleNode(moduleNode);
|
||||
|
||||
// prepare mainClassNode
|
||||
final ClassNode mainClassNode = this.initMainClassNode(compileUnit, templateClassSimpleName, moduleNode);
|
||||
final ClassNode mainClassNode = this.initMainClassNode(compileUnit, templateClassSimpleName);
|
||||
|
||||
// handle preamble
|
||||
final PreambleNode preambleNode = compilationUnitNode.getPreambleNode();
|
||||
@ -257,6 +229,9 @@ public class DefaultGroovyTranspiler implements GroovyTranspiler {
|
||||
this.handlePreamble(templateClassSimpleName, preambleNode, mainClassNode, moduleNode, positionSetter);
|
||||
}
|
||||
|
||||
// Moved here so that moduleNode#getMainClassName reflects fqn of mainClassName
|
||||
moduleNode.addClass(mainClassNode);
|
||||
|
||||
// getRenderer method and render closure
|
||||
// first, getRenderer params
|
||||
final Parameter componentContextParam = new Parameter(COMPONENT_CONTEXT_TYPE, COMPONENT_CONTEXT_NAME);
|
||||
|
@ -1,14 +1,12 @@
|
||||
package groowt.view.component.web.transpile;
|
||||
|
||||
import groowt.view.component.compiler.ComponentTemplateCompileException;
|
||||
import groowt.view.component.compiler.ComponentTemplateCompilerConfiguration;
|
||||
import groowt.view.component.web.ast.node.CompilationUnitNode;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit;
|
||||
|
||||
public interface GroovyTranspiler {
|
||||
|
||||
WebViewComponentSourceUnit transpile(
|
||||
ComponentTemplateCompilerConfiguration compilerConfiguration,
|
||||
WebViewComponentTemplateCompileUnit compileUnit,
|
||||
CompilationUnitNode compilationUnitNode,
|
||||
String templateClassSimpleName
|
||||
|
@ -1,7 +1,6 @@
|
||||
package groowt.view.component.web.transpile;
|
||||
|
||||
import groovy.lang.Tuple3;
|
||||
import groowt.view.component.web.transpile.resolve.ComponentClassNodeResolver;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
|
||||
import java.util.Map;
|
||||
@ -12,9 +11,8 @@ import static groowt.view.component.web.transpile.TranspilerUtil.*;
|
||||
|
||||
public class SimpleTranspilerConfiguration implements TranspilerConfiguration {
|
||||
|
||||
public static TranspilerConfiguration withDefaults(ComponentClassNodeResolver componentClassNodeResolver) {
|
||||
public static TranspilerConfiguration withDefaults() {
|
||||
final var c = new SimpleTranspilerConfiguration();
|
||||
c.setComponentClassNodeResolver(componentClassNodeResolver);
|
||||
|
||||
final var ct = new DefaultComponentTranspiler();
|
||||
final PositionSetter ps = new SimplePositionSetter();
|
||||
@ -27,7 +25,6 @@ public class SimpleTranspilerConfiguration implements TranspilerConfiguration {
|
||||
ct.setLeftShiftFactory(lsf);
|
||||
ct.setBodyTranspiler(bt);
|
||||
ct.setValueNodeTranspiler(vnt);
|
||||
ct.setComponentClassNodeResolver(componentClassNodeResolver);
|
||||
|
||||
c.setComponentTranspiler(ct);
|
||||
c.setPositionSetter(ps);
|
||||
@ -40,7 +37,6 @@ public class SimpleTranspilerConfiguration implements TranspilerConfiguration {
|
||||
return c;
|
||||
}
|
||||
|
||||
private ComponentClassNodeResolver componentClassNodeResolver;
|
||||
private ComponentTranspiler componentTranspiler;
|
||||
private PositionSetter positionSetter;
|
||||
private LeftShiftFactory leftShiftFactory;
|
||||
@ -49,14 +45,6 @@ public class SimpleTranspilerConfiguration implements TranspilerConfiguration {
|
||||
private BodyTranspiler bodyTranspiler;
|
||||
private ValueNodeTranspiler valueNodeTranspiler;
|
||||
|
||||
public ComponentClassNodeResolver getComponentClassNodeResolver() {
|
||||
return Objects.requireNonNull(this.componentClassNodeResolver);
|
||||
}
|
||||
|
||||
public void setComponentClassNodeResolver(ComponentClassNodeResolver componentClassNodeResolver) {
|
||||
this.componentClassNodeResolver = componentClassNodeResolver;
|
||||
}
|
||||
|
||||
public ComponentTranspiler getComponentTranspiler() {
|
||||
return Objects.requireNonNull(this.componentTranspiler);
|
||||
}
|
||||
|
@ -1,60 +0,0 @@
|
||||
package groowt.view.component.web.transpile.resolve;
|
||||
|
||||
import groowt.util.fp.either.Either;
|
||||
import groowt.view.component.web.WebViewComponent;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit;
|
||||
import org.codehaus.groovy.ast.ClassHelper;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CachingComponentClassNodeResolver implements ComponentClassNodeResolver {
|
||||
|
||||
private final List<ClassNode> classNodes = new ArrayList<>();
|
||||
|
||||
protected final WebViewComponentTemplateCompileUnit compileUnit;
|
||||
|
||||
public CachingComponentClassNodeResolver(WebViewComponentTemplateCompileUnit compileUnit) {
|
||||
this.compileUnit = compileUnit;
|
||||
}
|
||||
|
||||
public void addClass(Class<? extends WebViewComponent> clazz) {
|
||||
this.classNodes.add(ClassHelper.make(clazz));
|
||||
}
|
||||
|
||||
public void addClassNode(ClassNode classNode) {
|
||||
this.classNodes.add(classNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Either<ClassNodeResolveException, ClassNode> getClassForFqn(String fqn) {
|
||||
for (final var classNode : this.classNodes) {
|
||||
if (classNode.getName().equals(fqn)) {
|
||||
return Either.right(classNode);
|
||||
}
|
||||
}
|
||||
return Either.left(new ClassNodeResolveException(
|
||||
this.compileUnit,
|
||||
fqn,
|
||||
"Could not resolve ClassNode for fqn: " + fqn,
|
||||
null
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Either<ClassNodeResolveException, ClassNode> getClassForNameWithoutPackage(String nameWithoutPackage) {
|
||||
for (final var classNode : this.classNodes) {
|
||||
if (classNode.getNameWithoutPackage().equals(nameWithoutPackage)) {
|
||||
return Either.right(classNode);
|
||||
}
|
||||
}
|
||||
return Either.left(new ClassNodeResolveException(
|
||||
this.compileUnit,
|
||||
nameWithoutPackage,
|
||||
"Could not resolve ClassNode for nameWithoutPackage: " + nameWithoutPackage,
|
||||
null
|
||||
));
|
||||
}
|
||||
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package groowt.view.component.web.transpile.resolve;
|
||||
|
||||
import groowt.util.fp.either.Either;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ClassLoaderComponentClassNodeResolver extends ModuleNodeComponentClassNodeResolver {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ModuleNodeComponentClassNodeResolver.class);
|
||||
|
||||
protected final ClassLoader classLoader;
|
||||
|
||||
public ClassLoaderComponentClassNodeResolver(
|
||||
WebViewComponentTemplateCompileUnit compileUnit,
|
||||
ClassLoader classLoader
|
||||
) {
|
||||
super(compileUnit);
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
protected final Either<ClassNodeResolveException, ClassNode> resolveWithClassLoader(String fqn) {
|
||||
logger.debug("Trying to resolve {}", fqn);
|
||||
try {
|
||||
Class<?> clazz = this.classLoader.loadClass(ResolveUtil.convertCanonicalNameToBinaryName(fqn));
|
||||
final var classNode = ResolveUtil.getClassNode(clazz);
|
||||
return Either.right(classNode);
|
||||
} catch (ClassNotFoundException classNotFoundException) {
|
||||
return Either.left(
|
||||
new ClassNodeResolveException(
|
||||
this.compileUnit,
|
||||
fqn,
|
||||
"Could not find class " + fqn + " with classLoader " +
|
||||
this.classLoader,
|
||||
classNotFoundException
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Either<ClassNodeResolveException, ClassNode> getClassForFqn(String fqn) {
|
||||
return super.getClassForFqn(fqn).flatMapLeft(ignored -> {
|
||||
final var classLoaderResult = this.resolveWithClassLoader(fqn);
|
||||
if (classLoaderResult.isRight()) {
|
||||
this.addClassNode(classLoaderResult.getRight());
|
||||
}
|
||||
return classLoaderResult;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
package groowt.view.component.web.transpile.resolve;
|
||||
|
||||
import groowt.util.fp.either.Either;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileException;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
|
||||
public interface ComponentClassNodeResolver {
|
||||
|
||||
final class ClassNodeResolveException extends WebViewComponentTemplateCompileException {
|
||||
|
||||
private final String identifier;
|
||||
|
||||
public ClassNodeResolveException(
|
||||
WebViewComponentTemplateCompileUnit compileUnit,
|
||||
String identifier,
|
||||
String message
|
||||
) {
|
||||
super(compileUnit, message);
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public ClassNodeResolveException(
|
||||
WebViewComponentTemplateCompileUnit compileUnit,
|
||||
String identifier,
|
||||
String message,
|
||||
Throwable cause
|
||||
) {
|
||||
super(compileUnit, message, cause);
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return this.identifier;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Either<ClassNodeResolveException, ClassNode> getClassForFqn(String fqn);
|
||||
Either<ClassNodeResolveException, ClassNode> getClassForNameWithoutPackage(String nameWithoutPackage);
|
||||
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
package groowt.view.component.web.transpile.resolve;
|
||||
|
||||
import groowt.util.fp.either.Either;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.codehaus.groovy.ast.ModuleNode;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class ModuleNodeComponentClassNodeResolver extends CachingComponentClassNodeResolver {
|
||||
|
||||
private ModuleNode moduleNode;
|
||||
|
||||
public ModuleNodeComponentClassNodeResolver(WebViewComponentTemplateCompileUnit compileUnit) {
|
||||
super(compileUnit);
|
||||
}
|
||||
|
||||
public ModuleNode getModuleNode() {
|
||||
return Objects.requireNonNull(this.moduleNode);
|
||||
}
|
||||
|
||||
public void setModuleNode(ModuleNode moduleNode) {
|
||||
this.moduleNode = Objects.requireNonNull(moduleNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Either<ClassNodeResolveException, ClassNode> getClassForNameWithoutPackage(String nameWithoutPackage) {
|
||||
return super.getClassForNameWithoutPackage(nameWithoutPackage).flatMapLeft(ignored -> {
|
||||
// try regular imports first
|
||||
final var importedClassNode = this.getModuleNode().getImportType(nameWithoutPackage);
|
||||
if (importedClassNode != null) {
|
||||
this.addClassNode(importedClassNode);
|
||||
return Either.right(importedClassNode);
|
||||
}
|
||||
|
||||
// try star imports
|
||||
final var starImports = this.getModuleNode().getStarImports();
|
||||
for (final var starImport : starImports) {
|
||||
final var packageName = starImport.getPackageName();
|
||||
final String fqn;
|
||||
if (!packageName.equals(".") && packageName.endsWith(".")) {
|
||||
fqn = packageName + nameWithoutPackage;
|
||||
} else {
|
||||
fqn = packageName + "." + nameWithoutPackage;
|
||||
}
|
||||
final var withPackage = this.getClassForFqn(fqn);
|
||||
if (withPackage.isRight()) {
|
||||
return withPackage;
|
||||
}
|
||||
}
|
||||
|
||||
// try pre-pending package and asking for fqn
|
||||
final String moduleNodePackageName = this.getModuleNode().getPackageName();
|
||||
final String packageName;
|
||||
if (moduleNodePackageName != null) {
|
||||
packageName = moduleNodePackageName;
|
||||
} else {
|
||||
packageName = "";
|
||||
}
|
||||
|
||||
final String fqn;
|
||||
if (packageName.equals(".") || packageName.isEmpty()) {
|
||||
fqn = nameWithoutPackage;
|
||||
} else if (packageName.endsWith(".")) {
|
||||
fqn = packageName + nameWithoutPackage;
|
||||
} else {
|
||||
fqn = packageName + "." + nameWithoutPackage;
|
||||
}
|
||||
|
||||
final var withPackage = this.getClassForFqn(fqn);
|
||||
if (withPackage.isRight()) {
|
||||
return withPackage;
|
||||
} else {
|
||||
return Either.left(new ClassNodeResolveException(
|
||||
this.compileUnit,
|
||||
nameWithoutPackage,
|
||||
"Cannot resolve " + nameWithoutPackage
|
||||
+ " from imports, package-local classes, or pre-added classes."
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package groowt.view.component.web.transpile.resolve;
|
||||
|
||||
import org.codehaus.groovy.ast.ClassHelper;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class ResolveUtil {
|
||||
|
||||
private static final Pattern packageSplitter = Pattern.compile("^(?<package>(?>\\p{Ll}[^.]*\\.)*)(?<top>\\p{Lu}[^.]*)(?<members>(?>\\.\\p{Lu}[^.]*)*)$");
|
||||
|
||||
public static ClassNode getClassNode(Class<?> clazz) {
|
||||
return ClassHelper.makeCached(clazz);
|
||||
}
|
||||
|
||||
public static String convertCanonicalNameToBinaryName(String canonicalName) {
|
||||
final var matcher = packageSplitter.matcher(canonicalName);
|
||||
if (matcher.matches()) {
|
||||
return new StringBuilder()
|
||||
.append(matcher.group("package"))
|
||||
.append(matcher.group("top"))
|
||||
.append(matcher.group("members").replaceAll("\\.", "\\$"))
|
||||
.toString();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Cannot split apart " + canonicalName);
|
||||
}
|
||||
}
|
||||
|
||||
private ResolveUtil() {}
|
||||
|
||||
}
|
@ -1,5 +1,16 @@
|
||||
package groowt.view.component.web.groovyc
|
||||
|
||||
import org.codehaus.groovy.control.CompilerConfiguration
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer
|
||||
|
||||
(configuration as CompilerConfiguration).tap {
|
||||
pluginFactory = new WebViewComponentParserPluginFactory()
|
||||
addCompilationCustomizers(new ImportCustomizer().tap {
|
||||
addStarImports(
|
||||
"groowt.view.component.web.lib",
|
||||
"groowt.view.component.web.runtime",
|
||||
"groowt.view.component.runtime"
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
(configuration as CompilerConfiguration).pluginFactory = new WebViewComponentParserPluginFactory()
|
||||
|
@ -3,7 +3,6 @@ package groowt.view.component.web.transpiler;
|
||||
import groowt.view.component.web.compiler.WebViewComponentTemplateCompileUnit;
|
||||
import groowt.view.component.web.transpile.SimpleTranspilerConfiguration;
|
||||
import groowt.view.component.web.transpile.TranspilerConfiguration;
|
||||
import groowt.view.component.web.transpile.resolve.CachingComponentClassNodeResolver;
|
||||
import org.codehaus.groovy.ast.ModuleNode;
|
||||
|
||||
public class DefaultBodyTranspilerTests extends BodyTranspilerTests {
|
||||
@ -13,7 +12,7 @@ public class DefaultBodyTranspilerTests extends BodyTranspilerTests {
|
||||
WebViewComponentTemplateCompileUnit compileUnit,
|
||||
ModuleNode moduleNode
|
||||
) {
|
||||
return SimpleTranspilerConfiguration.withDefaults(new CachingComponentClassNodeResolver(compileUnit));
|
||||
return SimpleTranspilerConfiguration.withDefaults();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
package groowt.view.component.web.transpiler;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static groowt.view.component.web.transpile.resolve.ResolveUtil.convertCanonicalNameToBinaryName;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class ResolveUtilTests {
|
||||
|
||||
@Test
|
||||
public void abcABC() {
|
||||
assertEquals("a.b.c.A$B$C", convertCanonicalNameToBinaryName("a.b.c.A.B.C"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ABC() {
|
||||
assertEquals("A$B$C", convertCanonicalNameToBinaryName("A.B.C"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void abcA() {
|
||||
assertEquals("a.b.c.A", convertCanonicalNameToBinaryName("a.b.c.A"));
|
||||
}
|
||||
|
||||
}
|
@ -2,7 +2,6 @@ package groowt.view.component.web.transpiler;
|
||||
|
||||
import groovy.lang.Tuple2;
|
||||
import groowt.view.component.compiler.ComponentTemplateCompileException;
|
||||
import groowt.view.component.compiler.DefaultComponentTemplateCompilerConfiguration;
|
||||
import groowt.view.component.compiler.source.StringSource;
|
||||
import groowt.view.component.web.BaseWebViewComponent;
|
||||
import groowt.view.component.web.antlr.ParserUtil;
|
||||
@ -55,7 +54,6 @@ public abstract class GroovyTranspilerTests {
|
||||
final var cuNode = astBuilder.buildCompilationUnit(parseResult.getCompilationUnitContext());
|
||||
try {
|
||||
this.transpiler.transpile(
|
||||
new DefaultComponentTemplateCompilerConfiguration(),
|
||||
new DefaultWebViewComponentTemplateCompileUnit(
|
||||
"<anonymous string source>",
|
||||
AnonymousWebViewComponent.class,
|
||||
|
@ -9,6 +9,7 @@ import org.apache.logging.log4j.core.LoggerContext;
|
||||
import org.codehaus.groovy.control.CompilationFailedException;
|
||||
import org.codehaus.groovy.control.CompilationUnit;
|
||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer;
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@ -71,6 +72,15 @@ public final class GroovyWvcCompiler implements Callable<Integer> {
|
||||
|
||||
public Integer doCompile() {
|
||||
final CompilerConfiguration configuration = new CompilerConfiguration();
|
||||
|
||||
final var addGroowtImports = new ImportCustomizer();
|
||||
addGroowtImports.addStarImports(
|
||||
"groowt.view.component.web.lib",
|
||||
"groowt.view.component.web.runtime",
|
||||
"groowt.view.component.runtime"
|
||||
);
|
||||
configuration.addCompilationCustomizers(addGroowtImports);
|
||||
|
||||
configuration.setPluginFactory(new WebViewComponentParserPluginFactory());
|
||||
final CompilationUnit compilationUnit = new CompilationUnit(configuration);
|
||||
|
||||
|
@ -4,13 +4,14 @@ import groowt.view.component.ViewComponent;
|
||||
import groowt.view.component.compiler.AbstractComponentTemplateCompileUnit;
|
||||
import groowt.view.component.compiler.ComponentTemplateCompileException;
|
||||
import groowt.view.component.compiler.ComponentTemplateCompileResult;
|
||||
import groowt.view.component.compiler.ComponentTemplateCompilerConfiguration;
|
||||
import groowt.view.component.compiler.source.ComponentTemplateSource;
|
||||
import groowt.view.component.compiler.source.FileSource;
|
||||
import groowt.view.component.compiler.source.URISource;
|
||||
import groowt.view.component.compiler.source.URLSource;
|
||||
import org.codehaus.groovy.control.CompilationUnit;
|
||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||
import org.codehaus.groovy.control.Janitor;
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer;
|
||||
import org.codehaus.groovy.control.io.ReaderSource;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ -20,8 +21,20 @@ import java.net.URI;
|
||||
public class DefaultWebViewComponentTemplateCompileUnit extends AbstractComponentTemplateCompileUnit
|
||||
implements ReaderSource, WebViewComponentTemplateCompileUnit {
|
||||
|
||||
private static CompilationUnit getCompilationUnit() {
|
||||
final var configuration = new CompilerConfiguration();
|
||||
final var addGroowtImports = new ImportCustomizer();
|
||||
addGroowtImports.addStarImports(
|
||||
"groowt.view.component.web.lib",
|
||||
"groowt.view.component.web.runtime",
|
||||
"groowt.view.component.runtime"
|
||||
);
|
||||
configuration.addCompilationCustomizers(addGroowtImports);
|
||||
return new CompilationUnit(configuration);
|
||||
}
|
||||
|
||||
private final String defaultPackageName;
|
||||
private final CompilationUnit groovyCompilationUnit = new CompilationUnit();
|
||||
private final CompilationUnit groovyCompilationUnit;
|
||||
|
||||
public DefaultWebViewComponentTemplateCompileUnit(
|
||||
String descriptiveName,
|
||||
@ -35,6 +48,7 @@ public class DefaultWebViewComponentTemplateCompileUnit extends AbstractComponen
|
||||
} else {
|
||||
this.defaultPackageName = defaultPackageName;
|
||||
}
|
||||
this.groovyCompilationUnit = getCompilationUnit();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -53,9 +67,8 @@ public class DefaultWebViewComponentTemplateCompileUnit extends AbstractComponen
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentTemplateCompileResult compile(ComponentTemplateCompilerConfiguration configuration)
|
||||
throws ComponentTemplateCompileException {
|
||||
final WebViewComponentTemplateCompiler compiler = WebViewComponentTemplateCompiler.get(configuration);
|
||||
public ComponentTemplateCompileResult compile() throws ComponentTemplateCompileException {
|
||||
final WebViewComponentTemplateCompiler compiler = WebViewComponentTemplateCompiler.get();
|
||||
return compiler.compile(this);
|
||||
}
|
||||
|
||||
|
@ -9,10 +9,10 @@ public interface WebViewComponentTemplateCompiler
|
||||
extends ComponentTemplateCompiler<WebViewComponentTemplateCompileUnit> {
|
||||
|
||||
static WebViewComponentTemplateCompiler get() {
|
||||
return get(new DefaultComponentTemplateCompilerConfiguration());
|
||||
return get(new WebViewComponentTemplateCompilerConfiguration());
|
||||
}
|
||||
|
||||
static WebViewComponentTemplateCompiler get(ComponentTemplateCompilerConfiguration configuration) {
|
||||
static WebViewComponentTemplateCompiler get(WebViewComponentTemplateCompilerConfiguration configuration) {
|
||||
final ServiceLoader<WebViewComponentTemplateCompilerFactory> factoryServiceLoader =
|
||||
ServiceLoader.load(WebViewComponentTemplateCompilerFactory.class);
|
||||
final var factory = factoryServiceLoader.findFirst()
|
||||
|
@ -0,0 +1,17 @@
|
||||
package groowt.view.component.web.compiler;
|
||||
|
||||
import org.codehaus.groovy.control.CompilePhase;
|
||||
|
||||
public class WebViewComponentTemplateCompilerConfiguration {
|
||||
|
||||
private CompilePhase compilePhase = CompilePhase.CLASS_GENERATION;
|
||||
|
||||
public CompilePhase getCompilePhase() {
|
||||
return this.compilePhase;
|
||||
}
|
||||
|
||||
public void setCompilePhase(CompilePhase compilePhase) {
|
||||
this.compilePhase = compilePhase;
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
package groowt.view.component.web.compiler;
|
||||
|
||||
import groowt.view.component.compiler.ComponentTemplateCompilerConfiguration;
|
||||
|
||||
public interface WebViewComponentTemplateCompilerFactory {
|
||||
WebViewComponentTemplateCompiler create(ComponentTemplateCompilerConfiguration configuration);
|
||||
WebViewComponentTemplateCompiler create(WebViewComponentTemplateCompilerConfiguration configuration);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user