diff --git a/gcp-api/build.gradle b/gcp-api/build.gradle deleted file mode 100644 index b2e673a..0000000 --- a/gcp-api/build.gradle +++ /dev/null @@ -1,25 +0,0 @@ -plugins { - id 'ssg.common' - id 'ssg.lib' -} - -repositories { - mavenCentral() -} - -dependencies { - // https://mvnrepository.com/artifact/org.apache.groovy/groovy-templates - implementation 'org.apache.groovy:groovy-templates:4.0.7' - - // https://archiva.jessebrault.com/#artifact/com.jessebrault.fsm/lib/0.1.0-SNAPSHOT - implementation 'com.jessebrault.fsm:lib:0.1.0-SNAPSHOT' - - // https://archiva.jessebrault.com/#artifact/com.jessebrault.fsm/groovy-extension/0.1.0-SNAPSHOT - implementation 'com.jessebrault.fsm:groovy-extension:0.1.0-SNAPSHOT' - - testRuntimeOnly project(':gcp-impl') -} - -jar { - archivesBaseName = 'gcp-api' -} \ No newline at end of file diff --git a/gcp-api/src/main/groovy/com/jessebrault/gcp/Component.groovy b/gcp-api/src/main/groovy/com/jessebrault/gcp/Component.groovy deleted file mode 100644 index 7cc8026..0000000 --- a/gcp-api/src/main/groovy/com/jessebrault/gcp/Component.groovy +++ /dev/null @@ -1,5 +0,0 @@ -package com.jessebrault.gcp - -interface Component { - String render(Map attr, String body) -} \ No newline at end of file diff --git a/gcp-api/src/main/groovy/com/jessebrault/gcp/ComponentFactory.groovy b/gcp-api/src/main/groovy/com/jessebrault/gcp/ComponentFactory.groovy deleted file mode 100644 index 86cb176..0000000 --- a/gcp-api/src/main/groovy/com/jessebrault/gcp/ComponentFactory.groovy +++ /dev/null @@ -1,5 +0,0 @@ -package com.jessebrault.gcp - -interface ComponentFactory { - Component get() -} \ No newline at end of file diff --git a/gcp-api/src/main/groovy/com/jessebrault/gcp/ComponentsContainer.groovy b/gcp-api/src/main/groovy/com/jessebrault/gcp/ComponentsContainer.groovy deleted file mode 100644 index 43f3f14..0000000 --- a/gcp-api/src/main/groovy/com/jessebrault/gcp/ComponentsContainer.groovy +++ /dev/null @@ -1,43 +0,0 @@ -package com.jessebrault.gcp - -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import org.slf4j.Marker -import org.slf4j.MarkerFactory - -class ComponentsContainer { - - private static final Logger logger = LoggerFactory.getLogger(ComponentsContainer) - private static final Marker enter = MarkerFactory.getMarker('ENTER') - private static final Marker exit = MarkerFactory.getMarker('EXIT') - - private final Map componentCache = [:] - private final GroovyClassLoader loader - - ComponentsContainer(Collection componentDirUrls, Collection components) { - logger.trace(enter, 'componentDirUrls: {}, components: {}', componentDirUrls, components) - this.loader = new GroovyClassLoader() - componentDirUrls.each { this.loader.addURL(it) } - components.each { - this.componentCache[it.class.simpleName] = it - } - logger.debug('this.loader: {}', this.loader) - logger.debug('this.componentCache: {}', this.componentCache) - logger.trace(exit, '') - } - - Component get(String name) { - logger.trace('name: {}', name) - def component = this.componentCache.computeIfAbsent(name, { - def componentClass = (Class) this.loader.loadClass(it) - componentClass.getDeclaredConstructor().newInstance() // must be a default constructor (for now) - }) - logger.trace(exit, 'component: {}', component) - component - } - - Component getAt(String name) { - this.get(name) - } - -} diff --git a/gcp-api/src/main/groovy/com/jessebrault/gcp/GcpTemplate.groovy b/gcp-api/src/main/groovy/com/jessebrault/gcp/GcpTemplate.groovy deleted file mode 100644 index 880e1d5..0000000 --- a/gcp-api/src/main/groovy/com/jessebrault/gcp/GcpTemplate.groovy +++ /dev/null @@ -1,31 +0,0 @@ -package com.jessebrault.gcp - -import groovy.text.Template - -class GcpTemplate implements Template { - - Closure templateClosure - ComponentsContainer components - - String renderComponent(String componentName, Closure configureComponentInstance) { - Map attr = [:] - def bodyOut = new StringBuilder() - configureComponentInstance(attr, bodyOut) - - def component = this.components[componentName] - component.render(attr, bodyOut.toString()) - } - - @Override - final Writable make() { - this.make([:]) - } - - @Override - final Writable make(Map binding) { - def rehydrated = this.templateClosure.rehydrate(binding, this, this).asWritable() - rehydrated.setResolveStrategy(Closure.DELEGATE_FIRST) - rehydrated - } - -} \ No newline at end of file diff --git a/gcp-api/src/main/groovy/com/jessebrault/gcp/GcpTemplateEngine.groovy b/gcp-api/src/main/groovy/com/jessebrault/gcp/GcpTemplateEngine.groovy deleted file mode 100644 index 14c41fe..0000000 --- a/gcp-api/src/main/groovy/com/jessebrault/gcp/GcpTemplateEngine.groovy +++ /dev/null @@ -1,61 +0,0 @@ -package com.jessebrault.gcp - -import groovy.text.Template -import groovy.text.TemplateEngine -import groovy.transform.TupleConstructor -import org.codehaus.groovy.control.CompilationFailedException -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import java.util.concurrent.atomic.AtomicInteger -import java.util.function.Supplier - -final class GcpTemplateEngine extends TemplateEngine { - - private static final Logger logger = LoggerFactory.getLogger(GcpTemplateEngine) - - private static GcpToScriptConverter getConverter() { - ServiceLoader.load(GcpToScriptConverter).findFirst().orElseThrow({ - new NullPointerException('Could not find an implementation of GcpToScriptConverter') - }) - } - - @TupleConstructor(defaults = false) - static class Configuration { - Supplier ssgTemplateSupplier - Collection componentDirUrls - Collection components - } - - private final Configuration configuration - private final File scriptsDir = File.createTempDir() - private final AtomicInteger templateCount = new AtomicInteger(0) - private final GroovyScriptEngine scriptEngine - - GcpTemplateEngine(Configuration configuration) { - this.configuration = configuration - this.scriptEngine = new GroovyScriptEngine([this.scriptsDir.toURI().toURL()] as URL[]) - } - - @Override - Template createTemplate(Reader reader) throws CompilationFailedException, ClassNotFoundException, IOException { - def templateSrc = reader.text - - def converter = getConverter() - def scriptSrc = converter.convert(templateSrc) - logger.debug('scriptSrc: {}', scriptSrc) - def scriptName = "SsgTemplate${ this.templateCount.getAndIncrement() }.groovy" - new File(this.scriptsDir, scriptName).write(scriptSrc) - - def script = this.scriptEngine.createScript(scriptName, new Binding()) - - def templateClosure = (Closure) script.invokeMethod('getTemplate', null) - - def template = this.configuration.ssgTemplateSupplier.get() - template.templateClosure = templateClosure - template.components = new ComponentsContainer(this.configuration.componentDirUrls, this.configuration.components) - - template - } - -} diff --git a/gcp-api/src/main/groovy/com/jessebrault/gcp/GcpToScriptConverter.groovy b/gcp-api/src/main/groovy/com/jessebrault/gcp/GcpToScriptConverter.groovy deleted file mode 100644 index f7010d6..0000000 --- a/gcp-api/src/main/groovy/com/jessebrault/gcp/GcpToScriptConverter.groovy +++ /dev/null @@ -1,5 +0,0 @@ -package com.jessebrault.gcp - -interface GcpToScriptConverter { - String convert(String gcpSrc) -} \ No newline at end of file diff --git a/gcp-api/src/main/groovy/com/jessebrault/gcp/tokenizer/Token.java b/gcp-api/src/main/groovy/com/jessebrault/gcp/tokenizer/Token.java deleted file mode 100644 index e4e0a35..0000000 --- a/gcp-api/src/main/groovy/com/jessebrault/gcp/tokenizer/Token.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.jessebrault.gcp.tokenizer; - -import java.util.Collection; - -public interface Token { - - enum Type { - TEXT, - - DOLLAR, - GROOVY_REFERENCE, - CURLY_OPEN, - SCRIPTLET, - CURLY_CLOSE, - BLOCK_SCRIPTLET_OPEN, - EXPRESSION_SCRIPTLET_OPEN, - SCRIPTLET_CLOSE, - - CLASS_NAME, - PACKAGE_NAME, - DOT, - - WHITESPACE, - - KEY, - EQUALS, - - DOUBLE_QUOTE, - STRING, - SINGLE_QUOTE, - - COMPONENT_START, - FORWARD_SLASH, - COMPONENT_END, - ; - - boolean isAnyOf(Collection types) { - return types.contains(this); - } - - } - - Type getType(); - CharSequence getText(); - int getInputIndex(); - int getLine(); - int getCol(); - -} diff --git a/gcp-api/src/main/groovy/com/jessebrault/gcp/tokenizer/Tokenizer.java b/gcp-api/src/main/groovy/com/jessebrault/gcp/tokenizer/Tokenizer.java deleted file mode 100644 index 26e21a1..0000000 --- a/gcp-api/src/main/groovy/com/jessebrault/gcp/tokenizer/Tokenizer.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.jessebrault.gcp.tokenizer; - -import java.util.LinkedList; -import java.util.Queue; - -public interface Tokenizer { - - enum State { - TEXT, - COMPONENT_NAME, - COMPONENT_KEYS_AND_VALUES - } - - void start(CharSequence input, int startOffset, int endOffset, State initialState); - boolean hasNext(); - Token next(); - State getCurrentState(); - - default Queue tokenizeAll(CharSequence input, State initialState) { - this.start(input, 0, input.length(), initialState); - final Queue tokens = new LinkedList<>(); - while (this.hasNext()) { - tokens.add(this.next()); - } - return tokens; - } - -} diff --git a/gcp-api/src/test/groovy/com/jessebrault/gcp/GcpTemplateEngineIntegrationTests.groovy b/gcp-api/src/test/groovy/com/jessebrault/gcp/GcpTemplateEngineIntegrationTests.groovy deleted file mode 100644 index b15f781..0000000 --- a/gcp-api/src/test/groovy/com/jessebrault/gcp/GcpTemplateEngineIntegrationTests.groovy +++ /dev/null @@ -1,159 +0,0 @@ -package com.jessebrault.gcp - - -import groovy.text.TemplateEngine -import org.junit.jupiter.api.Test - -import static org.junit.jupiter.api.Assertions.assertEquals - -class GcpTemplateEngineIntegrationTests { - - private final TemplateEngine engine = new GcpTemplateEngine(new GcpTemplateEngine.Configuration( - { new GcpTemplate() }, - [], - [] - )) - - @Test - void doctype() { - def src = '' - def r = this.engine.createTemplate(src).make().toString() - assertEquals('', r) - } - - @Test - void handlesNewlines() { - def src = '\n' - def r = this.engine.createTemplate(src).make().toString() - assertEquals(src, r) - } - - @Test - void emptyScriptlet() { - def src = '<%%>' - def r = this.engine.createTemplate(src).make().toString() - assertEquals('', r) - } - - @Test - void simpleOut() { - def src = '<% out << "Hello, World!" %>' - def r = this.engine.createTemplate(src).make().toString() - assertEquals('Hello, World!', r) - } - - @Test - void scriptletInString() { - def src = '">' - def r = this.engine.createTemplate(src).make().toString() - assertEquals('', r) - } - - @Test - void expressionScriptlet() { - def src = '<%= 13 %>' - def r = this.engine.createTemplate(src).make().toString() - assertEquals('13', r) - } - - @Test - void bindingWorks() { - def src = '<%= greeting %>' - def r = this.engine.createTemplate(src).make([greeting: 'Hello, World!']).toString() - assertEquals('Hello, World!', r) - } - - static class CustomBaseTemplate extends GcpTemplate { - - def greeting = 'Greetings!' - def name = 'Jesse' - - @SuppressWarnings('GrMethodMayBeStatic') - def greet() { - 'Hello, World!' - } - - } - - @Test - void baseTemplateMethodsPresent() { - def src = '<%= greet() %>' - def configuration = new GcpTemplateEngine.Configuration({ new CustomBaseTemplate() }, [], []) - def engine = new GcpTemplateEngine(configuration) - def r = engine.createTemplate(src).make().toString() - assertEquals('Hello, World!', r) - } - - @Test - void baseTemplatePropertiesPresent() { - def src = '<%= this.greeting %>' - def configuration = new GcpTemplateEngine.Configuration({ new CustomBaseTemplate() }, [], []) - def engine = new GcpTemplateEngine(configuration) - def r = engine.createTemplate(src).make().toString() - assertEquals('Greetings!', r) - } - - @Test - void bindingOverridesCustomBaseTemplate() { - def src = '<%= greet() %>' - def configuration = new GcpTemplateEngine.Configuration({ new CustomBaseTemplate() }, [], []) - def engine = new GcpTemplateEngine(configuration) - def r = engine.createTemplate(src).make([greet: { "Hello, Person!" }]).toString() - assertEquals('Hello, Person!', r) - } - - static class Greeter implements Component { - - @Override - String render(Map attr, String body) { - "${ attr.greeting }, ${ attr.person }!" - } - - } - - @Test - void selfClosingComponent() { - def src = '' - def configuration = new GcpTemplateEngine.Configuration({ new GcpTemplate() }, [], [new Greeter()]) - def engine = new GcpTemplateEngine(configuration) - def r = engine.createTemplate(src).make().toString() - assertEquals('Hello, World!', r) - } - - @Test - void componentWithGStringAttrValue() { - def src = '' - def configuration = new GcpTemplateEngine.Configuration({ new GcpTemplate() }, [], [new Greeter()]) - def engine = new GcpTemplateEngine(configuration) - def r = engine.createTemplate(src).make().toString() - assertEquals('Hello, person number 13!', r) - } - - @Test - void componentWithGStringAttrValueCanAccessBinding() { - def src = '' - def configuration = new GcpTemplateEngine.Configuration({ new GcpTemplate() }, [], [new Greeter()]) - def engine = new GcpTemplateEngine(configuration) - def r = engine.createTemplate(src).make([name: 'Jesse']).toString() - assertEquals('Hello, person named Jesse!', r) - } - - @Test - void componentWithGStringAttrValueCanAccessBaseTemplateMethod() { - def src = '' - def configuration = new GcpTemplateEngine.Configuration({ new CustomBaseTemplate() }, [], [new Greeter()]) - def engine = new GcpTemplateEngine(configuration) - def r = engine.createTemplate(src).make().toString() - assertEquals('Hello, person named Jesse!', r) - } - - @Test - void componentWithGStringAttrValueCanAccessBaseTemplateProperty() { - def src = '' - def configuration = new GcpTemplateEngine.Configuration({ new CustomBaseTemplate() }, [], [new Greeter()]) - def engine = new GcpTemplateEngine(configuration) - def r = engine.createTemplate(src).make().toString() - assertEquals('Hello, person named Jesse!', r) - } - -} diff --git a/gcp-api/src/test/resources/components/Greeting.groovy b/gcp-api/src/test/resources/components/Greeting.groovy deleted file mode 100644 index 303c43a..0000000 --- a/gcp-api/src/test/resources/components/Greeting.groovy +++ /dev/null @@ -1,12 +0,0 @@ -package components - -import com.jessebrault.gcp.Component - -class Greeting implements Component { - - @Override - String render(Map attr, String body) { - "

${ attr.person }, ${ attr.person }!

" - } - -} diff --git a/gcp-api/src/test/resources/components/Head.groovy b/gcp-api/src/test/resources/components/Head.groovy deleted file mode 100644 index 1923de4..0000000 --- a/gcp-api/src/test/resources/components/Head.groovy +++ /dev/null @@ -1,16 +0,0 @@ -package components - -import com.jessebrault.gcp.Component - -class Head implements Component { - - @Override - String render(Map attr, String body) { - def b = new StringBuilder() - b << '\n' - b << " ${ attr.title }\n" - b << '\n' - b.toString() - } - -} diff --git a/gcp-api/src/test/resources/log4j2.xml b/gcp-api/src/test/resources/log4j2.xml deleted file mode 100644 index fe10995..0000000 --- a/gcp-api/src/test/resources/log4j2.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/gcp-api/src/test/resources/test.gcp b/gcp-api/src/test/resources/test.gcp deleted file mode 100644 index f26679c..0000000 --- a/gcp-api/src/test/resources/test.gcp +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/gcp-api/src/test/resources/test.ssg b/gcp-api/src/test/resources/test.ssg deleted file mode 100644 index c8b636a..0000000 --- a/gcp-api/src/test/resources/test.ssg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/gcp-impl/build.gradle b/gcp-impl/build.gradle deleted file mode 100644 index 6d048c0..0000000 --- a/gcp-impl/build.gradle +++ /dev/null @@ -1,25 +0,0 @@ -plugins { - id 'ssg.common' - id 'ssg.lib' -} - -repositories { - mavenCentral() -} - -dependencies { - implementation project(':gcp-api') - - // https://mvnrepository.com/artifact/org.apache.groovy/groovy-templates - implementation 'org.apache.groovy:groovy-templates:4.0.7' - - // https://archiva.jessebrault.com/#artifact/com.jessebrault.fsm/lib/0.1.0-SNAPSHOT - implementation 'com.jessebrault.fsm:lib:0.1.0-SNAPSHOT' - - // https://archiva.jessebrault.com/#artifact/com.jessebrault.fsm/groovy-extension/0.1.0-SNAPSHOT - implementation 'com.jessebrault.fsm:groovy-extension:0.1.0-SNAPSHOT' -} - -jar { - archivesBaseName = 'gcp-impl' -} \ No newline at end of file diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/GcpParser.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/GcpParser.groovy deleted file mode 100644 index fd5abd3..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/GcpParser.groovy +++ /dev/null @@ -1,80 +0,0 @@ -package com.jessebrault.gcp - -import com.jessebrault.gcp.groovy.BlockScriptletParser -import com.jessebrault.gcp.groovy.DollarReferenceParser -import com.jessebrault.gcp.groovy.DollarScriptletParser -import com.jessebrault.gcp.groovy.ExpressionScriptletParser -import com.jessebrault.gcp.node.Document -import com.jessebrault.gcp.node.DollarReference -import com.jessebrault.gcp.node.DollarScriptlet -import com.jessebrault.gcp.node.ExpressionScriptlet -import com.jessebrault.gcp.node.Html -import com.jessebrault.gcp.node.BlockScriptlet - -import java.util.regex.Matcher -import java.util.regex.Pattern - -class GcpParser { - -// private static enum State { -// HTML, DOLLAR_GROOVY, SCRIPTLET, EXPRESSION_SCRIPTLET -// } -// -// private static FunctionFsmBuilder getFsmBuilder() { -// new FunctionFsmBuilderImpl<>() -// } - - private static final Pattern html = ~/^(?:[\w\W&&[^<$]]|<(?![%\p{Lu}]))+/ - - private static final Pattern groovyIdentifier = ~/^[a-zA-Z_\u0024\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u00ff\u0100-\ufff3][a-zA-Z_\u00240-9\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u00ff\u0100-\ufff3]*/ - - - static Document parse(String gcp) { - - } - - private static Document document(String gcp) { - def document = new Document() - def remaining = gcp - while (remaining.length() > 0) { - Matcher m - DollarReferenceParser.Result dollarReferenceResult - DollarScriptletParser.Result dollarScriptletResult - BlockScriptletParser.Result blockScriptletResult - ExpressionScriptletParser.Result expressionScriptletResult - - String match - - if ((m = html.matcher(remaining)).find()) { - match = m.group() - document.children << new Html().tap { - text = match - } - } else if (dollarReferenceResult = DollarReferenceParser.parse(remaining)) { - match = dollarReferenceResult.fullMatch - document.children << new DollarReference().tap { - reference = dollarReferenceResult.reference - } - } else if (dollarScriptletResult = DollarScriptletParser.parseResult(remaining)) { - match = dollarScriptletResult.fullMatch - document.children << new DollarScriptlet().tap { - scriptlet = dollarScriptletResult.scriptlet - } - } else if (blockScriptletResult = BlockScriptletParser.parseResult(remaining)) { - match = blockScriptletResult.fullMatch - document.children << new BlockScriptlet().tap { - scriptlet = blockScriptletResult.scriptlet - } - } else if (expressionScriptletResult = ExpressionScriptletParser.parseResult(remaining)) { - match = expressionScriptletResult.fullMatch - document.children << new ExpressionScriptlet().tap { - scriptlet = expressionScriptletResult.scriptlet - } - } - - remaining = remaining.substring(match.length()) - } - document - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/GcpToScriptConverterImpl.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/GcpToScriptConverterImpl.groovy deleted file mode 100644 index 58fa1cc..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/GcpToScriptConverterImpl.groovy +++ /dev/null @@ -1,180 +0,0 @@ -package com.jessebrault.gcp - -import com.jessebrault.fsm.stackfunction.StackFunctionFsmBuilder -import com.jessebrault.fsm.stackfunction.StackFunctionFsmBuilderImpl -import com.jessebrault.gcp.util.PatternFunction - -class GcpToScriptConverterImpl implements GcpToScriptConverter { - - enum State { - HTML, - SCRIPTLET, - EXPRESSION_SCRIPTLET, - DOLLAR, - - COMPONENT, - - COMPONENT_IDENTIFIER, - - COMPONENT_ATTR_KEY, - COMPONENT_ATTR_VALUE_OPEN, - - COMPONENT_ATTR_VALUE_STRING, - COMPONENT_ATTR_VALUE_STRING_CLOSE, - - COMPONENT_CLOSE - } - - private static final PatternFunction html = new PatternFunction(~/^(?:[\w\W&&[^<$]]|<(?!%|\p{Lu})|\$(?!\{))+/) - private static final PatternFunction scriptletOpen = new PatternFunction(~/^<%(?!=)/) - private static final PatternFunction expressionScriptletOpen = new PatternFunction(~/^<%=/) - private static final PatternFunction scriptletText = new PatternFunction(~/^.+(?=%>)/) - private static final PatternFunction scriptletClose = new PatternFunction(~/^%>/) - - private static final PatternFunction componentOpen = new PatternFunction(~/^<(?=\p{Lu})/) - private static final PatternFunction componentIdentifier = new PatternFunction(~/^\p{Lu}.*?(?=\s|\\/)/) - private static final PatternFunction attrKeyWithValue = new PatternFunction(~/^\s*[\p{Ll}\p{Lu}0-9_\-]+=/) - private static final PatternFunction attrKeyBoolean = new PatternFunction(~/^\s*[\p{Ll}\p{Lu}0-9_\-]++(?!=)/) - private static final PatternFunction componentSelfClose = new PatternFunction(~/^\s*\/>/) - - private static final PatternFunction attrValueStringOpen = new PatternFunction(~/^["']/) - private static final PatternFunction attrValueStringContents = new PatternFunction(~/^(?:[\w\W&&[^\\"]]|\\\\|\\")*(?=")/) - private static final PatternFunction attrValueStringClose = new PatternFunction(~/["']/) - - private static StackFunctionFsmBuilder getFsmBuilder() { - new StackFunctionFsmBuilderImpl<>() - } - - @Override - String convert(String src) { - def b = new StringBuilder() - def stringAcc = new StringBuilder() - - b << 'def getTemplate() {\nreturn { out ->\n' - - def fsm = getFsmBuilder().with { - initialState = State.HTML - - whileIn(State.HTML) { - on html exec { - stringAcc << it - } - on scriptletOpen shiftTo State.SCRIPTLET exec { - if (stringAcc.length() > 0) { - b << 'out << """' << stringAcc.toString() << '""";\n' - stringAcc = new StringBuilder() - } - } - on expressionScriptletOpen shiftTo State.EXPRESSION_SCRIPTLET exec { - stringAcc << '${' - } - on componentOpen shiftTo State.COMPONENT_IDENTIFIER exec { - if (stringAcc.length() > 0) { - b << 'out << """' << stringAcc.toString() << '""";\n' - stringAcc = new StringBuilder() - } - } - } - - whileIn(State.SCRIPTLET) { - on scriptletText exec { - b << it - } - on scriptletClose shiftTo HTML exec { - b << ';\n' - } - } - - whileIn(State.EXPRESSION_SCRIPTLET) { - on scriptletText exec { - stringAcc << it - } - on scriptletClose shiftTo HTML exec { - stringAcc << '}' - } - } - - whileIn(State.COMPONENT) { - // tokenize component, figure out body, and tokenize closing component - } - - whileIn(COMPONENT_IDENTIFIER) { - on componentIdentifier shiftTo COMPONENT_ATTR_KEY exec { - b << "out << renderComponent('${ it }') { attr, bodyOut ->\n" - } - onNoMatch() exec { - throw new RuntimeException('expected a Component Identifier') - } - } - - whileIn(COMPONENT_ATTR_KEY) { - on attrKeyWithValue shiftTo COMPONENT_ATTR_VALUE_OPEN exec { String s -> - def trimmed = s.trim() - def key = trimmed.substring(0, trimmed.length() - 1) - b << "attr['${ key }'] = " - } - on attrKeyBoolean exec { String s -> - def trimmed = s.trim() - def key = trimmed.substring(0, trimmed.length() - 1) - b << "attr['${ key }'] = true" - } - on componentSelfClose shiftTo HTML exec { - b << '};\n' - } - onNoMatch() exec { - throw new RuntimeException('expected either an attr key or a closing />') - } - } - - whileIn(COMPONENT_ATTR_VALUE_OPEN) { - on attrValueStringOpen shiftTo COMPONENT_ATTR_VALUE_STRING exec { - b << '"' - } - onNoMatch() exec { - throw new RuntimeException('expected a string opening') - } - } - - whileIn(COMPONENT_ATTR_VALUE_STRING) { - on attrValueStringContents shiftTo COMPONENT_ATTR_VALUE_STRING_CLOSE exec { - b << it - } - onNoMatch() exec { - throw new RuntimeException('expected string contents') - } - } - - whileIn(COMPONENT_ATTR_VALUE_STRING_CLOSE) { - on attrValueStringClose shiftTo COMPONENT_ATTR_KEY exec { - b << '";\n' - } - onNoMatch() exec { - throw new RuntimeException('expected string close') - } - } - - build() - } - - def remaining = src - while (remaining.length() > 0) { - def output = fsm.apply(remaining) - if (output != null) { - remaining = remaining.substring(output.length()) - } else if (output != null && output.length() == 0) { - throw new RuntimeException('output length is zero') - } else { - throw new RuntimeException('output is null') - } - } - - if (fsm.currentState == HTML && stringAcc.length() > 0) { - b << 'out << """' << stringAcc.toString() << '""";\n' - stringAcc = new StringBuilder() - } - b << '}}\n' - - b.toString() - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/ComponentParser.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/ComponentParser.groovy deleted file mode 100644 index a1d7c35..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/ComponentParser.groovy +++ /dev/null @@ -1,221 +0,0 @@ -package com.jessebrault.gcp.component - -import com.jessebrault.gcp.component.ComponentToken.Type -import com.jessebrault.gcp.component.node.ComponentRoot -import com.jessebrault.gcp.component.node.DollarReferenceValue -import com.jessebrault.gcp.component.node.DollarScriptletValue -import com.jessebrault.gcp.component.node.ExpressionScriptletValue -import com.jessebrault.gcp.component.node.GStringValue -import com.jessebrault.gcp.component.node.KeyAndValue -import com.jessebrault.gcp.component.node.KeysAndValues -import com.jessebrault.gcp.component.node.ComponentNode -import com.jessebrault.gcp.component.node.ScriptletValue -import com.jessebrault.gcp.component.node.StringValue -import com.jessebrault.gcp.util.PeekBefore -import groovy.transform.PackageScope - -import static com.jessebrault.gcp.component.ComponentToken.Type.* - -/** - * NOT thread safe - */ -@PackageScope -class ComponentParser { - - private Queue tokens - private String currentIdentifier - - ComponentRoot parse(Queue tokens) { - this.tokens = tokens - this.selfClosingComponent() - } - - String parse(Queue openingTokens, String bodyClosure, Queue closingTokens) { - this.tokens = openingTokens - def componentNode = this.openingComponent() - - componentNode.body = bodyClosure - - this.tokens = closingTokens - this.closingComponent() - - componentNode - } - - private static void error(Collection expectedTypes, ComponentToken actual) { - throw new RuntimeException("expected ${ expectedTypes.join(' or ') } but got ${ actual ? "'${ actual }'" : 'null' }") - } - - private ComponentToken expect(Collection types) { - def t = this.tokens.poll() - if (!t || !t.type.isAnyOf(types)) { - error(types, t) - } - t - } - - private ComponentToken expect(Type type) { - this.expect([type]) - } - - private boolean peek(Type type) { - def t = this.tokens.peek() - t && t.type == type - } - - private boolean peekSecond(Type type) { - def t = this.tokens[1] - t && t.type == type - } - - private boolean peekThird(Type type) { - def t = this.tokens[2] - t && t.type == type - } - - private ComponentRoot selfClosingComponent() { - this.startOfOpeningOrSelfClosingComponent() - def keysAndValues = this.keysAndValues() - this.expect(FORWARD_SLASH) - this.expect(GT) - new ComponentRoot().tap { - it.identifier = this.currentIdentifier - it.children << keysAndValues - } - } - - private ComponentRoot openingComponent() { - this.startOfOpeningOrSelfClosingComponent() - def keysAndValues = this.keysAndValues() - this.expect(GT) - new ComponentRoot().tap { - it.identifier = this.currentIdentifier - it.children << keysAndValues - } - } - - private void closingComponent() { - this.expect(LT) - this.expect(FORWARD_SLASH) - def identifierToken = this.expect(IDENTIFIER) - if (identifierToken.text != this.currentIdentifier) { - throw new RuntimeException("expected '${ this.currentIdentifier }' but got '${ t2.text }'") - } - this.expect(GT) - } - - private void startOfOpeningOrSelfClosingComponent() { - this.expect(LT) - def identifierToken = this.expect(IDENTIFIER) - this.currentIdentifier = identifierToken.text - } - - private KeysAndValues keysAndValues() { - List children = [] - while (true) { - if (this.peek(KEY)) { - def keyAndValue = this.keyAndValue() - children << keyAndValue - } else if (this.peek(FORWARD_SLASH)) { - break - } else { - error([KEY, FORWARD_SLASH], this.tokens.poll()) - } - } - new KeysAndValues().tap { - it.children.addAll(children) - } - } - - @PeekBefore(KEY) - private KeyAndValue keyAndValue() { - def keyToken = this.expect(KEY) - this.expect(EQUALS) - def value = this.value() - new KeyAndValue().tap { - key = keyToken.text - it.children << value - } - } - - private ComponentNode value() { - if (this.peek(DOUBLE_QUOTE)) { - return this.doubleQuoteStringValue() - } else if (this.peek(SINGLE_QUOTE)) { - return this.singleQuoteStringValue() - } else if (this.peek(GROOVY_IDENTIFIER)) { - return this.dollarReferenceValue() - } else if (this.peek(GROOVY)) { - return this.dollarScriptletValue() - } else if (this.peek(LT) && this.peekSecond(PERCENT) && this.peekThird(EQUALS)) { - return this.expressionScriptletValue() - } else if (this.peek(LT) && this.peekSecond(PERCENT)) { - return this.scriptletValue() - } else { - error([DOUBLE_QUOTE, SINGLE_QUOTE, GROOVY_IDENTIFIER, GROOVY, LT], this.tokens.poll()) - } - throw new RuntimeException('should not get here') - } - - @PeekBefore(DOUBLE_QUOTE) - private GStringValue doubleQuoteStringValue() { - this.expect(DOUBLE_QUOTE) - def stringToken = this.expect(STRING) - this.expect(DOUBLE_QUOTE) - new GStringValue().tap { - gString = stringToken.text - } - } - - @PeekBefore(SINGLE_QUOTE) - private StringValue singleQuoteStringValue() { - this.expect(SINGLE_QUOTE) - def stringToken = this.expect(STRING) - this.expect(SINGLE_QUOTE) - new StringValue().tap { - string = stringToken.text - } - } - - @PeekBefore([GROOVY_IDENTIFIER]) - private DollarReferenceValue dollarReferenceValue() { - def groovyIdentifierToken = this.expect(GROOVY_IDENTIFIER) - new DollarReferenceValue().tap { - reference = groovyIdentifierToken.text - } - } - - @PeekBefore([GROOVY]) - private DollarScriptletValue dollarScriptletValue() { - def groovyToken = this.expect(GROOVY) - new DollarScriptletValue().tap { - scriptlet = groovyToken.text - } - } - - @PeekBefore([LT, PERCENT, EQUALS]) - private ExpressionScriptletValue expressionScriptletValue() { - this.expect(LT) - this.expect(PERCENT) - this.expect(EQUALS) - def groovyToken = this.expect(GROOVY) - this.expect(PERCENT) - this.expect(GT) - new ExpressionScriptletValue().tap { - scriptlet = groovyToken.text - } - } - - @PeekBefore([LT, PERCENT]) - private ScriptletValue scriptletValue() { - this.expect(LT) - this.expect(PERCENT) - def groovyToken = this.expect(GROOVY) - this.expect(PERCENT) - this.expect(GT) - new ScriptletValue().tap { - scriptlet = groovyToken.text - } - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/ComponentToClosureVisitor.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/ComponentToClosureVisitor.groovy deleted file mode 100644 index 9a70d5a..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/ComponentToClosureVisitor.groovy +++ /dev/null @@ -1,77 +0,0 @@ -package com.jessebrault.gcp.component - -import com.jessebrault.gcp.component.node.BooleanValue -import com.jessebrault.gcp.component.node.ComponentRoot -import com.jessebrault.gcp.component.node.DollarReferenceValue -import com.jessebrault.gcp.component.node.DollarScriptletValue -import com.jessebrault.gcp.component.node.ExpressionScriptletValue -import com.jessebrault.gcp.component.node.GStringValue -import com.jessebrault.gcp.component.node.KeyAndValue -import com.jessebrault.gcp.component.node.KeysAndValues -import com.jessebrault.gcp.component.node.ComponentNodeVisitor -import com.jessebrault.gcp.component.node.ScriptletValue -import com.jessebrault.gcp.component.node.StringValue - -// NOT THREAD SAFE -class ComponentToClosureVisitor extends ComponentNodeVisitor { - - private StringBuilder b = new StringBuilder() - - String getResult() { - b.toString() - } - - void reset() { - b = new StringBuilder() - } - - void visit(ComponentRoot componentNode) { - b << '{ ' - super.visit(componentNode) - if (componentNode.body != null) { - b << "bodyOut << ${ componentNode.body }; " - } - b << '};' - } - - void visit(KeysAndValues keysAndValues) { - b << 'attr { ' - super.visit(keysAndValues) - b << '}; ' - } - - void visit(KeyAndValue keyAndValue) { - b << "${ keyAndValue.key } = " - super.visit(keyAndValue) - b << '; ' - } - - void visit(GStringValue gStringValue) { - b << "\"${ gStringValue.gString }\"" - } - - void visit(StringValue stringValue) { - b << "'${ stringValue.string }'" - } - - void visit(DollarReferenceValue dollarReferenceValue) { - b << dollarReferenceValue.reference - } - - void visit(DollarScriptletValue dollarScriptletValue) { - b << dollarScriptletValue.scriptlet - } - - void visit(ScriptletValue scriptletValue) { - b << "render { out -> ${ scriptletValue.scriptlet } }" - } - - void visit(ExpressionScriptletValue expressionScriptletValue) { - b << expressionScriptletValue.scriptlet - } - - void visit(BooleanValue booleanValue) { - b << booleanValue.value.toString() - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/ComponentToken.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/ComponentToken.groovy deleted file mode 100644 index 8a0fcca..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/ComponentToken.groovy +++ /dev/null @@ -1,37 +0,0 @@ -package com.jessebrault.gcp.component - -import groovy.transform.TupleConstructor - -@TupleConstructor -class ComponentToken { - - enum Type { - LT, - GT, - IDENTIFIER, - KEY, - EQUALS, - DOUBLE_QUOTE, - SINGLE_QUOTE, - STRING, - GROOVY, - GROOVY_IDENTIFIER, - PERCENT, - FORWARD_SLASH - ; - - boolean isAnyOf(Collection types) { - types.contains(this) - } - - } - - Type type - String text - - @Override - String toString() { - "ComponentToken(${ this.type }, ${ this.text })" - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/ComponentTokenizer.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/ComponentTokenizer.groovy deleted file mode 100644 index fa249fd..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/ComponentTokenizer.groovy +++ /dev/null @@ -1,159 +0,0 @@ -package com.jessebrault.gcp.component - -import com.jessebrault.fsm.function.FunctionFsmBuilder -import com.jessebrault.fsm.function.FunctionFsmBuilderImpl -import com.jessebrault.gcp.groovy.DollarScriptletParser -import com.jessebrault.gcp.util.PatternFunction - -import static ComponentToken.Type - -class ComponentTokenizer { - - private static final PatternFunction lessThan = new PatternFunction(~/^/) - private static final PatternFunction identifier = new PatternFunction(~/^\p{Lu}.*?(?=\s|\/)/) - private static final PatternFunction whitespace = new PatternFunction(~/^\s+/) - private static final PatternFunction key = new PatternFunction(~/^[\p{L}0-9_\-]+/) - private static final PatternFunction equals = new PatternFunction(~/^=/) - private static final PatternFunction doubleQuote = new PatternFunction(~/^"/) - private static final PatternFunction doubleQuoteStringContent = new PatternFunction(~/^(?:[\w\W&&[^\\"]]|\\")+/) - private static final PatternFunction singleQuote = new PatternFunction(~/^'/) - private static final PatternFunction singleQuoteStringContent = new PatternFunction(~/^(?:[\w\W&&[^\\']]|\\')+/) - - // https://docs.groovy-lang.org/latest/html/documentation/#_identifiers - //'\u00C0' to '\u00D6' - //'\u00D8' to '\u00F6' - //'\u00F8' to '\u00FF' - //'\u0100' to '\uFFFE' - private static final PatternFunction dollarReference = new PatternFunction(~/^\$[a-zA-Z_$\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u00ff\u0100-\ufff3][a-zA-Z_$0-9\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u00ff\u0100-\ufff3]*(?=[\s\/>])/) - - private static final PatternFunction percent = new PatternFunction(~/^%/) - private static final PatternFunction expressionScriptletGroovy = new PatternFunction(~/^.*?%>/) - private static final PatternFunction forwardSlash = new PatternFunction(~/^\//) - - static enum State { - START, - IDENTIFIER, - KEYS_AND_VALUES, - DOUBLE_QUOTE_STRING, - SINGLE_QUOTE_STRING, - EXPRESSION_SCRIPTLET_GROOVY, - DONE - } - - private static FunctionFsmBuilder getFsmBuilder() { - new FunctionFsmBuilderImpl<>() - } - - Queue tokenize(String src) { - Queue tokens = new LinkedList<>() - - def fsm = getFsmBuilder().with { - initialState = State.START - - whileIn(State.START) { - on lessThan shiftTo State.IDENTIFIER exec { - tokens << new ComponentToken(Type.LT, it) - } - onNoMatch() exec { - throw new IllegalArgumentException() - } - } - - whileIn(State.IDENTIFIER) { - on identifier shiftTo State.KEYS_AND_VALUES exec { - tokens << new ComponentToken(Type.IDENTIFIER, it) - } - onNoMatch() exec { - throw new IllegalArgumentException() - } - } - - whileIn(State.KEYS_AND_VALUES) { - on greaterThan shiftTo State.DONE exec { - tokens << new ComponentToken(Type.GT, it) - } - on whitespace exec { } - on key exec { - tokens << new ComponentToken(Type.KEY, it) - } - on equals exec { - tokens << new ComponentToken(Type.EQUALS, it) - } - on doubleQuote shiftTo State.DOUBLE_QUOTE_STRING exec { - tokens << new ComponentToken(Type.DOUBLE_QUOTE, it) - } - on singleQuote shiftTo State.SINGLE_QUOTE_STRING exec { - tokens << new ComponentToken(Type.SINGLE_QUOTE, it) - } - on dollarReference exec { String s -> - tokens << new ComponentToken(Type.GROOVY_IDENTIFIER, s.substring(1)) // skip opening $ - } - //noinspection GroovyAssignabilityCheck // for some reason IntelliJ is confused by this - on DollarScriptletParser::parse exec { String s -> - tokens << new ComponentToken(Type.GROOVY, s.substring(2, s.length() - 1)) - } - on percent shiftTo State.EXPRESSION_SCRIPTLET_GROOVY exec { - tokens << new ComponentToken(Type.PERCENT, it) - } - on forwardSlash exec { - tokens << new ComponentToken(Type.FORWARD_SLASH, it) - } - onNoMatch() exec { - throw new IllegalArgumentException() - } - } - - whileIn(State.DOUBLE_QUOTE_STRING) { - on doubleQuoteStringContent exec { - tokens << new ComponentToken(Type.STRING, it) - } - on doubleQuote shiftTo State.KEYS_AND_VALUES exec { - tokens << new ComponentToken(Type.DOUBLE_QUOTE, it) - } - onNoMatch() exec { - throw new IllegalArgumentException() - } - } - - whileIn(State.SINGLE_QUOTE_STRING) { - on singleQuoteStringContent exec { - tokens << new ComponentToken(Type.STRING, it) - } - on singleQuote shiftTo State.KEYS_AND_VALUES exec { - tokens << new ComponentToken(Type.SINGLE_QUOTE, it) - } - onNoMatch() exec { - throw new IllegalArgumentException() - } - } - - whileIn(State.EXPRESSION_SCRIPTLET_GROOVY) { - on expressionScriptletGroovy shiftTo State.KEYS_AND_VALUES exec { String s -> - tokens << new ComponentToken(Type.GROOVY, s.substring(0, s.length() - 2)) - tokens << new ComponentToken(Type.PERCENT, '%') - tokens << new ComponentToken(Type.GT, '>') - } - onNoMatch() exec { - throw new IllegalArgumentException() - } - } - - build() - } - - def remaining = src - - while (fsm.currentState != State.DONE) { - def output = fsm.apply(remaining) - if (!output) { - throw new IllegalStateException() - } else { - remaining = remaining.substring(output.length()) - } - } - - tokens - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/BooleanValue.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/BooleanValue.groovy deleted file mode 100644 index 56ad04c..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/BooleanValue.groovy +++ /dev/null @@ -1,11 +0,0 @@ -package com.jessebrault.gcp.component.node - -class BooleanValue extends ComponentNode { - boolean value - - @Override - String toString() { - "BooleanValue(${ this.value })" - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/ComponentNode.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/ComponentNode.groovy deleted file mode 100644 index ce7ce01..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/ComponentNode.groovy +++ /dev/null @@ -1,5 +0,0 @@ -package com.jessebrault.gcp.component.node - -abstract class ComponentNode { - List children = [] -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/ComponentNodeVisitor.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/ComponentNodeVisitor.groovy deleted file mode 100644 index ec60217..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/ComponentNodeVisitor.groovy +++ /dev/null @@ -1,15 +0,0 @@ -package com.jessebrault.gcp.component.node - -abstract class ComponentNodeVisitor { - - void visit(ComponentNode node) { - this.visitChildren(node) - } - - void visitChildren(ComponentNode node) { - node.children.each { - this.visit(it) - } - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/ComponentRoot.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/ComponentRoot.groovy deleted file mode 100644 index fbd8bb8..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/ComponentRoot.groovy +++ /dev/null @@ -1,13 +0,0 @@ -package com.jessebrault.gcp.component.node - -class ComponentRoot extends ComponentNode { - - String identifier - String body - - @Override - String toString() { - "ComponentNode(identifier: ${ this.identifier }, body: ${ this.body }, children: ${ this.children })" - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/DollarReferenceValue.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/DollarReferenceValue.groovy deleted file mode 100644 index 31d5157..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/DollarReferenceValue.groovy +++ /dev/null @@ -1,12 +0,0 @@ -package com.jessebrault.gcp.component.node - -class DollarReferenceValue extends ComponentNode { - - String reference - - @Override - String toString() { - "DollarReferenceValue(${ this.reference })" - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/DollarScriptletValue.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/DollarScriptletValue.groovy deleted file mode 100644 index b777756..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/DollarScriptletValue.groovy +++ /dev/null @@ -1,12 +0,0 @@ -package com.jessebrault.gcp.component.node - -class DollarScriptletValue extends ComponentNode { - - String scriptlet - - @Override - String toString() { - "DollarScriptletValue(${ this.scriptlet })" - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/ExpressionScriptletValue.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/ExpressionScriptletValue.groovy deleted file mode 100644 index 191c147..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/ExpressionScriptletValue.groovy +++ /dev/null @@ -1,12 +0,0 @@ -package com.jessebrault.gcp.component.node - -class ExpressionScriptletValue extends ComponentNode { - - String scriptlet - - @Override - String toString() { - "ExpressionScriptletValue(${ this.scriptlet })" - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/GStringValue.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/GStringValue.groovy deleted file mode 100644 index a518247..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/GStringValue.groovy +++ /dev/null @@ -1,12 +0,0 @@ -package com.jessebrault.gcp.component.node - -class GStringValue extends ComponentNode { - - String gString - - @Override - String toString() { - "GStringValue(${ this.gString })" - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/KeyAndValue.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/KeyAndValue.groovy deleted file mode 100644 index 774f167..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/KeyAndValue.groovy +++ /dev/null @@ -1,12 +0,0 @@ -package com.jessebrault.gcp.component.node - -class KeyAndValue extends ComponentNode { - - String key - - @Override - String toString() { - "KeyAndValue(key: ${ this.key }, children: ${ this.children })" - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/KeysAndValues.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/KeysAndValues.groovy deleted file mode 100644 index bdf39df..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/KeysAndValues.groovy +++ /dev/null @@ -1,10 +0,0 @@ -package com.jessebrault.gcp.component.node - -class KeysAndValues extends ComponentNode { - - @Override - String toString() { - "KeysAndValues(${ this.children })" - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/ScriptletValue.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/ScriptletValue.groovy deleted file mode 100644 index 247b81b..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/ScriptletValue.groovy +++ /dev/null @@ -1,12 +0,0 @@ -package com.jessebrault.gcp.component.node - -class ScriptletValue extends ComponentNode { - - String scriptlet - - @Override - String toString() { - "ScriptletValue(${ this.scriptlet })" - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/StringValue.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/StringValue.groovy deleted file mode 100644 index 570bbcd..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/component/node/StringValue.groovy +++ /dev/null @@ -1,12 +0,0 @@ -package com.jessebrault.gcp.component.node - -class StringValue extends ComponentNode { - - String string - - @Override - String toString() { - "StringValue(${ this.string })" - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/groovy/BlockScriptletParser.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/groovy/BlockScriptletParser.groovy deleted file mode 100644 index 332cabd..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/groovy/BlockScriptletParser.groovy +++ /dev/null @@ -1,22 +0,0 @@ -package com.jessebrault.gcp.groovy - -class BlockScriptletParser { - - static class Result { - String fullMatch - String scriptlet - } - - static String parse(String input) { - - } - - static Result parseResult(String input) { - def match = parse(input) - match != null ? new Result().tap { - fullMatch = match - scriptlet = fullMatch.substring(2, fullMatch.length() - 2) - } : null - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/groovy/DollarReferenceParser.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/groovy/DollarReferenceParser.groovy deleted file mode 100644 index 813ddd4..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/groovy/DollarReferenceParser.groovy +++ /dev/null @@ -1,14 +0,0 @@ -package com.jessebrault.gcp.groovy - -class DollarReferenceParser { - - static class Result { - String fullMatch - String reference - } - - static Result parse(String input) { - - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/groovy/DollarScriptletParser.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/groovy/DollarScriptletParser.groovy deleted file mode 100644 index e78f4bc..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/groovy/DollarScriptletParser.groovy +++ /dev/null @@ -1,146 +0,0 @@ -package com.jessebrault.gcp.groovy - -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -class DollarScriptletParser { - - private static Logger logger = LoggerFactory.getLogger(DollarScriptletParser) - - static class Result { - String fullMatch - String scriptlet - } - - private enum State { - NO_STRING, G_STRING, SINGLE_QUOTE_STRING - } - - private static class Counter { - - int count = 0 - - void increment() { - this.count++ - } - - void decrement() { - this.count-- - } - - void next() { - this.increment() - } - - void previous() { - this.decrement() - } - - boolean isZero() { - this.count == 0 - } - - @Override - String toString() { - "Counter(${ this.count })" - } - - } - - static String parse(String input) { - def acc = new StringBuilder() - def stateStack = new LinkedList([State.NO_STRING]) - def counterStack = new LinkedList([new Counter()]) - def iterator = input.iterator() as Iterator - - if (!iterator.hasNext() || iterator.next() != '$') { - return null - } else { - acc << '$' - counterStack.peek()++ - } - - if (!iterator.hasNext() || iterator.next() != '{') { - return null - } else { - acc << '{' - } - - while (iterator.hasNext()) { - assert counterStack.size() > 0 - assert stateStack.size() > 0 - - def c0 = iterator.next() - acc << c0 - logger.debug('----') - logger.debug('c0: {}', c0) - logger.debug('acc: {}', acc) - if (stateStack.peek() == State.NO_STRING) { - if (c0 == '{') { - counterStack.peek()++ - } else if (c0 == '}') { - counterStack.peek()-- - if (counterStack.peek().isZero()) { - if (counterStack.size() == 1) { - logger.debug('single Counter is zero; breaking while loop') - break // escape while loop - } else { - logger.debug('counterStack.size() is greater than zero and top Counter is zero; ' + - 'popping state and counter stacks') - counterStack.pop() - stateStack.pop() - } - } - } else if (c0 == '"') { - stateStack.push(State.G_STRING) - } else if (c0 == "'") { - stateStack.push(State.SINGLE_QUOTE_STRING) - } - } else if (stateStack.peek() == State.G_STRING) { - if (c0 == '\\') { - if (iterator.hasNext()) { - acc << iterator.next() - } else { - throw new IllegalArgumentException('Ill-formed dollar groovy') - } - } else if (c0 == '$') { - if (iterator.hasNext()) { - def c1 = iterator.next() - acc << c1 - if (c1 == '{') { - stateStack.push(State.NO_STRING) - counterStack.push(new Counter()) - counterStack.peek()++ - } - } else { - throw new IllegalArgumentException('Ill-formed dollar groovy') - } - } else if (c0 == '"') { - logger.debug('popping G_STRING state') - stateStack.pop() - } - } else if (stateStack.peek() == State.SINGLE_QUOTE_STRING) { - if (c0 == "'") { - logger.debug('popping SINGLE_QUOTE_STRING state') - stateStack.pop() - } - } - logger.debug('stateStack: {}', stateStack) - logger.debug('counterStack: {}', counterStack) - } - acc.toString() - } - - static Result parseResult(String input) { - def match = parse(input) - if (match) { - new Result().tap { - fullMatch = match - scriptlet = fullMatch.substring(2, fullMatch.length() - 1) - } - } else { - null - } - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/groovy/ExpressionScriptletParser.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/groovy/ExpressionScriptletParser.groovy deleted file mode 100644 index 0114279..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/groovy/ExpressionScriptletParser.groovy +++ /dev/null @@ -1,22 +0,0 @@ -package com.jessebrault.gcp.groovy - -class ExpressionScriptletParser { - - static class Result { - String fullMatch - String scriptlet - } - - static String parse(String input) { - - } - - static Result parseResult(String input) { - def match = parse(input) - match != null ? new Result().tap { - fullMatch = match - scriptlet = fullMatch.substring(3, fullMatch.length() - 2) - } : null - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/BlockScriptlet.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/BlockScriptlet.groovy deleted file mode 100644 index 2076642..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/BlockScriptlet.groovy +++ /dev/null @@ -1,5 +0,0 @@ -package com.jessebrault.gcp.node - -class BlockScriptlet extends GcpNode { - String scriptlet -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/ComponentInstance.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/ComponentInstance.groovy deleted file mode 100644 index 9599811..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/ComponentInstance.groovy +++ /dev/null @@ -1,6 +0,0 @@ -package com.jessebrault.gcp.node - -class ComponentInstance extends GcpNode { - String opening - String closing -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/Document.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/Document.groovy deleted file mode 100644 index 7df17af..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/Document.groovy +++ /dev/null @@ -1,3 +0,0 @@ -package com.jessebrault.gcp.node - -class Document extends GcpNode {} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/DollarReference.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/DollarReference.groovy deleted file mode 100644 index 652fa1e..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/DollarReference.groovy +++ /dev/null @@ -1,5 +0,0 @@ -package com.jessebrault.gcp.node - -class DollarReference extends GcpNode { - String reference -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/DollarScriptlet.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/DollarScriptlet.groovy deleted file mode 100644 index 270888e..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/DollarScriptlet.groovy +++ /dev/null @@ -1,5 +0,0 @@ -package com.jessebrault.gcp.node - -class DollarScriptlet extends GcpNode { - String scriptlet -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/ExpressionScriptlet.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/ExpressionScriptlet.groovy deleted file mode 100644 index a48765a..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/ExpressionScriptlet.groovy +++ /dev/null @@ -1,5 +0,0 @@ -package com.jessebrault.gcp.node - -class ExpressionScriptlet extends GcpNode { - String scriptlet -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/GcpNode.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/GcpNode.groovy deleted file mode 100644 index bce57eb..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/GcpNode.groovy +++ /dev/null @@ -1,5 +0,0 @@ -package com.jessebrault.gcp.node - -abstract class GcpNode { - List children = [] -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/GcpNodeVisitor.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/GcpNodeVisitor.groovy deleted file mode 100644 index 2c59eba..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/GcpNodeVisitor.groovy +++ /dev/null @@ -1,13 +0,0 @@ -package com.jessebrault.gcp.node - -abstract class GcpNodeVisitor { - - void visit(GcpNode node) { - this.visitChildren(node) - } - - void visitChildren(GcpNode node) { - node.children.each(this.&visit) - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/Html.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/Html.groovy deleted file mode 100644 index 9954803..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/node/Html.groovy +++ /dev/null @@ -1,5 +0,0 @@ -package com.jessebrault.gcp.node - -class Html extends GcpNode { - String text -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/Accumulator.java b/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/Accumulator.java deleted file mode 100644 index 1d30ece..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/Accumulator.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.jessebrault.gcp.tokenizer; - -import java.util.Queue; -import java.util.regex.Pattern; - -final class Accumulator { - - private static final Pattern newline = Pattern.compile("([\n\r])"); - - private final Queue tokens; - private int inputIndex = 0; - private int line = 1; - private int col = 1; - - public Accumulator(Queue tokenQueue) { - this.tokens = tokenQueue; - } - - public void accumulate(Token.Type type, CharSequence text) { - this.tokens.add(new TokenImpl(type, text, this.inputIndex, this.line, this.col)); - this.inputIndex += text.length(); - final var m = newline.matcher(text); - if (m.find()) { - this.line += m.groupCount(); - this.col = 1; - } else { - this.col += text.length(); - } - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/Counter.java b/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/Counter.java deleted file mode 100644 index c465c18..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/Counter.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.jessebrault.gcp.tokenizer; - -final class Counter { - - private int count = 0; - - public void increment() { - this.count++; - } - - public void decrement() { - this.count--; - } - - public boolean isZero() { - return this.count == 0; - } - - @Override - public String toString() { - return "Counter(" + this.count + ")"; - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/DollarScriptletMatcher.java b/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/DollarScriptletMatcher.java deleted file mode 100644 index 96a5dc8..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/DollarScriptletMatcher.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.jessebrault.gcp.tokenizer; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Deque; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.function.Supplier; - -final class DollarScriptletMatcher implements FsmFunction { - - private static final Logger logger = LoggerFactory.getLogger(DollarScriptletMatcher.class); - - private static final class DollarScriptletMatcherOutput implements FsmOutput { - - private final CharSequence entire; - private final String scriptlet; - - public DollarScriptletMatcherOutput( - String entire, - String scriptlet - ) { - this.entire = entire; - this.scriptlet = scriptlet; - } - - @Override - public CharSequence entire() { - return this.entire; - } - - @Override - public CharSequence part(int index) { - return switch (index) { - case 1 -> "$"; - case 2 -> "{"; - case 3 -> this.scriptlet; - case 4 -> "}"; - default -> throw new IllegalArgumentException(); - }; - } - - } - - private enum State { - NO_STRING, G_STRING, SINGLE_QUOTE_STRING - } - - private static final class CharSequenceIterator implements Iterator { - - private final CharSequence input; - private int cur; - - public CharSequenceIterator(CharSequence input) { - this.input = input; - } - - @Override - public boolean hasNext() { - return this.cur < input.length(); - } - - @Override - public String next() { - final var c = String.valueOf(input.charAt(this.cur)); - this.cur++; - return c; - } - - } - - @Override - public FsmOutput apply(CharSequence s) { - final Deque stateStack = new LinkedList<>(); - final Deque counterStack = new LinkedList<>(); - - final Supplier currentCounterSupplier = () -> { - final var currentCounter = counterStack.peek(); - if (currentCounter == null) { - throw new IllegalStateException("currentCounter is null"); - } - return currentCounter; - }; - - stateStack.push(State.NO_STRING); - counterStack.push(new Counter()); - - final Iterator iterator = new CharSequenceIterator(s); - - final var entireAcc = new StringBuilder(); - - if (!iterator.hasNext() || !iterator.next().equals("$")) { - return null; - } else { - entireAcc.append("$"); - } - - if (!iterator.hasNext() || !iterator.next().equals("{")) { - return null; - } else { - entireAcc.append("{"); - currentCounterSupplier.get().increment(); - } - - outer: - while (iterator.hasNext()) { - if (stateStack.isEmpty()) { - throw new IllegalStateException("stateStack is empty"); - } - if (counterStack.isEmpty()) { - throw new IllegalStateException("counterStack is empty"); - } - - final var c0 = iterator.next(); - entireAcc.append(c0); - - logger.debug("----"); - logger.debug("c0: {}", c0); - - if (stateStack.peek() == State.NO_STRING) { - switch (c0) { - case "{" -> currentCounterSupplier.get().increment(); - case "}" -> { - final var currentCounter = currentCounterSupplier.get(); - currentCounter.decrement(); - if (currentCounter.isZero()) { - if (counterStack.size() == 1) { - logger.debug("last Counter is zero; breaking while loop"); - break outer; - } else { - logger.debug("counterStack.size() is greater than 1 and top Counter is zero; " + - "popping state and counter stacks."); - stateStack.pop(); - counterStack.pop(); - } - } - } - case "\"" -> stateStack.push(State.G_STRING); - case "'" -> stateStack.push(State.SINGLE_QUOTE_STRING); - } - } else if (stateStack.peek() == State.G_STRING) { - switch (c0) { - case "\\" -> { - if (iterator.hasNext()) { - final var c1 = iterator.next(); - entireAcc.append(c1); - } else { - throw new IllegalArgumentException( - "Ill-formed dollarScriptlet (backslash followed by nothing)" - ); - } - } - case "$" -> { - if (iterator.hasNext()) { - final var c1 = iterator.next(); - entireAcc.append(c1); - if (c1.equals("{")) { - stateStack.push(State.NO_STRING); - counterStack.push(new Counter()); - currentCounterSupplier.get().increment(); - } - } else { - throw new IllegalArgumentException("Ill-formed dollarScriptlet (ends with a dollar)"); - } - } - case "\"" -> { - logger.debug("popping G_STRING state"); - stateStack.pop(); - } - } - } else if (stateStack.peek() == State.SINGLE_QUOTE_STRING) { - switch (c0) { - case "\\" -> { - if (iterator.hasNext()) { - entireAcc.append(iterator.next()); - } else { - throw new IllegalArgumentException( - "Ill-formed dollarScriptlet (backslash followed by nothing)" - ); - } - } - case "'" -> { - logger.debug("popping SINGLE_QUOTE_STRING state"); - stateStack.pop(); - } - } - } else { - throw new IllegalStateException( - "stateStack contains something which does not equal a state or is null" - ); - } - - logger.debug("entireAcc: {}", entireAcc); - logger.debug("stateStack: {}", stateStack); - logger.debug("counterStack: {}", counterStack); - } - - return new DollarScriptletMatcherOutput( - entireAcc.toString(), - entireAcc.substring(2, entireAcc.length() - 1) - ); - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/FsmFunction.java b/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/FsmFunction.java deleted file mode 100644 index 99d7b8d..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/FsmFunction.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.jessebrault.gcp.tokenizer; - -import java.util.function.Function; - -interface FsmFunction extends Function {} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/FsmOutput.java b/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/FsmOutput.java deleted file mode 100644 index 97c763c..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/FsmOutput.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.jessebrault.gcp.tokenizer; - -interface FsmOutput { - CharSequence entire(); - CharSequence part(int index); -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/GStringMatcher.java b/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/GStringMatcher.java deleted file mode 100644 index 07238b5..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/GStringMatcher.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.jessebrault.gcp.tokenizer; - -import com.jessebrault.fsm.stackfunction.StackFunctionFsm; -import com.jessebrault.fsm.stackfunction.StackFunctionFsmBuilder; -import com.jessebrault.fsm.stackfunction.StackFunctionFsmBuilderImpl; - -import java.util.regex.Pattern; - -final class GStringMatcher implements FsmFunction { - - private static final class GStringMatcherOutput implements FsmOutput { - - private final CharSequence entire; - private final CharSequence contents; - - public GStringMatcherOutput(String entire, String contents) { - this.entire = entire; - this.contents = contents; - } - - @Override - public CharSequence entire() { - return this.entire; - } - - @Override - public CharSequence part(int index) { - return switch(index) { - case 1, 3 -> "\""; - case 2 -> this.contents; - default -> throw new IllegalArgumentException(); - }; - } - - } - - private static final PatternMatcher text = new PatternMatcher( - Pattern.compile("^(?:[\\w\\W&&[^$\\\\\"\\n\\r]]|\\\\[\"nrbfst\\\\u]|\\$(?!\\{|[\\w$]+(?:\\.[\\w$]+)*))+") - ); - private static final DollarScriptletMatcher dollarScriptlet = new DollarScriptletMatcher(); - private static final PatternMatcher doubleQuote = new PatternMatcher( - Pattern.compile("^\"") - ); - - private enum State { - START, CONTENTS, DONE - } - - private static StackFunctionFsmBuilder getFsmBuilder() { - return new StackFunctionFsmBuilderImpl<>(); - } - - private static StackFunctionFsm getFsm(StringBuilder acc) { - return getFsmBuilder() - .setInitialState(State.START) - .whileIn(State.START, sc -> { - sc.on(doubleQuote).shiftTo(State.CONTENTS).exec(o -> { - acc.append(o.entire()); - }); - sc.onNoMatch().exec(input -> { - throw new IllegalArgumentException(); - }); - }) - .whileIn(State.CONTENTS, sc -> { - sc.on(text).exec(o -> { - acc.append(o.entire()); - }); - sc.on(dollarScriptlet).exec(o -> { - acc.append(o.entire()); - }); - sc.on(doubleQuote).shiftTo(State.DONE).exec(o -> { - acc.append(o.entire()); - }); - sc.onNoMatch().exec(input -> { - throw new IllegalArgumentException(); - }); - }) - .build(); - } - - @Override - public FsmOutput apply(final CharSequence s) { - final var acc = new StringBuilder(); - final var fsm = getFsm(acc); - - CharSequence remaining = s; - - // Look-ahead - if (!String.valueOf(remaining.charAt(0)).equals("\"")) { - return null; - } - - while (remaining.length() > 0) { - final var output = fsm.apply(remaining); - if (output == null) { - throw new IllegalStateException("output is null"); - } - if (fsm.getCurrentState() == State.DONE) { - break; - } - remaining = remaining.subSequence(output.entire().length(), remaining.length()); - } - - final var entire = acc.toString(); - return new GStringMatcherOutput(entire, entire.substring(1, entire.length() - 1)); - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/PatternMatcher.java b/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/PatternMatcher.java deleted file mode 100644 index 16eca52..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/PatternMatcher.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.jessebrault.gcp.tokenizer; - -import java.util.regex.MatchResult; -import java.util.regex.Pattern; - -final class PatternMatcher implements FsmFunction { - - private static final class MatchResultFsmOutput implements FsmOutput { - - private final MatchResult matchResult; - - public MatchResultFsmOutput(MatchResult matchResult) { - this.matchResult = matchResult; - } - - @Override - public CharSequence entire() { - return this.matchResult.group(0); - } - - @Override - public CharSequence part(int index) { - return this.matchResult.group(index); - } - - @Override - public String toString() { - return "MatchResultFsmOutput(" + this.entire() + ")"; - } - - } - - private final Pattern pattern; - - public PatternMatcher(Pattern pattern) { - this.pattern = pattern; - } - - @Override - public FsmOutput apply(CharSequence s) { - final var m = this.pattern.matcher(s); - return m.find() ? new MatchResultFsmOutput(m) : null; - } - - @Override - public String toString() { - return "MatcherFunction(" + this.pattern + ")"; - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/TokenImpl.java b/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/TokenImpl.java deleted file mode 100644 index 479b52e..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/TokenImpl.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.jessebrault.gcp.tokenizer; - -public final class TokenImpl implements Token { - - private final Type type; - private final CharSequence text; - private final int inputIndex; - private final int line; - private final int col; - - public TokenImpl(Type type, CharSequence text, int inputIndex, int line, int col) { - this.type = type; - this.text = text; - this.inputIndex = inputIndex; - this.line = line; - this.col = col; - } - - @Override - public Type getType() { - return type; - } - - @Override - public CharSequence getText() { - return text; - } - - @Override - public int getInputIndex() { - return 0; - } - - @Override - public int getLine() { - return line; - } - - @Override - public int getCol() { - return col; - } - - @Override - public String toString() { - return String.format("Token(%s, %s, %d, %d, %d)", this.type, this.text, this.inputIndex, this.line, this.col); - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/TokenizerFsm.java b/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/TokenizerFsm.java deleted file mode 100644 index 6449c83..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/TokenizerFsm.java +++ /dev/null @@ -1,195 +0,0 @@ -package com.jessebrault.gcp.tokenizer; - -import com.jessebrault.fsm.function.FunctionFsm; -import com.jessebrault.fsm.function.FunctionFsmBuilder; -import com.jessebrault.fsm.function.FunctionFsmBuilderImpl; - -import static com.jessebrault.gcp.tokenizer.Token.Type.*; - -import java.util.regex.Pattern; - -final class TokenizerFsm { - - /** - * Text - */ - private static final FsmFunction text = new PatternMatcher( - Pattern.compile("^(?:[\\w\\W&&[^<$]]|<(?!%|/?\\p{Lu}|/?[\\p{L}0-9_$]+(?:\\.[\\p{L}0-9_$]+)+)|\\$(?![\\w$]+(?:\\.[\\w$]+)*))+") - ); - - /** - * Gsp dollar reference and scriptlets, also used as component values - */ - private static final FsmFunction dollarReference = new PatternMatcher( - Pattern.compile("^(\\$)([\\w$]+(?:\\.[\\w$]+)*)") - ); - private static final FsmFunction dollarScriptlet = new DollarScriptletMatcher(); - private static final FsmFunction blockScriptlet = new PatternMatcher( - Pattern.compile("^(<%)(.*?)(%>)") - ); - private static final FsmFunction expressionScriptlet = new PatternMatcher( - Pattern.compile("^(<%=)(.*?)(%>)") - ); - - /** - * Component starts - */ - private static final FsmFunction openingComponentStart = new PatternMatcher( - Pattern.compile("^<(?=\\p{Lu}|[\\p{L}0-9_$]+(?:\\.[\\p{L}0-9_$]+)+)") - ); - private static final FsmFunction closingComponentStart = new PatternMatcher( - Pattern.compile("^(<)(/)(?=\\p{Lu}|[\\p{L}0-9_$]+(?:\\.[\\p{L}0-9_$]+)+)") - ); - - /** - * Component names - */ - private static final FsmFunction className = new PatternMatcher( - Pattern.compile("^\\p{Lu}[\\p{L}0-9_$]*") - ); - private static final FsmFunction packageName = new PatternMatcher( - Pattern.compile("^[\\p{L}0-9_$]+(?=\\.)") - ); - private static final FsmFunction dot = new PatternMatcher( - Pattern.compile("^\\.") - ); - - /** - * Whitespace - */ - private static final FsmFunction whitespace = new PatternMatcher(Pattern.compile("^\\s+")); - - /** - * Keys and values - */ - private static final FsmFunction key = new PatternMatcher( - Pattern.compile("^[\\p{L}0-9_$]+") - ); - private static final FsmFunction equals = new PatternMatcher(Pattern.compile("^=")); - private static final FsmFunction singleQuoteString = new PatternMatcher( - Pattern.compile("^(')((?:[\\w\\W&&[^\\\\'\\n\\r]]|\\\\['nrbfst\\\\u])*)(')") - ); - private static final FsmFunction gString = new GStringMatcher(); - - /** - * Component ends - */ - private static final FsmFunction forwardSlash = new PatternMatcher(Pattern.compile("^/")); - private static final FsmFunction componentEnd = new PatternMatcher(Pattern.compile("^>")); - - private static FunctionFsmBuilder getFsmBuilder() { - return new FunctionFsmBuilderImpl<>(); - } - - public static FunctionFsm get(Accumulator acc, Tokenizer.State state) { - return getFsmBuilder() - .setInitialState(state) - .whileIn(Tokenizer.State.TEXT, sc -> { - sc.on(text).exec(o -> { - acc.accumulate(TEXT, o.entire()); - }); - sc.on(dollarReference).exec(o -> { - acc.accumulate(DOLLAR, o.part(1)); - acc.accumulate(GROOVY_REFERENCE, o.part(2)); - }); - sc.on(dollarScriptlet).exec(o -> { - acc.accumulate(DOLLAR, o.part(1)); - acc.accumulate(CURLY_OPEN, o.part(2)); - acc.accumulate(SCRIPTLET, o.part(3)); - acc.accumulate(CURLY_CLOSE, o.part(4)); - }); - sc.on(blockScriptlet).exec(o -> { - acc.accumulate(BLOCK_SCRIPTLET_OPEN, o.part(1)); - acc.accumulate(SCRIPTLET, o.part(2)); - acc.accumulate(SCRIPTLET_CLOSE, o.part(3)); - }); - sc.on(expressionScriptlet).exec(o -> { - acc.accumulate(EXPRESSION_SCRIPTLET_OPEN, o.part(1)); - acc.accumulate(SCRIPTLET, o.part(2)); - acc.accumulate(SCRIPTLET_CLOSE, o.part(3)); - }); - sc.on(openingComponentStart).shiftTo(Tokenizer.State.COMPONENT_NAME).exec(o -> - acc.accumulate(COMPONENT_START, o.entire()) - ); - sc.on(closingComponentStart).shiftTo(Tokenizer.State.COMPONENT_NAME).exec(o -> { - acc.accumulate(COMPONENT_START, o.part(1)); - acc.accumulate(FORWARD_SLASH, o.part(2)); - }); - sc.onNoMatch().exec(input -> { throw new IllegalArgumentException(); }); - }) - .whileIn(Tokenizer.State.COMPONENT_NAME, sc -> { - sc.on(packageName).exec(o -> { - acc.accumulate(PACKAGE_NAME, o.entire()); - }); - sc.on(dot).exec(o -> { - acc.accumulate(DOT, o.entire()); - }); - sc.on(className).exec(o -> { - acc.accumulate(CLASS_NAME, o.entire()); - }); - sc.on(forwardSlash).exec(o -> { - acc.accumulate(FORWARD_SLASH, o.entire()); - }); - sc.on(componentEnd).shiftTo(Tokenizer.State.TEXT).exec(o -> { - acc.accumulate(COMPONENT_END, o.entire()); - }); - sc.on(whitespace).shiftTo(Tokenizer.State.COMPONENT_KEYS_AND_VALUES).exec(o -> { - acc.accumulate(WHITESPACE, o.entire()); - }); - sc.onNoMatch().exec(input -> { throw new IllegalArgumentException(); }); - }) - .whileIn(Tokenizer.State.COMPONENT_KEYS_AND_VALUES, sc -> { - sc.on(componentEnd).shiftTo(Tokenizer.State.TEXT).exec(o -> { - acc.accumulate(COMPONENT_END, o.entire()); - }); - sc.on(whitespace).exec(o -> { - acc.accumulate(WHITESPACE, o.entire()); - }); - sc.on(key).exec(o -> { - acc.accumulate(KEY, o.entire()); - }); - sc.on(equals).exec(o -> { - acc.accumulate(EQUALS, o.entire()); - }); - sc.on(gString).exec(o -> { - acc.accumulate(DOUBLE_QUOTE, o.part(1)); - acc.accumulate(STRING, o.part(2)); - acc.accumulate(DOUBLE_QUOTE, o.part(3)); - }); - sc.on(singleQuoteString).exec(o -> { - acc.accumulate(SINGLE_QUOTE, o.part(1)); - acc.accumulate(STRING, o.part(2)); - acc.accumulate(SINGLE_QUOTE, o.part(3)); - }); - sc.on(dollarReference).exec(o -> { - acc.accumulate(DOLLAR, o.part(1)); - acc.accumulate(GROOVY_REFERENCE, o.part(2)); - }); - sc.on(dollarScriptlet).exec(o -> { - acc.accumulate(DOLLAR, o.part(1)); - acc.accumulate(CURLY_OPEN, o.part(2)); - acc.accumulate(SCRIPTLET, o.part(3)); - acc.accumulate(CURLY_CLOSE, o.part(4)); - }); - sc.on(blockScriptlet).exec(o -> { - acc.accumulate(BLOCK_SCRIPTLET_OPEN, o.part(1)); - acc.accumulate(SCRIPTLET, o.part(2)); - acc.accumulate(SCRIPTLET_CLOSE, o.part(3)); - }); - sc.on(expressionScriptlet).exec(o -> { - acc.accumulate(EXPRESSION_SCRIPTLET_OPEN, o.part(1)); - acc.accumulate(SCRIPTLET, o.part(2)); - acc.accumulate(SCRIPTLET_CLOSE, o.part(3)); - }); - sc.on(forwardSlash).exec(o -> { - acc.accumulate(FORWARD_SLASH, o.entire()); - }); - sc.on(componentEnd).shiftTo(Tokenizer.State.TEXT).exec(o -> { - acc.accumulate(COMPONENT_END, o.entire()); - }); - sc.onNoMatch().exec(input -> { throw new IllegalArgumentException(); }); - }) - .build(); - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/TokenizerImpl.java b/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/TokenizerImpl.java deleted file mode 100644 index 7308dfa..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/tokenizer/TokenizerImpl.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.jessebrault.gcp.tokenizer; - -import com.jessebrault.fsm.function.FunctionFsm; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.LinkedList; -import java.util.Queue; - -public final class TokenizerImpl implements Tokenizer { - - private static final Logger logger = LoggerFactory.getLogger(TokenizerImpl.class); - - private CharSequence input; - private int currentOffset; - private int endOffset; - - private Queue tokens; - private FunctionFsm fsm; - - @Override - public void start(CharSequence input, int startOffset, int endOffset, State initialState) { - this.input = input; - this.currentOffset = startOffset; - this.endOffset = endOffset; - this.tokens = new LinkedList<>(); - this.fsm = TokenizerFsm.get(new Accumulator(this.tokens), initialState); - } - - @Override - public boolean hasNext() { - if (this.tokens.isEmpty()) { - this.getNextTokens(); - } - return !this.tokens.isEmpty(); - } - - private void getNextTokens() { - if (this.currentOffset != this.endOffset) { - final var match = this.fsm.apply(this.input.subSequence(this.currentOffset, this.endOffset)); - if (match == null) { - logger.error("match is null!"); - } else { - this.currentOffset += match.entire().length(); - } - } - } - - @Override - public Token next() { - if (this.tokens.isEmpty()) { - throw new IllegalStateException("currentAccumulatedTokens is empty"); - } - return this.tokens.remove(); - } - - @Override - public State getCurrentState() { - return this.fsm.getCurrentState(); - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/util/PatternFunction.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/util/PatternFunction.groovy deleted file mode 100644 index b79df74..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/util/PatternFunction.groovy +++ /dev/null @@ -1,25 +0,0 @@ -package com.jessebrault.gcp.util - -import groovy.transform.PackageScope -import groovy.transform.TupleConstructor - -import java.util.function.Function -import java.util.regex.Pattern - -@TupleConstructor(includeFields = true, defaults = false) -class PatternFunction implements Function { - - protected final Pattern pattern - - @Override - String apply(String s) { - def matcher = this.pattern.matcher(s) - matcher.find() ? matcher.group() : null - } - - @Override - String toString() { - "PatternFunction(pattern: ${ this.pattern })" - } - -} diff --git a/gcp-impl/src/main/groovy/com/jessebrault/gcp/util/PeekBefore.groovy b/gcp-impl/src/main/groovy/com/jessebrault/gcp/util/PeekBefore.groovy deleted file mode 100644 index bca4528..0000000 --- a/gcp-impl/src/main/groovy/com/jessebrault/gcp/util/PeekBefore.groovy +++ /dev/null @@ -1,11 +0,0 @@ -package com.jessebrault.gcp.util - -import com.jessebrault.gcp.component.ComponentToken - -import java.lang.annotation.Retention -import java.lang.annotation.RetentionPolicy - -@Retention(RetentionPolicy.SOURCE) -@interface PeekBefore { - ComponentToken.Type[] value() -} \ No newline at end of file diff --git a/gcp-impl/src/main/resources/META-INF/services/com.jessebrault.gcp.GcpToScriptConverter b/gcp-impl/src/main/resources/META-INF/services/com.jessebrault.gcp.GcpToScriptConverter deleted file mode 100644 index e531eeb..0000000 --- a/gcp-impl/src/main/resources/META-INF/services/com.jessebrault.gcp.GcpToScriptConverter +++ /dev/null @@ -1 +0,0 @@ -com.jessebrault.gcp.GcpToScriptConverterImpl \ No newline at end of file diff --git a/gcp-impl/src/main/resources/test.gdsl b/gcp-impl/src/main/resources/test.gdsl deleted file mode 100644 index 24bc0c2..0000000 --- a/gcp-impl/src/main/resources/test.gdsl +++ /dev/null @@ -1,6 +0,0 @@ -def ctx = context(filetypes: ['gsp']) - -contributor(ctx) { - method name: 'foo', params: [bar: 'String'], type: 'int' - property name: 'texts', type: 'java.util.List', doc: 'Some texts.' -} \ No newline at end of file diff --git a/gcp-impl/src/main/resources/test.groovy b/gcp-impl/src/main/resources/test.groovy deleted file mode 100644 index 8b13789..0000000 --- a/gcp-impl/src/main/resources/test.groovy +++ /dev/null @@ -1 +0,0 @@ - diff --git a/gcp-impl/src/main/resources/test.gsp b/gcp-impl/src/main/resources/test.gsp deleted file mode 100644 index 20645f1..0000000 --- a/gcp-impl/src/main/resources/test.gsp +++ /dev/null @@ -1,5 +0,0 @@ -def elf = foo('elf') - -texts.each { - -} \ No newline at end of file diff --git a/gcp-impl/src/test/groovy/com/jessebrault/gcp/component/ComponentParserTests.groovy b/gcp-impl/src/test/groovy/com/jessebrault/gcp/component/ComponentParserTests.groovy deleted file mode 100644 index 2af67b4..0000000 --- a/gcp-impl/src/test/groovy/com/jessebrault/gcp/component/ComponentParserTests.groovy +++ /dev/null @@ -1,137 +0,0 @@ -package com.jessebrault.gcp.component - -import com.jessebrault.gcp.component.node.* -import groovy.transform.stc.ClosureParams -import groovy.transform.stc.FirstParam -import groovy.transform.stc.SimpleType -import org.junit.jupiter.api.Test -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import static com.jessebrault.gcp.component.ComponentToken.Type.* - -import static org.junit.jupiter.api.Assertions.assertEquals -import static org.junit.jupiter.api.Assertions.assertTrue - -class ComponentParserTests { - - private static final Logger logger = LoggerFactory.getLogger(ComponentParserTests) - - private static class NodeSpec { - - Class nodeClass - Closure tests - - NodeSpec( - Class nodeClass, - @DelegatesTo(value = NodeTester, strategy = Closure.DELEGATE_FIRST) - @ClosureParams(FirstParam.FirstGenericType) - Closure tests = null - ) { - this.nodeClass = Objects.requireNonNull(nodeClass) - this.tests = tests - } - - void test(ComponentNode actual) { - logger.debug('actual: {}', actual) - assertTrue(nodeClass.isAssignableFrom(actual.class)) - if (this.tests != null) { - def nodeTester = new NodeTester() - this.tests.setDelegate(nodeTester) - this.tests.setResolveStrategy(Closure.DELEGATE_FIRST) - this.tests(actual) - - def childIterator = actual.children.iterator() - assertEquals(nodeTester.childSpecs.size(), actual.children.size()) - - nodeTester.childSpecs.each { - assertTrue(childIterator.hasNext()) - def next = childIterator.next() - it.test(next) - } - } - } - - @Override - String toString() { - "NodeSpec(${ this.nodeClass.simpleName })" - } - - } - - private static class NodeTester { - - List> childSpecs = [] - - def void expect( - Class childNodeClass, - @DelegatesTo(value = NodeTester, strategy = Closure.DELEGATE_FIRST) - @ClosureParams(FirstParam.FirstGenericType) - Closure furtherTests - ) { - this.childSpecs << new NodeSpec(childNodeClass, furtherTests) - } - - void expect(Class nodeClass) { - this.childSpecs << new NodeSpec(nodeClass) - } - - } - - private final ComponentParser parser = new ComponentParser() - - private void selfClosing( - Queue tokens, - @DelegatesTo(value = NodeTester, strategy = Closure.DELEGATE_FIRST) - @ClosureParams(value = SimpleType, options = ['com.jessebrault.gcp.component.node.ComponentNode']) - Closure tests - ) { - def componentNode = this.parser.parse(tokens) - logger.debug('componentNode: {}', componentNode) - - def componentSpec = new NodeSpec(ComponentRoot, tests) - logger.debug('nodeSpec: {}', componentSpec) - componentSpec.test(componentNode) - } - - @Test - void selfClosingNoKeysOrValues() { - this.selfClosing(new LinkedList<>([ - new ComponentToken(LT), - new ComponentToken(IDENTIFIER, 'Test'), - new ComponentToken(FORWARD_SLASH), - new ComponentToken(GT) - ])) { - assertEquals('Test', it.identifier) - expect(KeysAndValues) { - assertEquals(0, it.children.size()) - } - } - } - - @Test - void selfClosingWithGStringValue() { - this.selfClosing(new LinkedList<>([ - new ComponentToken(LT), - new ComponentToken(IDENTIFIER, 'Test'), - new ComponentToken(KEY, 'test'), - new ComponentToken(EQUALS), - new ComponentToken(DOUBLE_QUOTE), - new ComponentToken(STRING, 'Hello, World!'), - new ComponentToken(DOUBLE_QUOTE), - new ComponentToken(FORWARD_SLASH), - new ComponentToken(GT) - ])) { - assertEquals('Test', it.identifier) - expect(KeysAndValues) { - expect(KeyAndValue) { - assertEquals('test', it.key) - expect(GStringValue) { - assertEquals('Hello, World!', it.gString) - } - } - } - } - } - -} diff --git a/gcp-impl/src/test/groovy/com/jessebrault/gcp/component/ComponentToClosureVisitorTests.groovy b/gcp-impl/src/test/groovy/com/jessebrault/gcp/component/ComponentToClosureVisitorTests.groovy deleted file mode 100644 index 3ec0b34..0000000 --- a/gcp-impl/src/test/groovy/com/jessebrault/gcp/component/ComponentToClosureVisitorTests.groovy +++ /dev/null @@ -1,40 +0,0 @@ -package com.jessebrault.gcp.component - -import com.jessebrault.gcp.component.node.ComponentRoot -import com.jessebrault.gcp.component.node.GStringValue -import com.jessebrault.gcp.component.node.KeyAndValue -import com.jessebrault.gcp.component.node.KeysAndValues -import org.junit.jupiter.api.Test - -import static org.junit.jupiter.api.Assertions.assertEquals - -class ComponentToClosureVisitorTests { - - @Test - void withEmptyKeysAndValues() { - def cn = new ComponentRoot().tap { - it.children << new KeysAndValues() - } - def v = new ComponentToClosureVisitor() - v.visit(cn) - assertEquals('{ attr { }; };', v.result) - } - - @Test - void withGStringKeyAndValue() { - def cn = new ComponentRoot().tap { - it.children << new KeysAndValues().tap { - it.children << new KeyAndValue().tap { - key = 'greeting' - it.children << new GStringValue().tap { - gString = 'Hello, ${ frontMatter.person }!' - } - } - } - } - def v = new ComponentToClosureVisitor() - v.visit(cn) - assertEquals('{ attr { greeting = "Hello, ${ frontMatter.person }!"; }; };', v.result) - } - -} diff --git a/gcp-impl/src/test/groovy/com/jessebrault/gcp/component/ComponentTokenizerTests.groovy b/gcp-impl/src/test/groovy/com/jessebrault/gcp/component/ComponentTokenizerTests.groovy deleted file mode 100644 index b3f065d..0000000 --- a/gcp-impl/src/test/groovy/com/jessebrault/gcp/component/ComponentTokenizerTests.groovy +++ /dev/null @@ -1,158 +0,0 @@ -package com.jessebrault.gcp.component - - -import org.junit.jupiter.api.Test -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import static com.jessebrault.gcp.component.ComponentToken.Type.* -import static org.junit.jupiter.api.Assertions.assertEquals -import static org.junit.jupiter.api.Assertions.assertTrue - -class ComponentTokenizerTests { - - private static final Logger logger = LoggerFactory.getLogger(ComponentTokenizerTests) - - private static class TokenSpec { - - ComponentToken.Type type - String text - - TokenSpec(ComponentToken.Type type, String text = null) { - this.type = Objects.requireNonNull(type) - this.text = text - } - - void compare(ComponentToken actual) { - assertEquals(this.type, actual.type) - if (this.text != null) { - assertEquals(this.text, actual.text) - } - } - - @Override - String toString() { - "TokenSpec(${ this.type }, ${ this.text })" - } - - } - - private static class TesterConfigurator { - - Queue specs = new LinkedList<>() - - void expect(ComponentToken.Type type, String text) { - this.specs << new TokenSpec(type, text) - } - - void expect(ComponentToken.Type type) { - this.specs << new TokenSpec(type) - } - - } - - private final ComponentTokenizer tokenizer = new ComponentTokenizer() - - private void test( - String src, - @DelegatesTo(value = TesterConfigurator, strategy = Closure.DELEGATE_FIRST) - Closure configure - ) { - def configurator = new TesterConfigurator() - configure.setDelegate(configurator) - configure.setResolveStrategy(Closure.DELEGATE_FIRST) - configure() - - def r = this.tokenizer.tokenize(src) - logger.debug('r: {}', r) - logger.debug('configurator.specs: {}', configurator.specs) - - assertEquals(configurator.specs.size(), r.size()) - - def resultIterator = r.iterator() - configurator.specs.each { - assertTrue(resultIterator.hasNext()) - it.compare(resultIterator.next()) - } - } - - @Test - void selfClosingComponent() { - this.test('') { - expect LT - expect IDENTIFIER, 'Test' - expect FORWARD_SLASH - expect GT - } - } - - @Test - void selfClosingComponentWithDoubleQuotedString() { - this.test('') { - expect LT - expect IDENTIFIER, 'Test' - expect KEY, 'key' - expect EQUALS - expect DOUBLE_QUOTE - expect STRING, 'value' - expect DOUBLE_QUOTE - expect FORWARD_SLASH - expect GT - } - } - - @Test - void selfClosingComponentWithSingleQuotedString() { - this.test("") { - expect LT - expect IDENTIFIER, 'Test' - expect KEY, 'key' - expect EQUALS - expect SINGLE_QUOTE - expect STRING, 'value' - expect SINGLE_QUOTE - expect FORWARD_SLASH - expect GT - } - } - - @Test - void componentWithSimpleDollarGroovy() { - this.test('') { - expect LT - expect IDENTIFIER, 'Test' - expect KEY, 'key' - expect EQUALS - expect GROOVY, ' test ' - expect FORWARD_SLASH - expect GT - } - } - - @Test - void dollarGroovyNestedBraces() { - this.test('') { - expect LT - expect IDENTIFIER, 'Test' - expect KEY, 'key' - expect EQUALS - expect GROOVY, ' test.each { it.test() } ' - expect FORWARD_SLASH - expect GT - } - } - - @Test - void dollarReference() { - this.test('') { - expect LT - expect IDENTIFIER, 'Test' - expect KEY, 'key' - expect EQUALS - expect GROOVY_IDENTIFIER, 'test' - expect FORWARD_SLASH - expect GT - } - } - -} diff --git a/gcp-impl/src/test/groovy/com/jessebrault/gcp/groovy/DollarScriptletParserTests.groovy b/gcp-impl/src/test/groovy/com/jessebrault/gcp/groovy/DollarScriptletParserTests.groovy deleted file mode 100644 index 295e7a7..0000000 --- a/gcp-impl/src/test/groovy/com/jessebrault/gcp/groovy/DollarScriptletParserTests.groovy +++ /dev/null @@ -1,65 +0,0 @@ -package com.jessebrault.gcp.groovy - -import org.junit.jupiter.api.Test - -import static com.jessebrault.gcp.groovy.DollarScriptletParser.parse -import static org.junit.jupiter.api.Assertions.assertEquals - -class DollarScriptletParserTests { - - @Test - void empty() { - assertEquals('${}', parse('${}')) - } - - @Test - void simple() { - assertEquals('${ 1 + 2 }', parse('${ 1 + 2 }')) - } - - @Test - void nestedString() { - assertEquals('${ "myString" }', parse('${ "myString" }')) - } - - @Test - void nestedCurlyBraces() { - assertEquals( - '${ [1, 2, 3].collect { it + 1 }.size() }', - parse('${ [1, 2, 3].collect { it + 1 }.size() }') - ) - } - - @Test - void nestedSingleQuoteString() { - assertEquals( - '${ \'abc\' }', - parse('${ \'abc\' }') - ) - } - - @Test - void nestedGString() { - assertEquals( - '${ "abc" }', - parse('${ "abc" }') - ) - } - - @Test - void nestedGStringWithClosure() { - assertEquals( - '${ "abc${ it }" }', - parse('${ "abc${ it }" }') - ) - } - - @Test - void takesOnlyAsNeeded() { - assertEquals( - '${ 1 + 2 }', - parse('${ 1 + 2 } someOther=${ 3 + 4 }') - ) - } - -} diff --git a/gcp-impl/src/test/groovy/com/jessebrault/gcp/tokenizer/DollarScriptletMatcherTests.groovy b/gcp-impl/src/test/groovy/com/jessebrault/gcp/tokenizer/DollarScriptletMatcherTests.groovy deleted file mode 100644 index ae2debb..0000000 --- a/gcp-impl/src/test/groovy/com/jessebrault/gcp/tokenizer/DollarScriptletMatcherTests.groovy +++ /dev/null @@ -1,60 +0,0 @@ -package com.jessebrault.gcp.tokenizer - -import org.junit.jupiter.api.Test - -import static org.junit.jupiter.api.Assertions.assertEquals - -class DollarScriptletMatcherTests { - - private final DollarScriptletMatcher matcher = new DollarScriptletMatcher(); - - private void test(String expectedEntire, String input) { - def r = this.matcher.apply(input) - assertEquals(expectedEntire, r.entire()) - assertEquals('$', r.part(1)) - assertEquals('{', r.part(2)) - assertEquals(expectedEntire.substring(2, expectedEntire.length() - 1), r.part(3)) - assertEquals('}', r.part(4)) - } - - @Test - void empty() { - test '${}', '${}' - } - - @Test - void simple() { - test '${ 1 + 2 }', '${ 1 + 2 }' - } - - @Test - void nestedString() { - test '${ "myString" }', '${ "myString" }' - } - - @Test - void nestedCurlyBraces() { - test '${ [1, 2, 3].collect { it + 1 }.size() }', '${ [1, 2, 3].collect { it + 1 }.size() }' - } - - @Test - void nestedSingleQuoteString() { - test '${ \'abc\' }', '${ \'abc\' }' - } - - @Test - void nestedGString() { - test '${ "abc" }', '${ "abc" }' - } - - @Test - void nestedGStringWithClosure() { - test '${ "abc${ it }" }', '${ "abc${ it }" }' - } - - @Test - void takesOnlyAsNeeded() { - test '${ 1 + 2 }', '${ 1 + 2 } someOther=${ 3 + 4 }' - } - -} diff --git a/gcp-impl/src/test/groovy/com/jessebrault/gcp/tokenizer/GStringMatcherTests.groovy b/gcp-impl/src/test/groovy/com/jessebrault/gcp/tokenizer/GStringMatcherTests.groovy deleted file mode 100644 index 83ed339..0000000 --- a/gcp-impl/src/test/groovy/com/jessebrault/gcp/tokenizer/GStringMatcherTests.groovy +++ /dev/null @@ -1,44 +0,0 @@ -package com.jessebrault.gcp.tokenizer - -import org.junit.jupiter.api.Test - -import static org.junit.jupiter.api.Assertions.assertEquals - -class GStringMatcherTests { - - private final GStringMatcher matcher = new GStringMatcher() - - private void test(String expectedEntire, String input) { - def output = this.matcher.apply(input) - assertEquals(expectedEntire, output.entire()) - assertEquals('"', output.part(1)) - assertEquals(expectedEntire.substring(1, expectedEntire.length() - 1), output.part(2)) - assertEquals('"', output.part(3)) - } - - @Test - void empty() { - test '""', '""' - } - - @Test - void simple() { - test '"abc"', '"abc"' - } - - @Test - void nestedDollarClosureWithGString() { - test '"abc ${ \'def\'.each { "$it " }.join() }"', '"abc ${ \'def\'.each { "$it " }.join() }"' - } - - @Test - void nestedDollarClosureWithGStringTakesOnlyAsNeeded() { - test '"abc ${ \'def\'.each { "$it " }.join() }"', '"abc ${ \'def\'.each { "$it " }.join() }" test="rest"' - } - - @Test - void takesOnlyAsNeeded() { - test '"abc"', '"abc" test="def"' - } - -} diff --git a/gcp-impl/src/test/groovy/com/jessebrault/gcp/tokenizer/TokenizerTests.groovy b/gcp-impl/src/test/groovy/com/jessebrault/gcp/tokenizer/TokenizerTests.groovy deleted file mode 100644 index cd648d8..0000000 --- a/gcp-impl/src/test/groovy/com/jessebrault/gcp/tokenizer/TokenizerTests.groovy +++ /dev/null @@ -1,196 +0,0 @@ -package com.jessebrault.gcp.tokenizer - -import org.junit.jupiter.api.Test -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import static com.jessebrault.gcp.tokenizer.Token.Type.* -import static org.junit.jupiter.api.Assertions.assertEquals -import static org.junit.jupiter.api.Assertions.assertTrue - -class TokenizerTests { - - private static final Logger logger = LoggerFactory.getLogger(TokenizerTests) - - private static class TokenSpec { - - Token.Type type - String text - int line - int col - - TokenSpec(Token.Type type, String text = null, line = 0, col = 0) { - this.type = Objects.requireNonNull(type) - this.text = text - this.line = line - this.col = col - } - - void compare(Token actual) { - assertEquals(this.type, actual.type) - if (this.text != null) { - assertEquals(this.text, actual.text) - } - if (this.line != 0) { - assertEquals(this.line, actual.line) - } - if (this.col != 0) { - assertEquals(this.col, actual.col) - } - } - - @Override - String toString() { - "TokenSpec(${ this.type }, ${ this.text }, ${ this.line }, ${ this.col })" - } - - } - - private static class TesterConfigurator { - - Queue specs = new LinkedList<>() - - void expect(Token.Type type, String text = null, line = 0, col = 0) { - this.specs << new TokenSpec(type, text, line, col) - } - - } - - private static void test( - String src, - @DelegatesTo(value = TesterConfigurator, strategy = Closure.DELEGATE_FIRST) - Closure configure - ) { - def configurator = new TesterConfigurator() - configure.setDelegate(configurator) - configure.setResolveStrategy(Closure.DELEGATE_FIRST) - configure() - - def r = new TokenizerImpl().tokenizeAll(src, Tokenizer.State.TEXT) - logger.debug('r: {}', r) - logger.debug('configurator.specs: {}', configurator.specs) - - assertEquals(configurator.specs.size(), r.size()) - - def resultIterator = r.iterator() - configurator.specs.each { - assertTrue(resultIterator.hasNext()) - it.compare(resultIterator.next()) - } - } - - @Test - void doctypeHtmlIsText() { - test('') { - expect TEXT, '', 1, 1 - } - } - - @Test - void htmlLangEnIsText() { - test('') { - expect TEXT, '', 1, 1 - } - } - - @Test - void component() { - test('') { - expect COMPONENT_START, '<', 1, 1 - expect CLASS_NAME, 'Test', 1, 2 - expect WHITESPACE, ' ', 1, 6 - expect FORWARD_SLASH, '/', 1, 7 - expect COMPONENT_END, '>', 1, 8 - } - } - - @Test - void componentWithGString() { - test('') { - expect COMPONENT_START, '<', 1, 1 - expect CLASS_NAME, 'Test', 1, 2 - expect WHITESPACE, ' ', 1, 6 - expect KEY, 'test', 1, 7 - expect EQUALS, '=', 1, 11 - expect DOUBLE_QUOTE, '"', 1, 12 - expect STRING, 'test', 1, 13 - expect DOUBLE_QUOTE, '"', 1, 17 - expect WHITESPACE, ' ', 1, 18 - expect FORWARD_SLASH, '/', 1, 19 - expect COMPONENT_END, '>', 1, 20 - } - } - - @Test - void componentWithGStringWithNestedGString() { - test('') { - expect COMPONENT_START, '<', 1, 1 - expect CLASS_NAME, 'Test', 1, 2 - expect WHITESPACE, ' ', 1, 6 - expect KEY, 'test', 1, 7 - expect EQUALS, '=', 1, 11 - expect DOUBLE_QUOTE, '"', 1, 12 - expect STRING, 'abc ${ \'abc\'.collect { "it " }.join() }', 1, 13 - expect DOUBLE_QUOTE, '"', 1, 52 - expect WHITESPACE, ' ', 1, 53 - expect FORWARD_SLASH, '/', 1, 54 - expect COMPONENT_END, '>', 1, 55 - } - } - - @Test - void newlinesCounted() { - test('Hello,\n$person!') { - expect TEXT, 'Hello,\n', 1, 1 - expect DOLLAR, '$', 2, 1 - expect GROOVY_REFERENCE, 'person', 2, 2 - expect TEXT, '!', 2, 8 - } - } - - @Test - void componentWithSingleQuoteString() { - test("") { - expect COMPONENT_START, '<', 1, 1 - expect CLASS_NAME, 'Test', 1, 2 - expect WHITESPACE, ' ', 1, 6 - expect KEY, 'test', 1, 7 - expect EQUALS, '=', 1, 11 - expect SINGLE_QUOTE, "'", 1, 12 - expect STRING, 'Hello, World!', 1, 13 - expect SINGLE_QUOTE, "'", 1, 26 - expect WHITESPACE, ' ', 1, 27 - expect FORWARD_SLASH, '/', 1, 28 - expect COMPONENT_END, '>', 1, 29 - } - } - - @Test - void componentWithFullyQualifiedName() { - test('') { - expect COMPONENT_START, '<', 1, 1 - expect PACKAGE_NAME, 'com', 1, 2 - expect DOT, '.', 1, 5 - expect PACKAGE_NAME, 'jessebrault', 1, 6 - expect DOT, '.', 1, 17 - expect PACKAGE_NAME, 'gcp', 1, 18 - expect DOT, '.', 1, 21 - expect CLASS_NAME, 'Test', 1, 22 - expect WHITESPACE, ' ', 1, 26 - expect FORWARD_SLASH, '/', 1, 27 - expect COMPONENT_END, '>', 1, 28 - } - } - - @Test - void componentWithNewlineWhitespace() { - test('') { - expect COMPONENT_START, '<', 1, 1 - expect CLASS_NAME, 'Test', 1, 2 - expect WHITESPACE, '\n', 1, 6 - expect FORWARD_SLASH, '/', 2, 1 - expect COMPONENT_END, '>', 2, 2 - } - } - -} diff --git a/gcp-impl/src/test/resources/log4j2.xml b/gcp-impl/src/test/resources/log4j2.xml deleted file mode 100644 index fe10995..0000000 --- a/gcp-impl/src/test/resources/log4j2.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 827f737..d673b74 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ rootProject.name = 'ssg' -include 'cli', 'gcp-api', 'gcp-impl', 'lib' \ No newline at end of file +include 'cli', 'lib' \ No newline at end of file