From 5b5ba7bedf5bd08c475cedd729546b59df3de516 Mon Sep 17 00:00:00 2001 From: "igor.petrenko" Date: Wed, 22 Apr 2026 12:54:45 +0300 Subject: [PATCH 1/4] CE-148 oap-template: interpreter mode --- .../oap-logstream/oap-logstream-test/pom.xml | 5 + .../java/oap/logstream/LoggerJsonTest.java | 5 +- .../test/java/oap/logstream/LoggerTest.java | 8 +- .../logstream/disk/AbstractWriterTest.java | 22 +- .../logstream/disk/DiskLoggerBackendTest.java | 9 +- .../logstream/disk/RowBinaryWriterTest.java | 5 +- .../java/oap/logstream/LogIdTemplate.java | 37 +- .../oap/logstream/disk/AbstractWriter.java | 14 +- .../oap/logstream/disk/DiskLoggerBackend.java | 16 +- .../oap/logstream/disk/RowBinaryWriter.java | 5 +- oap-formats/oap-template-test/pom.xml | 33 + .../oap/template/TemplateEngineFixture.java | 15 + .../main/antlr4/TemplateGrammarExpression.g4 | 29 +- .../main/antlr4/TemplateLexerExpression.g4 | 4 + .../template/TemplateGrammarExpression.interp | 14 +- .../template/TemplateGrammarExpression.java | 1139 +++++++++++------ .../template/TemplateGrammarExpression.tokens | 72 +- ...TemplateGrammarExpressionBaseListener.java | 53 + .../TemplateGrammarExpressionListener.java | 45 + .../template/TemplateLexerExpression.interp | 14 +- .../oap/template/TemplateLexerExpression.java | 626 ++++----- .../template/TemplateLexerExpression.tokens | 72 +- .../java/oap/template/RuntimeTemplate.java | 72 ++ .../oap/template/TemplateConditionHelper.java | 44 + .../java/oap/template/TemplateEngine.java | 53 + .../java/oap/template/render/AstRender.java | 4 + .../oap/template/render/AstRenderBlockIf.java | 12 + .../template/render/AstRenderBlockRange.java | 61 + .../render/AstRenderBlockRangeInterval.java | 20 + .../template/render/AstRenderBlockWith.java | 9 + .../template/render/AstRenderBooleanIf.java | 12 + .../render/AstRenderCaptureBoolean.java | 43 +- .../render/AstRenderCaptureScope.java | 6 + .../oap/template/render/AstRenderComment.java | 6 + .../render/AstRenderConcatenation.java | 13 + .../render/AstRenderConditionAnd.java | 60 + .../render/AstRenderConditionNot.java | 53 + .../template/render/AstRenderConditionOr.java | 60 + .../template/render/AstRenderExpression.java | 6 + .../oap/template/render/AstRenderField.java | 16 + .../template/render/AstRenderFunction.java | 30 + .../oap/template/render/AstRenderIfElse.java | 6 + .../oap/template/render/AstRenderMap.java | 21 +- .../oap/template/render/AstRenderMath.java | 34 + .../oap/template/render/AstRenderMethod.java | 9 + .../template/render/AstRenderNullable.java | 11 + .../template/render/AstRenderOptional.java | 14 + .../java/oap/template/render/AstRenderOr.java | 26 + .../render/AstRenderPathNotFound.java | 7 + .../template/render/AstRenderPrintField.java | 8 + .../template/render/AstRenderPrintValue.java | 14 + .../oap/template/render/AstRenderRoot.java | 6 + .../render/AstRenderSwitchToRoot.java | 7 + .../oap/template/render/AstRenderText.java | 6 + .../template/render/AstRenderTryBlock.java | 6 + .../oap/template/render/AstRenderVarRef.java | 8 + .../oap/template/render/AstRenderWith.java | 8 + .../render/AstRendererDynamicMap.java | 17 + .../main/java/oap/template/render/Render.java | 10 +- .../oap/template/render/TemplateAstUtils.java | 35 +- .../oap/template/runtime/AcceptDispatch.java | 181 +++ .../oap/template/runtime/ReflectionCache.java | 129 ++ .../oap/template/runtime/RuntimeContext.java | 114 ++ .../oap/template/tree/AndConditionExpr.java | 27 + .../java/oap/template/tree/ConditionExpr.java | 27 + .../java/oap/template/tree/Expression.java | 2 +- .../oap/template/tree/FieldConditionExpr.java | 27 + .../java/oap/template/tree/IfCondition.java | 4 +- .../oap/template/tree/NotConditionExpr.java | 27 + .../oap/template/tree/OrConditionExpr.java | 27 + .../template/AbstractTemplateEngineTest.java | 51 + ...emplateEngineConcatenationRuntimeTest.java | 8 + .../TemplateEngineConcatenationTest.java | 12 +- .../TemplateEngineConditionRuntimeTest.java | 8 + .../template/TemplateEngineConditionTest.java | 153 ++- .../TemplateEngineEnumRuntimeTest.java | 8 + .../oap/template/TemplateEngineEnumTest.java | 12 +- .../TemplateEngineFunctionsRuntimeTest.java | 8 + .../template/TemplateEngineFunctionsTest.java | 46 +- .../template/TemplateEngineOrRuntimeTest.java | 8 + .../oap/template/TemplateEngineOrTest.java | 6 +- .../TemplateEngineRangeRuntimeTest.java | 8 + .../oap/template/TemplateEngineRangeTest.java | 38 +- .../template/TemplateEngineRuntimeTest.java | 8 + .../java/oap/template/TemplateEngineTest.java | 104 +- .../TemplateEngineTrimRuntimeTest.java | 8 + .../oap/template/TemplateEngineTrimTest.java | 39 +- .../TemplateEngineTypesRuntimeTest.java | 8 + .../oap/template/TemplateEngineTypesTest.java | 12 +- .../TemplateEngineWithRuntimeTest.java | 8 + .../oap/template/TemplateEngineWithTest.java | 42 +- oap-formats/pom.xml | 1 + pom.xml | 2 +- 93 files changed, 3185 insertions(+), 1053 deletions(-) create mode 100644 oap-formats/oap-template-test/pom.xml create mode 100644 oap-formats/oap-template-test/src/main/java/oap/template/TemplateEngineFixture.java create mode 100644 oap-formats/oap-template/src/main/java/oap/template/RuntimeTemplate.java create mode 100644 oap-formats/oap-template/src/main/java/oap/template/TemplateConditionHelper.java create mode 100644 oap-formats/oap-template/src/main/java/oap/template/render/AstRenderConditionAnd.java create mode 100644 oap-formats/oap-template/src/main/java/oap/template/render/AstRenderConditionNot.java create mode 100644 oap-formats/oap-template/src/main/java/oap/template/render/AstRenderConditionOr.java create mode 100644 oap-formats/oap-template/src/main/java/oap/template/runtime/AcceptDispatch.java create mode 100644 oap-formats/oap-template/src/main/java/oap/template/runtime/ReflectionCache.java create mode 100644 oap-formats/oap-template/src/main/java/oap/template/runtime/RuntimeContext.java create mode 100644 oap-formats/oap-template/src/main/java/oap/template/tree/AndConditionExpr.java create mode 100644 oap-formats/oap-template/src/main/java/oap/template/tree/ConditionExpr.java create mode 100644 oap-formats/oap-template/src/main/java/oap/template/tree/FieldConditionExpr.java create mode 100644 oap-formats/oap-template/src/main/java/oap/template/tree/NotConditionExpr.java create mode 100644 oap-formats/oap-template/src/main/java/oap/template/tree/OrConditionExpr.java create mode 100644 oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConcatenationRuntimeTest.java create mode 100644 oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConditionRuntimeTest.java create mode 100644 oap-formats/oap-template/src/test/java/oap/template/TemplateEngineEnumRuntimeTest.java create mode 100644 oap-formats/oap-template/src/test/java/oap/template/TemplateEngineFunctionsRuntimeTest.java create mode 100644 oap-formats/oap-template/src/test/java/oap/template/TemplateEngineOrRuntimeTest.java create mode 100644 oap-formats/oap-template/src/test/java/oap/template/TemplateEngineRangeRuntimeTest.java create mode 100644 oap-formats/oap-template/src/test/java/oap/template/TemplateEngineRuntimeTest.java create mode 100644 oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTrimRuntimeTest.java create mode 100644 oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTypesRuntimeTest.java create mode 100644 oap-formats/oap-template/src/test/java/oap/template/TemplateEngineWithRuntimeTest.java diff --git a/oap-formats/oap-logstream/oap-logstream-test/pom.xml b/oap-formats/oap-logstream/oap-logstream-test/pom.xml index fb8cbef5a..171a90764 100644 --- a/oap-formats/oap-logstream/oap-logstream-test/pom.xml +++ b/oap-formats/oap-logstream/oap-logstream-test/pom.xml @@ -39,6 +39,11 @@ oap-stdlib-test ${project.version} + + oap + oap-template-test + ${project.version} + org.apache.commons commons-csv diff --git a/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/LoggerJsonTest.java b/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/LoggerJsonTest.java index c26a943c8..b0950c895 100644 --- a/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/LoggerJsonTest.java +++ b/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/LoggerJsonTest.java @@ -29,6 +29,7 @@ import oap.json.Binder; import oap.logstream.disk.DiskLoggerBackend; import oap.logstream.formats.rowbinary.RowBinaryUtils; +import oap.template.TemplateEngineFixture; import oap.template.Types; import oap.testng.Fixtures; import oap.testng.TestDirectoryFixture; @@ -49,9 +50,11 @@ public class LoggerJsonTest extends Fixtures { private final TestDirectoryFixture testDirectoryFixture; + private final TemplateEngineFixture templateEngineFixture; public LoggerJsonTest() { testDirectoryFixture = fixture( new TestDirectoryFixture() ); + templateEngineFixture = fixture( new TemplateEngineFixture() ); } @Test @@ -61,7 +64,7 @@ public void diskJSON() throws IOException { String content = "{\"title\":\"response\",\"status\":false,\"values\":[1,2,3]}"; String[] headers = new String[] { "test" }; byte[][] types = new byte[][] { new byte[] { Types.STRING.id } }; - try( DiskLoggerBackend backend = new DiskLoggerBackend( testDirectoryFixture.testPath( "logs" ), BPH_12, DEFAULT_BUFFER, "localhost" ) ) { + try( DiskLoggerBackend backend = new DiskLoggerBackend( templateEngineFixture.templateEngine, testDirectoryFixture.testPath( "logs" ), BPH_12, DEFAULT_BUFFER, "localhost" ) ) { Logger logger = new Logger( backend ); SimpleJson o = contentOfTestResource( getClass(), "simple_json.json", ofJson( SimpleJson.class ) ); diff --git a/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/LoggerTest.java b/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/LoggerTest.java index f384866c2..6c689533f 100644 --- a/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/LoggerTest.java +++ b/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/LoggerTest.java @@ -33,6 +33,8 @@ import oap.logstream.net.server.SocketLoggerServer; import oap.message.client.MessageSender; import oap.message.server.MessageHttpHandler; +import oap.template.TemplateEngine; +import oap.template.TemplateEngineFixture; import oap.template.Types; import oap.testng.Fixtures; import oap.testng.Ports; @@ -61,9 +63,11 @@ @Slf4j public class LoggerTest extends Fixtures { private final TestDirectoryFixture testDirectoryFixture; + private final TemplateEngineFixture templateEngineFixture; public LoggerTest() { testDirectoryFixture = fixture( new TestDirectoryFixture() ); + templateEngineFixture = fixture( new TemplateEngineFixture() ); } @Test @@ -78,7 +82,7 @@ public void disk() throws IOException { byte[] line2 = Compression.gzip( RowBinaryUtils.line( lineData2 ) ); String[] headers2 = new String[] { "TIMESTAMP", "REQUEST_ID2" }; byte[][] types2 = new byte[][] { new byte[] { Types.DATETIME.id }, new byte[] { Types.STRING.id } }; - try( DiskLoggerBackend backend = new DiskLoggerBackend( testDirectoryFixture.testPath( "logs" ), BPH_12, DEFAULT_BUFFER, "localhost" ) ) { + try( DiskLoggerBackend backend = new DiskLoggerBackend( templateEngineFixture.templateEngine, testDirectoryFixture.testPath( "logs" ), BPH_12, DEFAULT_BUFFER, "localhost" ) ) { Logger logger = new Logger( backend ); logger.log( "lfn1", Map.of(), "log", headers1, types1, line1 ); logger.log( "lfn2", Map.of(), "log", headers1, types1, line1 ); @@ -114,7 +118,7 @@ public void net() throws IOException { String[] headers2 = new String[] { "TIMESTAMP", "REQUEST_ID2" }; byte[][] types2 = new byte[][] { new byte[] { Types.DATETIME.id }, new byte[] { Types.STRING.id } }; - try( DiskLoggerBackend serverBackend = new DiskLoggerBackend( testDirectoryFixture.testPath( "logs" ), BPH_12, DEFAULT_BUFFER, "localhost" ); + try( DiskLoggerBackend serverBackend = new DiskLoggerBackend( templateEngineFixture.templateEngine, testDirectoryFixture.testPath( "logs" ), BPH_12, DEFAULT_BUFFER, "localhost" ); SocketLoggerServer server = new SocketLoggerServer( serverBackend ); NioHttpServer mServer = new NioHttpServer( new NioHttpServer.DefaultPort( port ) ); MessageHttpHandler messageHttpHandler = new MessageHttpHandler( mServer, "/messages", controlStatePath, List.of( server ), -1 ); diff --git a/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/disk/AbstractWriterTest.java b/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/disk/AbstractWriterTest.java index f5479a381..aa2980531 100644 --- a/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/disk/AbstractWriterTest.java +++ b/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/disk/AbstractWriterTest.java @@ -26,7 +26,9 @@ import oap.logstream.LogId; import oap.logstream.Timestamp; +import oap.template.TemplateEngineFixture; import oap.template.Types; +import oap.testng.Fixtures; import oap.util.Dates; import org.testng.annotations.Test; @@ -34,7 +36,13 @@ import static org.assertj.core.api.Assertions.assertThat; -public class AbstractWriterTest { +public class AbstractWriterTest extends Fixtures { + private final TemplateEngineFixture templateEngineFixture; + + public AbstractWriterTest() { + templateEngineFixture = fixture( new TemplateEngineFixture() ); + } + @Test public void testFileName() { String[] h1Headers = new String[] { "h1" }; @@ -44,15 +52,15 @@ public void testFileName() { Dates.setTimeFixed( 2023, 1, 23, 21, 6, 0 ); - assertThat( AbstractWriter.currentPattern( LogFormat.TSV_GZ, "${LOG_FORMAT_TSV_GZ}-${INTERVAL} -${LOG_VERSION}-#{if}(${ORGANIZATION})${ORGANIZATION}#{else}UNKNOWN#{end}.${LOG_FORMAT}", lid1, Timestamp.BPH_12, 1, Dates.nowUtc(), "localhost" ) ) + assertThat( AbstractWriter.currentPattern( templateEngineFixture.templateEngine, LogFormat.TSV_GZ, "{{ LOG_FORMAT_TSV_GZ }}-{{ INTERVAL }}-{{ LOG_VERSION }}-{{% if ORGANIZATION }}{{ ORGANIZATION }}{{% else }}UNKNOWN{{% end }}.{{ LOG_FORMAT }}", lid1, Timestamp.BPH_12, 1, Dates.nowUtc(), "localhost" ) ) .isEqualTo( "ln/tsv.gz-01-855943970-1-UNKNOWN.tsv.gz.rb.gz" ); - assertThat( AbstractWriter.currentPattern( LogFormat.TSV_GZ, "${INTERVAL}-${LOG_VERSION}-${ORGANIZATION}.${LOG_FORMAT}", lid1, Timestamp.BPH_12, 1, Dates.nowUtc(), "localhost" ) ) + assertThat( AbstractWriter.currentPattern( templateEngineFixture.templateEngine, LogFormat.TSV_GZ, "{{ INTERVAL }}-{{ LOG_VERSION }}-{{ ORGANIZATION }}.{{ LOG_FORMAT }}", lid1, Timestamp.BPH_12, 1, Dates.nowUtc(), "localhost" ) ) .isEqualTo( "ln/01-855943970-1-.tsv.gz.rb.gz" ); - assertThat( AbstractWriter.currentPattern( LogFormat.TSV_GZ, "${INTERVAL}-${LOG_VERSION}-${ORGANIZATION}.${LOG_FORMAT}", lid1, Timestamp.BPH_12, 1, Dates.nowUtc(), "localhost" ) ) + assertThat( AbstractWriter.currentPattern( templateEngineFixture.templateEngine, LogFormat.TSV_GZ, "{{ INTERVAL }}-{{ LOG_VERSION}}-{{ ORGANIZATION }}.{{ LOG_FORMAT }}", lid1, Timestamp.BPH_12, 1, Dates.nowUtc(), "localhost" ) ) .isEqualTo( "ln/01-855943970-1-.tsv.gz.rb.gz" ); - assertThat( AbstractWriter.currentPattern( LogFormat.TSV_GZ, "${LOG_TIME_INTERVAL}.log.gz", lid1, Timestamp.BPH_6, 1, Dates.nowUtc(), "localhost" ) ) + assertThat( AbstractWriter.currentPattern( templateEngineFixture.templateEngine, LogFormat.TSV_GZ, "{{ LOG_TIME_INTERVAL }}.log.gz", lid1, Timestamp.BPH_6, 1, Dates.nowUtc(), "localhost" ) ) .isEqualTo( "ln/10.log.gz.rb.gz" ); } @@ -64,11 +72,11 @@ public void testFileNameConditional() { Dates.setTimeFixed( 2023, 1, 23, 21, 6, 0 ); LogId lid1 = new LogId( "ln", "lt", "chn", Map.of(), h1Headers, strTypes ); - assertThat( AbstractWriter.currentPattern( LogFormat.TSV_GZ, "#{if}(${ORGANIZATION}&&${ACCOUNT})${ORGANIZATION}/${ACCOUNT}/#{end}${INTERVAL}-${LOG_VERSION}.${LOG_FORMAT}", lid1, Timestamp.BPH_12, 1, Dates.nowUtc(), "localhost" ) ) + assertThat( AbstractWriter.currentPattern( templateEngineFixture.templateEngine, LogFormat.TSV_GZ, "{{% if ORGANIZATION and ACCOUNT }}{{ ORGANIZATION }}/{{ ACCOUNT }}/{{% end }}{{ INTERVAL }}-{{ LOG_VERSION }}.{{ LOG_FORMAT }}", lid1, Timestamp.BPH_12, 1, Dates.nowUtc(), "localhost" ) ) .isEqualTo( "ln/01-855943970-1.tsv.gz.rb.gz" ); lid1 = new LogId( "ln", "lt", "chn", Map.of( "ORGANIZATION", "org1", "ACCOUNT", "acc1" ), h1Headers, strTypes ); - assertThat( AbstractWriter.currentPattern( LogFormat.PARQUET, "#{if}(${ORGANIZATION}&&${ACCOUNT})${ORGANIZATION}/${ACCOUNT}/#{end}${INTERVAL}-${LOG_VERSION}.${LOG_FORMAT}", lid1, Timestamp.BPH_12, 1, Dates.nowUtc(), "localhost" ) ) + assertThat( AbstractWriter.currentPattern( templateEngineFixture.templateEngine, LogFormat.PARQUET, "{{% if ORGANIZATION and ACCOUNT }}{{ ORGANIZATION }}/{{ ACCOUNT }}/{{% end }}{{ INTERVAL }}-{{ LOG_VERSION }}.{{ LOG_FORMAT }}", lid1, Timestamp.BPH_12, 1, Dates.nowUtc(), "localhost" ) ) .isEqualTo( "ln/org1/acc1/01-855943970-1.parquet.rb.gz" ); } } diff --git a/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/disk/DiskLoggerBackendTest.java b/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/disk/DiskLoggerBackendTest.java index f64557bcc..aca4bb8f3 100644 --- a/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/disk/DiskLoggerBackendTest.java +++ b/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/disk/DiskLoggerBackendTest.java @@ -28,6 +28,7 @@ import oap.logstream.Logger; import oap.logstream.Timestamp; import oap.logstream.formats.rowbinary.RowBinaryUtils; +import oap.template.TemplateEngineFixture; import oap.template.Types; import oap.testng.Fixtures; import oap.testng.TestDirectoryFixture; @@ -48,14 +49,16 @@ public class DiskLoggerBackendTest extends Fixtures { private final TestDirectoryFixture testDirectoryFixture; + private final TemplateEngineFixture templateEngineFixture; public DiskLoggerBackendTest() { testDirectoryFixture = fixture( new TestDirectoryFixture() ); + templateEngineFixture = fixture( new TemplateEngineFixture() ); } @Test public void spaceAvailable() { - try( DiskLoggerBackend backend = new DiskLoggerBackend( testDirectoryFixture.testPath( "logs" ), Timestamp.BPH_12, 4000, "localhost" ) ) { + try( DiskLoggerBackend backend = new DiskLoggerBackend( templateEngineFixture.templateEngine, testDirectoryFixture.testPath( "logs" ), Timestamp.BPH_12, 4000, "localhost" ) ) { backend.start(); assertTrue( backend.isLoggingAvailable() ); @@ -73,7 +76,7 @@ public void testPatternByType() throws IOException { byte[][] types = new byte[][] { new byte[] { Types.STRING.id }, new byte[] { Types.STRING.id } }; byte[] lines = Compression.gzip( RowBinaryUtils.lines( List.of( List.of( "12345678", "rrrr5678" ), List.of( "1", "2" ) ) ) ); - try( DiskLoggerBackend backend = new DiskLoggerBackend( testDirectoryFixture.testPath( "logs" ), Timestamp.BPH_12, 4000, "localhost" ) ) { + try( DiskLoggerBackend backend = new DiskLoggerBackend( templateEngineFixture.templateEngine, testDirectoryFixture.testPath( "logs" ), Timestamp.BPH_12, 4000, "localhost" ) ) { backend.filePattern = "${LOG_TYPE}_${LOG_VERSION}_${INTERVAL}.tsv.gz"; backend.filePatternByType.put( "LOG_TYPE_WITH_DIFFERENT_FILE_PATTERN", new DiskLoggerBackend.FilePatternConfiguration( "${LOG_TYPE}_${LOG_VERSION}_${MINUTE}.parquet" ) ); @@ -106,7 +109,7 @@ public void testWriteSync() throws IOException { byte[][] types = new byte[][] { new byte[] { Types.STRING.id }, new byte[] { Types.STRING.id } }; byte[] lines = Compression.gzip( RowBinaryUtils.lines( List.of( List.of( "12345678", "rrrr5678" ), List.of( "1", "2" ) ) ) ); //init new logger - try( DiskLoggerBackend backend = new DiskLoggerBackend( testDirectoryFixture.testPath( "logs" ), BPH_12, DEFAULT_BUFFER, "localhost" ) ) { + try( DiskLoggerBackend backend = new DiskLoggerBackend( templateEngineFixture.templateEngine, testDirectoryFixture.testPath( "logs" ), BPH_12, DEFAULT_BUFFER, "localhost" ) ) { backend.start(); Logger logger = new Logger( backend ); diff --git a/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/disk/RowBinaryWriterTest.java b/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/disk/RowBinaryWriterTest.java index a2c89452c..5081b760e 100644 --- a/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/disk/RowBinaryWriterTest.java +++ b/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/disk/RowBinaryWriterTest.java @@ -27,6 +27,7 @@ import oap.compression.Compression; import oap.logstream.LogId; import oap.logstream.formats.rowbinary.RowBinaryUtils; +import oap.template.TemplateEngineFixture; import oap.template.Types; import oap.testng.Fixtures; import oap.testng.TestDirectoryFixture; @@ -49,9 +50,11 @@ public class RowBinaryWriterTest extends Fixtures { private static final String FILE_PATTERN = "${p}-file-${INTERVAL}-${LOG_VERSION}.rb.gz"; private final TestDirectoryFixture testDirectoryFixture; + private final TemplateEngineFixture templateEngineFixture; public RowBinaryWriterTest() { testDirectoryFixture = fixture( new TestDirectoryFixture() ); + templateEngineFixture = fixture( new TemplateEngineFixture() ); } @Test @@ -78,7 +81,7 @@ public void testWrite() throws IOException { LogId logId = new LogId( "", "log", "log", Map.of( "p", "1" ), headers, types ); Path logs = testDirectoryFixture.testPath( "logs" ); - try( RowBinaryWriter writer = new RowBinaryWriter( logs, FILE_PATTERN, logId, 1024, BPH_12, 20, "localhost" ) ) { + try( RowBinaryWriter writer = new RowBinaryWriter( templateEngineFixture.templateEngine, logs, FILE_PATTERN, logId, 1024, BPH_12, 20, "localhost" ) ) { writer.write( CURRENT_PROTOCOL_VERSION, content1 ); writer.write( CURRENT_PROTOCOL_VERSION, content2 ); } diff --git a/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/LogIdTemplate.java b/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/LogIdTemplate.java index 0eeb0e683..4f204326d 100644 --- a/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/LogIdTemplate.java +++ b/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/LogIdTemplate.java @@ -24,17 +24,13 @@ package oap.logstream; -import oap.io.Closeables; import oap.kubernetes.ReplicaUtils; import oap.net.Inet; -import org.apache.velocity.VelocityContext; -import org.apache.velocity.app.VelocityEngine; -import org.apache.velocity.app.event.EventCartridge; -import org.apache.velocity.app.event.ReferenceInsertionEventHandler; -import org.apache.velocity.context.Context; +import oap.reflect.TypeRef; +import oap.template.TemplateAccumulators; +import oap.template.TemplateEngine; import org.joda.time.DateTime; -import java.io.StringWriter; import java.util.LinkedHashMap; import java.util.Map; @@ -45,8 +41,6 @@ * @see oap.logstream.disk.AbstractWriter */ public class LogIdTemplate { - private final VelocityEngine engine = new VelocityEngine(); - private final LogId logId; private final LinkedHashMap variables = new LinkedHashMap<>(); @@ -66,29 +60,16 @@ public LogIdTemplate addVariables( Map variables ) { return this; } - public String render( String template, DateTime time, Timestamp timestamp, int version, String hostname ) { - VelocityContext context = new VelocityContext(); - EventCartridge eventCartridge = new EventCartridge(); - context.attachEventCartridge( eventCartridge ); - eventCartridge.addReferenceInsertionEventHandler( new ReferenceInsertionEventHandler() { - @Override - public Object referenceInsert( Context context, String s, Object o ) { - return o == null ? "" : o; - } - } ); - + public String render( TemplateEngine templateEngine, String template, DateTime time, Timestamp timestamp, int version, String hostname ) { + LinkedHashMap context = new LinkedHashMap<>(); init( context, time, timestamp, version, hostname ); - variables.forEach( context::put ); - - StringWriter writer = new StringWriter(); - engine.evaluate( context, writer, "log-id-template", template ); - Closeables.close( writer ); + context.putAll( variables ); - return writer.toString(); + return templateEngine.getTemplate( "LogIdTemplate", new TypeRef>() {}, template, TemplateAccumulators.STRING, _ -> {} ).render( context ).get(); } - public void init( VelocityContext context, DateTime time, Timestamp timestamp, int version, String hostname ) { + public void init( Map context, DateTime time, Timestamp timestamp, int version, String hostname ) { context.put( "LOG_TYPE", logId.logType ); context.put( "LOG_VERSION", getHashWithVersion( version, hostname ) ); context.put( "SERVER_HOST", Inet.HOSTNAME ); @@ -103,7 +84,7 @@ public void init( VelocityContext context, DateTime time, Timestamp timestamp, i context.put( "LOG_TIME_INTERVAL", String.valueOf( 60 / timestamp.bucketsPerHour ) ); context.put( "REGION", System.getenv( "REGION" ) ); - logId.properties.forEach( context::put ); + context.putAll( logId.properties ); } public String getHashWithVersion( int version, String hostname ) { diff --git a/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/disk/AbstractWriter.java b/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/disk/AbstractWriter.java index 15804224e..53f4b180c 100644 --- a/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/disk/AbstractWriter.java +++ b/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/disk/AbstractWriter.java @@ -34,8 +34,8 @@ import oap.logstream.LogStreamProtocol.ProtocolVersion; import oap.logstream.LoggerException; import oap.logstream.Timestamp; +import oap.template.TemplateEngine; import oap.util.Dates; -import org.codehaus.plexus.util.StringUtils; import org.joda.time.DateTime; import java.io.Closeable; @@ -48,6 +48,7 @@ @Slf4j public abstract class AbstractWriter implements Closeable { public final LogFormat logFormat; + protected final TemplateEngine templateEngine; protected final Path logDirectory; protected final String filePattern; protected final LogId logId; @@ -63,8 +64,9 @@ public abstract class AbstractWriter implements Closeable { protected int fileVersion = 1; protected boolean closed = false; - protected AbstractWriter( LogFormat logFormat, Path logDirectory, String filePattern, LogId logId, int bufferSize, Timestamp timestamp, + protected AbstractWriter( TemplateEngine templateEngine, LogFormat logFormat, Path logDirectory, String filePattern, LogId logId, int bufferSize, Timestamp timestamp, int maxVersions, String hostname ) { + this.templateEngine = templateEngine; this.logFormat = logFormat; this.logDirectory = logDirectory; this.filePattern = filePattern; @@ -82,7 +84,7 @@ protected AbstractWriter( LogFormat logFormat, Path logDirectory, String filePat } @SneakyThrows - static String currentPattern( LogFormat logFormat, String filePattern, LogId logId, Timestamp timestamp, int version, DateTime time, String hostname ) { + static String currentPattern( TemplateEngine templateEngine, LogFormat logFormat, String filePattern, LogId logId, Timestamp timestamp, int version, DateTime time, String hostname ) { String suffix = filePattern; if( filePattern.startsWith( "/" ) && filePattern.endsWith( "/" ) ) suffix = suffix.substring( 1 ); else if( !filePattern.startsWith( "/" ) && !logId.filePrefixPattern.endsWith( "/" ) ) suffix = "/" + suffix; @@ -97,15 +99,15 @@ static String currentPattern( LogFormat logFormat, String filePattern, LogId log logIdTemplate .addVariable( "LOG_FORMAT", logFormat.extension ) .addVariable( "LOG_FORMAT_" + logFormat.name(), logFormat.extension ); - return logIdTemplate.render( StringUtils.replace( pattern, " ", "" ), time, timestamp, version, hostname ); + return logIdTemplate.render( templateEngine, pattern, time, timestamp, version, hostname ); } protected String currentPattern( int version ) { - return currentPattern( logFormat, filePattern, logId, timestamp, version, Dates.nowUtc(), hostname ); + return currentPattern( templateEngine, logFormat, filePattern, logId, timestamp, version, Dates.nowUtc(), hostname ); } protected String currentPattern() { - return currentPattern( logFormat, filePattern, logId, timestamp, fileVersion, Dates.nowUtc(), hostname ); + return currentPattern( templateEngine, logFormat, filePattern, logId, timestamp, fileVersion, Dates.nowUtc(), hostname ); } public void write( ProtocolVersion protocolVersion, byte[] buffer ) throws LoggerException { diff --git a/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/disk/DiskLoggerBackend.java b/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/disk/DiskLoggerBackend.java index c2dff1e06..d42267d36 100644 --- a/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/disk/DiskLoggerBackend.java +++ b/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/disk/DiskLoggerBackend.java @@ -49,6 +49,7 @@ import oap.logstream.LogStreamProtocol.ProtocolVersion; import oap.logstream.LoggerException; import oap.logstream.Timestamp; +import oap.template.TemplateEngine; import oap.util.Dates; import oap.util.Lists; import org.apache.commons.io.FileUtils; @@ -84,6 +85,7 @@ public class DiskLoggerBackend extends AbstractLoggerBackend implements Cloneabl public final int bufferSize; public final LoadingCache> writers; public final ScheduledExecutorService pool; + protected final TemplateEngine templateEngine; public String filePattern = "/${YEAR}-${MONTH}/${DAY}/${LOG_TYPE}_v${LOG_VERSION}_${CLIENT_HOST}-${YEAR}-${MONTH}-${DAY}-${HOUR}-${INTERVAL}.tsv.gz"; public long requiredFreeSpace = DEFAULT_FREE_SPACE_REQUIRED; public int maxVersions = 20; @@ -92,13 +94,15 @@ public class DiskLoggerBackend extends AbstractLoggerBackend implements Cloneabl public volatile boolean closed; public final String hostname; - public DiskLoggerBackend( Path logDirectory, Timestamp timestamp, int bufferSize, String hostname ) { - this( logDirectory, new WriterConfiguration(), timestamp, bufferSize, hostname ); + public DiskLoggerBackend( TemplateEngine templateEngine, Path logDirectory, Timestamp timestamp, int bufferSize, String hostname ) { + this( templateEngine, logDirectory, new WriterConfiguration(), timestamp, bufferSize, hostname ); } @SuppressWarnings( "unchecked" ) - public DiskLoggerBackend( Path logDirectory, WriterConfiguration writerConfiguration, Timestamp timestamp, int bufferSize, String hostname ) { + public DiskLoggerBackend( TemplateEngine templateEngine, Path logDirectory, WriterConfiguration writerConfiguration, Timestamp timestamp, int bufferSize, String hostname ) { + this.templateEngine = templateEngine; this.hostname = hostname; + log.info( "logDirectory '{}' timestamp {} bufferSize {} writerConfiguration {} refreshInitDelay {} refreshPeriod {} hostname {}", logDirectory, timestamp, FileUtils.byteCountToDisplaySize( bufferSize ), writerConfiguration, Dates.durationToString( refreshInitDelay ), Dates.durationToString( refreshPeriod ), hostname ); @@ -122,7 +126,7 @@ public AbstractWriter load( LogId id ) { log.trace( "new writer id '{}' filePattern '{}'", id, fp ); - return new RowBinaryWriter( DiskLoggerBackend.this.logDirectory, fp.path, id, bufferSize, timestamp, maxVersions, hostname ); + return new RowBinaryWriter( templateEngine, DiskLoggerBackend.this.logDirectory, fp.path, id, bufferSize, timestamp, maxVersions, hostname ); } } ); Metrics.gauge( "logstream_logging_disk_writers", List.of( Tag.of( "path", this.logDirectory.toString() ) ), @@ -148,8 +152,8 @@ private void filePatternValidation( String type, String filePattern ) { LogId logId = new LogId( "", type, "", Map.of(), new String[] {}, new byte[][] {} ); DateTime time = Dates.nowUtc(); - String currentPattern = AbstractWriter.currentPattern( LogFormat.TSV_GZ, filePattern, logId, timestamp, 0, time, hostname ); - String previousPattern = AbstractWriter.currentPattern( LogFormat.TSV_GZ, filePattern, logId, timestamp, 0, time.minusMinutes( 60 / timestamp.bucketsPerHour ).minusSeconds( 1 ), hostname ); + String currentPattern = AbstractWriter.currentPattern( templateEngine, LogFormat.TSV_GZ, filePattern, logId, timestamp, 0, time, hostname ); + String previousPattern = AbstractWriter.currentPattern( templateEngine, LogFormat.TSV_GZ, filePattern, logId, timestamp, 0, time.minusMinutes( 60 / timestamp.bucketsPerHour ).minusSeconds( 1 ), hostname ); if( currentPattern.equals( previousPattern ) ) { log.error( "cp {}", currentPattern ); diff --git a/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/disk/RowBinaryWriter.java b/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/disk/RowBinaryWriter.java index 84b70bc11..b754d5d11 100644 --- a/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/disk/RowBinaryWriter.java +++ b/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/disk/RowBinaryWriter.java @@ -9,6 +9,7 @@ import oap.logstream.Timestamp; import oap.logstream.formats.rowbinary.RowBinaryOutputStream; import oap.net.Inet; +import oap.template.TemplateEngine; import oap.util.FastByteArrayOutputStream; import java.io.IOException; @@ -21,8 +22,8 @@ @Slf4j public class RowBinaryWriter extends AbstractWriter { - public RowBinaryWriter( Path logDirectory, String filePattern, LogId logId, int bufferSize, Timestamp timestamp, int maxVersions, String hostname ) { - super( LogFormat.ROW_BINARY_GZ, logDirectory, filePattern, logId, bufferSize, timestamp, maxVersions, hostname ); + public RowBinaryWriter( TemplateEngine templateEngine, Path logDirectory, String filePattern, LogId logId, int bufferSize, Timestamp timestamp, int maxVersions, String hostname ) { + super( templateEngine, LogFormat.ROW_BINARY_GZ, logDirectory, filePattern, logId, bufferSize, timestamp, maxVersions, hostname ); } @Override diff --git a/oap-formats/oap-template-test/pom.xml b/oap-formats/oap-template-test/pom.xml new file mode 100644 index 000000000..331c9058e --- /dev/null +++ b/oap-formats/oap-template-test/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + + oap + oap-formats-parent + ${oap.project.version} + + + oap-template-test + + + + oap + oap-template + ${project.parent.version} + + + + oap + oap-stdlib-test + ${project.parent.version} + + + + org.projectlombok + lombok + + + diff --git a/oap-formats/oap-template-test/src/main/java/oap/template/TemplateEngineFixture.java b/oap-formats/oap-template-test/src/main/java/oap/template/TemplateEngineFixture.java new file mode 100644 index 000000000..f1b58555c --- /dev/null +++ b/oap-formats/oap-template-test/src/main/java/oap/template/TemplateEngineFixture.java @@ -0,0 +1,15 @@ +package oap.template; + +import oap.testng.AbstractFixture; +import oap.util.Dates; + +import java.nio.file.Path; + +public class TemplateEngineFixture extends AbstractFixture { + public TemplateEngine templateEngine; + + @Override + protected void before() { + templateEngine = new TemplateEngine( Path.of( "/tmp/file-cache" ), Dates.d( 5 ) ); + } +} diff --git a/oap-formats/oap-template/src/main/antlr4/TemplateGrammarExpression.g4 b/oap-formats/oap-template/src/main/antlr4/TemplateGrammarExpression.g4 index 56fe8eac4..e045247dd 100644 --- a/oap-formats/oap-template/src/main/antlr4/TemplateGrammarExpression.g4 +++ b/oap-formats/oap-template/src/main/antlr4/TemplateGrammarExpression.g4 @@ -12,6 +12,11 @@ package oap.template; import oap.template.tree.*; import oap.template.tree.Math; import oap.template.tree.WithCondition; +import oap.template.tree.ConditionExpr; +import oap.template.tree.FieldConditionExpr; +import oap.template.tree.AndConditionExpr; +import oap.template.tree.OrConditionExpr; +import oap.template.tree.NotConditionExpr; import java.lang.reflect.Method; import java.util.ArrayList; @@ -64,8 +69,28 @@ exprsCode returns [ArrayList ret = new ArrayList<>()] } ; -ifCondition returns [Exprs ret] - : exprs { $ret = $exprs.ret; } +ifCondition returns [ConditionExpr ret] + : conditionOr { $ret = $conditionOr.ret; } + ; + +conditionOr returns [ConditionExpr ret] + : left=conditionAnd { $ret = $left.ret; } + ( OR right=conditionAnd { $ret = new OrConditionExpr( $ret, $right.ret ); } )* + ; + +conditionAnd returns [ConditionExpr ret] + : left=conditionNot { $ret = $left.ret; } + ( AND right=conditionNot { $ret = new AndConditionExpr( $ret, $right.ret ); } )* + ; + +conditionNot returns [ConditionExpr ret] + : ( NOT | BANG ) inner=conditionNot { $ret = new NotConditionExpr( $inner.ret ); } + | conditionAtom { $ret = $conditionAtom.ret; } + ; + +conditionAtom returns [ConditionExpr ret] + : LPAREN ifCondition RPAREN { $ret = $ifCondition.ret; } + | exprs { $ret = new FieldConditionExpr( $exprs.ret ); } ; diff --git a/oap-formats/oap-template/src/main/antlr4/TemplateLexerExpression.g4 b/oap-formats/oap-template/src/main/antlr4/TemplateLexerExpression.g4 index 4b5ceb0dc..312d8f3b8 100644 --- a/oap-formats/oap-template/src/main/antlr4/TemplateLexerExpression.g4 +++ b/oap-formats/oap-template/src/main/antlr4/TemplateLexerExpression.g4 @@ -86,6 +86,10 @@ THEN : 'then' ; ELSE : 'else' ; END : 'end' ; WITH : 'with' ; +AND : 'and' ; +OR : 'or' ; +NOT : 'not' ; +BANG : '!' ; VAR_ID : '$' NameChar (NameChar|DecDigit)* ; ROOT : '$' ; diff --git a/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateGrammarExpression.interp b/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateGrammarExpression.interp index 55889a542..04db1505a 100644 --- a/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateGrammarExpression.interp +++ b/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateGrammarExpression.interp @@ -6,6 +6,10 @@ null 'else' 'end' 'with' +'and' +'or' +'not' +'!' null '$' null @@ -46,6 +50,10 @@ THEN ELSE END WITH +AND +OR +NOT +BANG VAR_ID ROOT BLOCK_COMMENT @@ -84,6 +92,10 @@ ifCode withCode exprsCode ifCondition +conditionOr +conditionAnd +conditionNot +conditionAtom defaultValue defaultValueType longRule @@ -102,4 +114,4 @@ mathOperation atn: -[4, 1, 37, 313, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 1, 0, 3, 0, 42, 8, 0, 1, 0, 3, 0, 45, 8, 0, 1, 0, 1, 0, 1, 0, 3, 0, 50, 8, 0, 1, 0, 3, 0, 53, 8, 0, 1, 0, 3, 0, 56, 8, 0, 1, 0, 1, 0, 3, 0, 60, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 70, 8, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 108, 8, 6, 1, 7, 3, 7, 111, 8, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 3, 8, 119, 8, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 5, 9, 130, 8, 9, 10, 9, 12, 9, 133, 9, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 3, 10, 149, 8, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 158, 8, 11, 10, 11, 12, 11, 161, 9, 11, 1, 11, 3, 11, 164, 8, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 5, 12, 174, 8, 12, 10, 12, 12, 12, 177, 9, 12, 1, 12, 3, 12, 180, 8, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 5, 12, 190, 8, 12, 10, 12, 12, 12, 193, 9, 12, 1, 12, 3, 12, 196, 8, 12, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 202, 8, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 209, 8, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 5, 12, 220, 8, 12, 10, 12, 12, 12, 223, 9, 12, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 229, 8, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 5, 12, 239, 8, 12, 10, 12, 12, 12, 242, 9, 12, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 248, 8, 12, 1, 12, 1, 12, 1, 12, 3, 12, 253, 8, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 260, 8, 12, 1, 13, 1, 13, 1, 13, 3, 13, 265, 8, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 3, 13, 272, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 5, 15, 285, 8, 15, 10, 15, 12, 15, 288, 9, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 300, 8, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 3, 18, 309, 8, 18, 1, 19, 1, 19, 1, 19, 0, 0, 20, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 0, 1, 1, 0, 22, 26, 341, 0, 41, 1, 0, 0, 0, 2, 63, 1, 0, 0, 0, 4, 74, 1, 0, 0, 0, 6, 82, 1, 0, 0, 0, 8, 86, 1, 0, 0, 0, 10, 89, 1, 0, 0, 0, 12, 107, 1, 0, 0, 0, 14, 110, 1, 0, 0, 0, 16, 114, 1, 0, 0, 0, 18, 123, 1, 0, 0, 0, 20, 148, 1, 0, 0, 0, 22, 163, 1, 0, 0, 0, 24, 259, 1, 0, 0, 0, 26, 271, 1, 0, 0, 0, 28, 273, 1, 0, 0, 0, 30, 278, 1, 0, 0, 0, 32, 299, 1, 0, 0, 0, 34, 301, 1, 0, 0, 0, 36, 308, 1, 0, 0, 0, 38, 310, 1, 0, 0, 0, 40, 42, 5, 9, 0, 0, 41, 40, 1, 0, 0, 0, 41, 42, 1, 0, 0, 0, 42, 44, 1, 0, 0, 0, 43, 45, 5, 33, 0, 0, 44, 43, 1, 0, 0, 0, 44, 45, 1, 0, 0, 0, 45, 49, 1, 0, 0, 0, 46, 50, 3, 2, 1, 0, 47, 50, 3, 4, 2, 0, 48, 50, 3, 6, 3, 0, 49, 46, 1, 0, 0, 0, 49, 47, 1, 0, 0, 0, 49, 48, 1, 0, 0, 0, 50, 52, 1, 0, 0, 0, 51, 53, 3, 10, 5, 0, 52, 51, 1, 0, 0, 0, 52, 53, 1, 0, 0, 0, 53, 55, 1, 0, 0, 0, 54, 56, 3, 16, 8, 0, 55, 54, 1, 0, 0, 0, 55, 56, 1, 0, 0, 0, 56, 59, 1, 0, 0, 0, 57, 58, 5, 2, 0, 0, 58, 60, 3, 8, 4, 0, 59, 57, 1, 0, 0, 0, 59, 60, 1, 0, 0, 0, 60, 61, 1, 0, 0, 0, 61, 62, 6, 0, -1, 0, 62, 1, 1, 0, 0, 0, 63, 64, 5, 2, 0, 0, 64, 65, 3, 8, 4, 0, 65, 66, 5, 3, 0, 0, 66, 69, 3, 24, 12, 0, 67, 68, 5, 4, 0, 0, 68, 70, 3, 24, 12, 0, 69, 67, 1, 0, 0, 0, 69, 70, 1, 0, 0, 0, 70, 71, 1, 0, 0, 0, 71, 72, 5, 5, 0, 0, 72, 73, 6, 1, -1, 0, 73, 3, 1, 0, 0, 0, 74, 75, 5, 6, 0, 0, 75, 76, 5, 15, 0, 0, 76, 77, 3, 24, 12, 0, 77, 78, 5, 16, 0, 0, 78, 79, 3, 6, 3, 0, 79, 80, 5, 5, 0, 0, 80, 81, 6, 2, -1, 0, 81, 5, 1, 0, 0, 0, 82, 83, 3, 24, 12, 0, 83, 84, 3, 22, 11, 0, 84, 85, 6, 3, -1, 0, 85, 7, 1, 0, 0, 0, 86, 87, 3, 24, 12, 0, 87, 88, 6, 4, -1, 0, 88, 9, 1, 0, 0, 0, 89, 90, 5, 19, 0, 0, 90, 91, 3, 12, 6, 0, 91, 92, 6, 5, -1, 0, 92, 11, 1, 0, 0, 0, 93, 94, 5, 28, 0, 0, 94, 108, 6, 6, -1, 0, 95, 96, 5, 27, 0, 0, 96, 108, 6, 6, -1, 0, 97, 98, 3, 14, 7, 0, 98, 99, 6, 6, -1, 0, 99, 108, 1, 0, 0, 0, 100, 101, 5, 30, 0, 0, 101, 108, 6, 6, -1, 0, 102, 103, 5, 31, 0, 0, 103, 108, 6, 6, -1, 0, 104, 105, 5, 17, 0, 0, 105, 106, 5, 18, 0, 0, 106, 108, 6, 6, -1, 0, 107, 93, 1, 0, 0, 0, 107, 95, 1, 0, 0, 0, 107, 97, 1, 0, 0, 0, 107, 100, 1, 0, 0, 0, 107, 102, 1, 0, 0, 0, 107, 104, 1, 0, 0, 0, 108, 13, 1, 0, 0, 0, 109, 111, 5, 26, 0, 0, 110, 109, 1, 0, 0, 0, 110, 111, 1, 0, 0, 0, 111, 112, 1, 0, 0, 0, 112, 113, 5, 29, 0, 0, 113, 15, 1, 0, 0, 0, 114, 115, 5, 20, 0, 0, 115, 116, 5, 32, 0, 0, 116, 118, 5, 15, 0, 0, 117, 119, 3, 18, 9, 0, 118, 117, 1, 0, 0, 0, 118, 119, 1, 0, 0, 0, 119, 120, 1, 0, 0, 0, 120, 121, 5, 16, 0, 0, 121, 122, 6, 8, -1, 0, 122, 17, 1, 0, 0, 0, 123, 124, 3, 20, 10, 0, 124, 131, 6, 9, -1, 0, 125, 126, 5, 21, 0, 0, 126, 127, 3, 20, 10, 0, 127, 128, 6, 9, -1, 0, 128, 130, 1, 0, 0, 0, 129, 125, 1, 0, 0, 0, 130, 133, 1, 0, 0, 0, 131, 129, 1, 0, 0, 0, 131, 132, 1, 0, 0, 0, 132, 19, 1, 0, 0, 0, 133, 131, 1, 0, 0, 0, 134, 135, 5, 29, 0, 0, 135, 149, 6, 10, -1, 0, 136, 137, 5, 26, 0, 0, 137, 138, 5, 29, 0, 0, 138, 149, 6, 10, -1, 0, 139, 140, 5, 30, 0, 0, 140, 149, 6, 10, -1, 0, 141, 142, 5, 26, 0, 0, 142, 143, 5, 30, 0, 0, 143, 149, 6, 10, -1, 0, 144, 145, 5, 28, 0, 0, 145, 149, 6, 10, -1, 0, 146, 147, 5, 27, 0, 0, 147, 149, 6, 10, -1, 0, 148, 134, 1, 0, 0, 0, 148, 136, 1, 0, 0, 0, 148, 139, 1, 0, 0, 0, 148, 141, 1, 0, 0, 0, 148, 144, 1, 0, 0, 0, 148, 146, 1, 0, 0, 0, 149, 21, 1, 0, 0, 0, 150, 151, 5, 1, 0, 0, 151, 152, 3, 24, 12, 0, 152, 159, 6, 11, -1, 0, 153, 154, 5, 1, 0, 0, 154, 155, 3, 24, 12, 0, 155, 156, 6, 11, -1, 0, 156, 158, 1, 0, 0, 0, 157, 153, 1, 0, 0, 0, 158, 161, 1, 0, 0, 0, 159, 157, 1, 0, 0, 0, 159, 160, 1, 0, 0, 0, 160, 164, 1, 0, 0, 0, 161, 159, 1, 0, 0, 0, 162, 164, 1, 0, 0, 0, 163, 150, 1, 0, 0, 0, 163, 162, 1, 0, 0, 0, 164, 23, 1, 0, 0, 0, 165, 166, 5, 8, 0, 0, 166, 167, 5, 14, 0, 0, 167, 168, 3, 26, 13, 0, 168, 175, 6, 12, -1, 0, 169, 170, 5, 14, 0, 0, 170, 171, 3, 26, 13, 0, 171, 172, 6, 12, -1, 0, 172, 174, 1, 0, 0, 0, 173, 169, 1, 0, 0, 0, 174, 177, 1, 0, 0, 0, 175, 173, 1, 0, 0, 0, 175, 176, 1, 0, 0, 0, 176, 179, 1, 0, 0, 0, 177, 175, 1, 0, 0, 0, 178, 180, 3, 34, 17, 0, 179, 178, 1, 0, 0, 0, 179, 180, 1, 0, 0, 0, 180, 181, 1, 0, 0, 0, 181, 182, 6, 12, -1, 0, 182, 260, 1, 0, 0, 0, 183, 184, 5, 7, 0, 0, 184, 191, 6, 12, -1, 0, 185, 186, 5, 14, 0, 0, 186, 187, 3, 26, 13, 0, 187, 188, 6, 12, -1, 0, 188, 190, 1, 0, 0, 0, 189, 185, 1, 0, 0, 0, 190, 193, 1, 0, 0, 0, 191, 189, 1, 0, 0, 0, 191, 192, 1, 0, 0, 0, 192, 195, 1, 0, 0, 0, 193, 191, 1, 0, 0, 0, 194, 196, 3, 34, 17, 0, 195, 194, 1, 0, 0, 0, 195, 196, 1, 0, 0, 0, 196, 197, 1, 0, 0, 0, 197, 260, 6, 12, -1, 0, 198, 199, 3, 26, 13, 0, 199, 201, 6, 12, -1, 0, 200, 202, 3, 34, 17, 0, 201, 200, 1, 0, 0, 0, 201, 202, 1, 0, 0, 0, 202, 203, 1, 0, 0, 0, 203, 204, 6, 12, -1, 0, 204, 260, 1, 0, 0, 0, 205, 206, 3, 26, 13, 0, 206, 208, 6, 12, -1, 0, 207, 209, 5, 14, 0, 0, 208, 207, 1, 0, 0, 0, 208, 209, 1, 0, 0, 0, 209, 210, 1, 0, 0, 0, 210, 211, 3, 28, 14, 0, 211, 212, 6, 12, -1, 0, 212, 260, 1, 0, 0, 0, 213, 214, 3, 26, 13, 0, 214, 221, 6, 12, -1, 0, 215, 216, 5, 14, 0, 0, 216, 217, 3, 26, 13, 0, 217, 218, 6, 12, -1, 0, 218, 220, 1, 0, 0, 0, 219, 215, 1, 0, 0, 0, 220, 223, 1, 0, 0, 0, 221, 219, 1, 0, 0, 0, 221, 222, 1, 0, 0, 0, 222, 224, 1, 0, 0, 0, 223, 221, 1, 0, 0, 0, 224, 225, 5, 14, 0, 0, 225, 226, 3, 26, 13, 0, 226, 228, 6, 12, -1, 0, 227, 229, 3, 34, 17, 0, 228, 227, 1, 0, 0, 0, 228, 229, 1, 0, 0, 0, 229, 230, 1, 0, 0, 0, 230, 231, 6, 12, -1, 0, 231, 260, 1, 0, 0, 0, 232, 233, 3, 26, 13, 0, 233, 240, 6, 12, -1, 0, 234, 235, 5, 14, 0, 0, 235, 236, 3, 26, 13, 0, 236, 237, 6, 12, -1, 0, 237, 239, 1, 0, 0, 0, 238, 234, 1, 0, 0, 0, 239, 242, 1, 0, 0, 0, 240, 238, 1, 0, 0, 0, 240, 241, 1, 0, 0, 0, 241, 243, 1, 0, 0, 0, 242, 240, 1, 0, 0, 0, 243, 244, 5, 14, 0, 0, 244, 245, 3, 26, 13, 0, 245, 247, 6, 12, -1, 0, 246, 248, 5, 14, 0, 0, 247, 246, 1, 0, 0, 0, 247, 248, 1, 0, 0, 0, 248, 249, 1, 0, 0, 0, 249, 250, 3, 28, 14, 0, 250, 252, 6, 12, -1, 0, 251, 253, 3, 34, 17, 0, 252, 251, 1, 0, 0, 0, 252, 253, 1, 0, 0, 0, 253, 254, 1, 0, 0, 0, 254, 255, 6, 12, -1, 0, 255, 260, 1, 0, 0, 0, 256, 257, 3, 28, 14, 0, 257, 258, 6, 12, -1, 0, 258, 260, 1, 0, 0, 0, 259, 165, 1, 0, 0, 0, 259, 183, 1, 0, 0, 0, 259, 198, 1, 0, 0, 0, 259, 205, 1, 0, 0, 0, 259, 213, 1, 0, 0, 0, 259, 232, 1, 0, 0, 0, 259, 256, 1, 0, 0, 0, 260, 25, 1, 0, 0, 0, 261, 262, 5, 32, 0, 0, 262, 264, 5, 15, 0, 0, 263, 265, 3, 18, 9, 0, 264, 263, 1, 0, 0, 0, 264, 265, 1, 0, 0, 0, 265, 266, 1, 0, 0, 0, 266, 267, 5, 16, 0, 0, 267, 268, 1, 0, 0, 0, 268, 272, 6, 13, -1, 0, 269, 270, 5, 32, 0, 0, 270, 272, 6, 13, -1, 0, 271, 261, 1, 0, 0, 0, 271, 269, 1, 0, 0, 0, 272, 27, 1, 0, 0, 0, 273, 274, 5, 12, 0, 0, 274, 275, 3, 30, 15, 0, 275, 276, 6, 14, -1, 0, 276, 277, 5, 13, 0, 0, 277, 29, 1, 0, 0, 0, 278, 279, 3, 32, 16, 0, 279, 286, 6, 15, -1, 0, 280, 281, 5, 21, 0, 0, 281, 282, 3, 32, 16, 0, 282, 283, 6, 15, -1, 0, 283, 285, 1, 0, 0, 0, 284, 280, 1, 0, 0, 0, 285, 288, 1, 0, 0, 0, 286, 284, 1, 0, 0, 0, 286, 287, 1, 0, 0, 0, 287, 31, 1, 0, 0, 0, 288, 286, 1, 0, 0, 0, 289, 290, 5, 32, 0, 0, 290, 300, 6, 16, -1, 0, 291, 292, 5, 27, 0, 0, 292, 300, 6, 16, -1, 0, 293, 294, 5, 28, 0, 0, 294, 300, 6, 16, -1, 0, 295, 296, 5, 29, 0, 0, 296, 300, 6, 16, -1, 0, 297, 298, 5, 30, 0, 0, 298, 300, 6, 16, -1, 0, 299, 289, 1, 0, 0, 0, 299, 291, 1, 0, 0, 0, 299, 293, 1, 0, 0, 0, 299, 295, 1, 0, 0, 0, 299, 297, 1, 0, 0, 0, 300, 33, 1, 0, 0, 0, 301, 302, 3, 38, 19, 0, 302, 303, 3, 36, 18, 0, 303, 304, 6, 17, -1, 0, 304, 35, 1, 0, 0, 0, 305, 309, 1, 0, 0, 0, 306, 309, 5, 29, 0, 0, 307, 309, 5, 30, 0, 0, 308, 305, 1, 0, 0, 0, 308, 306, 1, 0, 0, 0, 308, 307, 1, 0, 0, 0, 309, 37, 1, 0, 0, 0, 310, 311, 7, 0, 0, 0, 311, 39, 1, 0, 0, 0, 31, 41, 44, 49, 52, 55, 59, 69, 107, 110, 118, 131, 148, 159, 163, 175, 179, 191, 195, 201, 208, 221, 228, 240, 247, 252, 259, 264, 271, 286, 299, 308] \ No newline at end of file +[4, 1, 41, 362, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 1, 0, 3, 0, 50, 8, 0, 1, 0, 3, 0, 53, 8, 0, 1, 0, 1, 0, 1, 0, 3, 0, 58, 8, 0, 1, 0, 3, 0, 61, 8, 0, 1, 0, 3, 0, 64, 8, 0, 1, 0, 1, 0, 3, 0, 68, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 78, 8, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 104, 8, 5, 10, 5, 12, 5, 107, 9, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 5, 6, 115, 8, 6, 10, 6, 12, 6, 118, 9, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 3, 7, 127, 8, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 3, 8, 137, 8, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 3, 10, 157, 8, 10, 1, 11, 3, 11, 160, 8, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 168, 8, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 179, 8, 13, 10, 13, 12, 13, 182, 9, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 3, 14, 198, 8, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 5, 15, 207, 8, 15, 10, 15, 12, 15, 210, 9, 15, 1, 15, 3, 15, 213, 8, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 5, 16, 223, 8, 16, 10, 16, 12, 16, 226, 9, 16, 1, 16, 3, 16, 229, 8, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 5, 16, 239, 8, 16, 10, 16, 12, 16, 242, 9, 16, 1, 16, 3, 16, 245, 8, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 251, 8, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 258, 8, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 5, 16, 269, 8, 16, 10, 16, 12, 16, 272, 9, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 278, 8, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 5, 16, 288, 8, 16, 10, 16, 12, 16, 291, 9, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 297, 8, 16, 1, 16, 1, 16, 1, 16, 3, 16, 302, 8, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 309, 8, 16, 1, 17, 1, 17, 1, 17, 3, 17, 314, 8, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 3, 17, 321, 8, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 5, 19, 334, 8, 19, 10, 19, 12, 19, 337, 9, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 3, 20, 349, 8, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 3, 22, 358, 8, 22, 1, 23, 1, 23, 1, 23, 0, 0, 24, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 0, 2, 1, 0, 9, 10, 1, 0, 26, 30, 390, 0, 49, 1, 0, 0, 0, 2, 71, 1, 0, 0, 0, 4, 82, 1, 0, 0, 0, 6, 90, 1, 0, 0, 0, 8, 94, 1, 0, 0, 0, 10, 97, 1, 0, 0, 0, 12, 108, 1, 0, 0, 0, 14, 126, 1, 0, 0, 0, 16, 136, 1, 0, 0, 0, 18, 138, 1, 0, 0, 0, 20, 156, 1, 0, 0, 0, 22, 159, 1, 0, 0, 0, 24, 163, 1, 0, 0, 0, 26, 172, 1, 0, 0, 0, 28, 197, 1, 0, 0, 0, 30, 212, 1, 0, 0, 0, 32, 308, 1, 0, 0, 0, 34, 320, 1, 0, 0, 0, 36, 322, 1, 0, 0, 0, 38, 327, 1, 0, 0, 0, 40, 348, 1, 0, 0, 0, 42, 350, 1, 0, 0, 0, 44, 357, 1, 0, 0, 0, 46, 359, 1, 0, 0, 0, 48, 50, 5, 13, 0, 0, 49, 48, 1, 0, 0, 0, 49, 50, 1, 0, 0, 0, 50, 52, 1, 0, 0, 0, 51, 53, 5, 37, 0, 0, 52, 51, 1, 0, 0, 0, 52, 53, 1, 0, 0, 0, 53, 57, 1, 0, 0, 0, 54, 58, 3, 2, 1, 0, 55, 58, 3, 4, 2, 0, 56, 58, 3, 6, 3, 0, 57, 54, 1, 0, 0, 0, 57, 55, 1, 0, 0, 0, 57, 56, 1, 0, 0, 0, 58, 60, 1, 0, 0, 0, 59, 61, 3, 18, 9, 0, 60, 59, 1, 0, 0, 0, 60, 61, 1, 0, 0, 0, 61, 63, 1, 0, 0, 0, 62, 64, 3, 24, 12, 0, 63, 62, 1, 0, 0, 0, 63, 64, 1, 0, 0, 0, 64, 67, 1, 0, 0, 0, 65, 66, 5, 2, 0, 0, 66, 68, 3, 8, 4, 0, 67, 65, 1, 0, 0, 0, 67, 68, 1, 0, 0, 0, 68, 69, 1, 0, 0, 0, 69, 70, 6, 0, -1, 0, 70, 1, 1, 0, 0, 0, 71, 72, 5, 2, 0, 0, 72, 73, 3, 8, 4, 0, 73, 74, 5, 3, 0, 0, 74, 77, 3, 32, 16, 0, 75, 76, 5, 4, 0, 0, 76, 78, 3, 32, 16, 0, 77, 75, 1, 0, 0, 0, 77, 78, 1, 0, 0, 0, 78, 79, 1, 0, 0, 0, 79, 80, 5, 5, 0, 0, 80, 81, 6, 1, -1, 0, 81, 3, 1, 0, 0, 0, 82, 83, 5, 6, 0, 0, 83, 84, 5, 19, 0, 0, 84, 85, 3, 32, 16, 0, 85, 86, 5, 20, 0, 0, 86, 87, 3, 6, 3, 0, 87, 88, 5, 5, 0, 0, 88, 89, 6, 2, -1, 0, 89, 5, 1, 0, 0, 0, 90, 91, 3, 32, 16, 0, 91, 92, 3, 30, 15, 0, 92, 93, 6, 3, -1, 0, 93, 7, 1, 0, 0, 0, 94, 95, 3, 10, 5, 0, 95, 96, 6, 4, -1, 0, 96, 9, 1, 0, 0, 0, 97, 98, 3, 12, 6, 0, 98, 105, 6, 5, -1, 0, 99, 100, 5, 8, 0, 0, 100, 101, 3, 12, 6, 0, 101, 102, 6, 5, -1, 0, 102, 104, 1, 0, 0, 0, 103, 99, 1, 0, 0, 0, 104, 107, 1, 0, 0, 0, 105, 103, 1, 0, 0, 0, 105, 106, 1, 0, 0, 0, 106, 11, 1, 0, 0, 0, 107, 105, 1, 0, 0, 0, 108, 109, 3, 14, 7, 0, 109, 116, 6, 6, -1, 0, 110, 111, 5, 7, 0, 0, 111, 112, 3, 14, 7, 0, 112, 113, 6, 6, -1, 0, 113, 115, 1, 0, 0, 0, 114, 110, 1, 0, 0, 0, 115, 118, 1, 0, 0, 0, 116, 114, 1, 0, 0, 0, 116, 117, 1, 0, 0, 0, 117, 13, 1, 0, 0, 0, 118, 116, 1, 0, 0, 0, 119, 120, 7, 0, 0, 0, 120, 121, 3, 14, 7, 0, 121, 122, 6, 7, -1, 0, 122, 127, 1, 0, 0, 0, 123, 124, 3, 16, 8, 0, 124, 125, 6, 7, -1, 0, 125, 127, 1, 0, 0, 0, 126, 119, 1, 0, 0, 0, 126, 123, 1, 0, 0, 0, 127, 15, 1, 0, 0, 0, 128, 129, 5, 19, 0, 0, 129, 130, 3, 8, 4, 0, 130, 131, 5, 20, 0, 0, 131, 132, 6, 8, -1, 0, 132, 137, 1, 0, 0, 0, 133, 134, 3, 32, 16, 0, 134, 135, 6, 8, -1, 0, 135, 137, 1, 0, 0, 0, 136, 128, 1, 0, 0, 0, 136, 133, 1, 0, 0, 0, 137, 17, 1, 0, 0, 0, 138, 139, 5, 23, 0, 0, 139, 140, 3, 20, 10, 0, 140, 141, 6, 9, -1, 0, 141, 19, 1, 0, 0, 0, 142, 143, 5, 32, 0, 0, 143, 157, 6, 10, -1, 0, 144, 145, 5, 31, 0, 0, 145, 157, 6, 10, -1, 0, 146, 147, 3, 22, 11, 0, 147, 148, 6, 10, -1, 0, 148, 157, 1, 0, 0, 0, 149, 150, 5, 34, 0, 0, 150, 157, 6, 10, -1, 0, 151, 152, 5, 35, 0, 0, 152, 157, 6, 10, -1, 0, 153, 154, 5, 21, 0, 0, 154, 155, 5, 22, 0, 0, 155, 157, 6, 10, -1, 0, 156, 142, 1, 0, 0, 0, 156, 144, 1, 0, 0, 0, 156, 146, 1, 0, 0, 0, 156, 149, 1, 0, 0, 0, 156, 151, 1, 0, 0, 0, 156, 153, 1, 0, 0, 0, 157, 21, 1, 0, 0, 0, 158, 160, 5, 30, 0, 0, 159, 158, 1, 0, 0, 0, 159, 160, 1, 0, 0, 0, 160, 161, 1, 0, 0, 0, 161, 162, 5, 33, 0, 0, 162, 23, 1, 0, 0, 0, 163, 164, 5, 24, 0, 0, 164, 165, 5, 36, 0, 0, 165, 167, 5, 19, 0, 0, 166, 168, 3, 26, 13, 0, 167, 166, 1, 0, 0, 0, 167, 168, 1, 0, 0, 0, 168, 169, 1, 0, 0, 0, 169, 170, 5, 20, 0, 0, 170, 171, 6, 12, -1, 0, 171, 25, 1, 0, 0, 0, 172, 173, 3, 28, 14, 0, 173, 180, 6, 13, -1, 0, 174, 175, 5, 25, 0, 0, 175, 176, 3, 28, 14, 0, 176, 177, 6, 13, -1, 0, 177, 179, 1, 0, 0, 0, 178, 174, 1, 0, 0, 0, 179, 182, 1, 0, 0, 0, 180, 178, 1, 0, 0, 0, 180, 181, 1, 0, 0, 0, 181, 27, 1, 0, 0, 0, 182, 180, 1, 0, 0, 0, 183, 184, 5, 33, 0, 0, 184, 198, 6, 14, -1, 0, 185, 186, 5, 30, 0, 0, 186, 187, 5, 33, 0, 0, 187, 198, 6, 14, -1, 0, 188, 189, 5, 34, 0, 0, 189, 198, 6, 14, -1, 0, 190, 191, 5, 30, 0, 0, 191, 192, 5, 34, 0, 0, 192, 198, 6, 14, -1, 0, 193, 194, 5, 32, 0, 0, 194, 198, 6, 14, -1, 0, 195, 196, 5, 31, 0, 0, 196, 198, 6, 14, -1, 0, 197, 183, 1, 0, 0, 0, 197, 185, 1, 0, 0, 0, 197, 188, 1, 0, 0, 0, 197, 190, 1, 0, 0, 0, 197, 193, 1, 0, 0, 0, 197, 195, 1, 0, 0, 0, 198, 29, 1, 0, 0, 0, 199, 200, 5, 1, 0, 0, 200, 201, 3, 32, 16, 0, 201, 208, 6, 15, -1, 0, 202, 203, 5, 1, 0, 0, 203, 204, 3, 32, 16, 0, 204, 205, 6, 15, -1, 0, 205, 207, 1, 0, 0, 0, 206, 202, 1, 0, 0, 0, 207, 210, 1, 0, 0, 0, 208, 206, 1, 0, 0, 0, 208, 209, 1, 0, 0, 0, 209, 213, 1, 0, 0, 0, 210, 208, 1, 0, 0, 0, 211, 213, 1, 0, 0, 0, 212, 199, 1, 0, 0, 0, 212, 211, 1, 0, 0, 0, 213, 31, 1, 0, 0, 0, 214, 215, 5, 12, 0, 0, 215, 216, 5, 18, 0, 0, 216, 217, 3, 34, 17, 0, 217, 224, 6, 16, -1, 0, 218, 219, 5, 18, 0, 0, 219, 220, 3, 34, 17, 0, 220, 221, 6, 16, -1, 0, 221, 223, 1, 0, 0, 0, 222, 218, 1, 0, 0, 0, 223, 226, 1, 0, 0, 0, 224, 222, 1, 0, 0, 0, 224, 225, 1, 0, 0, 0, 225, 228, 1, 0, 0, 0, 226, 224, 1, 0, 0, 0, 227, 229, 3, 42, 21, 0, 228, 227, 1, 0, 0, 0, 228, 229, 1, 0, 0, 0, 229, 230, 1, 0, 0, 0, 230, 231, 6, 16, -1, 0, 231, 309, 1, 0, 0, 0, 232, 233, 5, 11, 0, 0, 233, 240, 6, 16, -1, 0, 234, 235, 5, 18, 0, 0, 235, 236, 3, 34, 17, 0, 236, 237, 6, 16, -1, 0, 237, 239, 1, 0, 0, 0, 238, 234, 1, 0, 0, 0, 239, 242, 1, 0, 0, 0, 240, 238, 1, 0, 0, 0, 240, 241, 1, 0, 0, 0, 241, 244, 1, 0, 0, 0, 242, 240, 1, 0, 0, 0, 243, 245, 3, 42, 21, 0, 244, 243, 1, 0, 0, 0, 244, 245, 1, 0, 0, 0, 245, 246, 1, 0, 0, 0, 246, 309, 6, 16, -1, 0, 247, 248, 3, 34, 17, 0, 248, 250, 6, 16, -1, 0, 249, 251, 3, 42, 21, 0, 250, 249, 1, 0, 0, 0, 250, 251, 1, 0, 0, 0, 251, 252, 1, 0, 0, 0, 252, 253, 6, 16, -1, 0, 253, 309, 1, 0, 0, 0, 254, 255, 3, 34, 17, 0, 255, 257, 6, 16, -1, 0, 256, 258, 5, 18, 0, 0, 257, 256, 1, 0, 0, 0, 257, 258, 1, 0, 0, 0, 258, 259, 1, 0, 0, 0, 259, 260, 3, 36, 18, 0, 260, 261, 6, 16, -1, 0, 261, 309, 1, 0, 0, 0, 262, 263, 3, 34, 17, 0, 263, 270, 6, 16, -1, 0, 264, 265, 5, 18, 0, 0, 265, 266, 3, 34, 17, 0, 266, 267, 6, 16, -1, 0, 267, 269, 1, 0, 0, 0, 268, 264, 1, 0, 0, 0, 269, 272, 1, 0, 0, 0, 270, 268, 1, 0, 0, 0, 270, 271, 1, 0, 0, 0, 271, 273, 1, 0, 0, 0, 272, 270, 1, 0, 0, 0, 273, 274, 5, 18, 0, 0, 274, 275, 3, 34, 17, 0, 275, 277, 6, 16, -1, 0, 276, 278, 3, 42, 21, 0, 277, 276, 1, 0, 0, 0, 277, 278, 1, 0, 0, 0, 278, 279, 1, 0, 0, 0, 279, 280, 6, 16, -1, 0, 280, 309, 1, 0, 0, 0, 281, 282, 3, 34, 17, 0, 282, 289, 6, 16, -1, 0, 283, 284, 5, 18, 0, 0, 284, 285, 3, 34, 17, 0, 285, 286, 6, 16, -1, 0, 286, 288, 1, 0, 0, 0, 287, 283, 1, 0, 0, 0, 288, 291, 1, 0, 0, 0, 289, 287, 1, 0, 0, 0, 289, 290, 1, 0, 0, 0, 290, 292, 1, 0, 0, 0, 291, 289, 1, 0, 0, 0, 292, 293, 5, 18, 0, 0, 293, 294, 3, 34, 17, 0, 294, 296, 6, 16, -1, 0, 295, 297, 5, 18, 0, 0, 296, 295, 1, 0, 0, 0, 296, 297, 1, 0, 0, 0, 297, 298, 1, 0, 0, 0, 298, 299, 3, 36, 18, 0, 299, 301, 6, 16, -1, 0, 300, 302, 3, 42, 21, 0, 301, 300, 1, 0, 0, 0, 301, 302, 1, 0, 0, 0, 302, 303, 1, 0, 0, 0, 303, 304, 6, 16, -1, 0, 304, 309, 1, 0, 0, 0, 305, 306, 3, 36, 18, 0, 306, 307, 6, 16, -1, 0, 307, 309, 1, 0, 0, 0, 308, 214, 1, 0, 0, 0, 308, 232, 1, 0, 0, 0, 308, 247, 1, 0, 0, 0, 308, 254, 1, 0, 0, 0, 308, 262, 1, 0, 0, 0, 308, 281, 1, 0, 0, 0, 308, 305, 1, 0, 0, 0, 309, 33, 1, 0, 0, 0, 310, 311, 5, 36, 0, 0, 311, 313, 5, 19, 0, 0, 312, 314, 3, 26, 13, 0, 313, 312, 1, 0, 0, 0, 313, 314, 1, 0, 0, 0, 314, 315, 1, 0, 0, 0, 315, 316, 5, 20, 0, 0, 316, 317, 1, 0, 0, 0, 317, 321, 6, 17, -1, 0, 318, 319, 5, 36, 0, 0, 319, 321, 6, 17, -1, 0, 320, 310, 1, 0, 0, 0, 320, 318, 1, 0, 0, 0, 321, 35, 1, 0, 0, 0, 322, 323, 5, 16, 0, 0, 323, 324, 3, 38, 19, 0, 324, 325, 6, 18, -1, 0, 325, 326, 5, 17, 0, 0, 326, 37, 1, 0, 0, 0, 327, 328, 3, 40, 20, 0, 328, 335, 6, 19, -1, 0, 329, 330, 5, 25, 0, 0, 330, 331, 3, 40, 20, 0, 331, 332, 6, 19, -1, 0, 332, 334, 1, 0, 0, 0, 333, 329, 1, 0, 0, 0, 334, 337, 1, 0, 0, 0, 335, 333, 1, 0, 0, 0, 335, 336, 1, 0, 0, 0, 336, 39, 1, 0, 0, 0, 337, 335, 1, 0, 0, 0, 338, 339, 5, 36, 0, 0, 339, 349, 6, 20, -1, 0, 340, 341, 5, 31, 0, 0, 341, 349, 6, 20, -1, 0, 342, 343, 5, 32, 0, 0, 343, 349, 6, 20, -1, 0, 344, 345, 5, 33, 0, 0, 345, 349, 6, 20, -1, 0, 346, 347, 5, 34, 0, 0, 347, 349, 6, 20, -1, 0, 348, 338, 1, 0, 0, 0, 348, 340, 1, 0, 0, 0, 348, 342, 1, 0, 0, 0, 348, 344, 1, 0, 0, 0, 348, 346, 1, 0, 0, 0, 349, 41, 1, 0, 0, 0, 350, 351, 3, 46, 23, 0, 351, 352, 3, 44, 22, 0, 352, 353, 6, 21, -1, 0, 353, 43, 1, 0, 0, 0, 354, 358, 1, 0, 0, 0, 355, 358, 5, 33, 0, 0, 356, 358, 5, 34, 0, 0, 357, 354, 1, 0, 0, 0, 357, 355, 1, 0, 0, 0, 357, 356, 1, 0, 0, 0, 358, 45, 1, 0, 0, 0, 359, 360, 7, 1, 0, 0, 360, 47, 1, 0, 0, 0, 35, 49, 52, 57, 60, 63, 67, 77, 105, 116, 126, 136, 156, 159, 167, 180, 197, 208, 212, 224, 228, 240, 244, 250, 257, 270, 277, 289, 296, 301, 308, 313, 320, 335, 348, 357] \ No newline at end of file diff --git a/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateGrammarExpression.java b/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateGrammarExpression.java index 4256e92ec..20d67dfba 100644 --- a/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateGrammarExpression.java +++ b/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateGrammarExpression.java @@ -5,6 +5,11 @@ import oap.template.tree.*; import oap.template.tree.Math; import oap.template.tree.WithCondition; +import oap.template.tree.ConditionExpr; +import oap.template.tree.FieldConditionExpr; +import oap.template.tree.AndConditionExpr; +import oap.template.tree.OrConditionExpr; +import oap.template.tree.NotConditionExpr; import java.lang.reflect.Method; import java.util.ArrayList; @@ -31,41 +36,44 @@ public class TemplateGrammarExpression extends TemplateGrammarAdaptor { protected static final PredictionContextCache _sharedContextCache = new PredictionContextCache(); public static final int - DEFAULT=1, IF=2, THEN=3, ELSE=4, END=5, WITH=6, VAR_ID=7, ROOT=8, BLOCK_COMMENT=9, - HORZ_WS=10, VERT_WS=11, LBRACE=12, RBRACE=13, DOT=14, LPAREN=15, RPAREN=16, - LBRACK=17, RBRACK=18, DQUESTION=19, SEMI=20, COMMA=21, STAR=22, SLASH=23, - PERCENT=24, PLUS=25, MINUS=26, DSTRING=27, SSTRING=28, DECDIGITS=29, FLOAT=30, - BOOLEAN=31, ID=32, CAST_TYPE=33, ERR_CHAR=34, C_HORZ_WS=35, C_VERT_WS=36, - CERR_CHAR=37; + DEFAULT=1, IF=2, THEN=3, ELSE=4, END=5, WITH=6, AND=7, OR=8, NOT=9, BANG=10, + VAR_ID=11, ROOT=12, BLOCK_COMMENT=13, HORZ_WS=14, VERT_WS=15, LBRACE=16, + RBRACE=17, DOT=18, LPAREN=19, RPAREN=20, LBRACK=21, RBRACK=22, DQUESTION=23, + SEMI=24, COMMA=25, STAR=26, SLASH=27, PERCENT=28, PLUS=29, MINUS=30, DSTRING=31, + SSTRING=32, DECDIGITS=33, FLOAT=34, BOOLEAN=35, ID=36, CAST_TYPE=37, ERR_CHAR=38, + C_HORZ_WS=39, C_VERT_WS=40, CERR_CHAR=41; public static final int RULE_expression = 0, RULE_ifCode = 1, RULE_withCode = 2, RULE_exprsCode = 3, - RULE_ifCondition = 4, RULE_defaultValue = 5, RULE_defaultValueType = 6, - RULE_longRule = 7, RULE_function = 8, RULE_functionArgs = 9, RULE_functionArg = 10, - RULE_orExprs = 11, RULE_exprs = 12, RULE_expr = 13, RULE_concatenation = 14, - RULE_citems = 15, RULE_citem = 16, RULE_math = 17, RULE_number = 18, RULE_mathOperation = 19; + RULE_ifCondition = 4, RULE_conditionOr = 5, RULE_conditionAnd = 6, RULE_conditionNot = 7, + RULE_conditionAtom = 8, RULE_defaultValue = 9, RULE_defaultValueType = 10, + RULE_longRule = 11, RULE_function = 12, RULE_functionArgs = 13, RULE_functionArg = 14, + RULE_orExprs = 15, RULE_exprs = 16, RULE_expr = 17, RULE_concatenation = 18, + RULE_citems = 19, RULE_citem = 20, RULE_math = 21, RULE_number = 22, RULE_mathOperation = 23; private static String[] makeRuleNames() { return new String[] { - "expression", "ifCode", "withCode", "exprsCode", "ifCondition", "defaultValue", - "defaultValueType", "longRule", "function", "functionArgs", "functionArg", - "orExprs", "exprs", "expr", "concatenation", "citems", "citem", "math", - "number", "mathOperation" + "expression", "ifCode", "withCode", "exprsCode", "ifCondition", "conditionOr", + "conditionAnd", "conditionNot", "conditionAtom", "defaultValue", "defaultValueType", + "longRule", "function", "functionArgs", "functionArg", "orExprs", "exprs", + "expr", "concatenation", "citems", "citem", "math", "number", "mathOperation" }; } public static final String[] ruleNames = makeRuleNames(); private static String[] makeLiteralNames() { return new String[] { - null, null, "'if'", "'then'", "'else'", "'end'", "'with'", null, "'$'" + null, null, "'if'", "'then'", "'else'", "'end'", "'with'", "'and'", "'or'", + "'not'", "'!'", null, "'$'" }; } private static final String[] _LITERAL_NAMES = makeLiteralNames(); private static String[] makeSymbolicNames() { return new String[] { - null, "DEFAULT", "IF", "THEN", "ELSE", "END", "WITH", "VAR_ID", "ROOT", - "BLOCK_COMMENT", "HORZ_WS", "VERT_WS", "LBRACE", "RBRACE", "DOT", "LPAREN", - "RPAREN", "LBRACK", "RBRACK", "DQUESTION", "SEMI", "COMMA", "STAR", "SLASH", - "PERCENT", "PLUS", "MINUS", "DSTRING", "SSTRING", "DECDIGITS", "FLOAT", - "BOOLEAN", "ID", "CAST_TYPE", "ERR_CHAR", "C_HORZ_WS", "C_VERT_WS", "CERR_CHAR" + null, "DEFAULT", "IF", "THEN", "ELSE", "END", "WITH", "AND", "OR", "NOT", + "BANG", "VAR_ID", "ROOT", "BLOCK_COMMENT", "HORZ_WS", "VERT_WS", "LBRACE", + "RBRACE", "DOT", "LPAREN", "RPAREN", "LBRACK", "RBRACK", "DQUESTION", + "SEMI", "COMMA", "STAR", "SLASH", "PERCENT", "PLUS", "MINUS", "DSTRING", + "SSTRING", "DECDIGITS", "FLOAT", "BOOLEAN", "ID", "CAST_TYPE", "ERR_CHAR", + "C_HORZ_WS", "C_VERT_WS", "CERR_CHAR" }; } private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); @@ -180,38 +188,38 @@ public final ExpressionContext expression() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(41); + setState(49); _errHandler.sync(this); _la = _input.LA(1); if (_la==BLOCK_COMMENT) { { - setState(40); + setState(48); ((ExpressionContext)_localctx).BLOCK_COMMENT = match(BLOCK_COMMENT); } } - setState(44); + setState(52); _errHandler.sync(this); _la = _input.LA(1); if (_la==CAST_TYPE) { { - setState(43); + setState(51); ((ExpressionContext)_localctx).CAST_TYPE = match(CAST_TYPE); } } - setState(49); + setState(57); _errHandler.sync(this); switch (_input.LA(1)) { case IF: { - setState(46); + setState(54); ((ExpressionContext)_localctx).ifCode = ifCode(); } break; case WITH: { - setState(47); + setState(55); ((ExpressionContext)_localctx).withCode = withCode(); } break; @@ -220,41 +228,41 @@ public final ExpressionContext expression() throws RecognitionException { case LBRACE: case ID: { - setState(48); + setState(56); ((ExpressionContext)_localctx).exprsCode = exprsCode(); } break; default: throw new NoViableAltException(this); } - setState(52); + setState(60); _errHandler.sync(this); _la = _input.LA(1); if (_la==DQUESTION) { { - setState(51); + setState(59); ((ExpressionContext)_localctx).defaultValue = defaultValue(); } } - setState(55); + setState(63); _errHandler.sync(this); _la = _input.LA(1); if (_la==SEMI) { { - setState(54); + setState(62); ((ExpressionContext)_localctx).function = function(); } } - setState(59); + setState(67); _errHandler.sync(this); _la = _input.LA(1); if (_la==IF) { { - setState(57); + setState(65); match(IF); - setState(58); + setState(66); ifCondition(); } } @@ -322,27 +330,27 @@ public final IfCodeContext ifCode() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(63); + setState(71); match(IF); - setState(64); + setState(72); ((IfCodeContext)_localctx).ifCondition = ifCondition(); - setState(65); + setState(73); match(THEN); - setState(66); + setState(74); ((IfCodeContext)_localctx).thenCode = exprs(); - setState(69); + setState(77); _errHandler.sync(this); _la = _input.LA(1); if (_la==ELSE) { { - setState(67); + setState(75); match(ELSE); - setState(68); + setState(76); ((IfCodeContext)_localctx).elseCode = exprs(); } } - setState(71); + setState(79); match(END); ((IfCodeContext)_localctx).ret = new IfCondition( ((IfCodeContext)_localctx).ifCondition.ret, ((IfCodeContext)_localctx).thenCode.ret, ((IfCodeContext)_localctx).elseCode != null ? ((IfCodeContext)_localctx).elseCode.ret : null ); @@ -395,17 +403,17 @@ public final WithCodeContext withCode() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(74); + setState(82); match(WITH); - setState(75); + setState(83); match(LPAREN); - setState(76); + setState(84); ((WithCodeContext)_localctx).scopePath = exprs(); - setState(77); + setState(85); match(RPAREN); - setState(78); + setState(86); ((WithCodeContext)_localctx).bodyExprs = exprsCode(); - setState(79); + setState(87); match(END); ((WithCodeContext)_localctx).ret = new WithCondition( ((WithCodeContext)_localctx).scopePath.ret, ((WithCodeContext)_localctx).bodyExprs.ret ); @@ -454,9 +462,9 @@ public final ExprsCodeContext exprsCode() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(82); + setState(90); ((ExprsCodeContext)_localctx).exprs = exprs(); - setState(83); + setState(91); ((ExprsCodeContext)_localctx).orExprs = orExprs(); _localctx.ret.add( ((ExprsCodeContext)_localctx).exprs.ret ); @@ -477,10 +485,10 @@ public final ExprsCodeContext exprsCode() throws RecognitionException { @SuppressWarnings("CheckReturnValue") public static class IfConditionContext extends ParserRuleContext { - public Exprs ret; - public ExprsContext exprs; - public ExprsContext exprs() { - return getRuleContext(ExprsContext.class,0); + public ConditionExpr ret; + public ConditionOrContext conditionOr; + public ConditionOrContext conditionOr() { + return getRuleContext(ConditionOrContext.class,0); } public IfConditionContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); @@ -502,9 +510,300 @@ public final IfConditionContext ifCondition() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(86); - ((IfConditionContext)_localctx).exprs = exprs(); - ((IfConditionContext)_localctx).ret = ((IfConditionContext)_localctx).exprs.ret; + setState(94); + ((IfConditionContext)_localctx).conditionOr = conditionOr(); + ((IfConditionContext)_localctx).ret = ((IfConditionContext)_localctx).conditionOr.ret; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class ConditionOrContext extends ParserRuleContext { + public ConditionExpr ret; + public ConditionAndContext left; + public ConditionAndContext right; + public List conditionAnd() { + return getRuleContexts(ConditionAndContext.class); + } + public ConditionAndContext conditionAnd(int i) { + return getRuleContext(ConditionAndContext.class,i); + } + public List OR() { return getTokens(TemplateGrammarExpression.OR); } + public TerminalNode OR(int i) { + return getToken(TemplateGrammarExpression.OR, i); + } + public ConditionOrContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_conditionOr; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TemplateGrammarExpressionListener ) ((TemplateGrammarExpressionListener)listener).enterConditionOr(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TemplateGrammarExpressionListener ) ((TemplateGrammarExpressionListener)listener).exitConditionOr(this); + } + } + + public final ConditionOrContext conditionOr() throws RecognitionException { + ConditionOrContext _localctx = new ConditionOrContext(_ctx, getState()); + enterRule(_localctx, 10, RULE_conditionOr); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(97); + ((ConditionOrContext)_localctx).left = conditionAnd(); + ((ConditionOrContext)_localctx).ret = ((ConditionOrContext)_localctx).left.ret; + setState(105); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==OR) { + { + { + setState(99); + match(OR); + setState(100); + ((ConditionOrContext)_localctx).right = conditionAnd(); + ((ConditionOrContext)_localctx).ret = new OrConditionExpr( _localctx.ret, ((ConditionOrContext)_localctx).right.ret ); + } + } + setState(107); + _errHandler.sync(this); + _la = _input.LA(1); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class ConditionAndContext extends ParserRuleContext { + public ConditionExpr ret; + public ConditionNotContext left; + public ConditionNotContext right; + public List conditionNot() { + return getRuleContexts(ConditionNotContext.class); + } + public ConditionNotContext conditionNot(int i) { + return getRuleContext(ConditionNotContext.class,i); + } + public List AND() { return getTokens(TemplateGrammarExpression.AND); } + public TerminalNode AND(int i) { + return getToken(TemplateGrammarExpression.AND, i); + } + public ConditionAndContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_conditionAnd; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TemplateGrammarExpressionListener ) ((TemplateGrammarExpressionListener)listener).enterConditionAnd(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TemplateGrammarExpressionListener ) ((TemplateGrammarExpressionListener)listener).exitConditionAnd(this); + } + } + + public final ConditionAndContext conditionAnd() throws RecognitionException { + ConditionAndContext _localctx = new ConditionAndContext(_ctx, getState()); + enterRule(_localctx, 12, RULE_conditionAnd); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(108); + ((ConditionAndContext)_localctx).left = conditionNot(); + ((ConditionAndContext)_localctx).ret = ((ConditionAndContext)_localctx).left.ret; + setState(116); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==AND) { + { + { + setState(110); + match(AND); + setState(111); + ((ConditionAndContext)_localctx).right = conditionNot(); + ((ConditionAndContext)_localctx).ret = new AndConditionExpr( _localctx.ret, ((ConditionAndContext)_localctx).right.ret ); + } + } + setState(118); + _errHandler.sync(this); + _la = _input.LA(1); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class ConditionNotContext extends ParserRuleContext { + public ConditionExpr ret; + public ConditionNotContext inner; + public ConditionAtomContext conditionAtom; + public TerminalNode NOT() { return getToken(TemplateGrammarExpression.NOT, 0); } + public TerminalNode BANG() { return getToken(TemplateGrammarExpression.BANG, 0); } + public ConditionNotContext conditionNot() { + return getRuleContext(ConditionNotContext.class,0); + } + public ConditionAtomContext conditionAtom() { + return getRuleContext(ConditionAtomContext.class,0); + } + public ConditionNotContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_conditionNot; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TemplateGrammarExpressionListener ) ((TemplateGrammarExpressionListener)listener).enterConditionNot(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TemplateGrammarExpressionListener ) ((TemplateGrammarExpressionListener)listener).exitConditionNot(this); + } + } + + public final ConditionNotContext conditionNot() throws RecognitionException { + ConditionNotContext _localctx = new ConditionNotContext(_ctx, getState()); + enterRule(_localctx, 14, RULE_conditionNot); + int _la; + try { + setState(126); + _errHandler.sync(this); + switch (_input.LA(1)) { + case NOT: + case BANG: + enterOuterAlt(_localctx, 1); + { + setState(119); + _la = _input.LA(1); + if ( !(_la==NOT || _la==BANG) ) { + _errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + setState(120); + ((ConditionNotContext)_localctx).inner = conditionNot(); + ((ConditionNotContext)_localctx).ret = new NotConditionExpr( ((ConditionNotContext)_localctx).inner.ret ); + } + break; + case VAR_ID: + case ROOT: + case LBRACE: + case LPAREN: + case ID: + enterOuterAlt(_localctx, 2); + { + setState(123); + ((ConditionNotContext)_localctx).conditionAtom = conditionAtom(); + ((ConditionNotContext)_localctx).ret = ((ConditionNotContext)_localctx).conditionAtom.ret; + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class ConditionAtomContext extends ParserRuleContext { + public ConditionExpr ret; + public IfConditionContext ifCondition; + public ExprsContext exprs; + public TerminalNode LPAREN() { return getToken(TemplateGrammarExpression.LPAREN, 0); } + public IfConditionContext ifCondition() { + return getRuleContext(IfConditionContext.class,0); + } + public TerminalNode RPAREN() { return getToken(TemplateGrammarExpression.RPAREN, 0); } + public ExprsContext exprs() { + return getRuleContext(ExprsContext.class,0); + } + public ConditionAtomContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_conditionAtom; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TemplateGrammarExpressionListener ) ((TemplateGrammarExpressionListener)listener).enterConditionAtom(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TemplateGrammarExpressionListener ) ((TemplateGrammarExpressionListener)listener).exitConditionAtom(this); + } + } + + public final ConditionAtomContext conditionAtom() throws RecognitionException { + ConditionAtomContext _localctx = new ConditionAtomContext(_ctx, getState()); + enterRule(_localctx, 16, RULE_conditionAtom); + try { + setState(136); + _errHandler.sync(this); + switch (_input.LA(1)) { + case LPAREN: + enterOuterAlt(_localctx, 1); + { + setState(128); + match(LPAREN); + setState(129); + ((ConditionAtomContext)_localctx).ifCondition = ifCondition(); + setState(130); + match(RPAREN); + ((ConditionAtomContext)_localctx).ret = ((ConditionAtomContext)_localctx).ifCondition.ret; + } + break; + case VAR_ID: + case ROOT: + case LBRACE: + case ID: + enterOuterAlt(_localctx, 2); + { + setState(133); + ((ConditionAtomContext)_localctx).exprs = exprs(); + ((ConditionAtomContext)_localctx).ret = new FieldConditionExpr( ((ConditionAtomContext)_localctx).exprs.ret ); + } + break; + default: + throw new NoViableAltException(this); } } catch (RecognitionException re) { @@ -542,13 +841,13 @@ public void exitRule(ParseTreeListener listener) { public final DefaultValueContext defaultValue() throws RecognitionException { DefaultValueContext _localctx = new DefaultValueContext(_ctx, getState()); - enterRule(_localctx, 10, RULE_defaultValue); + enterRule(_localctx, 18, RULE_defaultValue); try { enterOuterAlt(_localctx, 1); { - setState(89); + setState(138); match(DQUESTION); - setState(90); + setState(139); ((DefaultValueContext)_localctx).defaultValueType = defaultValueType(); ((DefaultValueContext)_localctx).ret = ((DefaultValueContext)_localctx).defaultValueType.ret; } @@ -597,15 +896,15 @@ public void exitRule(ParseTreeListener listener) { public final DefaultValueTypeContext defaultValueType() throws RecognitionException { DefaultValueTypeContext _localctx = new DefaultValueTypeContext(_ctx, getState()); - enterRule(_localctx, 12, RULE_defaultValueType); + enterRule(_localctx, 20, RULE_defaultValueType); try { - setState(107); + setState(156); _errHandler.sync(this); switch (_input.LA(1)) { case SSTRING: enterOuterAlt(_localctx, 1); { - setState(93); + setState(142); ((DefaultValueTypeContext)_localctx).SSTRING = match(SSTRING); ((DefaultValueTypeContext)_localctx).ret = sdStringToString( (((DefaultValueTypeContext)_localctx).SSTRING!=null?((DefaultValueTypeContext)_localctx).SSTRING.getText():null) ); } @@ -613,7 +912,7 @@ public final DefaultValueTypeContext defaultValueType() throws RecognitionExcept case DSTRING: enterOuterAlt(_localctx, 2); { - setState(95); + setState(144); ((DefaultValueTypeContext)_localctx).DSTRING = match(DSTRING); ((DefaultValueTypeContext)_localctx).ret = sdStringToString((((DefaultValueTypeContext)_localctx).DSTRING!=null?((DefaultValueTypeContext)_localctx).DSTRING.getText():null)); } @@ -622,7 +921,7 @@ public final DefaultValueTypeContext defaultValueType() throws RecognitionExcept case DECDIGITS: enterOuterAlt(_localctx, 3); { - setState(97); + setState(146); ((DefaultValueTypeContext)_localctx).longRule = longRule(); ((DefaultValueTypeContext)_localctx).ret = (((DefaultValueTypeContext)_localctx).longRule!=null?_input.getText(((DefaultValueTypeContext)_localctx).longRule.start,((DefaultValueTypeContext)_localctx).longRule.stop):null); } @@ -630,7 +929,7 @@ public final DefaultValueTypeContext defaultValueType() throws RecognitionExcept case FLOAT: enterOuterAlt(_localctx, 4); { - setState(100); + setState(149); ((DefaultValueTypeContext)_localctx).FLOAT = match(FLOAT); ((DefaultValueTypeContext)_localctx).ret = (((DefaultValueTypeContext)_localctx).FLOAT!=null?((DefaultValueTypeContext)_localctx).FLOAT.getText():null); } @@ -638,7 +937,7 @@ public final DefaultValueTypeContext defaultValueType() throws RecognitionExcept case BOOLEAN: enterOuterAlt(_localctx, 5); { - setState(102); + setState(151); ((DefaultValueTypeContext)_localctx).BOOLEAN = match(BOOLEAN); ((DefaultValueTypeContext)_localctx).ret = (((DefaultValueTypeContext)_localctx).BOOLEAN!=null?((DefaultValueTypeContext)_localctx).BOOLEAN.getText():null); } @@ -646,9 +945,9 @@ public final DefaultValueTypeContext defaultValueType() throws RecognitionExcept case LBRACK: enterOuterAlt(_localctx, 6); { - setState(104); + setState(153); match(LBRACK); - setState(105); + setState(154); match(RBRACK); ((DefaultValueTypeContext)_localctx).ret = "[]"; } @@ -688,22 +987,22 @@ public void exitRule(ParseTreeListener listener) { public final LongRuleContext longRule() throws RecognitionException { LongRuleContext _localctx = new LongRuleContext(_ctx, getState()); - enterRule(_localctx, 14, RULE_longRule); + enterRule(_localctx, 22, RULE_longRule); int _la; try { enterOuterAlt(_localctx, 1); { - setState(110); + setState(159); _errHandler.sync(this); _la = _input.LA(1); if (_la==MINUS) { { - setState(109); + setState(158); match(MINUS); } } - setState(112); + setState(161); match(DECDIGITS); } } @@ -746,28 +1045,28 @@ public void exitRule(ParseTreeListener listener) { public final FunctionContext function() throws RecognitionException { FunctionContext _localctx = new FunctionContext(_ctx, getState()); - enterRule(_localctx, 16, RULE_function); + enterRule(_localctx, 24, RULE_function); int _la; try { enterOuterAlt(_localctx, 1); { - setState(114); + setState(163); match(SEMI); - setState(115); + setState(164); ((FunctionContext)_localctx).ID = match(ID); - setState(116); + setState(165); match(LPAREN); - setState(118); + setState(167); _errHandler.sync(this); _la = _input.LA(1); - if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 2080374784L) != 0)) { + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 33285996544L) != 0)) { { - setState(117); + setState(166); ((FunctionContext)_localctx).functionArgs = functionArgs(); } } - setState(120); + setState(169); match(RPAREN); ((FunctionContext)_localctx).ret = new Func( (((FunctionContext)_localctx).ID!=null?((FunctionContext)_localctx).ID.getText():null), ((FunctionContext)_localctx).functionArgs != null ? ((FunctionContext)_localctx).functionArgs.ret : List.of() ); } @@ -813,28 +1112,28 @@ public void exitRule(ParseTreeListener listener) { public final FunctionArgsContext functionArgs() throws RecognitionException { FunctionArgsContext _localctx = new FunctionArgsContext(_ctx, getState()); - enterRule(_localctx, 18, RULE_functionArgs); + enterRule(_localctx, 26, RULE_functionArgs); int _la; try { enterOuterAlt(_localctx, 1); { - setState(123); + setState(172); ((FunctionArgsContext)_localctx).functionArg = functionArg(); _localctx.ret.add( ((FunctionArgsContext)_localctx).functionArg.ret ); - setState(131); + setState(180); _errHandler.sync(this); _la = _input.LA(1); while (_la==COMMA) { { { - setState(125); + setState(174); match(COMMA); - setState(126); + setState(175); ((FunctionArgsContext)_localctx).functionArg = functionArg(); _localctx.ret.add( ((FunctionArgsContext)_localctx).functionArg.ret ); } } - setState(133); + setState(182); _errHandler.sync(this); _la = _input.LA(1); } @@ -879,15 +1178,15 @@ public void exitRule(ParseTreeListener listener) { public final FunctionArgContext functionArg() throws RecognitionException { FunctionArgContext _localctx = new FunctionArgContext(_ctx, getState()); - enterRule(_localctx, 20, RULE_functionArg); + enterRule(_localctx, 28, RULE_functionArg); try { - setState(148); + setState(197); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,11,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,15,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(134); + setState(183); ((FunctionArgContext)_localctx).DECDIGITS = match(DECDIGITS); ((FunctionArgContext)_localctx).ret = (((FunctionArgContext)_localctx).DECDIGITS!=null?((FunctionArgContext)_localctx).DECDIGITS.getText():null); } @@ -895,9 +1194,9 @@ public final FunctionArgContext functionArg() throws RecognitionException { case 2: enterOuterAlt(_localctx, 2); { - setState(136); + setState(185); match(MINUS); - setState(137); + setState(186); ((FunctionArgContext)_localctx).DECDIGITS = match(DECDIGITS); ((FunctionArgContext)_localctx).ret = "-" + (((FunctionArgContext)_localctx).DECDIGITS!=null?((FunctionArgContext)_localctx).DECDIGITS.getText():null); } @@ -905,7 +1204,7 @@ public final FunctionArgContext functionArg() throws RecognitionException { case 3: enterOuterAlt(_localctx, 3); { - setState(139); + setState(188); ((FunctionArgContext)_localctx).FLOAT = match(FLOAT); ((FunctionArgContext)_localctx).ret = (((FunctionArgContext)_localctx).FLOAT!=null?((FunctionArgContext)_localctx).FLOAT.getText():null); } @@ -913,9 +1212,9 @@ public final FunctionArgContext functionArg() throws RecognitionException { case 4: enterOuterAlt(_localctx, 4); { - setState(141); + setState(190); match(MINUS); - setState(142); + setState(191); ((FunctionArgContext)_localctx).FLOAT = match(FLOAT); ((FunctionArgContext)_localctx).ret = "-" + (((FunctionArgContext)_localctx).FLOAT!=null?((FunctionArgContext)_localctx).FLOAT.getText():null); } @@ -923,7 +1222,7 @@ public final FunctionArgContext functionArg() throws RecognitionException { case 5: enterOuterAlt(_localctx, 5); { - setState(144); + setState(193); ((FunctionArgContext)_localctx).SSTRING = match(SSTRING); ((FunctionArgContext)_localctx).ret = sStringToDString( (((FunctionArgContext)_localctx).SSTRING!=null?((FunctionArgContext)_localctx).SSTRING.getText():null) ); } @@ -931,7 +1230,7 @@ public final FunctionArgContext functionArg() throws RecognitionException { case 6: enterOuterAlt(_localctx, 6); { - setState(146); + setState(195); ((FunctionArgContext)_localctx).DSTRING = match(DSTRING); ((FunctionArgContext)_localctx).ret = (((FunctionArgContext)_localctx).DSTRING!=null?((FunctionArgContext)_localctx).DSTRING.getText():null); } @@ -979,35 +1278,35 @@ public void exitRule(ParseTreeListener listener) { public final OrExprsContext orExprs() throws RecognitionException { OrExprsContext _localctx = new OrExprsContext(_ctx, getState()); - enterRule(_localctx, 22, RULE_orExprs); + enterRule(_localctx, 30, RULE_orExprs); int _la; try { - setState(163); + setState(212); _errHandler.sync(this); switch (_input.LA(1)) { case DEFAULT: enterOuterAlt(_localctx, 1); { { - setState(150); + setState(199); match(DEFAULT); - setState(151); + setState(200); ((OrExprsContext)_localctx).exprs = exprs(); _localctx.ret.add( ((OrExprsContext)_localctx).exprs.ret ); - setState(159); + setState(208); _errHandler.sync(this); _la = _input.LA(1); while (_la==DEFAULT) { { { - setState(153); + setState(202); match(DEFAULT); - setState(154); + setState(203); ((OrExprsContext)_localctx).exprs = exprs(); _localctx.ret.add( ((OrExprsContext)_localctx).exprs.ret ); } } - setState(161); + setState(210); _errHandler.sync(this); _la = _input.LA(1); } @@ -1079,46 +1378,46 @@ public void exitRule(ParseTreeListener listener) { public final ExprsContext exprs() throws RecognitionException { ExprsContext _localctx = new ExprsContext(_ctx, getState()); - enterRule(_localctx, 24, RULE_exprs); + enterRule(_localctx, 32, RULE_exprs); int _la; try { int _alt; - setState(259); + setState(308); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,25,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,29,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(165); + setState(214); match(ROOT); - setState(166); + setState(215); match(DOT); - setState(167); + setState(216); ((ExprsContext)_localctx).expr = expr(); _localctx.ret.rootScoped = true; _localctx.ret.exprs.add( ((ExprsContext)_localctx).expr.ret ); - setState(175); + setState(224); _errHandler.sync(this); _la = _input.LA(1); while (_la==DOT) { { { - setState(169); + setState(218); match(DOT); - setState(170); + setState(219); ((ExprsContext)_localctx).expr = expr(); _localctx.ret.exprs.add( ((ExprsContext)_localctx).expr.ret ); } } - setState(177); + setState(226); _errHandler.sync(this); _la = _input.LA(1); } - setState(179); + setState(228); _errHandler.sync(this); _la = _input.LA(1); - if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 130023424L) != 0)) { + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 2080374784L) != 0)) { { - setState(178); + setState(227); ((ExprsContext)_localctx).math = math(); } } @@ -1129,32 +1428,32 @@ public final ExprsContext exprs() throws RecognitionException { case 2: enterOuterAlt(_localctx, 2); { - setState(183); + setState(232); ((ExprsContext)_localctx).VAR_ID = match(VAR_ID); _localctx.ret.varName = (((ExprsContext)_localctx).VAR_ID!=null?((ExprsContext)_localctx).VAR_ID.getText():null).substring( 1 ); - setState(191); + setState(240); _errHandler.sync(this); _la = _input.LA(1); while (_la==DOT) { { { - setState(185); + setState(234); match(DOT); - setState(186); + setState(235); ((ExprsContext)_localctx).expr = expr(); _localctx.ret.exprs.add( ((ExprsContext)_localctx).expr.ret ); } } - setState(193); + setState(242); _errHandler.sync(this); _la = _input.LA(1); } - setState(195); + setState(244); _errHandler.sync(this); _la = _input.LA(1); - if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 130023424L) != 0)) { + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 2080374784L) != 0)) { { - setState(194); + setState(243); ((ExprsContext)_localctx).math = math(); } } @@ -1165,15 +1464,15 @@ public final ExprsContext exprs() throws RecognitionException { case 3: enterOuterAlt(_localctx, 3); { - setState(198); + setState(247); ((ExprsContext)_localctx).expr = expr(); _localctx.ret.exprs.add( ((ExprsContext)_localctx).expr.ret ); - setState(201); + setState(250); _errHandler.sync(this); _la = _input.LA(1); - if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 130023424L) != 0)) { + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 2080374784L) != 0)) { { - setState(200); + setState(249); ((ExprsContext)_localctx).math = math(); } } @@ -1184,20 +1483,20 @@ public final ExprsContext exprs() throws RecognitionException { case 4: enterOuterAlt(_localctx, 4); { - setState(205); + setState(254); ((ExprsContext)_localctx).expr = expr(); _localctx.ret.exprs.add( ((ExprsContext)_localctx).expr.ret ); - setState(208); + setState(257); _errHandler.sync(this); _la = _input.LA(1); if (_la==DOT) { { - setState(207); + setState(256); match(DOT); } } - setState(210); + setState(259); ((ExprsContext)_localctx).concatenation = concatenation(); _localctx.ret.concatenation = ((ExprsContext)_localctx).concatenation.ret; } @@ -1205,19 +1504,19 @@ public final ExprsContext exprs() throws RecognitionException { case 5: enterOuterAlt(_localctx, 5); { - setState(213); + setState(262); ((ExprsContext)_localctx).expr = expr(); _localctx.ret.exprs.add( ((ExprsContext)_localctx).expr.ret ); - setState(221); + setState(270); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,20,_ctx); + _alt = getInterpreter().adaptivePredict(_input,24,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(215); + setState(264); match(DOT); - setState(216); + setState(265); ((ExprsContext)_localctx).expr = expr(); _localctx.ret.exprs.add( ((ExprsContext)_localctx).expr.ret ); @@ -1225,21 +1524,21 @@ public final ExprsContext exprs() throws RecognitionException { } } } - setState(223); + setState(272); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,20,_ctx); + _alt = getInterpreter().adaptivePredict(_input,24,_ctx); } - setState(224); + setState(273); match(DOT); - setState(225); + setState(274); ((ExprsContext)_localctx).expr = expr(); _localctx.ret.exprs.add( ((ExprsContext)_localctx).expr.ret ); - setState(228); + setState(277); _errHandler.sync(this); _la = _input.LA(1); - if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 130023424L) != 0)) { + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 2080374784L) != 0)) { { - setState(227); + setState(276); ((ExprsContext)_localctx).math = math(); } } @@ -1250,52 +1549,52 @@ public final ExprsContext exprs() throws RecognitionException { case 6: enterOuterAlt(_localctx, 6); { - setState(232); + setState(281); ((ExprsContext)_localctx).expr = expr(); _localctx.ret.exprs.add( ((ExprsContext)_localctx).expr.ret ); - setState(240); + setState(289); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,22,_ctx); + _alt = getInterpreter().adaptivePredict(_input,26,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(234); + setState(283); match(DOT); - setState(235); + setState(284); ((ExprsContext)_localctx).expr = expr(); _localctx.ret.exprs.add( ((ExprsContext)_localctx).expr.ret ); } } } - setState(242); + setState(291); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,22,_ctx); + _alt = getInterpreter().adaptivePredict(_input,26,_ctx); } - setState(243); + setState(292); match(DOT); - setState(244); + setState(293); ((ExprsContext)_localctx).expr = expr(); _localctx.ret.exprs.add( ((ExprsContext)_localctx).expr.ret ); - setState(247); + setState(296); _errHandler.sync(this); _la = _input.LA(1); if (_la==DOT) { { - setState(246); + setState(295); match(DOT); } } - setState(249); + setState(298); ((ExprsContext)_localctx).concatenation = concatenation(); _localctx.ret.concatenation = ((ExprsContext)_localctx).concatenation.ret; - setState(252); + setState(301); _errHandler.sync(this); _la = _input.LA(1); - if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 130023424L) != 0)) { + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 2080374784L) != 0)) { { - setState(251); + setState(300); ((ExprsContext)_localctx).math = math(); } } @@ -1306,7 +1605,7 @@ public final ExprsContext exprs() throws RecognitionException { case 7: enterOuterAlt(_localctx, 7); { - setState(256); + setState(305); ((ExprsContext)_localctx).concatenation = concatenation(); _localctx.ret.concatenation = ((ExprsContext)_localctx).concatenation.ret; } @@ -1351,31 +1650,31 @@ public void exitRule(ParseTreeListener listener) { public final ExprContext expr() throws RecognitionException { ExprContext _localctx = new ExprContext(_ctx, getState()); - enterRule(_localctx, 26, RULE_expr); + enterRule(_localctx, 34, RULE_expr); int _la; try { - setState(271); + setState(320); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,27,_ctx) ) { + switch ( getInterpreter().adaptivePredict(_input,31,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { { - setState(261); + setState(310); ((ExprContext)_localctx).ID = match(ID); - setState(262); + setState(311); match(LPAREN); - setState(264); + setState(313); _errHandler.sync(this); _la = _input.LA(1); - if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 2080374784L) != 0)) { + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & 33285996544L) != 0)) { { - setState(263); + setState(312); ((ExprContext)_localctx).functionArgs = functionArgs(); } } - setState(266); + setState(315); match(RPAREN); } ((ExprContext)_localctx).ret = new Expr((((ExprContext)_localctx).ID!=null?((ExprContext)_localctx).ID.getText():null), true, ((ExprContext)_localctx).functionArgs != null ? ((ExprContext)_localctx).functionArgs.ret : List.of() ); @@ -1384,7 +1683,7 @@ public final ExprContext expr() throws RecognitionException { case 2: enterOuterAlt(_localctx, 2); { - setState(269); + setState(318); ((ExprContext)_localctx).ID = match(ID); ((ExprContext)_localctx).ret = new Expr((((ExprContext)_localctx).ID!=null?((ExprContext)_localctx).ID.getText():null), false, List.of() ); } @@ -1427,16 +1726,16 @@ public void exitRule(ParseTreeListener listener) { public final ConcatenationContext concatenation() throws RecognitionException { ConcatenationContext _localctx = new ConcatenationContext(_ctx, getState()); - enterRule(_localctx, 28, RULE_concatenation); + enterRule(_localctx, 36, RULE_concatenation); try { enterOuterAlt(_localctx, 1); { - setState(273); + setState(322); match(LBRACE); - setState(274); + setState(323); ((ConcatenationContext)_localctx).citems = citems(); ((ConcatenationContext)_localctx).ret = new Concatenation( ((ConcatenationContext)_localctx).citems.ret ); - setState(276); + setState(325); match(RBRACE); } } @@ -1481,28 +1780,28 @@ public void exitRule(ParseTreeListener listener) { public final CitemsContext citems() throws RecognitionException { CitemsContext _localctx = new CitemsContext(_ctx, getState()); - enterRule(_localctx, 30, RULE_citems); + enterRule(_localctx, 38, RULE_citems); int _la; try { enterOuterAlt(_localctx, 1); { - setState(278); + setState(327); ((CitemsContext)_localctx).citem = citem(); _localctx.ret.add(((CitemsContext)_localctx).citem.ret); - setState(286); + setState(335); _errHandler.sync(this); _la = _input.LA(1); while (_la==COMMA) { { { - setState(280); + setState(329); match(COMMA); - setState(281); + setState(330); ((CitemsContext)_localctx).citem = citem(); _localctx.ret.add(((CitemsContext)_localctx).citem.ret); } } - setState(288); + setState(337); _errHandler.sync(this); _la = _input.LA(1); } @@ -1548,15 +1847,15 @@ public void exitRule(ParseTreeListener listener) { public final CitemContext citem() throws RecognitionException { CitemContext _localctx = new CitemContext(_ctx, getState()); - enterRule(_localctx, 32, RULE_citem); + enterRule(_localctx, 40, RULE_citem); try { - setState(299); + setState(348); _errHandler.sync(this); switch (_input.LA(1)) { case ID: enterOuterAlt(_localctx, 1); { - setState(289); + setState(338); ((CitemContext)_localctx).ID = match(ID); ((CitemContext)_localctx).ret = new Expr( (((CitemContext)_localctx).ID!=null?((CitemContext)_localctx).ID.getText():null), false, List.of() ); } @@ -1564,7 +1863,7 @@ public final CitemContext citem() throws RecognitionException { case DSTRING: enterOuterAlt(_localctx, 2); { - setState(291); + setState(340); ((CitemContext)_localctx).DSTRING = match(DSTRING); ((CitemContext)_localctx).ret = sdStringToString( (((CitemContext)_localctx).DSTRING!=null?((CitemContext)_localctx).DSTRING.getText():null) ); } @@ -1572,7 +1871,7 @@ public final CitemContext citem() throws RecognitionException { case SSTRING: enterOuterAlt(_localctx, 3); { - setState(293); + setState(342); ((CitemContext)_localctx).SSTRING = match(SSTRING); ((CitemContext)_localctx).ret = sdStringToString( (((CitemContext)_localctx).SSTRING!=null?((CitemContext)_localctx).SSTRING.getText():null) ); } @@ -1580,7 +1879,7 @@ public final CitemContext citem() throws RecognitionException { case DECDIGITS: enterOuterAlt(_localctx, 4); { - setState(295); + setState(344); ((CitemContext)_localctx).DECDIGITS = match(DECDIGITS); ((CitemContext)_localctx).ret = String.valueOf( (((CitemContext)_localctx).DECDIGITS!=null?((CitemContext)_localctx).DECDIGITS.getText():null) ); } @@ -1588,7 +1887,7 @@ public final CitemContext citem() throws RecognitionException { case FLOAT: enterOuterAlt(_localctx, 5); { - setState(297); + setState(346); ((CitemContext)_localctx).FLOAT = match(FLOAT); ((CitemContext)_localctx).ret = String.valueOf( (((CitemContext)_localctx).FLOAT!=null?((CitemContext)_localctx).FLOAT.getText():null) ); } @@ -1635,13 +1934,13 @@ public void exitRule(ParseTreeListener listener) { public final MathContext math() throws RecognitionException { MathContext _localctx = new MathContext(_ctx, getState()); - enterRule(_localctx, 34, RULE_math); + enterRule(_localctx, 42, RULE_math); try { enterOuterAlt(_localctx, 1); { - setState(301); + setState(350); ((MathContext)_localctx).mathOperation = mathOperation(); - setState(302); + setState(351); ((MathContext)_localctx).number = number(); ((MathContext)_localctx).ret = new Math( (((MathContext)_localctx).mathOperation!=null?_input.getText(((MathContext)_localctx).mathOperation.start,((MathContext)_localctx).mathOperation.stop):null), (((MathContext)_localctx).number!=null?_input.getText(((MathContext)_localctx).number.start,((MathContext)_localctx).number.stop):null) ); } @@ -1677,9 +1976,9 @@ public void exitRule(ParseTreeListener listener) { public final NumberContext number() throws RecognitionException { NumberContext _localctx = new NumberContext(_ctx, getState()); - enterRule(_localctx, 36, RULE_number); + enterRule(_localctx, 44, RULE_number); try { - setState(308); + setState(357); _errHandler.sync(this); switch (_input.LA(1)) { case EOF: @@ -1688,6 +1987,8 @@ public final NumberContext number() throws RecognitionException { case THEN: case ELSE: case END: + case AND: + case OR: case RPAREN: case DQUESTION: case SEMI: @@ -1698,14 +1999,14 @@ public final NumberContext number() throws RecognitionException { case DECDIGITS: enterOuterAlt(_localctx, 2); { - setState(306); + setState(355); match(DECDIGITS); } break; case FLOAT: enterOuterAlt(_localctx, 3); { - setState(307); + setState(356); match(FLOAT); } break; @@ -1747,14 +2048,14 @@ public void exitRule(ParseTreeListener listener) { public final MathOperationContext mathOperation() throws RecognitionException { MathOperationContext _localctx = new MathOperationContext(_ctx, getState()); - enterRule(_localctx, 38, RULE_mathOperation); + enterRule(_localctx, 46, RULE_mathOperation); int _la; try { enterOuterAlt(_localctx, 1); { - setState(310); + setState(359); _la = _input.LA(1); - if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 130023424L) != 0)) ) { + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 2080374784L) != 0)) ) { _errHandler.recoverInline(this); } else { @@ -1776,210 +2077,248 @@ public final MathOperationContext mathOperation() throws RecognitionException { } public static final String _serializedATN = - "\u0004\u0001%\u0139\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ + "\u0004\u0001)\u016a\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ "\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004\u0002"+ "\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007\u0002"+ "\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b\u0007\u000b\u0002"+ "\f\u0007\f\u0002\r\u0007\r\u0002\u000e\u0007\u000e\u0002\u000f\u0007\u000f"+ "\u0002\u0010\u0007\u0010\u0002\u0011\u0007\u0011\u0002\u0012\u0007\u0012"+ - "\u0002\u0013\u0007\u0013\u0001\u0000\u0003\u0000*\b\u0000\u0001\u0000"+ - "\u0003\u0000-\b\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0003\u0000"+ - "2\b\u0000\u0001\u0000\u0003\u00005\b\u0000\u0001\u0000\u0003\u00008\b"+ - "\u0000\u0001\u0000\u0001\u0000\u0003\u0000<\b\u0000\u0001\u0000\u0001"+ - "\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ - "\u0001\u0003\u0001F\b\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ - "\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001"+ - "\u0002\u0001\u0002\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001"+ - "\u0004\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005\u0001\u0005\u0001"+ - "\u0005\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001"+ - "\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001"+ - "\u0006\u0001\u0006\u0001\u0006\u0003\u0006l\b\u0006\u0001\u0007\u0003"+ - "\u0007o\b\u0007\u0001\u0007\u0001\u0007\u0001\b\u0001\b\u0001\b\u0001"+ - "\b\u0003\bw\b\b\u0001\b\u0001\b\u0001\b\u0001\t\u0001\t\u0001\t\u0001"+ - "\t\u0001\t\u0001\t\u0005\t\u0082\b\t\n\t\f\t\u0085\t\t\u0001\n\u0001\n"+ - "\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001"+ - "\n\u0001\n\u0001\n\u0001\n\u0003\n\u0095\b\n\u0001\u000b\u0001\u000b\u0001"+ - "\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0005\u000b\u009e"+ - "\b\u000b\n\u000b\f\u000b\u00a1\t\u000b\u0001\u000b\u0003\u000b\u00a4\b"+ - "\u000b\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f"+ - "\u0005\f\u00ae\b\f\n\f\f\f\u00b1\t\f\u0001\f\u0003\f\u00b4\b\f\u0001\f"+ - "\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0005\f\u00be"+ - "\b\f\n\f\f\f\u00c1\t\f\u0001\f\u0003\f\u00c4\b\f\u0001\f\u0001\f\u0001"+ - "\f\u0001\f\u0003\f\u00ca\b\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0003"+ - "\f\u00d1\b\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001"+ - "\f\u0001\f\u0005\f\u00dc\b\f\n\f\f\f\u00df\t\f\u0001\f\u0001\f\u0001\f"+ - "\u0001\f\u0003\f\u00e5\b\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001"+ - "\f\u0001\f\u0001\f\u0005\f\u00ef\b\f\n\f\f\f\u00f2\t\f\u0001\f\u0001\f"+ - "\u0001\f\u0001\f\u0003\f\u00f8\b\f\u0001\f\u0001\f\u0001\f\u0003\f\u00fd"+ - "\b\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0003\f\u0104\b\f\u0001\r"+ - "\u0001\r\u0001\r\u0003\r\u0109\b\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001"+ - "\r\u0003\r\u0110\b\r\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001"+ - "\u000e\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001"+ - "\u000f\u0005\u000f\u011d\b\u000f\n\u000f\f\u000f\u0120\t\u000f\u0001\u0010"+ - "\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010"+ - "\u0001\u0010\u0001\u0010\u0001\u0010\u0003\u0010\u012c\b\u0010\u0001\u0011"+ - "\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0012\u0001\u0012\u0001\u0012"+ - "\u0003\u0012\u0135\b\u0012\u0001\u0013\u0001\u0013\u0001\u0013\u0000\u0000"+ - "\u0014\u0000\u0002\u0004\u0006\b\n\f\u000e\u0010\u0012\u0014\u0016\u0018"+ - "\u001a\u001c\u001e \"$&\u0000\u0001\u0001\u0000\u0016\u001a\u0155\u0000"+ - ")\u0001\u0000\u0000\u0000\u0002?\u0001\u0000\u0000\u0000\u0004J\u0001"+ - "\u0000\u0000\u0000\u0006R\u0001\u0000\u0000\u0000\bV\u0001\u0000\u0000"+ - "\u0000\nY\u0001\u0000\u0000\u0000\fk\u0001\u0000\u0000\u0000\u000en\u0001"+ - "\u0000\u0000\u0000\u0010r\u0001\u0000\u0000\u0000\u0012{\u0001\u0000\u0000"+ - "\u0000\u0014\u0094\u0001\u0000\u0000\u0000\u0016\u00a3\u0001\u0000\u0000"+ - "\u0000\u0018\u0103\u0001\u0000\u0000\u0000\u001a\u010f\u0001\u0000\u0000"+ - "\u0000\u001c\u0111\u0001\u0000\u0000\u0000\u001e\u0116\u0001\u0000\u0000"+ - "\u0000 \u012b\u0001\u0000\u0000\u0000\"\u012d\u0001\u0000\u0000\u0000"+ - "$\u0134\u0001\u0000\u0000\u0000&\u0136\u0001\u0000\u0000\u0000(*\u0005"+ - "\t\u0000\u0000)(\u0001\u0000\u0000\u0000)*\u0001\u0000\u0000\u0000*,\u0001"+ - "\u0000\u0000\u0000+-\u0005!\u0000\u0000,+\u0001\u0000\u0000\u0000,-\u0001"+ - "\u0000\u0000\u0000-1\u0001\u0000\u0000\u0000.2\u0003\u0002\u0001\u0000"+ - "/2\u0003\u0004\u0002\u000002\u0003\u0006\u0003\u00001.\u0001\u0000\u0000"+ - "\u00001/\u0001\u0000\u0000\u000010\u0001\u0000\u0000\u000024\u0001\u0000"+ - "\u0000\u000035\u0003\n\u0005\u000043\u0001\u0000\u0000\u000045\u0001\u0000"+ - "\u0000\u000057\u0001\u0000\u0000\u000068\u0003\u0010\b\u000076\u0001\u0000"+ - "\u0000\u000078\u0001\u0000\u0000\u00008;\u0001\u0000\u0000\u00009:\u0005"+ - "\u0002\u0000\u0000:<\u0003\b\u0004\u0000;9\u0001\u0000\u0000\u0000;<\u0001"+ - "\u0000\u0000\u0000<=\u0001\u0000\u0000\u0000=>\u0006\u0000\uffff\uffff"+ - "\u0000>\u0001\u0001\u0000\u0000\u0000?@\u0005\u0002\u0000\u0000@A\u0003"+ - "\b\u0004\u0000AB\u0005\u0003\u0000\u0000BE\u0003\u0018\f\u0000CD\u0005"+ - "\u0004\u0000\u0000DF\u0003\u0018\f\u0000EC\u0001\u0000\u0000\u0000EF\u0001"+ - "\u0000\u0000\u0000FG\u0001\u0000\u0000\u0000GH\u0005\u0005\u0000\u0000"+ - "HI\u0006\u0001\uffff\uffff\u0000I\u0003\u0001\u0000\u0000\u0000JK\u0005"+ - "\u0006\u0000\u0000KL\u0005\u000f\u0000\u0000LM\u0003\u0018\f\u0000MN\u0005"+ - "\u0010\u0000\u0000NO\u0003\u0006\u0003\u0000OP\u0005\u0005\u0000\u0000"+ - "PQ\u0006\u0002\uffff\uffff\u0000Q\u0005\u0001\u0000\u0000\u0000RS\u0003"+ - "\u0018\f\u0000ST\u0003\u0016\u000b\u0000TU\u0006\u0003\uffff\uffff\u0000"+ - "U\u0007\u0001\u0000\u0000\u0000VW\u0003\u0018\f\u0000WX\u0006\u0004\uffff"+ - "\uffff\u0000X\t\u0001\u0000\u0000\u0000YZ\u0005\u0013\u0000\u0000Z[\u0003"+ - "\f\u0006\u0000[\\\u0006\u0005\uffff\uffff\u0000\\\u000b\u0001\u0000\u0000"+ - "\u0000]^\u0005\u001c\u0000\u0000^l\u0006\u0006\uffff\uffff\u0000_`\u0005"+ - "\u001b\u0000\u0000`l\u0006\u0006\uffff\uffff\u0000ab\u0003\u000e\u0007"+ - "\u0000bc\u0006\u0006\uffff\uffff\u0000cl\u0001\u0000\u0000\u0000de\u0005"+ - "\u001e\u0000\u0000el\u0006\u0006\uffff\uffff\u0000fg\u0005\u001f\u0000"+ - "\u0000gl\u0006\u0006\uffff\uffff\u0000hi\u0005\u0011\u0000\u0000ij\u0005"+ - "\u0012\u0000\u0000jl\u0006\u0006\uffff\uffff\u0000k]\u0001\u0000\u0000"+ - "\u0000k_\u0001\u0000\u0000\u0000ka\u0001\u0000\u0000\u0000kd\u0001\u0000"+ - "\u0000\u0000kf\u0001\u0000\u0000\u0000kh\u0001\u0000\u0000\u0000l\r\u0001"+ - "\u0000\u0000\u0000mo\u0005\u001a\u0000\u0000nm\u0001\u0000\u0000\u0000"+ - "no\u0001\u0000\u0000\u0000op\u0001\u0000\u0000\u0000pq\u0005\u001d\u0000"+ - "\u0000q\u000f\u0001\u0000\u0000\u0000rs\u0005\u0014\u0000\u0000st\u0005"+ - " \u0000\u0000tv\u0005\u000f\u0000\u0000uw\u0003\u0012\t\u0000vu\u0001"+ - "\u0000\u0000\u0000vw\u0001\u0000\u0000\u0000wx\u0001\u0000\u0000\u0000"+ - "xy\u0005\u0010\u0000\u0000yz\u0006\b\uffff\uffff\u0000z\u0011\u0001\u0000"+ - "\u0000\u0000{|\u0003\u0014\n\u0000|\u0083\u0006\t\uffff\uffff\u0000}~"+ - "\u0005\u0015\u0000\u0000~\u007f\u0003\u0014\n\u0000\u007f\u0080\u0006"+ - "\t\uffff\uffff\u0000\u0080\u0082\u0001\u0000\u0000\u0000\u0081}\u0001"+ - "\u0000\u0000\u0000\u0082\u0085\u0001\u0000\u0000\u0000\u0083\u0081\u0001"+ - "\u0000\u0000\u0000\u0083\u0084\u0001\u0000\u0000\u0000\u0084\u0013\u0001"+ - "\u0000\u0000\u0000\u0085\u0083\u0001\u0000\u0000\u0000\u0086\u0087\u0005"+ - "\u001d\u0000\u0000\u0087\u0095\u0006\n\uffff\uffff\u0000\u0088\u0089\u0005"+ - "\u001a\u0000\u0000\u0089\u008a\u0005\u001d\u0000\u0000\u008a\u0095\u0006"+ - "\n\uffff\uffff\u0000\u008b\u008c\u0005\u001e\u0000\u0000\u008c\u0095\u0006"+ - "\n\uffff\uffff\u0000\u008d\u008e\u0005\u001a\u0000\u0000\u008e\u008f\u0005"+ - "\u001e\u0000\u0000\u008f\u0095\u0006\n\uffff\uffff\u0000\u0090\u0091\u0005"+ - "\u001c\u0000\u0000\u0091\u0095\u0006\n\uffff\uffff\u0000\u0092\u0093\u0005"+ - "\u001b\u0000\u0000\u0093\u0095\u0006\n\uffff\uffff\u0000\u0094\u0086\u0001"+ - "\u0000\u0000\u0000\u0094\u0088\u0001\u0000\u0000\u0000\u0094\u008b\u0001"+ - "\u0000\u0000\u0000\u0094\u008d\u0001\u0000\u0000\u0000\u0094\u0090\u0001"+ - "\u0000\u0000\u0000\u0094\u0092\u0001\u0000\u0000\u0000\u0095\u0015\u0001"+ - "\u0000\u0000\u0000\u0096\u0097\u0005\u0001\u0000\u0000\u0097\u0098\u0003"+ - "\u0018\f\u0000\u0098\u009f\u0006\u000b\uffff\uffff\u0000\u0099\u009a\u0005"+ - "\u0001\u0000\u0000\u009a\u009b\u0003\u0018\f\u0000\u009b\u009c\u0006\u000b"+ - "\uffff\uffff\u0000\u009c\u009e\u0001\u0000\u0000\u0000\u009d\u0099\u0001"+ - "\u0000\u0000\u0000\u009e\u00a1\u0001\u0000\u0000\u0000\u009f\u009d\u0001"+ - "\u0000\u0000\u0000\u009f\u00a0\u0001\u0000\u0000\u0000\u00a0\u00a4\u0001"+ - "\u0000\u0000\u0000\u00a1\u009f\u0001\u0000\u0000\u0000\u00a2\u00a4\u0001"+ - "\u0000\u0000\u0000\u00a3\u0096\u0001\u0000\u0000\u0000\u00a3\u00a2\u0001"+ - "\u0000\u0000\u0000\u00a4\u0017\u0001\u0000\u0000\u0000\u00a5\u00a6\u0005"+ - "\b\u0000\u0000\u00a6\u00a7\u0005\u000e\u0000\u0000\u00a7\u00a8\u0003\u001a"+ - "\r\u0000\u00a8\u00af\u0006\f\uffff\uffff\u0000\u00a9\u00aa\u0005\u000e"+ - "\u0000\u0000\u00aa\u00ab\u0003\u001a\r\u0000\u00ab\u00ac\u0006\f\uffff"+ - "\uffff\u0000\u00ac\u00ae\u0001\u0000\u0000\u0000\u00ad\u00a9\u0001\u0000"+ - "\u0000\u0000\u00ae\u00b1\u0001\u0000\u0000\u0000\u00af\u00ad\u0001\u0000"+ - "\u0000\u0000\u00af\u00b0\u0001\u0000\u0000\u0000\u00b0\u00b3\u0001\u0000"+ - "\u0000\u0000\u00b1\u00af\u0001\u0000\u0000\u0000\u00b2\u00b4\u0003\"\u0011"+ - "\u0000\u00b3\u00b2\u0001\u0000\u0000\u0000\u00b3\u00b4\u0001\u0000\u0000"+ - "\u0000\u00b4\u00b5\u0001\u0000\u0000\u0000\u00b5\u00b6\u0006\f\uffff\uffff"+ - "\u0000\u00b6\u0104\u0001\u0000\u0000\u0000\u00b7\u00b8\u0005\u0007\u0000"+ - "\u0000\u00b8\u00bf\u0006\f\uffff\uffff\u0000\u00b9\u00ba\u0005\u000e\u0000"+ - "\u0000\u00ba\u00bb\u0003\u001a\r\u0000\u00bb\u00bc\u0006\f\uffff\uffff"+ - "\u0000\u00bc\u00be\u0001\u0000\u0000\u0000\u00bd\u00b9\u0001\u0000\u0000"+ - "\u0000\u00be\u00c1\u0001\u0000\u0000\u0000\u00bf\u00bd\u0001\u0000\u0000"+ - "\u0000\u00bf\u00c0\u0001\u0000\u0000\u0000\u00c0\u00c3\u0001\u0000\u0000"+ - "\u0000\u00c1\u00bf\u0001\u0000\u0000\u0000\u00c2\u00c4\u0003\"\u0011\u0000"+ - "\u00c3\u00c2\u0001\u0000\u0000\u0000\u00c3\u00c4\u0001\u0000\u0000\u0000"+ - "\u00c4\u00c5\u0001\u0000\u0000\u0000\u00c5\u0104\u0006\f\uffff\uffff\u0000"+ - "\u00c6\u00c7\u0003\u001a\r\u0000\u00c7\u00c9\u0006\f\uffff\uffff\u0000"+ - "\u00c8\u00ca\u0003\"\u0011\u0000\u00c9\u00c8\u0001\u0000\u0000\u0000\u00c9"+ - "\u00ca\u0001\u0000\u0000\u0000\u00ca\u00cb\u0001\u0000\u0000\u0000\u00cb"+ - "\u00cc\u0006\f\uffff\uffff\u0000\u00cc\u0104\u0001\u0000\u0000\u0000\u00cd"+ - "\u00ce\u0003\u001a\r\u0000\u00ce\u00d0\u0006\f\uffff\uffff\u0000\u00cf"+ - "\u00d1\u0005\u000e\u0000\u0000\u00d0\u00cf\u0001\u0000\u0000\u0000\u00d0"+ - "\u00d1\u0001\u0000\u0000\u0000\u00d1\u00d2\u0001\u0000\u0000\u0000\u00d2"+ - "\u00d3\u0003\u001c\u000e\u0000\u00d3\u00d4\u0006\f\uffff\uffff\u0000\u00d4"+ - "\u0104\u0001\u0000\u0000\u0000\u00d5\u00d6\u0003\u001a\r\u0000\u00d6\u00dd"+ - "\u0006\f\uffff\uffff\u0000\u00d7\u00d8\u0005\u000e\u0000\u0000\u00d8\u00d9"+ - "\u0003\u001a\r\u0000\u00d9\u00da\u0006\f\uffff\uffff\u0000\u00da\u00dc"+ - "\u0001\u0000\u0000\u0000\u00db\u00d7\u0001\u0000\u0000\u0000\u00dc\u00df"+ - "\u0001\u0000\u0000\u0000\u00dd\u00db\u0001\u0000\u0000\u0000\u00dd\u00de"+ - "\u0001\u0000\u0000\u0000\u00de\u00e0\u0001\u0000\u0000\u0000\u00df\u00dd"+ - "\u0001\u0000\u0000\u0000\u00e0\u00e1\u0005\u000e\u0000\u0000\u00e1\u00e2"+ - "\u0003\u001a\r\u0000\u00e2\u00e4\u0006\f\uffff\uffff\u0000\u00e3\u00e5"+ - "\u0003\"\u0011\u0000\u00e4\u00e3\u0001\u0000\u0000\u0000\u00e4\u00e5\u0001"+ - "\u0000\u0000\u0000\u00e5\u00e6\u0001\u0000\u0000\u0000\u00e6\u00e7\u0006"+ - "\f\uffff\uffff\u0000\u00e7\u0104\u0001\u0000\u0000\u0000\u00e8\u00e9\u0003"+ - "\u001a\r\u0000\u00e9\u00f0\u0006\f\uffff\uffff\u0000\u00ea\u00eb\u0005"+ - "\u000e\u0000\u0000\u00eb\u00ec\u0003\u001a\r\u0000\u00ec\u00ed\u0006\f"+ - "\uffff\uffff\u0000\u00ed\u00ef\u0001\u0000\u0000\u0000\u00ee\u00ea\u0001"+ - "\u0000\u0000\u0000\u00ef\u00f2\u0001\u0000\u0000\u0000\u00f0\u00ee\u0001"+ - "\u0000\u0000\u0000\u00f0\u00f1\u0001\u0000\u0000\u0000\u00f1\u00f3\u0001"+ - "\u0000\u0000\u0000\u00f2\u00f0\u0001\u0000\u0000\u0000\u00f3\u00f4\u0005"+ - "\u000e\u0000\u0000\u00f4\u00f5\u0003\u001a\r\u0000\u00f5\u00f7\u0006\f"+ - "\uffff\uffff\u0000\u00f6\u00f8\u0005\u000e\u0000\u0000\u00f7\u00f6\u0001"+ - "\u0000\u0000\u0000\u00f7\u00f8\u0001\u0000\u0000\u0000\u00f8\u00f9\u0001"+ - "\u0000\u0000\u0000\u00f9\u00fa\u0003\u001c\u000e\u0000\u00fa\u00fc\u0006"+ - "\f\uffff\uffff\u0000\u00fb\u00fd\u0003\"\u0011\u0000\u00fc\u00fb\u0001"+ - "\u0000\u0000\u0000\u00fc\u00fd\u0001\u0000\u0000\u0000\u00fd\u00fe\u0001"+ - "\u0000\u0000\u0000\u00fe\u00ff\u0006\f\uffff\uffff\u0000\u00ff\u0104\u0001"+ - "\u0000\u0000\u0000\u0100\u0101\u0003\u001c\u000e\u0000\u0101\u0102\u0006"+ - "\f\uffff\uffff\u0000\u0102\u0104\u0001\u0000\u0000\u0000\u0103\u00a5\u0001"+ - "\u0000\u0000\u0000\u0103\u00b7\u0001\u0000\u0000\u0000\u0103\u00c6\u0001"+ - "\u0000\u0000\u0000\u0103\u00cd\u0001\u0000\u0000\u0000\u0103\u00d5\u0001"+ - "\u0000\u0000\u0000\u0103\u00e8\u0001\u0000\u0000\u0000\u0103\u0100\u0001"+ - "\u0000\u0000\u0000\u0104\u0019\u0001\u0000\u0000\u0000\u0105\u0106\u0005"+ - " \u0000\u0000\u0106\u0108\u0005\u000f\u0000\u0000\u0107\u0109\u0003\u0012"+ - "\t\u0000\u0108\u0107\u0001\u0000\u0000\u0000\u0108\u0109\u0001\u0000\u0000"+ - "\u0000\u0109\u010a\u0001\u0000\u0000\u0000\u010a\u010b\u0005\u0010\u0000"+ - "\u0000\u010b\u010c\u0001\u0000\u0000\u0000\u010c\u0110\u0006\r\uffff\uffff"+ - "\u0000\u010d\u010e\u0005 \u0000\u0000\u010e\u0110\u0006\r\uffff\uffff"+ - "\u0000\u010f\u0105\u0001\u0000\u0000\u0000\u010f\u010d\u0001\u0000\u0000"+ - "\u0000\u0110\u001b\u0001\u0000\u0000\u0000\u0111\u0112\u0005\f\u0000\u0000"+ - "\u0112\u0113\u0003\u001e\u000f\u0000\u0113\u0114\u0006\u000e\uffff\uffff"+ - "\u0000\u0114\u0115\u0005\r\u0000\u0000\u0115\u001d\u0001\u0000\u0000\u0000"+ - "\u0116\u0117\u0003 \u0010\u0000\u0117\u011e\u0006\u000f\uffff\uffff\u0000"+ - "\u0118\u0119\u0005\u0015\u0000\u0000\u0119\u011a\u0003 \u0010\u0000\u011a"+ - "\u011b\u0006\u000f\uffff\uffff\u0000\u011b\u011d\u0001\u0000\u0000\u0000"+ - "\u011c\u0118\u0001\u0000\u0000\u0000\u011d\u0120\u0001\u0000\u0000\u0000"+ - "\u011e\u011c\u0001\u0000\u0000\u0000\u011e\u011f\u0001\u0000\u0000\u0000"+ - "\u011f\u001f\u0001\u0000\u0000\u0000\u0120\u011e\u0001\u0000\u0000\u0000"+ - "\u0121\u0122\u0005 \u0000\u0000\u0122\u012c\u0006\u0010\uffff\uffff\u0000"+ - "\u0123\u0124\u0005\u001b\u0000\u0000\u0124\u012c\u0006\u0010\uffff\uffff"+ - "\u0000\u0125\u0126\u0005\u001c\u0000\u0000\u0126\u012c\u0006\u0010\uffff"+ - "\uffff\u0000\u0127\u0128\u0005\u001d\u0000\u0000\u0128\u012c\u0006\u0010"+ - "\uffff\uffff\u0000\u0129\u012a\u0005\u001e\u0000\u0000\u012a\u012c\u0006"+ - "\u0010\uffff\uffff\u0000\u012b\u0121\u0001\u0000\u0000\u0000\u012b\u0123"+ - "\u0001\u0000\u0000\u0000\u012b\u0125\u0001\u0000\u0000\u0000\u012b\u0127"+ - "\u0001\u0000\u0000\u0000\u012b\u0129\u0001\u0000\u0000\u0000\u012c!\u0001"+ - "\u0000\u0000\u0000\u012d\u012e\u0003&\u0013\u0000\u012e\u012f\u0003$\u0012"+ - "\u0000\u012f\u0130\u0006\u0011\uffff\uffff\u0000\u0130#\u0001\u0000\u0000"+ - "\u0000\u0131\u0135\u0001\u0000\u0000\u0000\u0132\u0135\u0005\u001d\u0000"+ - "\u0000\u0133\u0135\u0005\u001e\u0000\u0000\u0134\u0131\u0001\u0000\u0000"+ - "\u0000\u0134\u0132\u0001\u0000\u0000\u0000\u0134\u0133\u0001\u0000\u0000"+ - "\u0000\u0135%\u0001\u0000\u0000\u0000\u0136\u0137\u0007\u0000\u0000\u0000"+ - "\u0137\'\u0001\u0000\u0000\u0000\u001f),147;Eknv\u0083\u0094\u009f\u00a3"+ - "\u00af\u00b3\u00bf\u00c3\u00c9\u00d0\u00dd\u00e4\u00f0\u00f7\u00fc\u0103"+ - "\u0108\u010f\u011e\u012b\u0134"; + "\u0002\u0013\u0007\u0013\u0002\u0014\u0007\u0014\u0002\u0015\u0007\u0015"+ + "\u0002\u0016\u0007\u0016\u0002\u0017\u0007\u0017\u0001\u0000\u0003\u0000"+ + "2\b\u0000\u0001\u0000\u0003\u00005\b\u0000\u0001\u0000\u0001\u0000\u0001"+ + "\u0000\u0003\u0000:\b\u0000\u0001\u0000\u0003\u0000=\b\u0000\u0001\u0000"+ + "\u0003\u0000@\b\u0000\u0001\u0000\u0001\u0000\u0003\u0000D\b\u0000\u0001"+ + "\u0000\u0001\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ + "\u0001\u0001\u0001\u0003\u0001N\b\u0001\u0001\u0001\u0001\u0001\u0001"+ + "\u0001\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001"+ + "\u0002\u0001\u0002\u0001\u0002\u0001\u0003\u0001\u0003\u0001\u0003\u0001"+ + "\u0003\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005\u0001"+ + "\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0005\u0005h\b\u0005\n\u0005"+ + "\f\u0005k\t\u0005\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001"+ + "\u0006\u0001\u0006\u0005\u0006s\b\u0006\n\u0006\f\u0006v\t\u0006\u0001"+ + "\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001"+ + "\u0007\u0003\u0007\u007f\b\u0007\u0001\b\u0001\b\u0001\b\u0001\b\u0001"+ + "\b\u0001\b\u0001\b\u0001\b\u0003\b\u0089\b\b\u0001\t\u0001\t\u0001\t\u0001"+ + "\t\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001"+ + "\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0003\n\u009d\b\n\u0001\u000b"+ + "\u0003\u000b\u00a0\b\u000b\u0001\u000b\u0001\u000b\u0001\f\u0001\f\u0001"+ + "\f\u0001\f\u0003\f\u00a8\b\f\u0001\f\u0001\f\u0001\f\u0001\r\u0001\r\u0001"+ + "\r\u0001\r\u0001\r\u0001\r\u0005\r\u00b3\b\r\n\r\f\r\u00b6\t\r\u0001\u000e"+ + "\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e"+ + "\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e"+ + "\u0001\u000e\u0003\u000e\u00c6\b\u000e\u0001\u000f\u0001\u000f\u0001\u000f"+ + "\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0005\u000f\u00cf\b\u000f"+ + "\n\u000f\f\u000f\u00d2\t\u000f\u0001\u000f\u0003\u000f\u00d5\b\u000f\u0001"+ + "\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001"+ + "\u0010\u0001\u0010\u0005\u0010\u00df\b\u0010\n\u0010\f\u0010\u00e2\t\u0010"+ + "\u0001\u0010\u0003\u0010\u00e5\b\u0010\u0001\u0010\u0001\u0010\u0001\u0010"+ + "\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0005\u0010"+ + "\u00ef\b\u0010\n\u0010\f\u0010\u00f2\t\u0010\u0001\u0010\u0003\u0010\u00f5"+ + "\b\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0003\u0010\u00fb"+ + "\b\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0003"+ + "\u0010\u0102\b\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001"+ + "\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0005\u0010\u010d"+ + "\b\u0010\n\u0010\f\u0010\u0110\t\u0010\u0001\u0010\u0001\u0010\u0001\u0010"+ + "\u0001\u0010\u0003\u0010\u0116\b\u0010\u0001\u0010\u0001\u0010\u0001\u0010"+ + "\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0005\u0010"+ + "\u0120\b\u0010\n\u0010\f\u0010\u0123\t\u0010\u0001\u0010\u0001\u0010\u0001"+ + "\u0010\u0001\u0010\u0003\u0010\u0129\b\u0010\u0001\u0010\u0001\u0010\u0001"+ + "\u0010\u0003\u0010\u012e\b\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001"+ + "\u0010\u0001\u0010\u0003\u0010\u0135\b\u0010\u0001\u0011\u0001\u0011\u0001"+ + "\u0011\u0003\u0011\u013a\b\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001"+ + "\u0011\u0001\u0011\u0003\u0011\u0141\b\u0011\u0001\u0012\u0001\u0012\u0001"+ + "\u0012\u0001\u0012\u0001\u0012\u0001\u0013\u0001\u0013\u0001\u0013\u0001"+ + "\u0013\u0001\u0013\u0001\u0013\u0005\u0013\u014e\b\u0013\n\u0013\f\u0013"+ + "\u0151\t\u0013\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014"+ + "\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0003\u0014"+ + "\u015d\b\u0014\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0016"+ + "\u0001\u0016\u0001\u0016\u0003\u0016\u0166\b\u0016\u0001\u0017\u0001\u0017"+ + "\u0001\u0017\u0000\u0000\u0018\u0000\u0002\u0004\u0006\b\n\f\u000e\u0010"+ + "\u0012\u0014\u0016\u0018\u001a\u001c\u001e \"$&(*,.\u0000\u0002\u0001"+ + "\u0000\t\n\u0001\u0000\u001a\u001e\u0186\u00001\u0001\u0000\u0000\u0000"+ + "\u0002G\u0001\u0000\u0000\u0000\u0004R\u0001\u0000\u0000\u0000\u0006Z"+ + "\u0001\u0000\u0000\u0000\b^\u0001\u0000\u0000\u0000\na\u0001\u0000\u0000"+ + "\u0000\fl\u0001\u0000\u0000\u0000\u000e~\u0001\u0000\u0000\u0000\u0010"+ + "\u0088\u0001\u0000\u0000\u0000\u0012\u008a\u0001\u0000\u0000\u0000\u0014"+ + "\u009c\u0001\u0000\u0000\u0000\u0016\u009f\u0001\u0000\u0000\u0000\u0018"+ + "\u00a3\u0001\u0000\u0000\u0000\u001a\u00ac\u0001\u0000\u0000\u0000\u001c"+ + "\u00c5\u0001\u0000\u0000\u0000\u001e\u00d4\u0001\u0000\u0000\u0000 \u0134"+ + "\u0001\u0000\u0000\u0000\"\u0140\u0001\u0000\u0000\u0000$\u0142\u0001"+ + "\u0000\u0000\u0000&\u0147\u0001\u0000\u0000\u0000(\u015c\u0001\u0000\u0000"+ + "\u0000*\u015e\u0001\u0000\u0000\u0000,\u0165\u0001\u0000\u0000\u0000."+ + "\u0167\u0001\u0000\u0000\u000002\u0005\r\u0000\u000010\u0001\u0000\u0000"+ + "\u000012\u0001\u0000\u0000\u000024\u0001\u0000\u0000\u000035\u0005%\u0000"+ + "\u000043\u0001\u0000\u0000\u000045\u0001\u0000\u0000\u000059\u0001\u0000"+ + "\u0000\u00006:\u0003\u0002\u0001\u00007:\u0003\u0004\u0002\u00008:\u0003"+ + "\u0006\u0003\u000096\u0001\u0000\u0000\u000097\u0001\u0000\u0000\u0000"+ + "98\u0001\u0000\u0000\u0000:<\u0001\u0000\u0000\u0000;=\u0003\u0012\t\u0000"+ + "<;\u0001\u0000\u0000\u0000<=\u0001\u0000\u0000\u0000=?\u0001\u0000\u0000"+ + "\u0000>@\u0003\u0018\f\u0000?>\u0001\u0000\u0000\u0000?@\u0001\u0000\u0000"+ + "\u0000@C\u0001\u0000\u0000\u0000AB\u0005\u0002\u0000\u0000BD\u0003\b\u0004"+ + "\u0000CA\u0001\u0000\u0000\u0000CD\u0001\u0000\u0000\u0000DE\u0001\u0000"+ + "\u0000\u0000EF\u0006\u0000\uffff\uffff\u0000F\u0001\u0001\u0000\u0000"+ + "\u0000GH\u0005\u0002\u0000\u0000HI\u0003\b\u0004\u0000IJ\u0005\u0003\u0000"+ + "\u0000JM\u0003 \u0010\u0000KL\u0005\u0004\u0000\u0000LN\u0003 \u0010\u0000"+ + "MK\u0001\u0000\u0000\u0000MN\u0001\u0000\u0000\u0000NO\u0001\u0000\u0000"+ + "\u0000OP\u0005\u0005\u0000\u0000PQ\u0006\u0001\uffff\uffff\u0000Q\u0003"+ + "\u0001\u0000\u0000\u0000RS\u0005\u0006\u0000\u0000ST\u0005\u0013\u0000"+ + "\u0000TU\u0003 \u0010\u0000UV\u0005\u0014\u0000\u0000VW\u0003\u0006\u0003"+ + "\u0000WX\u0005\u0005\u0000\u0000XY\u0006\u0002\uffff\uffff\u0000Y\u0005"+ + "\u0001\u0000\u0000\u0000Z[\u0003 \u0010\u0000[\\\u0003\u001e\u000f\u0000"+ + "\\]\u0006\u0003\uffff\uffff\u0000]\u0007\u0001\u0000\u0000\u0000^_\u0003"+ + "\n\u0005\u0000_`\u0006\u0004\uffff\uffff\u0000`\t\u0001\u0000\u0000\u0000"+ + "ab\u0003\f\u0006\u0000bi\u0006\u0005\uffff\uffff\u0000cd\u0005\b\u0000"+ + "\u0000de\u0003\f\u0006\u0000ef\u0006\u0005\uffff\uffff\u0000fh\u0001\u0000"+ + "\u0000\u0000gc\u0001\u0000\u0000\u0000hk\u0001\u0000\u0000\u0000ig\u0001"+ + "\u0000\u0000\u0000ij\u0001\u0000\u0000\u0000j\u000b\u0001\u0000\u0000"+ + "\u0000ki\u0001\u0000\u0000\u0000lm\u0003\u000e\u0007\u0000mt\u0006\u0006"+ + "\uffff\uffff\u0000no\u0005\u0007\u0000\u0000op\u0003\u000e\u0007\u0000"+ + "pq\u0006\u0006\uffff\uffff\u0000qs\u0001\u0000\u0000\u0000rn\u0001\u0000"+ + "\u0000\u0000sv\u0001\u0000\u0000\u0000tr\u0001\u0000\u0000\u0000tu\u0001"+ + "\u0000\u0000\u0000u\r\u0001\u0000\u0000\u0000vt\u0001\u0000\u0000\u0000"+ + "wx\u0007\u0000\u0000\u0000xy\u0003\u000e\u0007\u0000yz\u0006\u0007\uffff"+ + "\uffff\u0000z\u007f\u0001\u0000\u0000\u0000{|\u0003\u0010\b\u0000|}\u0006"+ + "\u0007\uffff\uffff\u0000}\u007f\u0001\u0000\u0000\u0000~w\u0001\u0000"+ + "\u0000\u0000~{\u0001\u0000\u0000\u0000\u007f\u000f\u0001\u0000\u0000\u0000"+ + "\u0080\u0081\u0005\u0013\u0000\u0000\u0081\u0082\u0003\b\u0004\u0000\u0082"+ + "\u0083\u0005\u0014\u0000\u0000\u0083\u0084\u0006\b\uffff\uffff\u0000\u0084"+ + "\u0089\u0001\u0000\u0000\u0000\u0085\u0086\u0003 \u0010\u0000\u0086\u0087"+ + "\u0006\b\uffff\uffff\u0000\u0087\u0089\u0001\u0000\u0000\u0000\u0088\u0080"+ + "\u0001\u0000\u0000\u0000\u0088\u0085\u0001\u0000\u0000\u0000\u0089\u0011"+ + "\u0001\u0000\u0000\u0000\u008a\u008b\u0005\u0017\u0000\u0000\u008b\u008c"+ + "\u0003\u0014\n\u0000\u008c\u008d\u0006\t\uffff\uffff\u0000\u008d\u0013"+ + "\u0001\u0000\u0000\u0000\u008e\u008f\u0005 \u0000\u0000\u008f\u009d\u0006"+ + "\n\uffff\uffff\u0000\u0090\u0091\u0005\u001f\u0000\u0000\u0091\u009d\u0006"+ + "\n\uffff\uffff\u0000\u0092\u0093\u0003\u0016\u000b\u0000\u0093\u0094\u0006"+ + "\n\uffff\uffff\u0000\u0094\u009d\u0001\u0000\u0000\u0000\u0095\u0096\u0005"+ + "\"\u0000\u0000\u0096\u009d\u0006\n\uffff\uffff\u0000\u0097\u0098\u0005"+ + "#\u0000\u0000\u0098\u009d\u0006\n\uffff\uffff\u0000\u0099\u009a\u0005"+ + "\u0015\u0000\u0000\u009a\u009b\u0005\u0016\u0000\u0000\u009b\u009d\u0006"+ + "\n\uffff\uffff\u0000\u009c\u008e\u0001\u0000\u0000\u0000\u009c\u0090\u0001"+ + "\u0000\u0000\u0000\u009c\u0092\u0001\u0000\u0000\u0000\u009c\u0095\u0001"+ + "\u0000\u0000\u0000\u009c\u0097\u0001\u0000\u0000\u0000\u009c\u0099\u0001"+ + "\u0000\u0000\u0000\u009d\u0015\u0001\u0000\u0000\u0000\u009e\u00a0\u0005"+ + "\u001e\u0000\u0000\u009f\u009e\u0001\u0000\u0000\u0000\u009f\u00a0\u0001"+ + "\u0000\u0000\u0000\u00a0\u00a1\u0001\u0000\u0000\u0000\u00a1\u00a2\u0005"+ + "!\u0000\u0000\u00a2\u0017\u0001\u0000\u0000\u0000\u00a3\u00a4\u0005\u0018"+ + "\u0000\u0000\u00a4\u00a5\u0005$\u0000\u0000\u00a5\u00a7\u0005\u0013\u0000"+ + "\u0000\u00a6\u00a8\u0003\u001a\r\u0000\u00a7\u00a6\u0001\u0000\u0000\u0000"+ + "\u00a7\u00a8\u0001\u0000\u0000\u0000\u00a8\u00a9\u0001\u0000\u0000\u0000"+ + "\u00a9\u00aa\u0005\u0014\u0000\u0000\u00aa\u00ab\u0006\f\uffff\uffff\u0000"+ + "\u00ab\u0019\u0001\u0000\u0000\u0000\u00ac\u00ad\u0003\u001c\u000e\u0000"+ + "\u00ad\u00b4\u0006\r\uffff\uffff\u0000\u00ae\u00af\u0005\u0019\u0000\u0000"+ + "\u00af\u00b0\u0003\u001c\u000e\u0000\u00b0\u00b1\u0006\r\uffff\uffff\u0000"+ + "\u00b1\u00b3\u0001\u0000\u0000\u0000\u00b2\u00ae\u0001\u0000\u0000\u0000"+ + "\u00b3\u00b6\u0001\u0000\u0000\u0000\u00b4\u00b2\u0001\u0000\u0000\u0000"+ + "\u00b4\u00b5\u0001\u0000\u0000\u0000\u00b5\u001b\u0001\u0000\u0000\u0000"+ + "\u00b6\u00b4\u0001\u0000\u0000\u0000\u00b7\u00b8\u0005!\u0000\u0000\u00b8"+ + "\u00c6\u0006\u000e\uffff\uffff\u0000\u00b9\u00ba\u0005\u001e\u0000\u0000"+ + "\u00ba\u00bb\u0005!\u0000\u0000\u00bb\u00c6\u0006\u000e\uffff\uffff\u0000"+ + "\u00bc\u00bd\u0005\"\u0000\u0000\u00bd\u00c6\u0006\u000e\uffff\uffff\u0000"+ + "\u00be\u00bf\u0005\u001e\u0000\u0000\u00bf\u00c0\u0005\"\u0000\u0000\u00c0"+ + "\u00c6\u0006\u000e\uffff\uffff\u0000\u00c1\u00c2\u0005 \u0000\u0000\u00c2"+ + "\u00c6\u0006\u000e\uffff\uffff\u0000\u00c3\u00c4\u0005\u001f\u0000\u0000"+ + "\u00c4\u00c6\u0006\u000e\uffff\uffff\u0000\u00c5\u00b7\u0001\u0000\u0000"+ + "\u0000\u00c5\u00b9\u0001\u0000\u0000\u0000\u00c5\u00bc\u0001\u0000\u0000"+ + "\u0000\u00c5\u00be\u0001\u0000\u0000\u0000\u00c5\u00c1\u0001\u0000\u0000"+ + "\u0000\u00c5\u00c3\u0001\u0000\u0000\u0000\u00c6\u001d\u0001\u0000\u0000"+ + "\u0000\u00c7\u00c8\u0005\u0001\u0000\u0000\u00c8\u00c9\u0003 \u0010\u0000"+ + "\u00c9\u00d0\u0006\u000f\uffff\uffff\u0000\u00ca\u00cb\u0005\u0001\u0000"+ + "\u0000\u00cb\u00cc\u0003 \u0010\u0000\u00cc\u00cd\u0006\u000f\uffff\uffff"+ + "\u0000\u00cd\u00cf\u0001\u0000\u0000\u0000\u00ce\u00ca\u0001\u0000\u0000"+ + "\u0000\u00cf\u00d2\u0001\u0000\u0000\u0000\u00d0\u00ce\u0001\u0000\u0000"+ + "\u0000\u00d0\u00d1\u0001\u0000\u0000\u0000\u00d1\u00d5\u0001\u0000\u0000"+ + "\u0000\u00d2\u00d0\u0001\u0000\u0000\u0000\u00d3\u00d5\u0001\u0000\u0000"+ + "\u0000\u00d4\u00c7\u0001\u0000\u0000\u0000\u00d4\u00d3\u0001\u0000\u0000"+ + "\u0000\u00d5\u001f\u0001\u0000\u0000\u0000\u00d6\u00d7\u0005\f\u0000\u0000"+ + "\u00d7\u00d8\u0005\u0012\u0000\u0000\u00d8\u00d9\u0003\"\u0011\u0000\u00d9"+ + "\u00e0\u0006\u0010\uffff\uffff\u0000\u00da\u00db\u0005\u0012\u0000\u0000"+ + "\u00db\u00dc\u0003\"\u0011\u0000\u00dc\u00dd\u0006\u0010\uffff\uffff\u0000"+ + "\u00dd\u00df\u0001\u0000\u0000\u0000\u00de\u00da\u0001\u0000\u0000\u0000"+ + "\u00df\u00e2\u0001\u0000\u0000\u0000\u00e0\u00de\u0001\u0000\u0000\u0000"+ + "\u00e0\u00e1\u0001\u0000\u0000\u0000\u00e1\u00e4\u0001\u0000\u0000\u0000"+ + "\u00e2\u00e0\u0001\u0000\u0000\u0000\u00e3\u00e5\u0003*\u0015\u0000\u00e4"+ + "\u00e3\u0001\u0000\u0000\u0000\u00e4\u00e5\u0001\u0000\u0000\u0000\u00e5"+ + "\u00e6\u0001\u0000\u0000\u0000\u00e6\u00e7\u0006\u0010\uffff\uffff\u0000"+ + "\u00e7\u0135\u0001\u0000\u0000\u0000\u00e8\u00e9\u0005\u000b\u0000\u0000"+ + "\u00e9\u00f0\u0006\u0010\uffff\uffff\u0000\u00ea\u00eb\u0005\u0012\u0000"+ + "\u0000\u00eb\u00ec\u0003\"\u0011\u0000\u00ec\u00ed\u0006\u0010\uffff\uffff"+ + "\u0000\u00ed\u00ef\u0001\u0000\u0000\u0000\u00ee\u00ea\u0001\u0000\u0000"+ + "\u0000\u00ef\u00f2\u0001\u0000\u0000\u0000\u00f0\u00ee\u0001\u0000\u0000"+ + "\u0000\u00f0\u00f1\u0001\u0000\u0000\u0000\u00f1\u00f4\u0001\u0000\u0000"+ + "\u0000\u00f2\u00f0\u0001\u0000\u0000\u0000\u00f3\u00f5\u0003*\u0015\u0000"+ + "\u00f4\u00f3\u0001\u0000\u0000\u0000\u00f4\u00f5\u0001\u0000\u0000\u0000"+ + "\u00f5\u00f6\u0001\u0000\u0000\u0000\u00f6\u0135\u0006\u0010\uffff\uffff"+ + "\u0000\u00f7\u00f8\u0003\"\u0011\u0000\u00f8\u00fa\u0006\u0010\uffff\uffff"+ + "\u0000\u00f9\u00fb\u0003*\u0015\u0000\u00fa\u00f9\u0001\u0000\u0000\u0000"+ + "\u00fa\u00fb\u0001\u0000\u0000\u0000\u00fb\u00fc\u0001\u0000\u0000\u0000"+ + "\u00fc\u00fd\u0006\u0010\uffff\uffff\u0000\u00fd\u0135\u0001\u0000\u0000"+ + "\u0000\u00fe\u00ff\u0003\"\u0011\u0000\u00ff\u0101\u0006\u0010\uffff\uffff"+ + "\u0000\u0100\u0102\u0005\u0012\u0000\u0000\u0101\u0100\u0001\u0000\u0000"+ + "\u0000\u0101\u0102\u0001\u0000\u0000\u0000\u0102\u0103\u0001\u0000\u0000"+ + "\u0000\u0103\u0104\u0003$\u0012\u0000\u0104\u0105\u0006\u0010\uffff\uffff"+ + "\u0000\u0105\u0135\u0001\u0000\u0000\u0000\u0106\u0107\u0003\"\u0011\u0000"+ + "\u0107\u010e\u0006\u0010\uffff\uffff\u0000\u0108\u0109\u0005\u0012\u0000"+ + "\u0000\u0109\u010a\u0003\"\u0011\u0000\u010a\u010b\u0006\u0010\uffff\uffff"+ + "\u0000\u010b\u010d\u0001\u0000\u0000\u0000\u010c\u0108\u0001\u0000\u0000"+ + "\u0000\u010d\u0110\u0001\u0000\u0000\u0000\u010e\u010c\u0001\u0000\u0000"+ + "\u0000\u010e\u010f\u0001\u0000\u0000\u0000\u010f\u0111\u0001\u0000\u0000"+ + "\u0000\u0110\u010e\u0001\u0000\u0000\u0000\u0111\u0112\u0005\u0012\u0000"+ + "\u0000\u0112\u0113\u0003\"\u0011\u0000\u0113\u0115\u0006\u0010\uffff\uffff"+ + "\u0000\u0114\u0116\u0003*\u0015\u0000\u0115\u0114\u0001\u0000\u0000\u0000"+ + "\u0115\u0116\u0001\u0000\u0000\u0000\u0116\u0117\u0001\u0000\u0000\u0000"+ + "\u0117\u0118\u0006\u0010\uffff\uffff\u0000\u0118\u0135\u0001\u0000\u0000"+ + "\u0000\u0119\u011a\u0003\"\u0011\u0000\u011a\u0121\u0006\u0010\uffff\uffff"+ + "\u0000\u011b\u011c\u0005\u0012\u0000\u0000\u011c\u011d\u0003\"\u0011\u0000"+ + "\u011d\u011e\u0006\u0010\uffff\uffff\u0000\u011e\u0120\u0001\u0000\u0000"+ + "\u0000\u011f\u011b\u0001\u0000\u0000\u0000\u0120\u0123\u0001\u0000\u0000"+ + "\u0000\u0121\u011f\u0001\u0000\u0000\u0000\u0121\u0122\u0001\u0000\u0000"+ + "\u0000\u0122\u0124\u0001\u0000\u0000\u0000\u0123\u0121\u0001\u0000\u0000"+ + "\u0000\u0124\u0125\u0005\u0012\u0000\u0000\u0125\u0126\u0003\"\u0011\u0000"+ + "\u0126\u0128\u0006\u0010\uffff\uffff\u0000\u0127\u0129\u0005\u0012\u0000"+ + "\u0000\u0128\u0127\u0001\u0000\u0000\u0000\u0128\u0129\u0001\u0000\u0000"+ + "\u0000\u0129\u012a\u0001\u0000\u0000\u0000\u012a\u012b\u0003$\u0012\u0000"+ + "\u012b\u012d\u0006\u0010\uffff\uffff\u0000\u012c\u012e\u0003*\u0015\u0000"+ + "\u012d\u012c\u0001\u0000\u0000\u0000\u012d\u012e\u0001\u0000\u0000\u0000"+ + "\u012e\u012f\u0001\u0000\u0000\u0000\u012f\u0130\u0006\u0010\uffff\uffff"+ + "\u0000\u0130\u0135\u0001\u0000\u0000\u0000\u0131\u0132\u0003$\u0012\u0000"+ + "\u0132\u0133\u0006\u0010\uffff\uffff\u0000\u0133\u0135\u0001\u0000\u0000"+ + "\u0000\u0134\u00d6\u0001\u0000\u0000\u0000\u0134\u00e8\u0001\u0000\u0000"+ + "\u0000\u0134\u00f7\u0001\u0000\u0000\u0000\u0134\u00fe\u0001\u0000\u0000"+ + "\u0000\u0134\u0106\u0001\u0000\u0000\u0000\u0134\u0119\u0001\u0000\u0000"+ + "\u0000\u0134\u0131\u0001\u0000\u0000\u0000\u0135!\u0001\u0000\u0000\u0000"+ + "\u0136\u0137\u0005$\u0000\u0000\u0137\u0139\u0005\u0013\u0000\u0000\u0138"+ + "\u013a\u0003\u001a\r\u0000\u0139\u0138\u0001\u0000\u0000\u0000\u0139\u013a"+ + "\u0001\u0000\u0000\u0000\u013a\u013b\u0001\u0000\u0000\u0000\u013b\u013c"+ + "\u0005\u0014\u0000\u0000\u013c\u013d\u0001\u0000\u0000\u0000\u013d\u0141"+ + "\u0006\u0011\uffff\uffff\u0000\u013e\u013f\u0005$\u0000\u0000\u013f\u0141"+ + "\u0006\u0011\uffff\uffff\u0000\u0140\u0136\u0001\u0000\u0000\u0000\u0140"+ + "\u013e\u0001\u0000\u0000\u0000\u0141#\u0001\u0000\u0000\u0000\u0142\u0143"+ + "\u0005\u0010\u0000\u0000\u0143\u0144\u0003&\u0013\u0000\u0144\u0145\u0006"+ + "\u0012\uffff\uffff\u0000\u0145\u0146\u0005\u0011\u0000\u0000\u0146%\u0001"+ + "\u0000\u0000\u0000\u0147\u0148\u0003(\u0014\u0000\u0148\u014f\u0006\u0013"+ + "\uffff\uffff\u0000\u0149\u014a\u0005\u0019\u0000\u0000\u014a\u014b\u0003"+ + "(\u0014\u0000\u014b\u014c\u0006\u0013\uffff\uffff\u0000\u014c\u014e\u0001"+ + "\u0000\u0000\u0000\u014d\u0149\u0001\u0000\u0000\u0000\u014e\u0151\u0001"+ + "\u0000\u0000\u0000\u014f\u014d\u0001\u0000\u0000\u0000\u014f\u0150\u0001"+ + "\u0000\u0000\u0000\u0150\'\u0001\u0000\u0000\u0000\u0151\u014f\u0001\u0000"+ + "\u0000\u0000\u0152\u0153\u0005$\u0000\u0000\u0153\u015d\u0006\u0014\uffff"+ + "\uffff\u0000\u0154\u0155\u0005\u001f\u0000\u0000\u0155\u015d\u0006\u0014"+ + "\uffff\uffff\u0000\u0156\u0157\u0005 \u0000\u0000\u0157\u015d\u0006\u0014"+ + "\uffff\uffff\u0000\u0158\u0159\u0005!\u0000\u0000\u0159\u015d\u0006\u0014"+ + "\uffff\uffff\u0000\u015a\u015b\u0005\"\u0000\u0000\u015b\u015d\u0006\u0014"+ + "\uffff\uffff\u0000\u015c\u0152\u0001\u0000\u0000\u0000\u015c\u0154\u0001"+ + "\u0000\u0000\u0000\u015c\u0156\u0001\u0000\u0000\u0000\u015c\u0158\u0001"+ + "\u0000\u0000\u0000\u015c\u015a\u0001\u0000\u0000\u0000\u015d)\u0001\u0000"+ + "\u0000\u0000\u015e\u015f\u0003.\u0017\u0000\u015f\u0160\u0003,\u0016\u0000"+ + "\u0160\u0161\u0006\u0015\uffff\uffff\u0000\u0161+\u0001\u0000\u0000\u0000"+ + "\u0162\u0166\u0001\u0000\u0000\u0000\u0163\u0166\u0005!\u0000\u0000\u0164"+ + "\u0166\u0005\"\u0000\u0000\u0165\u0162\u0001\u0000\u0000\u0000\u0165\u0163"+ + "\u0001\u0000\u0000\u0000\u0165\u0164\u0001\u0000\u0000\u0000\u0166-\u0001"+ + "\u0000\u0000\u0000\u0167\u0168\u0007\u0001\u0000\u0000\u0168/\u0001\u0000"+ + "\u0000\u0000#149The default implementation does nothing.

*/ @Override public void exitIfCondition(TemplateGrammarExpression.IfConditionContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterConditionOr(TemplateGrammarExpression.ConditionOrContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitConditionOr(TemplateGrammarExpression.ConditionOrContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterConditionAnd(TemplateGrammarExpression.ConditionAndContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitConditionAnd(TemplateGrammarExpression.ConditionAndContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterConditionNot(TemplateGrammarExpression.ConditionNotContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitConditionNot(TemplateGrammarExpression.ConditionNotContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterConditionAtom(TemplateGrammarExpression.ConditionAtomContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitConditionAtom(TemplateGrammarExpression.ConditionAtomContext ctx) { } /** * {@inheritDoc} * diff --git a/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateGrammarExpressionListener.java b/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateGrammarExpressionListener.java index 0b477ccbb..5025a8dd4 100644 --- a/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateGrammarExpressionListener.java +++ b/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateGrammarExpressionListener.java @@ -5,6 +5,11 @@ import oap.template.tree.*; import oap.template.tree.Math; import oap.template.tree.WithCondition; +import oap.template.tree.ConditionExpr; +import oap.template.tree.FieldConditionExpr; +import oap.template.tree.AndConditionExpr; +import oap.template.tree.OrConditionExpr; +import oap.template.tree.NotConditionExpr; import java.lang.reflect.Method; import java.util.ArrayList; @@ -71,6 +76,46 @@ public interface TemplateGrammarExpressionListener extends ParseTreeListener { * @param ctx the parse tree */ void exitIfCondition(TemplateGrammarExpression.IfConditionContext ctx); + /** + * Enter a parse tree produced by {@link TemplateGrammarExpression#conditionOr}. + * @param ctx the parse tree + */ + void enterConditionOr(TemplateGrammarExpression.ConditionOrContext ctx); + /** + * Exit a parse tree produced by {@link TemplateGrammarExpression#conditionOr}. + * @param ctx the parse tree + */ + void exitConditionOr(TemplateGrammarExpression.ConditionOrContext ctx); + /** + * Enter a parse tree produced by {@link TemplateGrammarExpression#conditionAnd}. + * @param ctx the parse tree + */ + void enterConditionAnd(TemplateGrammarExpression.ConditionAndContext ctx); + /** + * Exit a parse tree produced by {@link TemplateGrammarExpression#conditionAnd}. + * @param ctx the parse tree + */ + void exitConditionAnd(TemplateGrammarExpression.ConditionAndContext ctx); + /** + * Enter a parse tree produced by {@link TemplateGrammarExpression#conditionNot}. + * @param ctx the parse tree + */ + void enterConditionNot(TemplateGrammarExpression.ConditionNotContext ctx); + /** + * Exit a parse tree produced by {@link TemplateGrammarExpression#conditionNot}. + * @param ctx the parse tree + */ + void exitConditionNot(TemplateGrammarExpression.ConditionNotContext ctx); + /** + * Enter a parse tree produced by {@link TemplateGrammarExpression#conditionAtom}. + * @param ctx the parse tree + */ + void enterConditionAtom(TemplateGrammarExpression.ConditionAtomContext ctx); + /** + * Exit a parse tree produced by {@link TemplateGrammarExpression#conditionAtom}. + * @param ctx the parse tree + */ + void exitConditionAtom(TemplateGrammarExpression.ConditionAtomContext ctx); /** * Enter a parse tree produced by {@link TemplateGrammarExpression#defaultValue}. * @param ctx the parse tree diff --git a/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateLexerExpression.interp b/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateLexerExpression.interp index 17ea4c3aa..65c51daa6 100644 --- a/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateLexerExpression.interp +++ b/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateLexerExpression.interp @@ -6,6 +6,10 @@ null 'else' 'end' 'with' +'and' +'or' +'not' +'!' null '$' null @@ -46,6 +50,10 @@ THEN ELSE END WITH +AND +OR +NOT +BANG VAR_ID ROOT BLOCK_COMMENT @@ -122,6 +130,10 @@ THEN ELSE END WITH +AND +OR +NOT +BANG VAR_ID ROOT BLOCK_COMMENT @@ -172,4 +184,4 @@ DEFAULT_MODE Concatenation atn: -[4, 0, 37, 496, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 1, 0, 1, 0, 3, 0, 171, 8, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 5, 3, 181, 8, 3, 10, 3, 12, 3, 184, 9, 3, 1, 3, 1, 3, 1, 3, 3, 3, 189, 8, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 14, 1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 19, 1, 19, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 3, 25, 243, 8, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 3, 26, 250, 8, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 3, 27, 257, 8, 27, 3, 27, 259, 8, 27, 3, 27, 261, 8, 27, 3, 27, 263, 8, 27, 1, 28, 1, 28, 1, 28, 5, 28, 268, 8, 28, 10, 28, 12, 28, 271, 9, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 5, 29, 278, 8, 29, 10, 29, 12, 29, 281, 9, 29, 1, 29, 1, 29, 1, 30, 1, 30, 3, 30, 287, 8, 30, 1, 31, 1, 31, 1, 32, 1, 32, 1, 33, 4, 33, 294, 8, 33, 11, 33, 12, 33, 295, 1, 34, 1, 34, 1, 34, 3, 34, 301, 8, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 5, 37, 316, 8, 37, 10, 37, 12, 37, 319, 9, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 43, 5, 43, 349, 8, 43, 10, 43, 12, 43, 352, 9, 43, 1, 44, 1, 44, 1, 45, 1, 45, 1, 46, 4, 46, 359, 8, 46, 11, 46, 12, 46, 360, 1, 46, 1, 46, 1, 47, 4, 47, 366, 8, 47, 11, 47, 12, 47, 367, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 51, 1, 51, 1, 52, 1, 52, 1, 53, 1, 53, 1, 54, 1, 54, 1, 55, 1, 55, 1, 56, 1, 56, 1, 57, 1, 57, 1, 58, 1, 58, 1, 59, 1, 59, 1, 60, 1, 60, 1, 61, 1, 61, 1, 62, 1, 62, 1, 63, 1, 63, 1, 64, 1, 64, 1, 65, 1, 65, 1, 66, 1, 66, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 5, 68, 419, 8, 68, 10, 68, 12, 68, 422, 9, 68, 1, 69, 1, 69, 1, 69, 4, 69, 427, 8, 69, 11, 69, 12, 69, 428, 1, 69, 3, 69, 432, 8, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 72, 1, 72, 1, 73, 4, 73, 445, 8, 73, 11, 73, 12, 73, 446, 1, 73, 1, 73, 1, 74, 4, 74, 452, 8, 74, 11, 74, 12, 74, 453, 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 5, 77, 470, 8, 77, 10, 77, 12, 77, 473, 9, 77, 1, 77, 1, 77, 1, 78, 1, 78, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 182, 0, 83, 2, 0, 4, 0, 6, 0, 8, 0, 10, 0, 12, 0, 14, 0, 16, 0, 18, 0, 20, 0, 22, 0, 24, 0, 26, 0, 28, 0, 30, 0, 32, 0, 34, 0, 36, 0, 38, 0, 40, 0, 42, 0, 44, 0, 46, 0, 48, 0, 50, 0, 52, 0, 54, 0, 56, 0, 58, 0, 60, 0, 62, 0, 64, 0, 66, 0, 68, 0, 70, 0, 72, 0, 74, 0, 76, 1, 78, 2, 80, 3, 82, 4, 84, 5, 86, 6, 88, 7, 90, 8, 92, 9, 94, 10, 96, 11, 98, 12, 100, 13, 102, 14, 104, 15, 106, 16, 108, 17, 110, 18, 112, 19, 114, 20, 116, 21, 118, 22, 120, 23, 122, 24, 124, 25, 126, 26, 128, 27, 130, 28, 132, 29, 134, 30, 136, 31, 138, 32, 140, 33, 142, 34, 144, 0, 146, 0, 148, 35, 150, 36, 152, 0, 154, 0, 156, 0, 158, 0, 160, 0, 162, 0, 164, 0, 166, 37, 2, 0, 1, 9, 2, 0, 9, 9, 32, 32, 2, 0, 10, 10, 12, 13, 13, 0, 65, 90, 97, 122, 192, 214, 216, 246, 248, 767, 880, 893, 895, 8191, 8204, 8205, 8304, 8591, 11264, 12271, 12289, 55295, 63744, 64975, 65008, 65533, 3, 0, 183, 183, 768, 879, 8255, 8256, 8, 0, 34, 34, 39, 39, 92, 92, 98, 98, 102, 102, 110, 110, 114, 114, 116, 116, 4, 0, 10, 10, 13, 13, 39, 39, 92, 92, 4, 0, 10, 10, 13, 13, 34, 34, 92, 92, 3, 0, 48, 57, 65, 70, 97, 102, 1, 0, 48, 57, 488, 0, 76, 1, 0, 0, 0, 0, 78, 1, 0, 0, 0, 0, 80, 1, 0, 0, 0, 0, 82, 1, 0, 0, 0, 0, 84, 1, 0, 0, 0, 0, 86, 1, 0, 0, 0, 0, 88, 1, 0, 0, 0, 0, 90, 1, 0, 0, 0, 0, 92, 1, 0, 0, 0, 0, 94, 1, 0, 0, 0, 0, 96, 1, 0, 0, 0, 0, 98, 1, 0, 0, 0, 0, 100, 1, 0, 0, 0, 0, 102, 1, 0, 0, 0, 0, 104, 1, 0, 0, 0, 0, 106, 1, 0, 0, 0, 0, 108, 1, 0, 0, 0, 0, 110, 1, 0, 0, 0, 0, 112, 1, 0, 0, 0, 0, 114, 1, 0, 0, 0, 0, 116, 1, 0, 0, 0, 0, 118, 1, 0, 0, 0, 0, 120, 1, 0, 0, 0, 0, 122, 1, 0, 0, 0, 0, 124, 1, 0, 0, 0, 0, 126, 1, 0, 0, 0, 0, 128, 1, 0, 0, 0, 0, 130, 1, 0, 0, 0, 0, 132, 1, 0, 0, 0, 0, 134, 1, 0, 0, 0, 0, 136, 1, 0, 0, 0, 0, 138, 1, 0, 0, 0, 0, 140, 1, 0, 0, 0, 0, 142, 1, 0, 0, 0, 1, 148, 1, 0, 0, 0, 1, 150, 1, 0, 0, 0, 1, 152, 1, 0, 0, 0, 1, 154, 1, 0, 0, 0, 1, 156, 1, 0, 0, 0, 1, 158, 1, 0, 0, 0, 1, 160, 1, 0, 0, 0, 1, 162, 1, 0, 0, 0, 1, 164, 1, 0, 0, 0, 1, 166, 1, 0, 0, 0, 2, 170, 1, 0, 0, 0, 4, 172, 1, 0, 0, 0, 6, 174, 1, 0, 0, 0, 8, 176, 1, 0, 0, 0, 10, 190, 1, 0, 0, 0, 12, 192, 1, 0, 0, 0, 14, 194, 1, 0, 0, 0, 16, 196, 1, 0, 0, 0, 18, 198, 1, 0, 0, 0, 20, 200, 1, 0, 0, 0, 22, 202, 1, 0, 0, 0, 24, 204, 1, 0, 0, 0, 26, 206, 1, 0, 0, 0, 28, 208, 1, 0, 0, 0, 30, 210, 1, 0, 0, 0, 32, 212, 1, 0, 0, 0, 34, 214, 1, 0, 0, 0, 36, 216, 1, 0, 0, 0, 38, 218, 1, 0, 0, 0, 40, 220, 1, 0, 0, 0, 42, 222, 1, 0, 0, 0, 44, 224, 1, 0, 0, 0, 46, 227, 1, 0, 0, 0, 48, 229, 1, 0, 0, 0, 50, 231, 1, 0, 0, 0, 52, 242, 1, 0, 0, 0, 54, 244, 1, 0, 0, 0, 56, 251, 1, 0, 0, 0, 58, 264, 1, 0, 0, 0, 60, 274, 1, 0, 0, 0, 62, 286, 1, 0, 0, 0, 64, 288, 1, 0, 0, 0, 66, 290, 1, 0, 0, 0, 68, 293, 1, 0, 0, 0, 70, 297, 1, 0, 0, 0, 72, 302, 1, 0, 0, 0, 74, 307, 1, 0, 0, 0, 76, 313, 1, 0, 0, 0, 78, 322, 1, 0, 0, 0, 80, 325, 1, 0, 0, 0, 82, 330, 1, 0, 0, 0, 84, 335, 1, 0, 0, 0, 86, 339, 1, 0, 0, 0, 88, 344, 1, 0, 0, 0, 90, 353, 1, 0, 0, 0, 92, 355, 1, 0, 0, 0, 94, 358, 1, 0, 0, 0, 96, 365, 1, 0, 0, 0, 98, 371, 1, 0, 0, 0, 100, 375, 1, 0, 0, 0, 102, 379, 1, 0, 0, 0, 104, 381, 1, 0, 0, 0, 106, 383, 1, 0, 0, 0, 108, 385, 1, 0, 0, 0, 110, 387, 1, 0, 0, 0, 112, 389, 1, 0, 0, 0, 114, 391, 1, 0, 0, 0, 116, 393, 1, 0, 0, 0, 118, 395, 1, 0, 0, 0, 120, 397, 1, 0, 0, 0, 122, 399, 1, 0, 0, 0, 124, 401, 1, 0, 0, 0, 126, 403, 1, 0, 0, 0, 128, 405, 1, 0, 0, 0, 130, 407, 1, 0, 0, 0, 132, 409, 1, 0, 0, 0, 134, 411, 1, 0, 0, 0, 136, 413, 1, 0, 0, 0, 138, 415, 1, 0, 0, 0, 140, 423, 1, 0, 0, 0, 142, 435, 1, 0, 0, 0, 144, 439, 1, 0, 0, 0, 146, 441, 1, 0, 0, 0, 148, 444, 1, 0, 0, 0, 150, 451, 1, 0, 0, 0, 152, 457, 1, 0, 0, 0, 154, 462, 1, 0, 0, 0, 156, 466, 1, 0, 0, 0, 158, 476, 1, 0, 0, 0, 160, 480, 1, 0, 0, 0, 162, 484, 1, 0, 0, 0, 164, 488, 1, 0, 0, 0, 166, 492, 1, 0, 0, 0, 168, 171, 3, 4, 1, 0, 169, 171, 3, 6, 2, 0, 170, 168, 1, 0, 0, 0, 170, 169, 1, 0, 0, 0, 171, 3, 1, 0, 0, 0, 172, 173, 7, 0, 0, 0, 173, 5, 1, 0, 0, 0, 174, 175, 7, 1, 0, 0, 175, 7, 1, 0, 0, 0, 176, 177, 5, 47, 0, 0, 177, 178, 5, 42, 0, 0, 178, 182, 1, 0, 0, 0, 179, 181, 9, 0, 0, 0, 180, 179, 1, 0, 0, 0, 181, 184, 1, 0, 0, 0, 182, 183, 1, 0, 0, 0, 182, 180, 1, 0, 0, 0, 183, 188, 1, 0, 0, 0, 184, 182, 1, 0, 0, 0, 185, 186, 5, 42, 0, 0, 186, 189, 5, 47, 0, 0, 187, 189, 5, 0, 0, 1, 188, 185, 1, 0, 0, 0, 188, 187, 1, 0, 0, 0, 189, 9, 1, 0, 0, 0, 190, 191, 5, 92, 0, 0, 191, 11, 1, 0, 0, 0, 192, 193, 5, 39, 0, 0, 193, 13, 1, 0, 0, 0, 194, 195, 5, 34, 0, 0, 195, 15, 1, 0, 0, 0, 196, 197, 5, 95, 0, 0, 197, 17, 1, 0, 0, 0, 198, 199, 5, 44, 0, 0, 199, 19, 1, 0, 0, 0, 200, 201, 5, 59, 0, 0, 201, 21, 1, 0, 0, 0, 202, 203, 5, 124, 0, 0, 203, 23, 1, 0, 0, 0, 204, 205, 5, 46, 0, 0, 205, 25, 1, 0, 0, 0, 206, 207, 5, 40, 0, 0, 207, 27, 1, 0, 0, 0, 208, 209, 5, 41, 0, 0, 209, 29, 1, 0, 0, 0, 210, 211, 5, 91, 0, 0, 211, 31, 1, 0, 0, 0, 212, 213, 5, 93, 0, 0, 213, 33, 1, 0, 0, 0, 214, 215, 5, 42, 0, 0, 215, 35, 1, 0, 0, 0, 216, 217, 5, 47, 0, 0, 217, 37, 1, 0, 0, 0, 218, 219, 5, 37, 0, 0, 219, 39, 1, 0, 0, 0, 220, 221, 5, 43, 0, 0, 221, 41, 1, 0, 0, 0, 222, 223, 5, 45, 0, 0, 223, 43, 1, 0, 0, 0, 224, 225, 5, 63, 0, 0, 225, 226, 5, 63, 0, 0, 226, 45, 1, 0, 0, 0, 227, 228, 5, 60, 0, 0, 228, 47, 1, 0, 0, 0, 229, 230, 5, 62, 0, 0, 230, 49, 1, 0, 0, 0, 231, 232, 5, 100, 0, 0, 232, 233, 5, 101, 0, 0, 233, 234, 5, 102, 0, 0, 234, 235, 5, 97, 0, 0, 235, 236, 5, 117, 0, 0, 236, 237, 5, 108, 0, 0, 237, 238, 5, 116, 0, 0, 238, 51, 1, 0, 0, 0, 239, 243, 7, 2, 0, 0, 240, 243, 3, 16, 7, 0, 241, 243, 7, 3, 0, 0, 242, 239, 1, 0, 0, 0, 242, 240, 1, 0, 0, 0, 242, 241, 1, 0, 0, 0, 243, 53, 1, 0, 0, 0, 244, 249, 3, 10, 4, 0, 245, 250, 7, 4, 0, 0, 246, 250, 3, 56, 27, 0, 247, 250, 9, 0, 0, 0, 248, 250, 5, 0, 0, 1, 249, 245, 1, 0, 0, 0, 249, 246, 1, 0, 0, 0, 249, 247, 1, 0, 0, 0, 249, 248, 1, 0, 0, 0, 250, 55, 1, 0, 0, 0, 251, 262, 5, 117, 0, 0, 252, 260, 3, 64, 31, 0, 253, 258, 3, 64, 31, 0, 254, 256, 3, 64, 31, 0, 255, 257, 3, 64, 31, 0, 256, 255, 1, 0, 0, 0, 256, 257, 1, 0, 0, 0, 257, 259, 1, 0, 0, 0, 258, 254, 1, 0, 0, 0, 258, 259, 1, 0, 0, 0, 259, 261, 1, 0, 0, 0, 260, 253, 1, 0, 0, 0, 260, 261, 1, 0, 0, 0, 261, 263, 1, 0, 0, 0, 262, 252, 1, 0, 0, 0, 262, 263, 1, 0, 0, 0, 263, 57, 1, 0, 0, 0, 264, 269, 3, 12, 5, 0, 265, 268, 3, 54, 26, 0, 266, 268, 8, 5, 0, 0, 267, 265, 1, 0, 0, 0, 267, 266, 1, 0, 0, 0, 268, 271, 1, 0, 0, 0, 269, 267, 1, 0, 0, 0, 269, 270, 1, 0, 0, 0, 270, 272, 1, 0, 0, 0, 271, 269, 1, 0, 0, 0, 272, 273, 3, 12, 5, 0, 273, 59, 1, 0, 0, 0, 274, 279, 3, 14, 6, 0, 275, 278, 3, 54, 26, 0, 276, 278, 8, 6, 0, 0, 277, 275, 1, 0, 0, 0, 277, 276, 1, 0, 0, 0, 278, 281, 1, 0, 0, 0, 279, 277, 1, 0, 0, 0, 279, 280, 1, 0, 0, 0, 280, 282, 1, 0, 0, 0, 281, 279, 1, 0, 0, 0, 282, 283, 3, 14, 6, 0, 283, 61, 1, 0, 0, 0, 284, 287, 3, 72, 35, 0, 285, 287, 3, 74, 36, 0, 286, 284, 1, 0, 0, 0, 286, 285, 1, 0, 0, 0, 287, 63, 1, 0, 0, 0, 288, 289, 7, 7, 0, 0, 289, 65, 1, 0, 0, 0, 290, 291, 7, 8, 0, 0, 291, 67, 1, 0, 0, 0, 292, 294, 3, 66, 32, 0, 293, 292, 1, 0, 0, 0, 294, 295, 1, 0, 0, 0, 295, 293, 1, 0, 0, 0, 295, 296, 1, 0, 0, 0, 296, 69, 1, 0, 0, 0, 297, 298, 3, 68, 33, 0, 298, 300, 3, 24, 11, 0, 299, 301, 3, 68, 33, 0, 300, 299, 1, 0, 0, 0, 300, 301, 1, 0, 0, 0, 301, 71, 1, 0, 0, 0, 302, 303, 5, 116, 0, 0, 303, 304, 5, 114, 0, 0, 304, 305, 5, 117, 0, 0, 305, 306, 5, 101, 0, 0, 306, 73, 1, 0, 0, 0, 307, 308, 5, 102, 0, 0, 308, 309, 5, 97, 0, 0, 309, 310, 5, 108, 0, 0, 310, 311, 5, 115, 0, 0, 311, 312, 5, 101, 0, 0, 312, 75, 1, 0, 0, 0, 313, 317, 3, 22, 10, 0, 314, 316, 3, 4, 1, 0, 315, 314, 1, 0, 0, 0, 316, 319, 1, 0, 0, 0, 317, 315, 1, 0, 0, 0, 317, 318, 1, 0, 0, 0, 318, 320, 1, 0, 0, 0, 319, 317, 1, 0, 0, 0, 320, 321, 3, 50, 24, 0, 321, 77, 1, 0, 0, 0, 322, 323, 5, 105, 0, 0, 323, 324, 5, 102, 0, 0, 324, 79, 1, 0, 0, 0, 325, 326, 5, 116, 0, 0, 326, 327, 5, 104, 0, 0, 327, 328, 5, 101, 0, 0, 328, 329, 5, 110, 0, 0, 329, 81, 1, 0, 0, 0, 330, 331, 5, 101, 0, 0, 331, 332, 5, 108, 0, 0, 332, 333, 5, 115, 0, 0, 333, 334, 5, 101, 0, 0, 334, 83, 1, 0, 0, 0, 335, 336, 5, 101, 0, 0, 336, 337, 5, 110, 0, 0, 337, 338, 5, 100, 0, 0, 338, 85, 1, 0, 0, 0, 339, 340, 5, 119, 0, 0, 340, 341, 5, 105, 0, 0, 341, 342, 5, 116, 0, 0, 342, 343, 5, 104, 0, 0, 343, 87, 1, 0, 0, 0, 344, 345, 5, 36, 0, 0, 345, 350, 3, 52, 25, 0, 346, 349, 3, 52, 25, 0, 347, 349, 3, 66, 32, 0, 348, 346, 1, 0, 0, 0, 348, 347, 1, 0, 0, 0, 349, 352, 1, 0, 0, 0, 350, 348, 1, 0, 0, 0, 350, 351, 1, 0, 0, 0, 351, 89, 1, 0, 0, 0, 352, 350, 1, 0, 0, 0, 353, 354, 5, 36, 0, 0, 354, 91, 1, 0, 0, 0, 355, 356, 3, 8, 3, 0, 356, 93, 1, 0, 0, 0, 357, 359, 3, 4, 1, 0, 358, 357, 1, 0, 0, 0, 359, 360, 1, 0, 0, 0, 360, 358, 1, 0, 0, 0, 360, 361, 1, 0, 0, 0, 361, 362, 1, 0, 0, 0, 362, 363, 6, 46, 0, 0, 363, 95, 1, 0, 0, 0, 364, 366, 3, 6, 2, 0, 365, 364, 1, 0, 0, 0, 366, 367, 1, 0, 0, 0, 367, 365, 1, 0, 0, 0, 367, 368, 1, 0, 0, 0, 368, 369, 1, 0, 0, 0, 369, 370, 6, 47, 0, 0, 370, 97, 1, 0, 0, 0, 371, 372, 3, 144, 71, 0, 372, 373, 1, 0, 0, 0, 373, 374, 6, 48, 1, 0, 374, 99, 1, 0, 0, 0, 375, 376, 3, 146, 72, 0, 376, 377, 1, 0, 0, 0, 377, 378, 6, 49, 2, 0, 378, 101, 1, 0, 0, 0, 379, 380, 3, 24, 11, 0, 380, 103, 1, 0, 0, 0, 381, 382, 3, 26, 12, 0, 382, 105, 1, 0, 0, 0, 383, 384, 3, 28, 13, 0, 384, 107, 1, 0, 0, 0, 385, 386, 3, 30, 14, 0, 386, 109, 1, 0, 0, 0, 387, 388, 3, 32, 15, 0, 388, 111, 1, 0, 0, 0, 389, 390, 3, 44, 21, 0, 390, 113, 1, 0, 0, 0, 391, 392, 3, 20, 9, 0, 392, 115, 1, 0, 0, 0, 393, 394, 3, 18, 8, 0, 394, 117, 1, 0, 0, 0, 395, 396, 3, 34, 16, 0, 396, 119, 1, 0, 0, 0, 397, 398, 3, 36, 17, 0, 398, 121, 1, 0, 0, 0, 399, 400, 3, 38, 18, 0, 400, 123, 1, 0, 0, 0, 401, 402, 3, 40, 19, 0, 402, 125, 1, 0, 0, 0, 403, 404, 3, 42, 20, 0, 404, 127, 1, 0, 0, 0, 405, 406, 3, 60, 29, 0, 406, 129, 1, 0, 0, 0, 407, 408, 3, 58, 28, 0, 408, 131, 1, 0, 0, 0, 409, 410, 3, 68, 33, 0, 410, 133, 1, 0, 0, 0, 411, 412, 3, 70, 34, 0, 412, 135, 1, 0, 0, 0, 413, 414, 3, 62, 30, 0, 414, 137, 1, 0, 0, 0, 415, 420, 3, 52, 25, 0, 416, 419, 3, 52, 25, 0, 417, 419, 3, 66, 32, 0, 418, 416, 1, 0, 0, 0, 418, 417, 1, 0, 0, 0, 419, 422, 1, 0, 0, 0, 420, 418, 1, 0, 0, 0, 420, 421, 1, 0, 0, 0, 421, 139, 1, 0, 0, 0, 422, 420, 1, 0, 0, 0, 423, 426, 3, 46, 22, 0, 424, 427, 3, 52, 25, 0, 425, 427, 3, 102, 50, 0, 426, 424, 1, 0, 0, 0, 426, 425, 1, 0, 0, 0, 427, 428, 1, 0, 0, 0, 428, 426, 1, 0, 0, 0, 428, 429, 1, 0, 0, 0, 429, 431, 1, 0, 0, 0, 430, 432, 3, 140, 69, 0, 431, 430, 1, 0, 0, 0, 431, 432, 1, 0, 0, 0, 432, 433, 1, 0, 0, 0, 433, 434, 3, 48, 23, 0, 434, 141, 1, 0, 0, 0, 435, 436, 3, 4, 1, 0, 436, 437, 1, 0, 0, 0, 437, 438, 6, 70, 0, 0, 438, 143, 1, 0, 0, 0, 439, 440, 5, 123, 0, 0, 440, 145, 1, 0, 0, 0, 441, 442, 5, 125, 0, 0, 442, 147, 1, 0, 0, 0, 443, 445, 3, 4, 1, 0, 444, 443, 1, 0, 0, 0, 445, 446, 1, 0, 0, 0, 446, 444, 1, 0, 0, 0, 446, 447, 1, 0, 0, 0, 447, 448, 1, 0, 0, 0, 448, 449, 6, 73, 0, 0, 449, 149, 1, 0, 0, 0, 450, 452, 3, 6, 2, 0, 451, 450, 1, 0, 0, 0, 452, 453, 1, 0, 0, 0, 453, 451, 1, 0, 0, 0, 453, 454, 1, 0, 0, 0, 454, 455, 1, 0, 0, 0, 455, 456, 6, 74, 0, 0, 456, 151, 1, 0, 0, 0, 457, 458, 3, 146, 72, 0, 458, 459, 1, 0, 0, 0, 459, 460, 6, 75, 2, 0, 460, 461, 6, 75, 3, 0, 461, 153, 1, 0, 0, 0, 462, 463, 3, 18, 8, 0, 463, 464, 1, 0, 0, 0, 464, 465, 6, 76, 4, 0, 465, 155, 1, 0, 0, 0, 466, 471, 3, 52, 25, 0, 467, 470, 3, 52, 25, 0, 468, 470, 3, 66, 32, 0, 469, 467, 1, 0, 0, 0, 469, 468, 1, 0, 0, 0, 470, 473, 1, 0, 0, 0, 471, 469, 1, 0, 0, 0, 471, 472, 1, 0, 0, 0, 472, 474, 1, 0, 0, 0, 473, 471, 1, 0, 0, 0, 474, 475, 6, 77, 5, 0, 475, 157, 1, 0, 0, 0, 476, 477, 3, 60, 29, 0, 477, 478, 1, 0, 0, 0, 478, 479, 6, 78, 6, 0, 479, 159, 1, 0, 0, 0, 480, 481, 3, 58, 28, 0, 481, 482, 1, 0, 0, 0, 482, 483, 6, 79, 7, 0, 483, 161, 1, 0, 0, 0, 484, 485, 3, 68, 33, 0, 485, 486, 1, 0, 0, 0, 486, 487, 6, 80, 8, 0, 487, 163, 1, 0, 0, 0, 488, 489, 3, 70, 34, 0, 489, 490, 1, 0, 0, 0, 490, 491, 6, 81, 9, 0, 491, 165, 1, 0, 0, 0, 492, 493, 7, 0, 0, 0, 493, 494, 1, 0, 0, 0, 494, 495, 6, 82, 0, 0, 495, 167, 1, 0, 0, 0, 32, 0, 1, 170, 182, 188, 242, 249, 256, 258, 260, 262, 267, 269, 277, 279, 286, 295, 300, 317, 348, 350, 360, 367, 418, 420, 426, 428, 431, 446, 453, 469, 471, 10, 6, 0, 0, 5, 1, 0, 4, 0, 0, 7, 13, 0, 7, 21, 0, 7, 32, 0, 7, 27, 0, 7, 28, 0, 7, 29, 0, 7, 30, 0] \ No newline at end of file +[4, 0, 41, 517, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 1, 0, 1, 0, 3, 0, 179, 8, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 5, 3, 189, 8, 3, 10, 3, 12, 3, 192, 9, 3, 1, 3, 1, 3, 1, 3, 3, 3, 197, 8, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 14, 1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 19, 1, 19, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 3, 25, 251, 8, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 3, 26, 258, 8, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 3, 27, 265, 8, 27, 3, 27, 267, 8, 27, 3, 27, 269, 8, 27, 3, 27, 271, 8, 27, 1, 28, 1, 28, 1, 28, 5, 28, 276, 8, 28, 10, 28, 12, 28, 279, 9, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 5, 29, 286, 8, 29, 10, 29, 12, 29, 289, 9, 29, 1, 29, 1, 29, 1, 30, 1, 30, 3, 30, 295, 8, 30, 1, 31, 1, 31, 1, 32, 1, 32, 1, 33, 4, 33, 302, 8, 33, 11, 33, 12, 33, 303, 1, 34, 1, 34, 1, 34, 3, 34, 309, 8, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 5, 37, 324, 8, 37, 10, 37, 12, 37, 327, 9, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 5, 47, 370, 8, 47, 10, 47, 12, 47, 373, 9, 47, 1, 48, 1, 48, 1, 49, 1, 49, 1, 50, 4, 50, 380, 8, 50, 11, 50, 12, 50, 381, 1, 50, 1, 50, 1, 51, 4, 51, 387, 8, 51, 11, 51, 12, 51, 388, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 55, 1, 55, 1, 56, 1, 56, 1, 57, 1, 57, 1, 58, 1, 58, 1, 59, 1, 59, 1, 60, 1, 60, 1, 61, 1, 61, 1, 62, 1, 62, 1, 63, 1, 63, 1, 64, 1, 64, 1, 65, 1, 65, 1, 66, 1, 66, 1, 67, 1, 67, 1, 68, 1, 68, 1, 69, 1, 69, 1, 70, 1, 70, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 5, 72, 440, 8, 72, 10, 72, 12, 72, 443, 9, 72, 1, 73, 1, 73, 1, 73, 4, 73, 448, 8, 73, 11, 73, 12, 73, 449, 1, 73, 3, 73, 453, 8, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 76, 1, 76, 1, 77, 4, 77, 466, 8, 77, 11, 77, 12, 77, 467, 1, 77, 1, 77, 1, 78, 4, 78, 473, 8, 78, 11, 78, 12, 78, 474, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 5, 81, 491, 8, 81, 10, 81, 12, 81, 494, 9, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 1, 86, 1, 86, 1, 190, 0, 87, 2, 0, 4, 0, 6, 0, 8, 0, 10, 0, 12, 0, 14, 0, 16, 0, 18, 0, 20, 0, 22, 0, 24, 0, 26, 0, 28, 0, 30, 0, 32, 0, 34, 0, 36, 0, 38, 0, 40, 0, 42, 0, 44, 0, 46, 0, 48, 0, 50, 0, 52, 0, 54, 0, 56, 0, 58, 0, 60, 0, 62, 0, 64, 0, 66, 0, 68, 0, 70, 0, 72, 0, 74, 0, 76, 1, 78, 2, 80, 3, 82, 4, 84, 5, 86, 6, 88, 7, 90, 8, 92, 9, 94, 10, 96, 11, 98, 12, 100, 13, 102, 14, 104, 15, 106, 16, 108, 17, 110, 18, 112, 19, 114, 20, 116, 21, 118, 22, 120, 23, 122, 24, 124, 25, 126, 26, 128, 27, 130, 28, 132, 29, 134, 30, 136, 31, 138, 32, 140, 33, 142, 34, 144, 35, 146, 36, 148, 37, 150, 38, 152, 0, 154, 0, 156, 39, 158, 40, 160, 0, 162, 0, 164, 0, 166, 0, 168, 0, 170, 0, 172, 0, 174, 41, 2, 0, 1, 9, 2, 0, 9, 9, 32, 32, 2, 0, 10, 10, 12, 13, 13, 0, 65, 90, 97, 122, 192, 214, 216, 246, 248, 767, 880, 893, 895, 8191, 8204, 8205, 8304, 8591, 11264, 12271, 12289, 55295, 63744, 64975, 65008, 65533, 3, 0, 183, 183, 768, 879, 8255, 8256, 8, 0, 34, 34, 39, 39, 92, 92, 98, 98, 102, 102, 110, 110, 114, 114, 116, 116, 4, 0, 10, 10, 13, 13, 39, 39, 92, 92, 4, 0, 10, 10, 13, 13, 34, 34, 92, 92, 3, 0, 48, 57, 65, 70, 97, 102, 1, 0, 48, 57, 509, 0, 76, 1, 0, 0, 0, 0, 78, 1, 0, 0, 0, 0, 80, 1, 0, 0, 0, 0, 82, 1, 0, 0, 0, 0, 84, 1, 0, 0, 0, 0, 86, 1, 0, 0, 0, 0, 88, 1, 0, 0, 0, 0, 90, 1, 0, 0, 0, 0, 92, 1, 0, 0, 0, 0, 94, 1, 0, 0, 0, 0, 96, 1, 0, 0, 0, 0, 98, 1, 0, 0, 0, 0, 100, 1, 0, 0, 0, 0, 102, 1, 0, 0, 0, 0, 104, 1, 0, 0, 0, 0, 106, 1, 0, 0, 0, 0, 108, 1, 0, 0, 0, 0, 110, 1, 0, 0, 0, 0, 112, 1, 0, 0, 0, 0, 114, 1, 0, 0, 0, 0, 116, 1, 0, 0, 0, 0, 118, 1, 0, 0, 0, 0, 120, 1, 0, 0, 0, 0, 122, 1, 0, 0, 0, 0, 124, 1, 0, 0, 0, 0, 126, 1, 0, 0, 0, 0, 128, 1, 0, 0, 0, 0, 130, 1, 0, 0, 0, 0, 132, 1, 0, 0, 0, 0, 134, 1, 0, 0, 0, 0, 136, 1, 0, 0, 0, 0, 138, 1, 0, 0, 0, 0, 140, 1, 0, 0, 0, 0, 142, 1, 0, 0, 0, 0, 144, 1, 0, 0, 0, 0, 146, 1, 0, 0, 0, 0, 148, 1, 0, 0, 0, 0, 150, 1, 0, 0, 0, 1, 156, 1, 0, 0, 0, 1, 158, 1, 0, 0, 0, 1, 160, 1, 0, 0, 0, 1, 162, 1, 0, 0, 0, 1, 164, 1, 0, 0, 0, 1, 166, 1, 0, 0, 0, 1, 168, 1, 0, 0, 0, 1, 170, 1, 0, 0, 0, 1, 172, 1, 0, 0, 0, 1, 174, 1, 0, 0, 0, 2, 178, 1, 0, 0, 0, 4, 180, 1, 0, 0, 0, 6, 182, 1, 0, 0, 0, 8, 184, 1, 0, 0, 0, 10, 198, 1, 0, 0, 0, 12, 200, 1, 0, 0, 0, 14, 202, 1, 0, 0, 0, 16, 204, 1, 0, 0, 0, 18, 206, 1, 0, 0, 0, 20, 208, 1, 0, 0, 0, 22, 210, 1, 0, 0, 0, 24, 212, 1, 0, 0, 0, 26, 214, 1, 0, 0, 0, 28, 216, 1, 0, 0, 0, 30, 218, 1, 0, 0, 0, 32, 220, 1, 0, 0, 0, 34, 222, 1, 0, 0, 0, 36, 224, 1, 0, 0, 0, 38, 226, 1, 0, 0, 0, 40, 228, 1, 0, 0, 0, 42, 230, 1, 0, 0, 0, 44, 232, 1, 0, 0, 0, 46, 235, 1, 0, 0, 0, 48, 237, 1, 0, 0, 0, 50, 239, 1, 0, 0, 0, 52, 250, 1, 0, 0, 0, 54, 252, 1, 0, 0, 0, 56, 259, 1, 0, 0, 0, 58, 272, 1, 0, 0, 0, 60, 282, 1, 0, 0, 0, 62, 294, 1, 0, 0, 0, 64, 296, 1, 0, 0, 0, 66, 298, 1, 0, 0, 0, 68, 301, 1, 0, 0, 0, 70, 305, 1, 0, 0, 0, 72, 310, 1, 0, 0, 0, 74, 315, 1, 0, 0, 0, 76, 321, 1, 0, 0, 0, 78, 330, 1, 0, 0, 0, 80, 333, 1, 0, 0, 0, 82, 338, 1, 0, 0, 0, 84, 343, 1, 0, 0, 0, 86, 347, 1, 0, 0, 0, 88, 352, 1, 0, 0, 0, 90, 356, 1, 0, 0, 0, 92, 359, 1, 0, 0, 0, 94, 363, 1, 0, 0, 0, 96, 365, 1, 0, 0, 0, 98, 374, 1, 0, 0, 0, 100, 376, 1, 0, 0, 0, 102, 379, 1, 0, 0, 0, 104, 386, 1, 0, 0, 0, 106, 392, 1, 0, 0, 0, 108, 396, 1, 0, 0, 0, 110, 400, 1, 0, 0, 0, 112, 402, 1, 0, 0, 0, 114, 404, 1, 0, 0, 0, 116, 406, 1, 0, 0, 0, 118, 408, 1, 0, 0, 0, 120, 410, 1, 0, 0, 0, 122, 412, 1, 0, 0, 0, 124, 414, 1, 0, 0, 0, 126, 416, 1, 0, 0, 0, 128, 418, 1, 0, 0, 0, 130, 420, 1, 0, 0, 0, 132, 422, 1, 0, 0, 0, 134, 424, 1, 0, 0, 0, 136, 426, 1, 0, 0, 0, 138, 428, 1, 0, 0, 0, 140, 430, 1, 0, 0, 0, 142, 432, 1, 0, 0, 0, 144, 434, 1, 0, 0, 0, 146, 436, 1, 0, 0, 0, 148, 444, 1, 0, 0, 0, 150, 456, 1, 0, 0, 0, 152, 460, 1, 0, 0, 0, 154, 462, 1, 0, 0, 0, 156, 465, 1, 0, 0, 0, 158, 472, 1, 0, 0, 0, 160, 478, 1, 0, 0, 0, 162, 483, 1, 0, 0, 0, 164, 487, 1, 0, 0, 0, 166, 497, 1, 0, 0, 0, 168, 501, 1, 0, 0, 0, 170, 505, 1, 0, 0, 0, 172, 509, 1, 0, 0, 0, 174, 513, 1, 0, 0, 0, 176, 179, 3, 4, 1, 0, 177, 179, 3, 6, 2, 0, 178, 176, 1, 0, 0, 0, 178, 177, 1, 0, 0, 0, 179, 3, 1, 0, 0, 0, 180, 181, 7, 0, 0, 0, 181, 5, 1, 0, 0, 0, 182, 183, 7, 1, 0, 0, 183, 7, 1, 0, 0, 0, 184, 185, 5, 47, 0, 0, 185, 186, 5, 42, 0, 0, 186, 190, 1, 0, 0, 0, 187, 189, 9, 0, 0, 0, 188, 187, 1, 0, 0, 0, 189, 192, 1, 0, 0, 0, 190, 191, 1, 0, 0, 0, 190, 188, 1, 0, 0, 0, 191, 196, 1, 0, 0, 0, 192, 190, 1, 0, 0, 0, 193, 194, 5, 42, 0, 0, 194, 197, 5, 47, 0, 0, 195, 197, 5, 0, 0, 1, 196, 193, 1, 0, 0, 0, 196, 195, 1, 0, 0, 0, 197, 9, 1, 0, 0, 0, 198, 199, 5, 92, 0, 0, 199, 11, 1, 0, 0, 0, 200, 201, 5, 39, 0, 0, 201, 13, 1, 0, 0, 0, 202, 203, 5, 34, 0, 0, 203, 15, 1, 0, 0, 0, 204, 205, 5, 95, 0, 0, 205, 17, 1, 0, 0, 0, 206, 207, 5, 44, 0, 0, 207, 19, 1, 0, 0, 0, 208, 209, 5, 59, 0, 0, 209, 21, 1, 0, 0, 0, 210, 211, 5, 124, 0, 0, 211, 23, 1, 0, 0, 0, 212, 213, 5, 46, 0, 0, 213, 25, 1, 0, 0, 0, 214, 215, 5, 40, 0, 0, 215, 27, 1, 0, 0, 0, 216, 217, 5, 41, 0, 0, 217, 29, 1, 0, 0, 0, 218, 219, 5, 91, 0, 0, 219, 31, 1, 0, 0, 0, 220, 221, 5, 93, 0, 0, 221, 33, 1, 0, 0, 0, 222, 223, 5, 42, 0, 0, 223, 35, 1, 0, 0, 0, 224, 225, 5, 47, 0, 0, 225, 37, 1, 0, 0, 0, 226, 227, 5, 37, 0, 0, 227, 39, 1, 0, 0, 0, 228, 229, 5, 43, 0, 0, 229, 41, 1, 0, 0, 0, 230, 231, 5, 45, 0, 0, 231, 43, 1, 0, 0, 0, 232, 233, 5, 63, 0, 0, 233, 234, 5, 63, 0, 0, 234, 45, 1, 0, 0, 0, 235, 236, 5, 60, 0, 0, 236, 47, 1, 0, 0, 0, 237, 238, 5, 62, 0, 0, 238, 49, 1, 0, 0, 0, 239, 240, 5, 100, 0, 0, 240, 241, 5, 101, 0, 0, 241, 242, 5, 102, 0, 0, 242, 243, 5, 97, 0, 0, 243, 244, 5, 117, 0, 0, 244, 245, 5, 108, 0, 0, 245, 246, 5, 116, 0, 0, 246, 51, 1, 0, 0, 0, 247, 251, 7, 2, 0, 0, 248, 251, 3, 16, 7, 0, 249, 251, 7, 3, 0, 0, 250, 247, 1, 0, 0, 0, 250, 248, 1, 0, 0, 0, 250, 249, 1, 0, 0, 0, 251, 53, 1, 0, 0, 0, 252, 257, 3, 10, 4, 0, 253, 258, 7, 4, 0, 0, 254, 258, 3, 56, 27, 0, 255, 258, 9, 0, 0, 0, 256, 258, 5, 0, 0, 1, 257, 253, 1, 0, 0, 0, 257, 254, 1, 0, 0, 0, 257, 255, 1, 0, 0, 0, 257, 256, 1, 0, 0, 0, 258, 55, 1, 0, 0, 0, 259, 270, 5, 117, 0, 0, 260, 268, 3, 64, 31, 0, 261, 266, 3, 64, 31, 0, 262, 264, 3, 64, 31, 0, 263, 265, 3, 64, 31, 0, 264, 263, 1, 0, 0, 0, 264, 265, 1, 0, 0, 0, 265, 267, 1, 0, 0, 0, 266, 262, 1, 0, 0, 0, 266, 267, 1, 0, 0, 0, 267, 269, 1, 0, 0, 0, 268, 261, 1, 0, 0, 0, 268, 269, 1, 0, 0, 0, 269, 271, 1, 0, 0, 0, 270, 260, 1, 0, 0, 0, 270, 271, 1, 0, 0, 0, 271, 57, 1, 0, 0, 0, 272, 277, 3, 12, 5, 0, 273, 276, 3, 54, 26, 0, 274, 276, 8, 5, 0, 0, 275, 273, 1, 0, 0, 0, 275, 274, 1, 0, 0, 0, 276, 279, 1, 0, 0, 0, 277, 275, 1, 0, 0, 0, 277, 278, 1, 0, 0, 0, 278, 280, 1, 0, 0, 0, 279, 277, 1, 0, 0, 0, 280, 281, 3, 12, 5, 0, 281, 59, 1, 0, 0, 0, 282, 287, 3, 14, 6, 0, 283, 286, 3, 54, 26, 0, 284, 286, 8, 6, 0, 0, 285, 283, 1, 0, 0, 0, 285, 284, 1, 0, 0, 0, 286, 289, 1, 0, 0, 0, 287, 285, 1, 0, 0, 0, 287, 288, 1, 0, 0, 0, 288, 290, 1, 0, 0, 0, 289, 287, 1, 0, 0, 0, 290, 291, 3, 14, 6, 0, 291, 61, 1, 0, 0, 0, 292, 295, 3, 72, 35, 0, 293, 295, 3, 74, 36, 0, 294, 292, 1, 0, 0, 0, 294, 293, 1, 0, 0, 0, 295, 63, 1, 0, 0, 0, 296, 297, 7, 7, 0, 0, 297, 65, 1, 0, 0, 0, 298, 299, 7, 8, 0, 0, 299, 67, 1, 0, 0, 0, 300, 302, 3, 66, 32, 0, 301, 300, 1, 0, 0, 0, 302, 303, 1, 0, 0, 0, 303, 301, 1, 0, 0, 0, 303, 304, 1, 0, 0, 0, 304, 69, 1, 0, 0, 0, 305, 306, 3, 68, 33, 0, 306, 308, 3, 24, 11, 0, 307, 309, 3, 68, 33, 0, 308, 307, 1, 0, 0, 0, 308, 309, 1, 0, 0, 0, 309, 71, 1, 0, 0, 0, 310, 311, 5, 116, 0, 0, 311, 312, 5, 114, 0, 0, 312, 313, 5, 117, 0, 0, 313, 314, 5, 101, 0, 0, 314, 73, 1, 0, 0, 0, 315, 316, 5, 102, 0, 0, 316, 317, 5, 97, 0, 0, 317, 318, 5, 108, 0, 0, 318, 319, 5, 115, 0, 0, 319, 320, 5, 101, 0, 0, 320, 75, 1, 0, 0, 0, 321, 325, 3, 22, 10, 0, 322, 324, 3, 4, 1, 0, 323, 322, 1, 0, 0, 0, 324, 327, 1, 0, 0, 0, 325, 323, 1, 0, 0, 0, 325, 326, 1, 0, 0, 0, 326, 328, 1, 0, 0, 0, 327, 325, 1, 0, 0, 0, 328, 329, 3, 50, 24, 0, 329, 77, 1, 0, 0, 0, 330, 331, 5, 105, 0, 0, 331, 332, 5, 102, 0, 0, 332, 79, 1, 0, 0, 0, 333, 334, 5, 116, 0, 0, 334, 335, 5, 104, 0, 0, 335, 336, 5, 101, 0, 0, 336, 337, 5, 110, 0, 0, 337, 81, 1, 0, 0, 0, 338, 339, 5, 101, 0, 0, 339, 340, 5, 108, 0, 0, 340, 341, 5, 115, 0, 0, 341, 342, 5, 101, 0, 0, 342, 83, 1, 0, 0, 0, 343, 344, 5, 101, 0, 0, 344, 345, 5, 110, 0, 0, 345, 346, 5, 100, 0, 0, 346, 85, 1, 0, 0, 0, 347, 348, 5, 119, 0, 0, 348, 349, 5, 105, 0, 0, 349, 350, 5, 116, 0, 0, 350, 351, 5, 104, 0, 0, 351, 87, 1, 0, 0, 0, 352, 353, 5, 97, 0, 0, 353, 354, 5, 110, 0, 0, 354, 355, 5, 100, 0, 0, 355, 89, 1, 0, 0, 0, 356, 357, 5, 111, 0, 0, 357, 358, 5, 114, 0, 0, 358, 91, 1, 0, 0, 0, 359, 360, 5, 110, 0, 0, 360, 361, 5, 111, 0, 0, 361, 362, 5, 116, 0, 0, 362, 93, 1, 0, 0, 0, 363, 364, 5, 33, 0, 0, 364, 95, 1, 0, 0, 0, 365, 366, 5, 36, 0, 0, 366, 371, 3, 52, 25, 0, 367, 370, 3, 52, 25, 0, 368, 370, 3, 66, 32, 0, 369, 367, 1, 0, 0, 0, 369, 368, 1, 0, 0, 0, 370, 373, 1, 0, 0, 0, 371, 369, 1, 0, 0, 0, 371, 372, 1, 0, 0, 0, 372, 97, 1, 0, 0, 0, 373, 371, 1, 0, 0, 0, 374, 375, 5, 36, 0, 0, 375, 99, 1, 0, 0, 0, 376, 377, 3, 8, 3, 0, 377, 101, 1, 0, 0, 0, 378, 380, 3, 4, 1, 0, 379, 378, 1, 0, 0, 0, 380, 381, 1, 0, 0, 0, 381, 379, 1, 0, 0, 0, 381, 382, 1, 0, 0, 0, 382, 383, 1, 0, 0, 0, 383, 384, 6, 50, 0, 0, 384, 103, 1, 0, 0, 0, 385, 387, 3, 6, 2, 0, 386, 385, 1, 0, 0, 0, 387, 388, 1, 0, 0, 0, 388, 386, 1, 0, 0, 0, 388, 389, 1, 0, 0, 0, 389, 390, 1, 0, 0, 0, 390, 391, 6, 51, 0, 0, 391, 105, 1, 0, 0, 0, 392, 393, 3, 152, 75, 0, 393, 394, 1, 0, 0, 0, 394, 395, 6, 52, 1, 0, 395, 107, 1, 0, 0, 0, 396, 397, 3, 154, 76, 0, 397, 398, 1, 0, 0, 0, 398, 399, 6, 53, 2, 0, 399, 109, 1, 0, 0, 0, 400, 401, 3, 24, 11, 0, 401, 111, 1, 0, 0, 0, 402, 403, 3, 26, 12, 0, 403, 113, 1, 0, 0, 0, 404, 405, 3, 28, 13, 0, 405, 115, 1, 0, 0, 0, 406, 407, 3, 30, 14, 0, 407, 117, 1, 0, 0, 0, 408, 409, 3, 32, 15, 0, 409, 119, 1, 0, 0, 0, 410, 411, 3, 44, 21, 0, 411, 121, 1, 0, 0, 0, 412, 413, 3, 20, 9, 0, 413, 123, 1, 0, 0, 0, 414, 415, 3, 18, 8, 0, 415, 125, 1, 0, 0, 0, 416, 417, 3, 34, 16, 0, 417, 127, 1, 0, 0, 0, 418, 419, 3, 36, 17, 0, 419, 129, 1, 0, 0, 0, 420, 421, 3, 38, 18, 0, 421, 131, 1, 0, 0, 0, 422, 423, 3, 40, 19, 0, 423, 133, 1, 0, 0, 0, 424, 425, 3, 42, 20, 0, 425, 135, 1, 0, 0, 0, 426, 427, 3, 60, 29, 0, 427, 137, 1, 0, 0, 0, 428, 429, 3, 58, 28, 0, 429, 139, 1, 0, 0, 0, 430, 431, 3, 68, 33, 0, 431, 141, 1, 0, 0, 0, 432, 433, 3, 70, 34, 0, 433, 143, 1, 0, 0, 0, 434, 435, 3, 62, 30, 0, 435, 145, 1, 0, 0, 0, 436, 441, 3, 52, 25, 0, 437, 440, 3, 52, 25, 0, 438, 440, 3, 66, 32, 0, 439, 437, 1, 0, 0, 0, 439, 438, 1, 0, 0, 0, 440, 443, 1, 0, 0, 0, 441, 439, 1, 0, 0, 0, 441, 442, 1, 0, 0, 0, 442, 147, 1, 0, 0, 0, 443, 441, 1, 0, 0, 0, 444, 447, 3, 46, 22, 0, 445, 448, 3, 52, 25, 0, 446, 448, 3, 110, 54, 0, 447, 445, 1, 0, 0, 0, 447, 446, 1, 0, 0, 0, 448, 449, 1, 0, 0, 0, 449, 447, 1, 0, 0, 0, 449, 450, 1, 0, 0, 0, 450, 452, 1, 0, 0, 0, 451, 453, 3, 148, 73, 0, 452, 451, 1, 0, 0, 0, 452, 453, 1, 0, 0, 0, 453, 454, 1, 0, 0, 0, 454, 455, 3, 48, 23, 0, 455, 149, 1, 0, 0, 0, 456, 457, 3, 4, 1, 0, 457, 458, 1, 0, 0, 0, 458, 459, 6, 74, 0, 0, 459, 151, 1, 0, 0, 0, 460, 461, 5, 123, 0, 0, 461, 153, 1, 0, 0, 0, 462, 463, 5, 125, 0, 0, 463, 155, 1, 0, 0, 0, 464, 466, 3, 4, 1, 0, 465, 464, 1, 0, 0, 0, 466, 467, 1, 0, 0, 0, 467, 465, 1, 0, 0, 0, 467, 468, 1, 0, 0, 0, 468, 469, 1, 0, 0, 0, 469, 470, 6, 77, 0, 0, 470, 157, 1, 0, 0, 0, 471, 473, 3, 6, 2, 0, 472, 471, 1, 0, 0, 0, 473, 474, 1, 0, 0, 0, 474, 472, 1, 0, 0, 0, 474, 475, 1, 0, 0, 0, 475, 476, 1, 0, 0, 0, 476, 477, 6, 78, 0, 0, 477, 159, 1, 0, 0, 0, 478, 479, 3, 154, 76, 0, 479, 480, 1, 0, 0, 0, 480, 481, 6, 79, 2, 0, 481, 482, 6, 79, 3, 0, 482, 161, 1, 0, 0, 0, 483, 484, 3, 18, 8, 0, 484, 485, 1, 0, 0, 0, 485, 486, 6, 80, 4, 0, 486, 163, 1, 0, 0, 0, 487, 492, 3, 52, 25, 0, 488, 491, 3, 52, 25, 0, 489, 491, 3, 66, 32, 0, 490, 488, 1, 0, 0, 0, 490, 489, 1, 0, 0, 0, 491, 494, 1, 0, 0, 0, 492, 490, 1, 0, 0, 0, 492, 493, 1, 0, 0, 0, 493, 495, 1, 0, 0, 0, 494, 492, 1, 0, 0, 0, 495, 496, 6, 81, 5, 0, 496, 165, 1, 0, 0, 0, 497, 498, 3, 60, 29, 0, 498, 499, 1, 0, 0, 0, 499, 500, 6, 82, 6, 0, 500, 167, 1, 0, 0, 0, 501, 502, 3, 58, 28, 0, 502, 503, 1, 0, 0, 0, 503, 504, 6, 83, 7, 0, 504, 169, 1, 0, 0, 0, 505, 506, 3, 68, 33, 0, 506, 507, 1, 0, 0, 0, 507, 508, 6, 84, 8, 0, 508, 171, 1, 0, 0, 0, 509, 510, 3, 70, 34, 0, 510, 511, 1, 0, 0, 0, 511, 512, 6, 85, 9, 0, 512, 173, 1, 0, 0, 0, 513, 514, 7, 0, 0, 0, 514, 515, 1, 0, 0, 0, 515, 516, 6, 86, 0, 0, 516, 175, 1, 0, 0, 0, 32, 0, 1, 178, 190, 196, 250, 257, 264, 266, 268, 270, 275, 277, 285, 287, 294, 303, 308, 325, 369, 371, 381, 388, 439, 441, 447, 449, 452, 467, 474, 490, 492, 10, 6, 0, 0, 5, 1, 0, 4, 0, 0, 7, 17, 0, 7, 25, 0, 7, 36, 0, 7, 31, 0, 7, 32, 0, 7, 33, 0, 7, 34, 0] \ No newline at end of file diff --git a/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateLexerExpression.java b/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateLexerExpression.java index dcd9335a7..b25cedb29 100644 --- a/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateLexerExpression.java +++ b/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateLexerExpression.java @@ -19,12 +19,12 @@ public class TemplateLexerExpression extends Lexer { protected static final PredictionContextCache _sharedContextCache = new PredictionContextCache(); public static final int - DEFAULT=1, IF=2, THEN=3, ELSE=4, END=5, WITH=6, VAR_ID=7, ROOT=8, BLOCK_COMMENT=9, - HORZ_WS=10, VERT_WS=11, LBRACE=12, RBRACE=13, DOT=14, LPAREN=15, RPAREN=16, - LBRACK=17, RBRACK=18, DQUESTION=19, SEMI=20, COMMA=21, STAR=22, SLASH=23, - PERCENT=24, PLUS=25, MINUS=26, DSTRING=27, SSTRING=28, DECDIGITS=29, FLOAT=30, - BOOLEAN=31, ID=32, CAST_TYPE=33, ERR_CHAR=34, C_HORZ_WS=35, C_VERT_WS=36, - CERR_CHAR=37; + DEFAULT=1, IF=2, THEN=3, ELSE=4, END=5, WITH=6, AND=7, OR=8, NOT=9, BANG=10, + VAR_ID=11, ROOT=12, BLOCK_COMMENT=13, HORZ_WS=14, VERT_WS=15, LBRACE=16, + RBRACE=17, DOT=18, LPAREN=19, RPAREN=20, LBRACK=21, RBRACK=22, DQUESTION=23, + SEMI=24, COMMA=25, STAR=26, SLASH=27, PERCENT=28, PLUS=29, MINUS=30, DSTRING=31, + SSTRING=32, DECDIGITS=33, FLOAT=34, BOOLEAN=35, ID=36, CAST_TYPE=37, ERR_CHAR=38, + C_HORZ_WS=39, C_VERT_WS=40, CERR_CHAR=41; public static final int Concatenation=1; public static String[] channelNames = { @@ -42,30 +42,32 @@ private static String[] makeRuleNames() { "Star", "Slash", "Percent", "Plus", "Minus", "DQuestion", "LT", "GT", "Default", "NameChar", "EscSeq", "UnicodeEsc", "SQuoteLiteral", "DQuoteLiteral", "BoolLiteral", "HexDigit", "DecDigit", "DecDigits", "Float", "True", - "False", "DEFAULT", "IF", "THEN", "ELSE", "END", "WITH", "VAR_ID", "ROOT", - "BLOCK_COMMENT", "HORZ_WS", "VERT_WS", "LBRACE", "RBRACE", "DOT", "LPAREN", - "RPAREN", "LBRACK", "RBRACK", "DQUESTION", "SEMI", "COMMA", "STAR", "SLASH", - "PERCENT", "PLUS", "MINUS", "DSTRING", "SSTRING", "DECDIGITS", "FLOAT", - "BOOLEAN", "ID", "CAST_TYPE", "ERR_CHAR", "LBrace", "RBrace", "C_HORZ_WS", - "C_VERT_WS", "CRBRACE", "CCOMMA", "CID", "CDSTRING", "CSSTRING", "CDECDIGITS", - "CFLOAT", "CERR_CHAR" + "False", "DEFAULT", "IF", "THEN", "ELSE", "END", "WITH", "AND", "OR", + "NOT", "BANG", "VAR_ID", "ROOT", "BLOCK_COMMENT", "HORZ_WS", "VERT_WS", + "LBRACE", "RBRACE", "DOT", "LPAREN", "RPAREN", "LBRACK", "RBRACK", "DQUESTION", + "SEMI", "COMMA", "STAR", "SLASH", "PERCENT", "PLUS", "MINUS", "DSTRING", + "SSTRING", "DECDIGITS", "FLOAT", "BOOLEAN", "ID", "CAST_TYPE", "ERR_CHAR", + "LBrace", "RBrace", "C_HORZ_WS", "C_VERT_WS", "CRBRACE", "CCOMMA", "CID", + "CDSTRING", "CSSTRING", "CDECDIGITS", "CFLOAT", "CERR_CHAR" }; } public static final String[] ruleNames = makeRuleNames(); private static String[] makeLiteralNames() { return new String[] { - null, null, "'if'", "'then'", "'else'", "'end'", "'with'", null, "'$'" + null, null, "'if'", "'then'", "'else'", "'end'", "'with'", "'and'", "'or'", + "'not'", "'!'", null, "'$'" }; } private static final String[] _LITERAL_NAMES = makeLiteralNames(); private static String[] makeSymbolicNames() { return new String[] { - null, "DEFAULT", "IF", "THEN", "ELSE", "END", "WITH", "VAR_ID", "ROOT", - "BLOCK_COMMENT", "HORZ_WS", "VERT_WS", "LBRACE", "RBRACE", "DOT", "LPAREN", - "RPAREN", "LBRACK", "RBRACK", "DQUESTION", "SEMI", "COMMA", "STAR", "SLASH", - "PERCENT", "PLUS", "MINUS", "DSTRING", "SSTRING", "DECDIGITS", "FLOAT", - "BOOLEAN", "ID", "CAST_TYPE", "ERR_CHAR", "C_HORZ_WS", "C_VERT_WS", "CERR_CHAR" + null, "DEFAULT", "IF", "THEN", "ELSE", "END", "WITH", "AND", "OR", "NOT", + "BANG", "VAR_ID", "ROOT", "BLOCK_COMMENT", "HORZ_WS", "VERT_WS", "LBRACE", + "RBRACE", "DOT", "LPAREN", "RPAREN", "LBRACK", "RBRACK", "DQUESTION", + "SEMI", "COMMA", "STAR", "SLASH", "PERCENT", "PLUS", "MINUS", "DSTRING", + "SSTRING", "DECDIGITS", "FLOAT", "BOOLEAN", "ID", "CAST_TYPE", "ERR_CHAR", + "C_HORZ_WS", "C_VERT_WS", "CERR_CHAR" }; } private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); @@ -127,7 +129,7 @@ public TemplateLexerExpression(CharStream input) { public ATN getATN() { return _ATN; } public static final String _serializedATN = - "\u0004\u0000%\u01f0\u0006\uffff\uffff\u0006\uffff\uffff\u0002\u0000\u0007"+ + "\u0004\u0000)\u0205\u0006\uffff\uffff\u0006\uffff\uffff\u0002\u0000\u0007"+ "\u0000\u0002\u0001\u0007\u0001\u0002\u0002\u0007\u0002\u0002\u0003\u0007"+ "\u0003\u0002\u0004\u0007\u0004\u0002\u0005\u0007\u0005\u0002\u0006\u0007"+ "\u0006\u0002\u0007\u0007\u0007\u0002\b\u0007\b\u0002\t\u0007\t\u0002\n"+ @@ -148,292 +150,304 @@ public TemplateLexerExpression(CharStream input) { "C\u0007C\u0002D\u0007D\u0002E\u0007E\u0002F\u0007F\u0002G\u0007G\u0002"+ "H\u0007H\u0002I\u0007I\u0002J\u0007J\u0002K\u0007K\u0002L\u0007L\u0002"+ "M\u0007M\u0002N\u0007N\u0002O\u0007O\u0002P\u0007P\u0002Q\u0007Q\u0002"+ - "R\u0007R\u0001\u0000\u0001\u0000\u0003\u0000\u00ab\b\u0000\u0001\u0001"+ - "\u0001\u0001\u0001\u0002\u0001\u0002\u0001\u0003\u0001\u0003\u0001\u0003"+ - "\u0001\u0003\u0005\u0003\u00b5\b\u0003\n\u0003\f\u0003\u00b8\t\u0003\u0001"+ - "\u0003\u0001\u0003\u0001\u0003\u0003\u0003\u00bd\b\u0003\u0001\u0004\u0001"+ - "\u0004\u0001\u0005\u0001\u0005\u0001\u0006\u0001\u0006\u0001\u0007\u0001"+ - "\u0007\u0001\b\u0001\b\u0001\t\u0001\t\u0001\n\u0001\n\u0001\u000b\u0001"+ - "\u000b\u0001\f\u0001\f\u0001\r\u0001\r\u0001\u000e\u0001\u000e\u0001\u000f"+ - "\u0001\u000f\u0001\u0010\u0001\u0010\u0001\u0011\u0001\u0011\u0001\u0012"+ - "\u0001\u0012\u0001\u0013\u0001\u0013\u0001\u0014\u0001\u0014\u0001\u0015"+ - "\u0001\u0015\u0001\u0015\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017"+ - "\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018"+ - "\u0001\u0018\u0001\u0018\u0001\u0019\u0001\u0019\u0001\u0019\u0003\u0019"+ - "\u00f3\b\u0019\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a"+ - "\u0003\u001a\u00fa\b\u001a\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001b"+ - "\u0001\u001b\u0003\u001b\u0101\b\u001b\u0003\u001b\u0103\b\u001b\u0003"+ - "\u001b\u0105\b\u001b\u0003\u001b\u0107\b\u001b\u0001\u001c\u0001\u001c"+ - "\u0001\u001c\u0005\u001c\u010c\b\u001c\n\u001c\f\u001c\u010f\t\u001c\u0001"+ - "\u001c\u0001\u001c\u0001\u001d\u0001\u001d\u0001\u001d\u0005\u001d\u0116"+ - "\b\u001d\n\u001d\f\u001d\u0119\t\u001d\u0001\u001d\u0001\u001d\u0001\u001e"+ - "\u0001\u001e\u0003\u001e\u011f\b\u001e\u0001\u001f\u0001\u001f\u0001 "+ - "\u0001 \u0001!\u0004!\u0126\b!\u000b!\f!\u0127\u0001\"\u0001\"\u0001\""+ - "\u0003\"\u012d\b\"\u0001#\u0001#\u0001#\u0001#\u0001#\u0001$\u0001$\u0001"+ - "$\u0001$\u0001$\u0001$\u0001%\u0001%\u0005%\u013c\b%\n%\f%\u013f\t%\u0001"+ - "%\u0001%\u0001&\u0001&\u0001&\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'"+ - "\u0001(\u0001(\u0001(\u0001(\u0001(\u0001)\u0001)\u0001)\u0001)\u0001"+ - "*\u0001*\u0001*\u0001*\u0001*\u0001+\u0001+\u0001+\u0001+\u0005+\u015d"+ - "\b+\n+\f+\u0160\t+\u0001,\u0001,\u0001-\u0001-\u0001.\u0004.\u0167\b."+ - "\u000b.\f.\u0168\u0001.\u0001.\u0001/\u0004/\u016e\b/\u000b/\f/\u016f"+ - "\u0001/\u0001/\u00010\u00010\u00010\u00010\u00011\u00011\u00011\u0001"+ - "1\u00012\u00012\u00013\u00013\u00014\u00014\u00015\u00015\u00016\u0001"+ - "6\u00017\u00017\u00018\u00018\u00019\u00019\u0001:\u0001:\u0001;\u0001"+ - ";\u0001<\u0001<\u0001=\u0001=\u0001>\u0001>\u0001?\u0001?\u0001@\u0001"+ - "@\u0001A\u0001A\u0001B\u0001B\u0001C\u0001C\u0001D\u0001D\u0001D\u0005"+ - "D\u01a3\bD\nD\fD\u01a6\tD\u0001E\u0001E\u0001E\u0004E\u01ab\bE\u000bE"+ - "\fE\u01ac\u0001E\u0003E\u01b0\bE\u0001E\u0001E\u0001F\u0001F\u0001F\u0001"+ - "F\u0001G\u0001G\u0001H\u0001H\u0001I\u0004I\u01bd\bI\u000bI\fI\u01be\u0001"+ - "I\u0001I\u0001J\u0004J\u01c4\bJ\u000bJ\fJ\u01c5\u0001J\u0001J\u0001K\u0001"+ - "K\u0001K\u0001K\u0001K\u0001L\u0001L\u0001L\u0001L\u0001M\u0001M\u0001"+ - "M\u0005M\u01d6\bM\nM\fM\u01d9\tM\u0001M\u0001M\u0001N\u0001N\u0001N\u0001"+ - "N\u0001O\u0001O\u0001O\u0001O\u0001P\u0001P\u0001P\u0001P\u0001Q\u0001"+ - "Q\u0001Q\u0001Q\u0001R\u0001R\u0001R\u0001R\u0001\u00b6\u0000S\u0002\u0000"+ - "\u0004\u0000\u0006\u0000\b\u0000\n\u0000\f\u0000\u000e\u0000\u0010\u0000"+ - "\u0012\u0000\u0014\u0000\u0016\u0000\u0018\u0000\u001a\u0000\u001c\u0000"+ - "\u001e\u0000 \u0000\"\u0000$\u0000&\u0000(\u0000*\u0000,\u0000.\u0000"+ - "0\u00002\u00004\u00006\u00008\u0000:\u0000<\u0000>\u0000@\u0000B\u0000"+ - "D\u0000F\u0000H\u0000J\u0000L\u0001N\u0002P\u0003R\u0004T\u0005V\u0006"+ - "X\u0007Z\b\\\t^\n`\u000bb\fd\rf\u000eh\u000fj\u0010l\u0011n\u0012p\u0013"+ - "r\u0014t\u0015v\u0016x\u0017z\u0018|\u0019~\u001a\u0080\u001b\u0082\u001c"+ - "\u0084\u001d\u0086\u001e\u0088\u001f\u008a \u008c!\u008e\"\u0090\u0000"+ - "\u0092\u0000\u0094#\u0096$\u0098\u0000\u009a\u0000\u009c\u0000\u009e\u0000"+ - "\u00a0\u0000\u00a2\u0000\u00a4\u0000\u00a6%\u0002\u0000\u0001\t\u0002"+ - "\u0000\t\t \u0002\u0000\n\n\f\r\r\u0000AZaz\u00c0\u00d6\u00d8\u00f6\u00f8"+ - "\u02ff\u0370\u037d\u037f\u1fff\u200c\u200d\u2070\u218f\u2c00\u2fef\u3001"+ - "\u8000\ud7ff\u8000\uf900\u8000\ufdcf\u8000\ufdf0\u8000\ufffd\u0003\u0000"+ - "\u00b7\u00b7\u0300\u036f\u203f\u2040\b\u0000\"\"\'\'\\\\bbffnnrrtt\u0004"+ - "\u0000\n\n\r\r\'\'\\\\\u0004\u0000\n\n\r\r\"\"\\\\\u0003\u000009AFaf\u0001"+ - "\u000009\u01e8\u0000L\u0001\u0000\u0000\u0000\u0000N\u0001\u0000\u0000"+ - "\u0000\u0000P\u0001\u0000\u0000\u0000\u0000R\u0001\u0000\u0000\u0000\u0000"+ - "T\u0001\u0000\u0000\u0000\u0000V\u0001\u0000\u0000\u0000\u0000X\u0001"+ - "\u0000\u0000\u0000\u0000Z\u0001\u0000\u0000\u0000\u0000\\\u0001\u0000"+ - "\u0000\u0000\u0000^\u0001\u0000\u0000\u0000\u0000`\u0001\u0000\u0000\u0000"+ - "\u0000b\u0001\u0000\u0000\u0000\u0000d\u0001\u0000\u0000\u0000\u0000f"+ - "\u0001\u0000\u0000\u0000\u0000h\u0001\u0000\u0000\u0000\u0000j\u0001\u0000"+ - "\u0000\u0000\u0000l\u0001\u0000\u0000\u0000\u0000n\u0001\u0000\u0000\u0000"+ - "\u0000p\u0001\u0000\u0000\u0000\u0000r\u0001\u0000\u0000\u0000\u0000t"+ - "\u0001\u0000\u0000\u0000\u0000v\u0001\u0000\u0000\u0000\u0000x\u0001\u0000"+ - "\u0000\u0000\u0000z\u0001\u0000\u0000\u0000\u0000|\u0001\u0000\u0000\u0000"+ - "\u0000~\u0001\u0000\u0000\u0000\u0000\u0080\u0001\u0000\u0000\u0000\u0000"+ - "\u0082\u0001\u0000\u0000\u0000\u0000\u0084\u0001\u0000\u0000\u0000\u0000"+ - "\u0086\u0001\u0000\u0000\u0000\u0000\u0088\u0001\u0000\u0000\u0000\u0000"+ - "\u008a\u0001\u0000\u0000\u0000\u0000\u008c\u0001\u0000\u0000\u0000\u0000"+ - "\u008e\u0001\u0000\u0000\u0000\u0001\u0094\u0001\u0000\u0000\u0000\u0001"+ - "\u0096\u0001\u0000\u0000\u0000\u0001\u0098\u0001\u0000\u0000\u0000\u0001"+ - "\u009a\u0001\u0000\u0000\u0000\u0001\u009c\u0001\u0000\u0000\u0000\u0001"+ - "\u009e\u0001\u0000\u0000\u0000\u0001\u00a0\u0001\u0000\u0000\u0000\u0001"+ - "\u00a2\u0001\u0000\u0000\u0000\u0001\u00a4\u0001\u0000\u0000\u0000\u0001"+ - "\u00a6\u0001\u0000\u0000\u0000\u0002\u00aa\u0001\u0000\u0000\u0000\u0004"+ - "\u00ac\u0001\u0000\u0000\u0000\u0006\u00ae\u0001\u0000\u0000\u0000\b\u00b0"+ - "\u0001\u0000\u0000\u0000\n\u00be\u0001\u0000\u0000\u0000\f\u00c0\u0001"+ - "\u0000\u0000\u0000\u000e\u00c2\u0001\u0000\u0000\u0000\u0010\u00c4\u0001"+ - "\u0000\u0000\u0000\u0012\u00c6\u0001\u0000\u0000\u0000\u0014\u00c8\u0001"+ - "\u0000\u0000\u0000\u0016\u00ca\u0001\u0000\u0000\u0000\u0018\u00cc\u0001"+ - "\u0000\u0000\u0000\u001a\u00ce\u0001\u0000\u0000\u0000\u001c\u00d0\u0001"+ - "\u0000\u0000\u0000\u001e\u00d2\u0001\u0000\u0000\u0000 \u00d4\u0001\u0000"+ - "\u0000\u0000\"\u00d6\u0001\u0000\u0000\u0000$\u00d8\u0001\u0000\u0000"+ - "\u0000&\u00da\u0001\u0000\u0000\u0000(\u00dc\u0001\u0000\u0000\u0000*"+ - "\u00de\u0001\u0000\u0000\u0000,\u00e0\u0001\u0000\u0000\u0000.\u00e3\u0001"+ - "\u0000\u0000\u00000\u00e5\u0001\u0000\u0000\u00002\u00e7\u0001\u0000\u0000"+ - "\u00004\u00f2\u0001\u0000\u0000\u00006\u00f4\u0001\u0000\u0000\u00008"+ - "\u00fb\u0001\u0000\u0000\u0000:\u0108\u0001\u0000\u0000\u0000<\u0112\u0001"+ - "\u0000\u0000\u0000>\u011e\u0001\u0000\u0000\u0000@\u0120\u0001\u0000\u0000"+ - "\u0000B\u0122\u0001\u0000\u0000\u0000D\u0125\u0001\u0000\u0000\u0000F"+ - "\u0129\u0001\u0000\u0000\u0000H\u012e\u0001\u0000\u0000\u0000J\u0133\u0001"+ - "\u0000\u0000\u0000L\u0139\u0001\u0000\u0000\u0000N\u0142\u0001\u0000\u0000"+ - "\u0000P\u0145\u0001\u0000\u0000\u0000R\u014a\u0001\u0000\u0000\u0000T"+ - "\u014f\u0001\u0000\u0000\u0000V\u0153\u0001\u0000\u0000\u0000X\u0158\u0001"+ - "\u0000\u0000\u0000Z\u0161\u0001\u0000\u0000\u0000\\\u0163\u0001\u0000"+ - "\u0000\u0000^\u0166\u0001\u0000\u0000\u0000`\u016d\u0001\u0000\u0000\u0000"+ - "b\u0173\u0001\u0000\u0000\u0000d\u0177\u0001\u0000\u0000\u0000f\u017b"+ - "\u0001\u0000\u0000\u0000h\u017d\u0001\u0000\u0000\u0000j\u017f\u0001\u0000"+ - "\u0000\u0000l\u0181\u0001\u0000\u0000\u0000n\u0183\u0001\u0000\u0000\u0000"+ - "p\u0185\u0001\u0000\u0000\u0000r\u0187\u0001\u0000\u0000\u0000t\u0189"+ - "\u0001\u0000\u0000\u0000v\u018b\u0001\u0000\u0000\u0000x\u018d\u0001\u0000"+ - "\u0000\u0000z\u018f\u0001\u0000\u0000\u0000|\u0191\u0001\u0000\u0000\u0000"+ - "~\u0193\u0001\u0000\u0000\u0000\u0080\u0195\u0001\u0000\u0000\u0000\u0082"+ - "\u0197\u0001\u0000\u0000\u0000\u0084\u0199\u0001\u0000\u0000\u0000\u0086"+ - "\u019b\u0001\u0000\u0000\u0000\u0088\u019d\u0001\u0000\u0000\u0000\u008a"+ - "\u019f\u0001\u0000\u0000\u0000\u008c\u01a7\u0001\u0000\u0000\u0000\u008e"+ - "\u01b3\u0001\u0000\u0000\u0000\u0090\u01b7\u0001\u0000\u0000\u0000\u0092"+ - "\u01b9\u0001\u0000\u0000\u0000\u0094\u01bc\u0001\u0000\u0000\u0000\u0096"+ - "\u01c3\u0001\u0000\u0000\u0000\u0098\u01c9\u0001\u0000\u0000\u0000\u009a"+ - "\u01ce\u0001\u0000\u0000\u0000\u009c\u01d2\u0001\u0000\u0000\u0000\u009e"+ - "\u01dc\u0001\u0000\u0000\u0000\u00a0\u01e0\u0001\u0000\u0000\u0000\u00a2"+ - "\u01e4\u0001\u0000\u0000\u0000\u00a4\u01e8\u0001\u0000\u0000\u0000\u00a6"+ - "\u01ec\u0001\u0000\u0000\u0000\u00a8\u00ab\u0003\u0004\u0001\u0000\u00a9"+ - "\u00ab\u0003\u0006\u0002\u0000\u00aa\u00a8\u0001\u0000\u0000\u0000\u00aa"+ - "\u00a9\u0001\u0000\u0000\u0000\u00ab\u0003\u0001\u0000\u0000\u0000\u00ac"+ - "\u00ad\u0007\u0000\u0000\u0000\u00ad\u0005\u0001\u0000\u0000\u0000\u00ae"+ - "\u00af\u0007\u0001\u0000\u0000\u00af\u0007\u0001\u0000\u0000\u0000\u00b0"+ - "\u00b1\u0005/\u0000\u0000\u00b1\u00b2\u0005*\u0000\u0000\u00b2\u00b6\u0001"+ - "\u0000\u0000\u0000\u00b3\u00b5\t\u0000\u0000\u0000\u00b4\u00b3\u0001\u0000"+ - "\u0000\u0000\u00b5\u00b8\u0001\u0000\u0000\u0000\u00b6\u00b7\u0001\u0000"+ - "\u0000\u0000\u00b6\u00b4\u0001\u0000\u0000\u0000\u00b7\u00bc\u0001\u0000"+ - "\u0000\u0000\u00b8\u00b6\u0001\u0000\u0000\u0000\u00b9\u00ba\u0005*\u0000"+ - "\u0000\u00ba\u00bd\u0005/\u0000\u0000\u00bb\u00bd\u0005\u0000\u0000\u0001"+ - "\u00bc\u00b9\u0001\u0000\u0000\u0000\u00bc\u00bb\u0001\u0000\u0000\u0000"+ - "\u00bd\t\u0001\u0000\u0000\u0000\u00be\u00bf\u0005\\\u0000\u0000\u00bf"+ - "\u000b\u0001\u0000\u0000\u0000\u00c0\u00c1\u0005\'\u0000\u0000\u00c1\r"+ - "\u0001\u0000\u0000\u0000\u00c2\u00c3\u0005\"\u0000\u0000\u00c3\u000f\u0001"+ - "\u0000\u0000\u0000\u00c4\u00c5\u0005_\u0000\u0000\u00c5\u0011\u0001\u0000"+ - "\u0000\u0000\u00c6\u00c7\u0005,\u0000\u0000\u00c7\u0013\u0001\u0000\u0000"+ - "\u0000\u00c8\u00c9\u0005;\u0000\u0000\u00c9\u0015\u0001\u0000\u0000\u0000"+ - "\u00ca\u00cb\u0005|\u0000\u0000\u00cb\u0017\u0001\u0000\u0000\u0000\u00cc"+ - "\u00cd\u0005.\u0000\u0000\u00cd\u0019\u0001\u0000\u0000\u0000\u00ce\u00cf"+ - "\u0005(\u0000\u0000\u00cf\u001b\u0001\u0000\u0000\u0000\u00d0\u00d1\u0005"+ - ")\u0000\u0000\u00d1\u001d\u0001\u0000\u0000\u0000\u00d2\u00d3\u0005[\u0000"+ - "\u0000\u00d3\u001f\u0001\u0000\u0000\u0000\u00d4\u00d5\u0005]\u0000\u0000"+ - "\u00d5!\u0001\u0000\u0000\u0000\u00d6\u00d7\u0005*\u0000\u0000\u00d7#"+ - "\u0001\u0000\u0000\u0000\u00d8\u00d9\u0005/\u0000\u0000\u00d9%\u0001\u0000"+ - "\u0000\u0000\u00da\u00db\u0005%\u0000\u0000\u00db\'\u0001\u0000\u0000"+ - "\u0000\u00dc\u00dd\u0005+\u0000\u0000\u00dd)\u0001\u0000\u0000\u0000\u00de"+ - "\u00df\u0005-\u0000\u0000\u00df+\u0001\u0000\u0000\u0000\u00e0\u00e1\u0005"+ - "?\u0000\u0000\u00e1\u00e2\u0005?\u0000\u0000\u00e2-\u0001\u0000\u0000"+ - "\u0000\u00e3\u00e4\u0005<\u0000\u0000\u00e4/\u0001\u0000\u0000\u0000\u00e5"+ - "\u00e6\u0005>\u0000\u0000\u00e61\u0001\u0000\u0000\u0000\u00e7\u00e8\u0005"+ - "d\u0000\u0000\u00e8\u00e9\u0005e\u0000\u0000\u00e9\u00ea\u0005f\u0000"+ - "\u0000\u00ea\u00eb\u0005a\u0000\u0000\u00eb\u00ec\u0005u\u0000\u0000\u00ec"+ - "\u00ed\u0005l\u0000\u0000\u00ed\u00ee\u0005t\u0000\u0000\u00ee3\u0001"+ - "\u0000\u0000\u0000\u00ef\u00f3\u0007\u0002\u0000\u0000\u00f0\u00f3\u0003"+ - "\u0010\u0007\u0000\u00f1\u00f3\u0007\u0003\u0000\u0000\u00f2\u00ef\u0001"+ - "\u0000\u0000\u0000\u00f2\u00f0\u0001\u0000\u0000\u0000\u00f2\u00f1\u0001"+ - "\u0000\u0000\u0000\u00f35\u0001\u0000\u0000\u0000\u00f4\u00f9\u0003\n"+ - "\u0004\u0000\u00f5\u00fa\u0007\u0004\u0000\u0000\u00f6\u00fa\u00038\u001b"+ - "\u0000\u00f7\u00fa\t\u0000\u0000\u0000\u00f8\u00fa\u0005\u0000\u0000\u0001"+ - "\u00f9\u00f5\u0001\u0000\u0000\u0000\u00f9\u00f6\u0001\u0000\u0000\u0000"+ - "\u00f9\u00f7\u0001\u0000\u0000\u0000\u00f9\u00f8\u0001\u0000\u0000\u0000"+ - "\u00fa7\u0001\u0000\u0000\u0000\u00fb\u0106\u0005u\u0000\u0000\u00fc\u0104"+ - "\u0003@\u001f\u0000\u00fd\u0102\u0003@\u001f\u0000\u00fe\u0100\u0003@"+ - "\u001f\u0000\u00ff\u0101\u0003@\u001f\u0000\u0100\u00ff\u0001\u0000\u0000"+ - "\u0000\u0100\u0101\u0001\u0000\u0000\u0000\u0101\u0103\u0001\u0000\u0000"+ - "\u0000\u0102\u00fe\u0001\u0000\u0000\u0000\u0102\u0103\u0001\u0000\u0000"+ - "\u0000\u0103\u0105\u0001\u0000\u0000\u0000\u0104\u00fd\u0001\u0000\u0000"+ - "\u0000\u0104\u0105\u0001\u0000\u0000\u0000\u0105\u0107\u0001\u0000\u0000"+ - "\u0000\u0106\u00fc\u0001\u0000\u0000\u0000\u0106\u0107\u0001\u0000\u0000"+ - "\u0000\u01079\u0001\u0000\u0000\u0000\u0108\u010d\u0003\f\u0005\u0000"+ - "\u0109\u010c\u00036\u001a\u0000\u010a\u010c\b\u0005\u0000\u0000\u010b"+ - "\u0109\u0001\u0000\u0000\u0000\u010b\u010a\u0001\u0000\u0000\u0000\u010c"+ - "\u010f\u0001\u0000\u0000\u0000\u010d\u010b\u0001\u0000\u0000\u0000\u010d"+ - "\u010e\u0001\u0000\u0000\u0000\u010e\u0110\u0001\u0000\u0000\u0000\u010f"+ - "\u010d\u0001\u0000\u0000\u0000\u0110\u0111\u0003\f\u0005\u0000\u0111;"+ - "\u0001\u0000\u0000\u0000\u0112\u0117\u0003\u000e\u0006\u0000\u0113\u0116"+ - "\u00036\u001a\u0000\u0114\u0116\b\u0006\u0000\u0000\u0115\u0113\u0001"+ - "\u0000\u0000\u0000\u0115\u0114\u0001\u0000\u0000\u0000\u0116\u0119\u0001"+ - "\u0000\u0000\u0000\u0117\u0115\u0001\u0000\u0000\u0000\u0117\u0118\u0001"+ - "\u0000\u0000\u0000\u0118\u011a\u0001\u0000\u0000\u0000\u0119\u0117\u0001"+ - "\u0000\u0000\u0000\u011a\u011b\u0003\u000e\u0006\u0000\u011b=\u0001\u0000"+ - "\u0000\u0000\u011c\u011f\u0003H#\u0000\u011d\u011f\u0003J$\u0000\u011e"+ - "\u011c\u0001\u0000\u0000\u0000\u011e\u011d\u0001\u0000\u0000\u0000\u011f"+ - "?\u0001\u0000\u0000\u0000\u0120\u0121\u0007\u0007\u0000\u0000\u0121A\u0001"+ - "\u0000\u0000\u0000\u0122\u0123\u0007\b\u0000\u0000\u0123C\u0001\u0000"+ - "\u0000\u0000\u0124\u0126\u0003B \u0000\u0125\u0124\u0001\u0000\u0000\u0000"+ - "\u0126\u0127\u0001\u0000\u0000\u0000\u0127\u0125\u0001\u0000\u0000\u0000"+ - "\u0127\u0128\u0001\u0000\u0000\u0000\u0128E\u0001\u0000\u0000\u0000\u0129"+ - "\u012a\u0003D!\u0000\u012a\u012c\u0003\u0018\u000b\u0000\u012b\u012d\u0003"+ - "D!\u0000\u012c\u012b\u0001\u0000\u0000\u0000\u012c\u012d\u0001\u0000\u0000"+ - "\u0000\u012dG\u0001\u0000\u0000\u0000\u012e\u012f\u0005t\u0000\u0000\u012f"+ - "\u0130\u0005r\u0000\u0000\u0130\u0131\u0005u\u0000\u0000\u0131\u0132\u0005"+ - "e\u0000\u0000\u0132I\u0001\u0000\u0000\u0000\u0133\u0134\u0005f\u0000"+ - "\u0000\u0134\u0135\u0005a\u0000\u0000\u0135\u0136\u0005l\u0000\u0000\u0136"+ - "\u0137\u0005s\u0000\u0000\u0137\u0138\u0005e\u0000\u0000\u0138K\u0001"+ - "\u0000\u0000\u0000\u0139\u013d\u0003\u0016\n\u0000\u013a\u013c\u0003\u0004"+ - "\u0001\u0000\u013b\u013a\u0001\u0000\u0000\u0000\u013c\u013f\u0001\u0000"+ - "\u0000\u0000\u013d\u013b\u0001\u0000\u0000\u0000\u013d\u013e\u0001\u0000"+ - "\u0000\u0000\u013e\u0140\u0001\u0000\u0000\u0000\u013f\u013d\u0001\u0000"+ - "\u0000\u0000\u0140\u0141\u00032\u0018\u0000\u0141M\u0001\u0000\u0000\u0000"+ - "\u0142\u0143\u0005i\u0000\u0000\u0143\u0144\u0005f\u0000\u0000\u0144O"+ - "\u0001\u0000\u0000\u0000\u0145\u0146\u0005t\u0000\u0000\u0146\u0147\u0005"+ - "h\u0000\u0000\u0147\u0148\u0005e\u0000\u0000\u0148\u0149\u0005n\u0000"+ - "\u0000\u0149Q\u0001\u0000\u0000\u0000\u014a\u014b\u0005e\u0000\u0000\u014b"+ - "\u014c\u0005l\u0000\u0000\u014c\u014d\u0005s\u0000\u0000\u014d\u014e\u0005"+ - "e\u0000\u0000\u014eS\u0001\u0000\u0000\u0000\u014f\u0150\u0005e\u0000"+ - "\u0000\u0150\u0151\u0005n\u0000\u0000\u0151\u0152\u0005d\u0000\u0000\u0152"+ - "U\u0001\u0000\u0000\u0000\u0153\u0154\u0005w\u0000\u0000\u0154\u0155\u0005"+ - "i\u0000\u0000\u0155\u0156\u0005t\u0000\u0000\u0156\u0157\u0005h\u0000"+ - "\u0000\u0157W\u0001\u0000\u0000\u0000\u0158\u0159\u0005$\u0000\u0000\u0159"+ - "\u015e\u00034\u0019\u0000\u015a\u015d\u00034\u0019\u0000\u015b\u015d\u0003"+ - "B \u0000\u015c\u015a\u0001\u0000\u0000\u0000\u015c\u015b\u0001\u0000\u0000"+ - "\u0000\u015d\u0160\u0001\u0000\u0000\u0000\u015e\u015c\u0001\u0000\u0000"+ - "\u0000\u015e\u015f\u0001\u0000\u0000\u0000\u015fY\u0001\u0000\u0000\u0000"+ - "\u0160\u015e\u0001\u0000\u0000\u0000\u0161\u0162\u0005$\u0000\u0000\u0162"+ - "[\u0001\u0000\u0000\u0000\u0163\u0164\u0003\b\u0003\u0000\u0164]\u0001"+ - "\u0000\u0000\u0000\u0165\u0167\u0003\u0004\u0001\u0000\u0166\u0165\u0001"+ - "\u0000\u0000\u0000\u0167\u0168\u0001\u0000\u0000\u0000\u0168\u0166\u0001"+ - "\u0000\u0000\u0000\u0168\u0169\u0001\u0000\u0000\u0000\u0169\u016a\u0001"+ - "\u0000\u0000\u0000\u016a\u016b\u0006.\u0000\u0000\u016b_\u0001\u0000\u0000"+ - "\u0000\u016c\u016e\u0003\u0006\u0002\u0000\u016d\u016c\u0001\u0000\u0000"+ - "\u0000\u016e\u016f\u0001\u0000\u0000\u0000\u016f\u016d\u0001\u0000\u0000"+ - "\u0000\u016f\u0170\u0001\u0000\u0000\u0000\u0170\u0171\u0001\u0000\u0000"+ - "\u0000\u0171\u0172\u0006/\u0000\u0000\u0172a\u0001\u0000\u0000\u0000\u0173"+ - "\u0174\u0003\u0090G\u0000\u0174\u0175\u0001\u0000\u0000\u0000\u0175\u0176"+ - "\u00060\u0001\u0000\u0176c\u0001\u0000\u0000\u0000\u0177\u0178\u0003\u0092"+ - "H\u0000\u0178\u0179\u0001\u0000\u0000\u0000\u0179\u017a\u00061\u0002\u0000"+ - "\u017ae\u0001\u0000\u0000\u0000\u017b\u017c\u0003\u0018\u000b\u0000\u017c"+ - "g\u0001\u0000\u0000\u0000\u017d\u017e\u0003\u001a\f\u0000\u017ei\u0001"+ - "\u0000\u0000\u0000\u017f\u0180\u0003\u001c\r\u0000\u0180k\u0001\u0000"+ - "\u0000\u0000\u0181\u0182\u0003\u001e\u000e\u0000\u0182m\u0001\u0000\u0000"+ - "\u0000\u0183\u0184\u0003 \u000f\u0000\u0184o\u0001\u0000\u0000\u0000\u0185"+ - "\u0186\u0003,\u0015\u0000\u0186q\u0001\u0000\u0000\u0000\u0187\u0188\u0003"+ - "\u0014\t\u0000\u0188s\u0001\u0000\u0000\u0000\u0189\u018a\u0003\u0012"+ - "\b\u0000\u018au\u0001\u0000\u0000\u0000\u018b\u018c\u0003\"\u0010\u0000"+ - "\u018cw\u0001\u0000\u0000\u0000\u018d\u018e\u0003$\u0011\u0000\u018ey"+ - "\u0001\u0000\u0000\u0000\u018f\u0190\u0003&\u0012\u0000\u0190{\u0001\u0000"+ - "\u0000\u0000\u0191\u0192\u0003(\u0013\u0000\u0192}\u0001\u0000\u0000\u0000"+ - "\u0193\u0194\u0003*\u0014\u0000\u0194\u007f\u0001\u0000\u0000\u0000\u0195"+ - "\u0196\u0003<\u001d\u0000\u0196\u0081\u0001\u0000\u0000\u0000\u0197\u0198"+ - "\u0003:\u001c\u0000\u0198\u0083\u0001\u0000\u0000\u0000\u0199\u019a\u0003"+ - "D!\u0000\u019a\u0085\u0001\u0000\u0000\u0000\u019b\u019c\u0003F\"\u0000"+ - "\u019c\u0087\u0001\u0000\u0000\u0000\u019d\u019e\u0003>\u001e\u0000\u019e"+ - "\u0089\u0001\u0000\u0000\u0000\u019f\u01a4\u00034\u0019\u0000\u01a0\u01a3"+ - "\u00034\u0019\u0000\u01a1\u01a3\u0003B \u0000\u01a2\u01a0\u0001\u0000"+ - "\u0000\u0000\u01a2\u01a1\u0001\u0000\u0000\u0000\u01a3\u01a6\u0001\u0000"+ - "\u0000\u0000\u01a4\u01a2\u0001\u0000\u0000\u0000\u01a4\u01a5\u0001\u0000"+ - "\u0000\u0000\u01a5\u008b\u0001\u0000\u0000\u0000\u01a6\u01a4\u0001\u0000"+ - "\u0000\u0000\u01a7\u01aa\u0003.\u0016\u0000\u01a8\u01ab\u00034\u0019\u0000"+ - "\u01a9\u01ab\u0003f2\u0000\u01aa\u01a8\u0001\u0000\u0000\u0000\u01aa\u01a9"+ - "\u0001\u0000\u0000\u0000\u01ab\u01ac\u0001\u0000\u0000\u0000\u01ac\u01aa"+ - "\u0001\u0000\u0000\u0000\u01ac\u01ad\u0001\u0000\u0000\u0000\u01ad\u01af"+ - "\u0001\u0000\u0000\u0000\u01ae\u01b0\u0003\u008cE\u0000\u01af\u01ae\u0001"+ - "\u0000\u0000\u0000\u01af\u01b0\u0001\u0000\u0000\u0000\u01b0\u01b1\u0001"+ - "\u0000\u0000\u0000\u01b1\u01b2\u00030\u0017\u0000\u01b2\u008d\u0001\u0000"+ - "\u0000\u0000\u01b3\u01b4\u0003\u0004\u0001\u0000\u01b4\u01b5\u0001\u0000"+ - "\u0000\u0000\u01b5\u01b6\u0006F\u0000\u0000\u01b6\u008f\u0001\u0000\u0000"+ - "\u0000\u01b7\u01b8\u0005{\u0000\u0000\u01b8\u0091\u0001\u0000\u0000\u0000"+ - "\u01b9\u01ba\u0005}\u0000\u0000\u01ba\u0093\u0001\u0000\u0000\u0000\u01bb"+ - "\u01bd\u0003\u0004\u0001\u0000\u01bc\u01bb\u0001\u0000\u0000\u0000\u01bd"+ - "\u01be\u0001\u0000\u0000\u0000\u01be\u01bc\u0001\u0000\u0000\u0000\u01be"+ - "\u01bf\u0001\u0000\u0000\u0000\u01bf\u01c0\u0001\u0000\u0000\u0000\u01c0"+ - "\u01c1\u0006I\u0000\u0000\u01c1\u0095\u0001\u0000\u0000\u0000\u01c2\u01c4"+ - "\u0003\u0006\u0002\u0000\u01c3\u01c2\u0001\u0000\u0000\u0000\u01c4\u01c5"+ - "\u0001\u0000\u0000\u0000\u01c5\u01c3\u0001\u0000\u0000\u0000\u01c5\u01c6"+ - "\u0001\u0000\u0000\u0000\u01c6\u01c7\u0001\u0000\u0000\u0000\u01c7\u01c8"+ - "\u0006J\u0000\u0000\u01c8\u0097\u0001\u0000\u0000\u0000\u01c9\u01ca\u0003"+ - "\u0092H\u0000\u01ca\u01cb\u0001\u0000\u0000\u0000\u01cb\u01cc\u0006K\u0002"+ - "\u0000\u01cc\u01cd\u0006K\u0003\u0000\u01cd\u0099\u0001\u0000\u0000\u0000"+ - "\u01ce\u01cf\u0003\u0012\b\u0000\u01cf\u01d0\u0001\u0000\u0000\u0000\u01d0"+ - "\u01d1\u0006L\u0004\u0000\u01d1\u009b\u0001\u0000\u0000\u0000\u01d2\u01d7"+ - "\u00034\u0019\u0000\u01d3\u01d6\u00034\u0019\u0000\u01d4\u01d6\u0003B"+ - " \u0000\u01d5\u01d3\u0001\u0000\u0000\u0000\u01d5\u01d4\u0001\u0000\u0000"+ - "\u0000\u01d6\u01d9\u0001\u0000\u0000\u0000\u01d7\u01d5\u0001\u0000\u0000"+ - "\u0000\u01d7\u01d8\u0001\u0000\u0000\u0000\u01d8\u01da\u0001\u0000\u0000"+ - "\u0000\u01d9\u01d7\u0001\u0000\u0000\u0000\u01da\u01db\u0006M\u0005\u0000"+ - "\u01db\u009d\u0001\u0000\u0000\u0000\u01dc\u01dd\u0003<\u001d\u0000\u01dd"+ - "\u01de\u0001\u0000\u0000\u0000\u01de\u01df\u0006N\u0006\u0000\u01df\u009f"+ - "\u0001\u0000\u0000\u0000\u01e0\u01e1\u0003:\u001c\u0000\u01e1\u01e2\u0001"+ - "\u0000\u0000\u0000\u01e2\u01e3\u0006O\u0007\u0000\u01e3\u00a1\u0001\u0000"+ - "\u0000\u0000\u01e4\u01e5\u0003D!\u0000\u01e5\u01e6\u0001\u0000\u0000\u0000"+ - "\u01e6\u01e7\u0006P\b\u0000\u01e7\u00a3\u0001\u0000\u0000\u0000\u01e8"+ - "\u01e9\u0003F\"\u0000\u01e9\u01ea\u0001\u0000\u0000\u0000\u01ea\u01eb"+ - "\u0006Q\t\u0000\u01eb\u00a5\u0001\u0000\u0000\u0000\u01ec\u01ed\u0007"+ - "\u0000\u0000\u0000\u01ed\u01ee\u0001\u0000\u0000\u0000\u01ee\u01ef\u0006"+ - "R\u0000\u0000\u01ef\u00a7\u0001\u0000\u0000\u0000 \u0000\u0001\u00aa\u00b6"+ - "\u00bc\u00f2\u00f9\u0100\u0102\u0104\u0106\u010b\u010d\u0115\u0117\u011e"+ - "\u0127\u012c\u013d\u015c\u015e\u0168\u016f\u01a2\u01a4\u01aa\u01ac\u01af"+ - "\u01be\u01c5\u01d5\u01d7\n\u0006\u0000\u0000\u0005\u0001\u0000\u0004\u0000"+ - "\u0000\u0007\r\u0000\u0007\u0015\u0000\u0007 \u0000\u0007\u001b\u0000"+ - "\u0007\u001c\u0000\u0007\u001d\u0000\u0007\u001e\u0000"; + "R\u0007R\u0002S\u0007S\u0002T\u0007T\u0002U\u0007U\u0002V\u0007V\u0001"+ + "\u0000\u0001\u0000\u0003\u0000\u00b3\b\u0000\u0001\u0001\u0001\u0001\u0001"+ + "\u0002\u0001\u0002\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0005"+ + "\u0003\u00bd\b\u0003\n\u0003\f\u0003\u00c0\t\u0003\u0001\u0003\u0001\u0003"+ + "\u0001\u0003\u0003\u0003\u00c5\b\u0003\u0001\u0004\u0001\u0004\u0001\u0005"+ + "\u0001\u0005\u0001\u0006\u0001\u0006\u0001\u0007\u0001\u0007\u0001\b\u0001"+ + "\b\u0001\t\u0001\t\u0001\n\u0001\n\u0001\u000b\u0001\u000b\u0001\f\u0001"+ + "\f\u0001\r\u0001\r\u0001\u000e\u0001\u000e\u0001\u000f\u0001\u000f\u0001"+ + "\u0010\u0001\u0010\u0001\u0011\u0001\u0011\u0001\u0012\u0001\u0012\u0001"+ + "\u0013\u0001\u0013\u0001\u0014\u0001\u0014\u0001\u0015\u0001\u0015\u0001"+ + "\u0015\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017\u0001\u0018\u0001"+ + "\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001"+ + "\u0018\u0001\u0019\u0001\u0019\u0001\u0019\u0003\u0019\u00fb\b\u0019\u0001"+ + "\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0003\u001a\u0102"+ + "\b\u001a\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001b\u0003"+ + "\u001b\u0109\b\u001b\u0003\u001b\u010b\b\u001b\u0003\u001b\u010d\b\u001b"+ + "\u0003\u001b\u010f\b\u001b\u0001\u001c\u0001\u001c\u0001\u001c\u0005\u001c"+ + "\u0114\b\u001c\n\u001c\f\u001c\u0117\t\u001c\u0001\u001c\u0001\u001c\u0001"+ + "\u001d\u0001\u001d\u0001\u001d\u0005\u001d\u011e\b\u001d\n\u001d\f\u001d"+ + "\u0121\t\u001d\u0001\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0003\u001e"+ + "\u0127\b\u001e\u0001\u001f\u0001\u001f\u0001 \u0001 \u0001!\u0004!\u012e"+ + "\b!\u000b!\f!\u012f\u0001\"\u0001\"\u0001\"\u0003\"\u0135\b\"\u0001#\u0001"+ + "#\u0001#\u0001#\u0001#\u0001$\u0001$\u0001$\u0001$\u0001$\u0001$\u0001"+ + "%\u0001%\u0005%\u0144\b%\n%\f%\u0147\t%\u0001%\u0001%\u0001&\u0001&\u0001"+ + "&\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0001(\u0001(\u0001(\u0001("+ + "\u0001(\u0001)\u0001)\u0001)\u0001)\u0001*\u0001*\u0001*\u0001*\u0001"+ + "*\u0001+\u0001+\u0001+\u0001+\u0001,\u0001,\u0001,\u0001-\u0001-\u0001"+ + "-\u0001-\u0001.\u0001.\u0001/\u0001/\u0001/\u0001/\u0005/\u0172\b/\n/"+ + "\f/\u0175\t/\u00010\u00010\u00011\u00011\u00012\u00042\u017c\b2\u000b"+ + "2\f2\u017d\u00012\u00012\u00013\u00043\u0183\b3\u000b3\f3\u0184\u0001"+ + "3\u00013\u00014\u00014\u00014\u00014\u00015\u00015\u00015\u00015\u0001"+ + "6\u00016\u00017\u00017\u00018\u00018\u00019\u00019\u0001:\u0001:\u0001"+ + ";\u0001;\u0001<\u0001<\u0001=\u0001=\u0001>\u0001>\u0001?\u0001?\u0001"+ + "@\u0001@\u0001A\u0001A\u0001B\u0001B\u0001C\u0001C\u0001D\u0001D\u0001"+ + "E\u0001E\u0001F\u0001F\u0001G\u0001G\u0001H\u0001H\u0001H\u0005H\u01b8"+ + "\bH\nH\fH\u01bb\tH\u0001I\u0001I\u0001I\u0004I\u01c0\bI\u000bI\fI\u01c1"+ + "\u0001I\u0003I\u01c5\bI\u0001I\u0001I\u0001J\u0001J\u0001J\u0001J\u0001"+ + "K\u0001K\u0001L\u0001L\u0001M\u0004M\u01d2\bM\u000bM\fM\u01d3\u0001M\u0001"+ + "M\u0001N\u0004N\u01d9\bN\u000bN\fN\u01da\u0001N\u0001N\u0001O\u0001O\u0001"+ + "O\u0001O\u0001O\u0001P\u0001P\u0001P\u0001P\u0001Q\u0001Q\u0001Q\u0005"+ + "Q\u01eb\bQ\nQ\fQ\u01ee\tQ\u0001Q\u0001Q\u0001R\u0001R\u0001R\u0001R\u0001"+ + "S\u0001S\u0001S\u0001S\u0001T\u0001T\u0001T\u0001T\u0001U\u0001U\u0001"+ + "U\u0001U\u0001V\u0001V\u0001V\u0001V\u0001\u00be\u0000W\u0002\u0000\u0004"+ + "\u0000\u0006\u0000\b\u0000\n\u0000\f\u0000\u000e\u0000\u0010\u0000\u0012"+ + "\u0000\u0014\u0000\u0016\u0000\u0018\u0000\u001a\u0000\u001c\u0000\u001e"+ + "\u0000 \u0000\"\u0000$\u0000&\u0000(\u0000*\u0000,\u0000.\u00000\u0000"+ + "2\u00004\u00006\u00008\u0000:\u0000<\u0000>\u0000@\u0000B\u0000D\u0000"+ + "F\u0000H\u0000J\u0000L\u0001N\u0002P\u0003R\u0004T\u0005V\u0006X\u0007"+ + "Z\b\\\t^\n`\u000bb\fd\rf\u000eh\u000fj\u0010l\u0011n\u0012p\u0013r\u0014"+ + "t\u0015v\u0016x\u0017z\u0018|\u0019~\u001a\u0080\u001b\u0082\u001c\u0084"+ + "\u001d\u0086\u001e\u0088\u001f\u008a \u008c!\u008e\"\u0090#\u0092$\u0094"+ + "%\u0096&\u0098\u0000\u009a\u0000\u009c\'\u009e(\u00a0\u0000\u00a2\u0000"+ + "\u00a4\u0000\u00a6\u0000\u00a8\u0000\u00aa\u0000\u00ac\u0000\u00ae)\u0002"+ + "\u0000\u0001\t\u0002\u0000\t\t \u0002\u0000\n\n\f\r\r\u0000AZaz\u00c0"+ + "\u00d6\u00d8\u00f6\u00f8\u02ff\u0370\u037d\u037f\u1fff\u200c\u200d\u2070"+ + "\u218f\u2c00\u2fef\u3001\u8000\ud7ff\u8000\uf900\u8000\ufdcf\u8000\ufdf0"+ + "\u8000\ufffd\u0003\u0000\u00b7\u00b7\u0300\u036f\u203f\u2040\b\u0000\""+ + "\"\'\'\\\\bbffnnrrtt\u0004\u0000\n\n\r\r\'\'\\\\\u0004\u0000\n\n\r\r\""+ + "\"\\\\\u0003\u000009AFaf\u0001\u000009\u01fd\u0000L\u0001\u0000\u0000"+ + "\u0000\u0000N\u0001\u0000\u0000\u0000\u0000P\u0001\u0000\u0000\u0000\u0000"+ + "R\u0001\u0000\u0000\u0000\u0000T\u0001\u0000\u0000\u0000\u0000V\u0001"+ + "\u0000\u0000\u0000\u0000X\u0001\u0000\u0000\u0000\u0000Z\u0001\u0000\u0000"+ + "\u0000\u0000\\\u0001\u0000\u0000\u0000\u0000^\u0001\u0000\u0000\u0000"+ + "\u0000`\u0001\u0000\u0000\u0000\u0000b\u0001\u0000\u0000\u0000\u0000d"+ + "\u0001\u0000\u0000\u0000\u0000f\u0001\u0000\u0000\u0000\u0000h\u0001\u0000"+ + "\u0000\u0000\u0000j\u0001\u0000\u0000\u0000\u0000l\u0001\u0000\u0000\u0000"+ + "\u0000n\u0001\u0000\u0000\u0000\u0000p\u0001\u0000\u0000\u0000\u0000r"+ + "\u0001\u0000\u0000\u0000\u0000t\u0001\u0000\u0000\u0000\u0000v\u0001\u0000"+ + "\u0000\u0000\u0000x\u0001\u0000\u0000\u0000\u0000z\u0001\u0000\u0000\u0000"+ + "\u0000|\u0001\u0000\u0000\u0000\u0000~\u0001\u0000\u0000\u0000\u0000\u0080"+ + "\u0001\u0000\u0000\u0000\u0000\u0082\u0001\u0000\u0000\u0000\u0000\u0084"+ + "\u0001\u0000\u0000\u0000\u0000\u0086\u0001\u0000\u0000\u0000\u0000\u0088"+ + "\u0001\u0000\u0000\u0000\u0000\u008a\u0001\u0000\u0000\u0000\u0000\u008c"+ + "\u0001\u0000\u0000\u0000\u0000\u008e\u0001\u0000\u0000\u0000\u0000\u0090"+ + "\u0001\u0000\u0000\u0000\u0000\u0092\u0001\u0000\u0000\u0000\u0000\u0094"+ + "\u0001\u0000\u0000\u0000\u0000\u0096\u0001\u0000\u0000\u0000\u0001\u009c"+ + "\u0001\u0000\u0000\u0000\u0001\u009e\u0001\u0000\u0000\u0000\u0001\u00a0"+ + "\u0001\u0000\u0000\u0000\u0001\u00a2\u0001\u0000\u0000\u0000\u0001\u00a4"+ + "\u0001\u0000\u0000\u0000\u0001\u00a6\u0001\u0000\u0000\u0000\u0001\u00a8"+ + "\u0001\u0000\u0000\u0000\u0001\u00aa\u0001\u0000\u0000\u0000\u0001\u00ac"+ + "\u0001\u0000\u0000\u0000\u0001\u00ae\u0001\u0000\u0000\u0000\u0002\u00b2"+ + "\u0001\u0000\u0000\u0000\u0004\u00b4\u0001\u0000\u0000\u0000\u0006\u00b6"+ + "\u0001\u0000\u0000\u0000\b\u00b8\u0001\u0000\u0000\u0000\n\u00c6\u0001"+ + "\u0000\u0000\u0000\f\u00c8\u0001\u0000\u0000\u0000\u000e\u00ca\u0001\u0000"+ + "\u0000\u0000\u0010\u00cc\u0001\u0000\u0000\u0000\u0012\u00ce\u0001\u0000"+ + "\u0000\u0000\u0014\u00d0\u0001\u0000\u0000\u0000\u0016\u00d2\u0001\u0000"+ + "\u0000\u0000\u0018\u00d4\u0001\u0000\u0000\u0000\u001a\u00d6\u0001\u0000"+ + "\u0000\u0000\u001c\u00d8\u0001\u0000\u0000\u0000\u001e\u00da\u0001\u0000"+ + "\u0000\u0000 \u00dc\u0001\u0000\u0000\u0000\"\u00de\u0001\u0000\u0000"+ + "\u0000$\u00e0\u0001\u0000\u0000\u0000&\u00e2\u0001\u0000\u0000\u0000("+ + "\u00e4\u0001\u0000\u0000\u0000*\u00e6\u0001\u0000\u0000\u0000,\u00e8\u0001"+ + "\u0000\u0000\u0000.\u00eb\u0001\u0000\u0000\u00000\u00ed\u0001\u0000\u0000"+ + "\u00002\u00ef\u0001\u0000\u0000\u00004\u00fa\u0001\u0000\u0000\u00006"+ + "\u00fc\u0001\u0000\u0000\u00008\u0103\u0001\u0000\u0000\u0000:\u0110\u0001"+ + "\u0000\u0000\u0000<\u011a\u0001\u0000\u0000\u0000>\u0126\u0001\u0000\u0000"+ + "\u0000@\u0128\u0001\u0000\u0000\u0000B\u012a\u0001\u0000\u0000\u0000D"+ + "\u012d\u0001\u0000\u0000\u0000F\u0131\u0001\u0000\u0000\u0000H\u0136\u0001"+ + "\u0000\u0000\u0000J\u013b\u0001\u0000\u0000\u0000L\u0141\u0001\u0000\u0000"+ + "\u0000N\u014a\u0001\u0000\u0000\u0000P\u014d\u0001\u0000\u0000\u0000R"+ + "\u0152\u0001\u0000\u0000\u0000T\u0157\u0001\u0000\u0000\u0000V\u015b\u0001"+ + "\u0000\u0000\u0000X\u0160\u0001\u0000\u0000\u0000Z\u0164\u0001\u0000\u0000"+ + "\u0000\\\u0167\u0001\u0000\u0000\u0000^\u016b\u0001\u0000\u0000\u0000"+ + "`\u016d\u0001\u0000\u0000\u0000b\u0176\u0001\u0000\u0000\u0000d\u0178"+ + "\u0001\u0000\u0000\u0000f\u017b\u0001\u0000\u0000\u0000h\u0182\u0001\u0000"+ + "\u0000\u0000j\u0188\u0001\u0000\u0000\u0000l\u018c\u0001\u0000\u0000\u0000"+ + "n\u0190\u0001\u0000\u0000\u0000p\u0192\u0001\u0000\u0000\u0000r\u0194"+ + "\u0001\u0000\u0000\u0000t\u0196\u0001\u0000\u0000\u0000v\u0198\u0001\u0000"+ + "\u0000\u0000x\u019a\u0001\u0000\u0000\u0000z\u019c\u0001\u0000\u0000\u0000"+ + "|\u019e\u0001\u0000\u0000\u0000~\u01a0\u0001\u0000\u0000\u0000\u0080\u01a2"+ + "\u0001\u0000\u0000\u0000\u0082\u01a4\u0001\u0000\u0000\u0000\u0084\u01a6"+ + "\u0001\u0000\u0000\u0000\u0086\u01a8\u0001\u0000\u0000\u0000\u0088\u01aa"+ + "\u0001\u0000\u0000\u0000\u008a\u01ac\u0001\u0000\u0000\u0000\u008c\u01ae"+ + "\u0001\u0000\u0000\u0000\u008e\u01b0\u0001\u0000\u0000\u0000\u0090\u01b2"+ + "\u0001\u0000\u0000\u0000\u0092\u01b4\u0001\u0000\u0000\u0000\u0094\u01bc"+ + "\u0001\u0000\u0000\u0000\u0096\u01c8\u0001\u0000\u0000\u0000\u0098\u01cc"+ + "\u0001\u0000\u0000\u0000\u009a\u01ce\u0001\u0000\u0000\u0000\u009c\u01d1"+ + "\u0001\u0000\u0000\u0000\u009e\u01d8\u0001\u0000\u0000\u0000\u00a0\u01de"+ + "\u0001\u0000\u0000\u0000\u00a2\u01e3\u0001\u0000\u0000\u0000\u00a4\u01e7"+ + "\u0001\u0000\u0000\u0000\u00a6\u01f1\u0001\u0000\u0000\u0000\u00a8\u01f5"+ + "\u0001\u0000\u0000\u0000\u00aa\u01f9\u0001\u0000\u0000\u0000\u00ac\u01fd"+ + "\u0001\u0000\u0000\u0000\u00ae\u0201\u0001\u0000\u0000\u0000\u00b0\u00b3"+ + "\u0003\u0004\u0001\u0000\u00b1\u00b3\u0003\u0006\u0002\u0000\u00b2\u00b0"+ + "\u0001\u0000\u0000\u0000\u00b2\u00b1\u0001\u0000\u0000\u0000\u00b3\u0003"+ + "\u0001\u0000\u0000\u0000\u00b4\u00b5\u0007\u0000\u0000\u0000\u00b5\u0005"+ + "\u0001\u0000\u0000\u0000\u00b6\u00b7\u0007\u0001\u0000\u0000\u00b7\u0007"+ + "\u0001\u0000\u0000\u0000\u00b8\u00b9\u0005/\u0000\u0000\u00b9\u00ba\u0005"+ + "*\u0000\u0000\u00ba\u00be\u0001\u0000\u0000\u0000\u00bb\u00bd\t\u0000"+ + "\u0000\u0000\u00bc\u00bb\u0001\u0000\u0000\u0000\u00bd\u00c0\u0001\u0000"+ + "\u0000\u0000\u00be\u00bf\u0001\u0000\u0000\u0000\u00be\u00bc\u0001\u0000"+ + "\u0000\u0000\u00bf\u00c4\u0001\u0000\u0000\u0000\u00c0\u00be\u0001\u0000"+ + "\u0000\u0000\u00c1\u00c2\u0005*\u0000\u0000\u00c2\u00c5\u0005/\u0000\u0000"+ + "\u00c3\u00c5\u0005\u0000\u0000\u0001\u00c4\u00c1\u0001\u0000\u0000\u0000"+ + "\u00c4\u00c3\u0001\u0000\u0000\u0000\u00c5\t\u0001\u0000\u0000\u0000\u00c6"+ + "\u00c7\u0005\\\u0000\u0000\u00c7\u000b\u0001\u0000\u0000\u0000\u00c8\u00c9"+ + "\u0005\'\u0000\u0000\u00c9\r\u0001\u0000\u0000\u0000\u00ca\u00cb\u0005"+ + "\"\u0000\u0000\u00cb\u000f\u0001\u0000\u0000\u0000\u00cc\u00cd\u0005_"+ + "\u0000\u0000\u00cd\u0011\u0001\u0000\u0000\u0000\u00ce\u00cf\u0005,\u0000"+ + "\u0000\u00cf\u0013\u0001\u0000\u0000\u0000\u00d0\u00d1\u0005;\u0000\u0000"+ + "\u00d1\u0015\u0001\u0000\u0000\u0000\u00d2\u00d3\u0005|\u0000\u0000\u00d3"+ + "\u0017\u0001\u0000\u0000\u0000\u00d4\u00d5\u0005.\u0000\u0000\u00d5\u0019"+ + "\u0001\u0000\u0000\u0000\u00d6\u00d7\u0005(\u0000\u0000\u00d7\u001b\u0001"+ + "\u0000\u0000\u0000\u00d8\u00d9\u0005)\u0000\u0000\u00d9\u001d\u0001\u0000"+ + "\u0000\u0000\u00da\u00db\u0005[\u0000\u0000\u00db\u001f\u0001\u0000\u0000"+ + "\u0000\u00dc\u00dd\u0005]\u0000\u0000\u00dd!\u0001\u0000\u0000\u0000\u00de"+ + "\u00df\u0005*\u0000\u0000\u00df#\u0001\u0000\u0000\u0000\u00e0\u00e1\u0005"+ + "/\u0000\u0000\u00e1%\u0001\u0000\u0000\u0000\u00e2\u00e3\u0005%\u0000"+ + "\u0000\u00e3\'\u0001\u0000\u0000\u0000\u00e4\u00e5\u0005+\u0000\u0000"+ + "\u00e5)\u0001\u0000\u0000\u0000\u00e6\u00e7\u0005-\u0000\u0000\u00e7+"+ + "\u0001\u0000\u0000\u0000\u00e8\u00e9\u0005?\u0000\u0000\u00e9\u00ea\u0005"+ + "?\u0000\u0000\u00ea-\u0001\u0000\u0000\u0000\u00eb\u00ec\u0005<\u0000"+ + "\u0000\u00ec/\u0001\u0000\u0000\u0000\u00ed\u00ee\u0005>\u0000\u0000\u00ee"+ + "1\u0001\u0000\u0000\u0000\u00ef\u00f0\u0005d\u0000\u0000\u00f0\u00f1\u0005"+ + "e\u0000\u0000\u00f1\u00f2\u0005f\u0000\u0000\u00f2\u00f3\u0005a\u0000"+ + "\u0000\u00f3\u00f4\u0005u\u0000\u0000\u00f4\u00f5\u0005l\u0000\u0000\u00f5"+ + "\u00f6\u0005t\u0000\u0000\u00f63\u0001\u0000\u0000\u0000\u00f7\u00fb\u0007"+ + "\u0002\u0000\u0000\u00f8\u00fb\u0003\u0010\u0007\u0000\u00f9\u00fb\u0007"+ + "\u0003\u0000\u0000\u00fa\u00f7\u0001\u0000\u0000\u0000\u00fa\u00f8\u0001"+ + "\u0000\u0000\u0000\u00fa\u00f9\u0001\u0000\u0000\u0000\u00fb5\u0001\u0000"+ + "\u0000\u0000\u00fc\u0101\u0003\n\u0004\u0000\u00fd\u0102\u0007\u0004\u0000"+ + "\u0000\u00fe\u0102\u00038\u001b\u0000\u00ff\u0102\t\u0000\u0000\u0000"+ + "\u0100\u0102\u0005\u0000\u0000\u0001\u0101\u00fd\u0001\u0000\u0000\u0000"+ + "\u0101\u00fe\u0001\u0000\u0000\u0000\u0101\u00ff\u0001\u0000\u0000\u0000"+ + "\u0101\u0100\u0001\u0000\u0000\u0000\u01027\u0001\u0000\u0000\u0000\u0103"+ + "\u010e\u0005u\u0000\u0000\u0104\u010c\u0003@\u001f\u0000\u0105\u010a\u0003"+ + "@\u001f\u0000\u0106\u0108\u0003@\u001f\u0000\u0107\u0109\u0003@\u001f"+ + "\u0000\u0108\u0107\u0001\u0000\u0000\u0000\u0108\u0109\u0001\u0000\u0000"+ + "\u0000\u0109\u010b\u0001\u0000\u0000\u0000\u010a\u0106\u0001\u0000\u0000"+ + "\u0000\u010a\u010b\u0001\u0000\u0000\u0000\u010b\u010d\u0001\u0000\u0000"+ + "\u0000\u010c\u0105\u0001\u0000\u0000\u0000\u010c\u010d\u0001\u0000\u0000"+ + "\u0000\u010d\u010f\u0001\u0000\u0000\u0000\u010e\u0104\u0001\u0000\u0000"+ + "\u0000\u010e\u010f\u0001\u0000\u0000\u0000\u010f9\u0001\u0000\u0000\u0000"+ + "\u0110\u0115\u0003\f\u0005\u0000\u0111\u0114\u00036\u001a\u0000\u0112"+ + "\u0114\b\u0005\u0000\u0000\u0113\u0111\u0001\u0000\u0000\u0000\u0113\u0112"+ + "\u0001\u0000\u0000\u0000\u0114\u0117\u0001\u0000\u0000\u0000\u0115\u0113"+ + "\u0001\u0000\u0000\u0000\u0115\u0116\u0001\u0000\u0000\u0000\u0116\u0118"+ + "\u0001\u0000\u0000\u0000\u0117\u0115\u0001\u0000\u0000\u0000\u0118\u0119"+ + "\u0003\f\u0005\u0000\u0119;\u0001\u0000\u0000\u0000\u011a\u011f\u0003"+ + "\u000e\u0006\u0000\u011b\u011e\u00036\u001a\u0000\u011c\u011e\b\u0006"+ + "\u0000\u0000\u011d\u011b\u0001\u0000\u0000\u0000\u011d\u011c\u0001\u0000"+ + "\u0000\u0000\u011e\u0121\u0001\u0000\u0000\u0000\u011f\u011d\u0001\u0000"+ + "\u0000\u0000\u011f\u0120\u0001\u0000\u0000\u0000\u0120\u0122\u0001\u0000"+ + "\u0000\u0000\u0121\u011f\u0001\u0000\u0000\u0000\u0122\u0123\u0003\u000e"+ + "\u0006\u0000\u0123=\u0001\u0000\u0000\u0000\u0124\u0127\u0003H#\u0000"+ + "\u0125\u0127\u0003J$\u0000\u0126\u0124\u0001\u0000\u0000\u0000\u0126\u0125"+ + "\u0001\u0000\u0000\u0000\u0127?\u0001\u0000\u0000\u0000\u0128\u0129\u0007"+ + "\u0007\u0000\u0000\u0129A\u0001\u0000\u0000\u0000\u012a\u012b\u0007\b"+ + "\u0000\u0000\u012bC\u0001\u0000\u0000\u0000\u012c\u012e\u0003B \u0000"+ + "\u012d\u012c\u0001\u0000\u0000\u0000\u012e\u012f\u0001\u0000\u0000\u0000"+ + "\u012f\u012d\u0001\u0000\u0000\u0000\u012f\u0130\u0001\u0000\u0000\u0000"+ + "\u0130E\u0001\u0000\u0000\u0000\u0131\u0132\u0003D!\u0000\u0132\u0134"+ + "\u0003\u0018\u000b\u0000\u0133\u0135\u0003D!\u0000\u0134\u0133\u0001\u0000"+ + "\u0000\u0000\u0134\u0135\u0001\u0000\u0000\u0000\u0135G\u0001\u0000\u0000"+ + "\u0000\u0136\u0137\u0005t\u0000\u0000\u0137\u0138\u0005r\u0000\u0000\u0138"+ + "\u0139\u0005u\u0000\u0000\u0139\u013a\u0005e\u0000\u0000\u013aI\u0001"+ + "\u0000\u0000\u0000\u013b\u013c\u0005f\u0000\u0000\u013c\u013d\u0005a\u0000"+ + "\u0000\u013d\u013e\u0005l\u0000\u0000\u013e\u013f\u0005s\u0000\u0000\u013f"+ + "\u0140\u0005e\u0000\u0000\u0140K\u0001\u0000\u0000\u0000\u0141\u0145\u0003"+ + "\u0016\n\u0000\u0142\u0144\u0003\u0004\u0001\u0000\u0143\u0142\u0001\u0000"+ + "\u0000\u0000\u0144\u0147\u0001\u0000\u0000\u0000\u0145\u0143\u0001\u0000"+ + "\u0000\u0000\u0145\u0146\u0001\u0000\u0000\u0000\u0146\u0148\u0001\u0000"+ + "\u0000\u0000\u0147\u0145\u0001\u0000\u0000\u0000\u0148\u0149\u00032\u0018"+ + "\u0000\u0149M\u0001\u0000\u0000\u0000\u014a\u014b\u0005i\u0000\u0000\u014b"+ + "\u014c\u0005f\u0000\u0000\u014cO\u0001\u0000\u0000\u0000\u014d\u014e\u0005"+ + "t\u0000\u0000\u014e\u014f\u0005h\u0000\u0000\u014f\u0150\u0005e\u0000"+ + "\u0000\u0150\u0151\u0005n\u0000\u0000\u0151Q\u0001\u0000\u0000\u0000\u0152"+ + "\u0153\u0005e\u0000\u0000\u0153\u0154\u0005l\u0000\u0000\u0154\u0155\u0005"+ + "s\u0000\u0000\u0155\u0156\u0005e\u0000\u0000\u0156S\u0001\u0000\u0000"+ + "\u0000\u0157\u0158\u0005e\u0000\u0000\u0158\u0159\u0005n\u0000\u0000\u0159"+ + "\u015a\u0005d\u0000\u0000\u015aU\u0001\u0000\u0000\u0000\u015b\u015c\u0005"+ + "w\u0000\u0000\u015c\u015d\u0005i\u0000\u0000\u015d\u015e\u0005t\u0000"+ + "\u0000\u015e\u015f\u0005h\u0000\u0000\u015fW\u0001\u0000\u0000\u0000\u0160"+ + "\u0161\u0005a\u0000\u0000\u0161\u0162\u0005n\u0000\u0000\u0162\u0163\u0005"+ + "d\u0000\u0000\u0163Y\u0001\u0000\u0000\u0000\u0164\u0165\u0005o\u0000"+ + "\u0000\u0165\u0166\u0005r\u0000\u0000\u0166[\u0001\u0000\u0000\u0000\u0167"+ + "\u0168\u0005n\u0000\u0000\u0168\u0169\u0005o\u0000\u0000\u0169\u016a\u0005"+ + "t\u0000\u0000\u016a]\u0001\u0000\u0000\u0000\u016b\u016c\u0005!\u0000"+ + "\u0000\u016c_\u0001\u0000\u0000\u0000\u016d\u016e\u0005$\u0000\u0000\u016e"+ + "\u0173\u00034\u0019\u0000\u016f\u0172\u00034\u0019\u0000\u0170\u0172\u0003"+ + "B \u0000\u0171\u016f\u0001\u0000\u0000\u0000\u0171\u0170\u0001\u0000\u0000"+ + "\u0000\u0172\u0175\u0001\u0000\u0000\u0000\u0173\u0171\u0001\u0000\u0000"+ + "\u0000\u0173\u0174\u0001\u0000\u0000\u0000\u0174a\u0001\u0000\u0000\u0000"+ + "\u0175\u0173\u0001\u0000\u0000\u0000\u0176\u0177\u0005$\u0000\u0000\u0177"+ + "c\u0001\u0000\u0000\u0000\u0178\u0179\u0003\b\u0003\u0000\u0179e\u0001"+ + "\u0000\u0000\u0000\u017a\u017c\u0003\u0004\u0001\u0000\u017b\u017a\u0001"+ + "\u0000\u0000\u0000\u017c\u017d\u0001\u0000\u0000\u0000\u017d\u017b\u0001"+ + "\u0000\u0000\u0000\u017d\u017e\u0001\u0000\u0000\u0000\u017e\u017f\u0001"+ + "\u0000\u0000\u0000\u017f\u0180\u00062\u0000\u0000\u0180g\u0001\u0000\u0000"+ + "\u0000\u0181\u0183\u0003\u0006\u0002\u0000\u0182\u0181\u0001\u0000\u0000"+ + "\u0000\u0183\u0184\u0001\u0000\u0000\u0000\u0184\u0182\u0001\u0000\u0000"+ + "\u0000\u0184\u0185\u0001\u0000\u0000\u0000\u0185\u0186\u0001\u0000\u0000"+ + "\u0000\u0186\u0187\u00063\u0000\u0000\u0187i\u0001\u0000\u0000\u0000\u0188"+ + "\u0189\u0003\u0098K\u0000\u0189\u018a\u0001\u0000\u0000\u0000\u018a\u018b"+ + "\u00064\u0001\u0000\u018bk\u0001\u0000\u0000\u0000\u018c\u018d\u0003\u009a"+ + "L\u0000\u018d\u018e\u0001\u0000\u0000\u0000\u018e\u018f\u00065\u0002\u0000"+ + "\u018fm\u0001\u0000\u0000\u0000\u0190\u0191\u0003\u0018\u000b\u0000\u0191"+ + "o\u0001\u0000\u0000\u0000\u0192\u0193\u0003\u001a\f\u0000\u0193q\u0001"+ + "\u0000\u0000\u0000\u0194\u0195\u0003\u001c\r\u0000\u0195s\u0001\u0000"+ + "\u0000\u0000\u0196\u0197\u0003\u001e\u000e\u0000\u0197u\u0001\u0000\u0000"+ + "\u0000\u0198\u0199\u0003 \u000f\u0000\u0199w\u0001\u0000\u0000\u0000\u019a"+ + "\u019b\u0003,\u0015\u0000\u019by\u0001\u0000\u0000\u0000\u019c\u019d\u0003"+ + "\u0014\t\u0000\u019d{\u0001\u0000\u0000\u0000\u019e\u019f\u0003\u0012"+ + "\b\u0000\u019f}\u0001\u0000\u0000\u0000\u01a0\u01a1\u0003\"\u0010\u0000"+ + "\u01a1\u007f\u0001\u0000\u0000\u0000\u01a2\u01a3\u0003$\u0011\u0000\u01a3"+ + "\u0081\u0001\u0000\u0000\u0000\u01a4\u01a5\u0003&\u0012\u0000\u01a5\u0083"+ + "\u0001\u0000\u0000\u0000\u01a6\u01a7\u0003(\u0013\u0000\u01a7\u0085\u0001"+ + "\u0000\u0000\u0000\u01a8\u01a9\u0003*\u0014\u0000\u01a9\u0087\u0001\u0000"+ + "\u0000\u0000\u01aa\u01ab\u0003<\u001d\u0000\u01ab\u0089\u0001\u0000\u0000"+ + "\u0000\u01ac\u01ad\u0003:\u001c\u0000\u01ad\u008b\u0001\u0000\u0000\u0000"+ + "\u01ae\u01af\u0003D!\u0000\u01af\u008d\u0001\u0000\u0000\u0000\u01b0\u01b1"+ + "\u0003F\"\u0000\u01b1\u008f\u0001\u0000\u0000\u0000\u01b2\u01b3\u0003"+ + ">\u001e\u0000\u01b3\u0091\u0001\u0000\u0000\u0000\u01b4\u01b9\u00034\u0019"+ + "\u0000\u01b5\u01b8\u00034\u0019\u0000\u01b6\u01b8\u0003B \u0000\u01b7"+ + "\u01b5\u0001\u0000\u0000\u0000\u01b7\u01b6\u0001\u0000\u0000\u0000\u01b8"+ + "\u01bb\u0001\u0000\u0000\u0000\u01b9\u01b7\u0001\u0000\u0000\u0000\u01b9"+ + "\u01ba\u0001\u0000\u0000\u0000\u01ba\u0093\u0001\u0000\u0000\u0000\u01bb"+ + "\u01b9\u0001\u0000\u0000\u0000\u01bc\u01bf\u0003.\u0016\u0000\u01bd\u01c0"+ + "\u00034\u0019\u0000\u01be\u01c0\u0003n6\u0000\u01bf\u01bd\u0001\u0000"+ + "\u0000\u0000\u01bf\u01be\u0001\u0000\u0000\u0000\u01c0\u01c1\u0001\u0000"+ + "\u0000\u0000\u01c1\u01bf\u0001\u0000\u0000\u0000\u01c1\u01c2\u0001\u0000"+ + "\u0000\u0000\u01c2\u01c4\u0001\u0000\u0000\u0000\u01c3\u01c5\u0003\u0094"+ + "I\u0000\u01c4\u01c3\u0001\u0000\u0000\u0000\u01c4\u01c5\u0001\u0000\u0000"+ + "\u0000\u01c5\u01c6\u0001\u0000\u0000\u0000\u01c6\u01c7\u00030\u0017\u0000"+ + "\u01c7\u0095\u0001\u0000\u0000\u0000\u01c8\u01c9\u0003\u0004\u0001\u0000"+ + "\u01c9\u01ca\u0001\u0000\u0000\u0000\u01ca\u01cb\u0006J\u0000\u0000\u01cb"+ + "\u0097\u0001\u0000\u0000\u0000\u01cc\u01cd\u0005{\u0000\u0000\u01cd\u0099"+ + "\u0001\u0000\u0000\u0000\u01ce\u01cf\u0005}\u0000\u0000\u01cf\u009b\u0001"+ + "\u0000\u0000\u0000\u01d0\u01d2\u0003\u0004\u0001\u0000\u01d1\u01d0\u0001"+ + "\u0000\u0000\u0000\u01d2\u01d3\u0001\u0000\u0000\u0000\u01d3\u01d1\u0001"+ + "\u0000\u0000\u0000\u01d3\u01d4\u0001\u0000\u0000\u0000\u01d4\u01d5\u0001"+ + "\u0000\u0000\u0000\u01d5\u01d6\u0006M\u0000\u0000\u01d6\u009d\u0001\u0000"+ + "\u0000\u0000\u01d7\u01d9\u0003\u0006\u0002\u0000\u01d8\u01d7\u0001\u0000"+ + "\u0000\u0000\u01d9\u01da\u0001\u0000\u0000\u0000\u01da\u01d8\u0001\u0000"+ + "\u0000\u0000\u01da\u01db\u0001\u0000\u0000\u0000\u01db\u01dc\u0001\u0000"+ + "\u0000\u0000\u01dc\u01dd\u0006N\u0000\u0000\u01dd\u009f\u0001\u0000\u0000"+ + "\u0000\u01de\u01df\u0003\u009aL\u0000\u01df\u01e0\u0001\u0000\u0000\u0000"+ + "\u01e0\u01e1\u0006O\u0002\u0000\u01e1\u01e2\u0006O\u0003\u0000\u01e2\u00a1"+ + "\u0001\u0000\u0000\u0000\u01e3\u01e4\u0003\u0012\b\u0000\u01e4\u01e5\u0001"+ + "\u0000\u0000\u0000\u01e5\u01e6\u0006P\u0004\u0000\u01e6\u00a3\u0001\u0000"+ + "\u0000\u0000\u01e7\u01ec\u00034\u0019\u0000\u01e8\u01eb\u00034\u0019\u0000"+ + "\u01e9\u01eb\u0003B \u0000\u01ea\u01e8\u0001\u0000\u0000\u0000\u01ea\u01e9"+ + "\u0001\u0000\u0000\u0000\u01eb\u01ee\u0001\u0000\u0000\u0000\u01ec\u01ea"+ + "\u0001\u0000\u0000\u0000\u01ec\u01ed\u0001\u0000\u0000\u0000\u01ed\u01ef"+ + "\u0001\u0000\u0000\u0000\u01ee\u01ec\u0001\u0000\u0000\u0000\u01ef\u01f0"+ + "\u0006Q\u0005\u0000\u01f0\u00a5\u0001\u0000\u0000\u0000\u01f1\u01f2\u0003"+ + "<\u001d\u0000\u01f2\u01f3\u0001\u0000\u0000\u0000\u01f3\u01f4\u0006R\u0006"+ + "\u0000\u01f4\u00a7\u0001\u0000\u0000\u0000\u01f5\u01f6\u0003:\u001c\u0000"+ + "\u01f6\u01f7\u0001\u0000\u0000\u0000\u01f7\u01f8\u0006S\u0007\u0000\u01f8"+ + "\u00a9\u0001\u0000\u0000\u0000\u01f9\u01fa\u0003D!\u0000\u01fa\u01fb\u0001"+ + "\u0000\u0000\u0000\u01fb\u01fc\u0006T\b\u0000\u01fc\u00ab\u0001\u0000"+ + "\u0000\u0000\u01fd\u01fe\u0003F\"\u0000\u01fe\u01ff\u0001\u0000\u0000"+ + "\u0000\u01ff\u0200\u0006U\t\u0000\u0200\u00ad\u0001\u0000\u0000\u0000"+ + "\u0201\u0202\u0007\u0000\u0000\u0000\u0202\u0203\u0001\u0000\u0000\u0000"+ + "\u0203\u0204\u0006V\u0000\u0000\u0204\u00af\u0001\u0000\u0000\u0000 \u0000"+ + "\u0001\u00b2\u00be\u00c4\u00fa\u0101\u0108\u010a\u010c\u010e\u0113\u0115"+ + "\u011d\u011f\u0126\u012f\u0134\u0145\u0171\u0173\u017d\u0184\u01b7\u01b9"+ + "\u01bf\u01c1\u01c4\u01d3\u01da\u01ea\u01ec\n\u0006\u0000\u0000\u0005\u0001"+ + "\u0000\u0004\u0000\u0000\u0007\u0011\u0000\u0007\u0019\u0000\u0007$\u0000"+ + "\u0007\u001f\u0000\u0007 \u0000\u0007!\u0000\u0007\"\u0000"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateLexerExpression.tokens b/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateLexerExpression.tokens index d384822c9..c45df57c8 100644 --- a/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateLexerExpression.tokens +++ b/oap-formats/oap-template/src/main/java-antlr-generated/oap/template/TemplateLexerExpression.tokens @@ -4,40 +4,48 @@ THEN=3 ELSE=4 END=5 WITH=6 -VAR_ID=7 -ROOT=8 -BLOCK_COMMENT=9 -HORZ_WS=10 -VERT_WS=11 -LBRACE=12 -RBRACE=13 -DOT=14 -LPAREN=15 -RPAREN=16 -LBRACK=17 -RBRACK=18 -DQUESTION=19 -SEMI=20 -COMMA=21 -STAR=22 -SLASH=23 -PERCENT=24 -PLUS=25 -MINUS=26 -DSTRING=27 -SSTRING=28 -DECDIGITS=29 -FLOAT=30 -BOOLEAN=31 -ID=32 -CAST_TYPE=33 -ERR_CHAR=34 -C_HORZ_WS=35 -C_VERT_WS=36 -CERR_CHAR=37 +AND=7 +OR=8 +NOT=9 +BANG=10 +VAR_ID=11 +ROOT=12 +BLOCK_COMMENT=13 +HORZ_WS=14 +VERT_WS=15 +LBRACE=16 +RBRACE=17 +DOT=18 +LPAREN=19 +RPAREN=20 +LBRACK=21 +RBRACK=22 +DQUESTION=23 +SEMI=24 +COMMA=25 +STAR=26 +SLASH=27 +PERCENT=28 +PLUS=29 +MINUS=30 +DSTRING=31 +SSTRING=32 +DECDIGITS=33 +FLOAT=34 +BOOLEAN=35 +ID=36 +CAST_TYPE=37 +ERR_CHAR=38 +C_HORZ_WS=39 +C_VERT_WS=40 +CERR_CHAR=41 'if'=2 'then'=3 'else'=4 'end'=5 'with'=6 -'$'=8 +'and'=7 +'or'=8 +'not'=9 +'!'=10 +'$'=12 diff --git a/oap-formats/oap-template/src/main/java/oap/template/RuntimeTemplate.java b/oap-formats/oap-template/src/main/java/oap/template/RuntimeTemplate.java new file mode 100644 index 000000000..69f4fcdea --- /dev/null +++ b/oap-formats/oap-template/src/main/java/oap/template/RuntimeTemplate.java @@ -0,0 +1,72 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) Open Application Platform Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package oap.template; + +import oap.template.render.AstRenderRoot; +import oap.template.runtime.RuntimeContext; + +/** + * A {@link Template} implementation that interprets the AST directly at runtime + * using Java reflection — no code generation or compilation required. + * + *

Use {@link TemplateEngine#getRuntimeTemplate} to obtain an instance. + */ +public class RuntimeTemplate> + implements Template { + + private final TA acc; + private final AstRenderRoot ast; + + public RuntimeTemplate( TA acc, AstRenderRoot ast ) { + this.acc = acc; + this.ast = ast; + } + + @Override + public TA render( TIn obj, boolean eol ) { + TA newAcc = acc.newInstance(); + try { + ast.interpret( RuntimeContext.root( obj, newAcc ) ); + } catch( TemplateException e ) { + throw e; + } catch( Exception e ) { + throw new TemplateException( e ); + } + return newAcc.addEol( eol ); + } + + @Override + public TA render( TIn obj, boolean eol, TOutMutable tOut ) { + TA newAcc = acc.newInstance( tOut ); + try { + ast.interpret( RuntimeContext.root( obj, newAcc ) ); + } catch( TemplateException e ) { + throw e; + } catch( Exception e ) { + throw new TemplateException( e ); + } + return newAcc.addEol( eol ); + } +} diff --git a/oap-formats/oap-template/src/main/java/oap/template/TemplateConditionHelper.java b/oap-formats/oap-template/src/main/java/oap/template/TemplateConditionHelper.java new file mode 100644 index 000000000..0ed3ff089 --- /dev/null +++ b/oap-formats/oap-template/src/main/java/oap/template/TemplateConditionHelper.java @@ -0,0 +1,44 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) Open Application Platform Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package oap.template; + +import javax.annotation.Nullable; +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.Map; + +public final class TemplateConditionHelper { + private TemplateConditionHelper() {} + + public static boolean isTruthy( @Nullable Object value ) { + if( value == null ) return false; + if( value instanceof Boolean b ) return b; + if( value instanceof String s ) return !s.isEmpty(); + if( value instanceof Collection c ) return !c.isEmpty(); + if( value instanceof Map m ) return !m.isEmpty(); + if( value.getClass().isArray() ) return Array.getLength( value ) > 0; + return true; + } +} diff --git a/oap-formats/oap-template/src/main/java/oap/template/TemplateEngine.java b/oap-formats/oap-template/src/main/java/oap/template/TemplateEngine.java index 46eda98d7..bbc8312b8 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/TemplateEngine.java +++ b/oap-formats/oap-template/src/main/java/oap/template/TemplateEngine.java @@ -216,6 +216,59 @@ private void loadFunctions() { } } + public > Template + getRuntimeTemplate( String name, TypeRef type, String template, TA acc ) { + return getRuntimeTemplate( name, type, template, acc, Map.of(), ErrorStrategy.ERROR, null ); + } + + public > Template + getRuntimeTemplate( String name, TypeRef type, String template, TA acc, Consumer postProcess ) { + return getRuntimeTemplate( name, type, template, acc, Map.of(), ErrorStrategy.ERROR, postProcess ); + } + + public > Template + getRuntimeTemplate( String name, TypeRef type, String template, TA acc, Map aliases, Consumer postProcess ) { + return getRuntimeTemplate( name, type, template, acc, aliases, ErrorStrategy.ERROR, postProcess ); + } + + public > Template + getRuntimeTemplate( String name, TypeRef type, String template, TA acc, ErrorStrategy errorStrategy, Consumer postProcess ) { + return getRuntimeTemplate( name, type, template, acc, Map.of(), errorStrategy, postProcess ); + } + + public > Template + getRuntimeTemplate( String name, TypeRef type, String template, TA acc, Map aliases, ErrorStrategy errorStrategy ) { + return getRuntimeTemplate( name, type, template, acc, aliases, errorStrategy, null ); + } + + @SuppressWarnings( "unchecked" ) + public > Template + getRuntimeTemplate( String name, TypeRef type, String template, TA acc, + Map aliases, ErrorStrategy errorStrategy, Consumer postProcess ) { + Objects.requireNonNull( template ); + Objects.requireNonNull( acc ); + + try { + TemplateLexer lexer = new TemplateLexer( CharStreams.fromString( template ) ); + TemplateGrammar grammar = new TemplateGrammar( new BufferedTokenStream( lexer ), builtInFunction, errorStrategy ); + if( errorStrategy == ErrorStrategy.ERROR ) { + lexer.addErrorListener( ThrowingErrorListener.INSTANCE ); + grammar.addErrorListener( ThrowingErrorListener.INSTANCE ); + } + Elements elements = grammar.elements( aliases ).ret; + + AstRenderRoot ast = TemplateAstUtils.toAst( elements, new TemplateType( type.type() ), builtInFunction, errorStrategy ); + + if( postProcess != null ) postProcess.accept( ast ); + + return new RuntimeTemplate<>( acc, ast ); + } catch( TemplateException e ) { + throw e; + } catch( Exception e ) { + throw new TemplateException( e ); + } + } + public long getCacheSize() { return templates.size(); } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRender.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRender.java index 27a6ce296..24c6678a8 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRender.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRender.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; import java.util.ArrayList; import java.util.List; @@ -41,6 +42,9 @@ public AstRender( TemplateType type ) { public abstract void render( Render render ); + /** Interpret this node against the live context, writing output to {@code ctx.acc}. */ + public abstract void interpret( RuntimeContext ctx ); + public void addChild( AstRender astRender ) { children.add( astRender ); } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBlockIf.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBlockIf.java index f82ef81a2..7db7a1099 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBlockIf.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBlockIf.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; import javax.annotation.Nullable; import java.util.List; @@ -71,4 +72,15 @@ public void render( Render render ) { render.ntab().append( "}" ); } } + + @Override + public void interpret( RuntimeContext ctx ) { + boolean[] capture = { false }; + conditionAst.interpret( ctx.withBooleanCapture( capture ) ); + if( capture[0] ) { + thenChildren.forEach( c -> c.interpret( ctx ) ); + } else if( elseChildren != null ) { + elseChildren.forEach( c -> c.interpret( ctx ) ); + } + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBlockRange.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBlockRange.java index e0f8d0d20..45b3053f8 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBlockRange.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBlockRange.java @@ -25,9 +25,12 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; import javax.annotation.Nullable; +import java.util.Collection; import java.util.List; +import java.util.Map; /** * Block range over a collection or map. @@ -148,4 +151,62 @@ private void renderMap( Render render, Render outerRender, String collVar ) { for( AstRender child : bodyChildren ) child.render( bodyRender ); outerRender.ntab().append( "}" ); } + + @Override + @SuppressWarnings( "unchecked" ) + public void interpret( RuntimeContext ctx ) { + Object[] capture = { null }; + collectionAst.interpret( ctx.withScopeCapture( capture ) ); + Object coll = capture[0]; + + boolean nonEmpty = mode == Mode.MAP_KEY_VALUE + ? ( coll instanceof Map m && !m.isEmpty() ) + : ( coll instanceof Collection c && !c.isEmpty() ); + + if( nonEmpty ) { + if( mode == Mode.MAP_KEY_VALUE ) { + interpretMap( ctx, ( Map ) coll ); + } else if( mode == Mode.IMPLICIT_SCOPE ) { + interpretImplicit( ctx, ( Collection ) coll ); + } else if( mode == Mode.NAMED_INDEX_ITEM ) { + interpretIndexItem( ctx, ( Collection ) coll ); + } else { + interpretNamedItem( ctx, ( Collection ) coll ); + } + } else if( elseChildren != null ) { + elseChildren.forEach( c -> c.interpret( ctx ) ); + } + } + + private void interpretImplicit( RuntimeContext ctx, Collection coll ) { + for( Object item : coll ) { + RuntimeContext inner = ctx.withCurrentObject( item ); + bodyChildren.forEach( c -> c.interpret( inner ) ); + } + } + + private void interpretNamedItem( RuntimeContext ctx, Collection coll ) { + for( Object item : coll ) { + RuntimeContext inner = ctx.withRangeVar( itemVarName, item ); + bodyChildren.forEach( c -> c.interpret( inner ) ); + } + } + + private void interpretIndexItem( RuntimeContext ctx, Collection coll ) { + int idx = 0; + for( Object item : coll ) { + RuntimeContext inner = ctx.withRangeVar( indexOrKeyVarName, idx ).withRangeVar( itemVarName, item ); + bodyChildren.forEach( c -> c.interpret( inner ) ); + idx++; + } + } + + private void interpretMap( RuntimeContext ctx, Map map ) { + for( Map.Entry entry : map.entrySet() ) { + RuntimeContext inner = ctx + .withRangeVar( indexOrKeyVarName, entry.getKey() ) + .withRangeVar( itemVarName, entry.getValue() ); + bodyChildren.forEach( c -> c.interpret( inner ) ); + } + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBlockRangeInterval.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBlockRangeInterval.java index 9901f83de..39b0979a9 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBlockRangeInterval.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBlockRangeInterval.java @@ -25,6 +25,8 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.ReflectionCache; +import oap.template.runtime.RuntimeContext; import javax.annotation.Nullable; import java.util.List; @@ -88,4 +90,22 @@ public void render( Render render ) { render.ntab().append( "}" ); } + + @Override + public void interpret( RuntimeContext ctx ) { + int fromVal = resolveInt( from, ctx ); + int toVal = resolveInt( to, ctx ); + int stepVal = resolveInt( step, ctx ); + for( int k = fromVal; k <= toVal; k += stepVal ) { + RuntimeContext inner = ctx.withRangeVar( varName, k ); + bodyChildren.forEach( c -> c.interpret( inner ) ); + } + } + + private static int resolveInt( IntRangeValue v, RuntimeContext ctx ) { + if( v instanceof IntRangeValue.Literal lit ) return lit.value(); + IntRangeValue.Field fv = ( IntRangeValue.Field ) v; + Object val = ReflectionCache.getFieldValue( ctx.currentObject, fv.fieldName() ); + return val instanceof Number n ? n.intValue() : Integer.parseInt( String.valueOf( val ) ); + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBlockWith.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBlockWith.java index f36f7a6c3..e33b15fda 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBlockWith.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBlockWith.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; import java.util.List; @@ -55,4 +56,12 @@ public void render( Render render ) { child.render( bodyRender ); } } + + @Override + public void interpret( RuntimeContext ctx ) { + Object[] capture = { null }; + scopeAst.interpret( ctx.withScopeCapture( capture ) ); + RuntimeContext bodyCtx = ctx.withCurrentObject( capture[0] ); + bodyChildren.forEach( c -> c.interpret( bodyCtx ) ); + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBooleanIf.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBooleanIf.java index 4c8eb8ef0..7b2ec14a0 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBooleanIf.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderBooleanIf.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; import javax.annotation.Nullable; @@ -65,4 +66,15 @@ public void render( Render render ) { render.ntab().append( "}" ); } } + + @Override + public void interpret( RuntimeContext ctx ) { + boolean[] capture = { false }; + conditionAst.interpret( ctx.withBooleanCapture( capture ) ); + if( capture[0] ) { + thenCode.interpret( ctx ); + } else if( elseCode != null ) { + elseCode.interpret( ctx ); + } + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderCaptureBoolean.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderCaptureBoolean.java index 9c6f1848d..246c8b1c3 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderCaptureBoolean.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderCaptureBoolean.java @@ -25,11 +25,25 @@ package oap.template.render; import lombok.ToString; +import oap.template.TemplateConditionHelper; +import oap.template.runtime.RuntimeContext; + +import java.util.Collection; +import java.util.Map; /** - * Leaf node for the condition path in AstRenderBooleanIf. - * Assigns render.field (the resolved boolean variable) into render.booleanIfVar - * (the hoisted variable declared by AstRenderBooleanIf). + * Leaf node for the condition path in AstRenderBooleanIf / AstRenderBlockIf. + * Evaluates the current field value as a boolean condition and writes the result + * into render.booleanIfVar (codegen) or ctx.booleanCapture (interpreter). + *

+ * Truthiness rules: + *

    + *
  • {@code boolean} / {@code Boolean} — the value itself
  • + *
  • {@code String} — not empty
  • + *
  • {@code Collection} / {@code Map} — not empty
  • + *
  • array — length > 0
  • + *
  • any other non-null object — true
  • + *
*/ @ToString( callSuper = true ) class AstRenderCaptureBoolean extends AstRender { @@ -39,6 +53,27 @@ class AstRenderCaptureBoolean extends AstRender { @Override public void render( Render render ) { - render.ntab().append( "%s = %s;", render.booleanIfVar, render.field ); + Class tc = type.getTypeClass(); + if( boolean.class.equals( tc ) ) { + render.ntab().append( "%s = %s;", render.booleanIfVar, render.field ); + } else if( Boolean.class.equals( tc ) ) { + render.ntab().append( "%s = Boolean.TRUE.equals( %s );", render.booleanIfVar, render.field ); + } else if( String.class.equals( tc ) ) { + render.ntab().append( "%s = !%s.isEmpty();", render.booleanIfVar, render.field ); + } else if( Collection.class.isAssignableFrom( tc ) || Map.class.isAssignableFrom( tc ) ) { + render.ntab().append( "%s = !%s.isEmpty();", render.booleanIfVar, render.field ); + } else if( tc.isArray() ) { + render.ntab().append( "%s = %s.length > 0;", render.booleanIfVar, render.field ); + } else { + render.ntab().append( "%s = oap.template.TemplateConditionHelper.isTruthy( %s );", + render.booleanIfVar, render.field ); + } + } + + @Override + public void interpret( RuntimeContext ctx ) { + if( ctx.booleanCapture != null ) { + ctx.booleanCapture[0] = TemplateConditionHelper.isTruthy( ctx.currentObject ); + } } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderCaptureScope.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderCaptureScope.java index 9317c6838..e4b9aac1d 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderCaptureScope.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderCaptureScope.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; /** * Leaf node for the scope path in AstRenderWith / AstRenderBlockWith. @@ -40,4 +41,9 @@ class AstRenderCaptureScope extends AstRender { public void render( Render render ) { render.ntab().append( "%s = %s;", render.scopeVar, render.field ); } + + @Override + public void interpret( RuntimeContext ctx ) { + if( ctx.scopeCapture != null ) ctx.scopeCapture[0] = ctx.currentObject; + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderComment.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderComment.java index 7e86653a1..307328077 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderComment.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderComment.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; @ToString( callSuper = true ) class AstRenderComment extends AstRender { @@ -42,4 +43,9 @@ public void render( Render render ) { children.forEach( a -> a.render( render ) ); } + + @Override + public void interpret( RuntimeContext ctx ) { + children.forEach( c -> c.interpret( ctx ) ); + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderConcatenation.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderConcatenation.java index 3f1d1a2cb..45e71ff2a 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderConcatenation.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderConcatenation.java @@ -26,6 +26,8 @@ import lombok.ToString; import oap.template.TemplateAccumulator; +import oap.template.TemplateAccumulatorString; +import oap.template.runtime.RuntimeContext; import java.util.ArrayList; import java.util.List; @@ -54,6 +56,17 @@ public void render( Render render ) { children.forEach( a -> a.render( newRender ) ); } + @Override + @SuppressWarnings( { "unchecked", "rawtypes" } ) + public void interpret( RuntimeContext ctx ) { + TemplateAccumulatorString subAcc = new TemplateAccumulatorString(); + RuntimeContext subCtx = ctx.withAcc( subAcc ); + for( AstRender item : items ) item.interpret( subCtx ); + RuntimeContext nextCtx = ctx.withCurrentObject( subAcc ) + .withAcc( ctx.acc ); + children.forEach( c -> c.interpret( nextCtx ) ); + } + @Override public void print( StringBuilder buffer, String prefix, String childrenPrefix ) { printTop( buffer, prefix ); diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderConditionAnd.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderConditionAnd.java new file mode 100644 index 000000000..6922e2ab4 --- /dev/null +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderConditionAnd.java @@ -0,0 +1,60 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) Open Application Platform Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package oap.template.render; + +import lombok.ToString; +import oap.template.runtime.RuntimeContext; + +@ToString( callSuper = true ) +public class AstRenderConditionAnd extends AstRender { + private final AstRender left; + private final AstRender right; + + public AstRenderConditionAnd( TemplateType type, AstRender left, AstRender right ) { + super( type ); + this.left = left; + this.right = right; + } + + @Override + public void render( Render render ) { + String leftVar = render.newVariable(); + String rightVar = render.newVariable(); + render.ntab().append( "boolean %s = false;", leftVar ); + left.render( render.withBooleanIfVar( leftVar ) ); + render.ntab().append( "boolean %s = false;", rightVar ); + right.render( render.withBooleanIfVar( rightVar ) ); + render.ntab().append( "%s = %s && %s;", render.booleanIfVar, leftVar, rightVar ); + } + + @Override + public void interpret( RuntimeContext ctx ) { + boolean[] leftCapture = { false }; + boolean[] rightCapture = { false }; + left.interpret( ctx.withBooleanCapture( leftCapture ) ); + right.interpret( ctx.withBooleanCapture( rightCapture ) ); + if( ctx.booleanCapture != null ) ctx.booleanCapture[0] = leftCapture[0] && rightCapture[0]; + } +} diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderConditionNot.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderConditionNot.java new file mode 100644 index 000000000..b655de99b --- /dev/null +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderConditionNot.java @@ -0,0 +1,53 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) Open Application Platform Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package oap.template.render; + +import lombok.ToString; +import oap.template.runtime.RuntimeContext; + +@ToString( callSuper = true ) +public class AstRenderConditionNot extends AstRender { + private final AstRender inner; + + public AstRenderConditionNot( TemplateType type, AstRender inner ) { + super( type ); + this.inner = inner; + } + + @Override + public void render( Render render ) { + String innerVar = render.newVariable(); + render.ntab().append( "boolean %s = false;", innerVar ); + inner.render( render.withBooleanIfVar( innerVar ) ); + render.ntab().append( "%s = !%s;", render.booleanIfVar, innerVar ); + } + + @Override + public void interpret( RuntimeContext ctx ) { + boolean[] innerCapture = { false }; + inner.interpret( ctx.withBooleanCapture( innerCapture ) ); + if( ctx.booleanCapture != null ) ctx.booleanCapture[0] = !innerCapture[0]; + } +} diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderConditionOr.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderConditionOr.java new file mode 100644 index 000000000..ded03d4cf --- /dev/null +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderConditionOr.java @@ -0,0 +1,60 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) Open Application Platform Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package oap.template.render; + +import lombok.ToString; +import oap.template.runtime.RuntimeContext; + +@ToString( callSuper = true ) +public class AstRenderConditionOr extends AstRender { + private final AstRender left; + private final AstRender right; + + public AstRenderConditionOr( TemplateType type, AstRender left, AstRender right ) { + super( type ); + this.left = left; + this.right = right; + } + + @Override + public void render( Render render ) { + String leftVar = render.newVariable(); + String rightVar = render.newVariable(); + render.ntab().append( "boolean %s = false;", leftVar ); + left.render( render.withBooleanIfVar( leftVar ) ); + render.ntab().append( "boolean %s = false;", rightVar ); + right.render( render.withBooleanIfVar( rightVar ) ); + render.ntab().append( "%s = %s || %s;", render.booleanIfVar, leftVar, rightVar ); + } + + @Override + public void interpret( RuntimeContext ctx ) { + boolean[] leftCapture = { false }; + boolean[] rightCapture = { false }; + left.interpret( ctx.withBooleanCapture( leftCapture ) ); + right.interpret( ctx.withBooleanCapture( rightCapture ) ); + if( ctx.booleanCapture != null ) ctx.booleanCapture[0] = leftCapture[0] || rightCapture[0]; + } +} diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderExpression.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderExpression.java index 10bef386e..1f6583fa1 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderExpression.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderExpression.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; import org.apache.commons.text.StringEscapeUtils; import java.util.ArrayList; @@ -46,4 +47,9 @@ public void render( Render render ) { } children.forEach( a -> a.render( render.withContent( String.join( " | ", content ) ) ) ); } + + @Override + public void interpret( RuntimeContext ctx ) { + children.forEach( c -> c.interpret( ctx ) ); + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderField.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderField.java index c43c25d48..639f5b0a2 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderField.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderField.java @@ -25,6 +25,8 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.ReflectionCache; +import oap.template.runtime.RuntimeContext; @ToString( callSuper = true ) public class AstRenderField extends AstRender { @@ -66,4 +68,18 @@ public void render( Render render ) { var newRender = render.withField( variableName.name ).withParentType( type ); children.forEach( a -> a.render( newRender ) ); } + + @Override + @SuppressWarnings( "unchecked" ) + public void interpret( RuntimeContext ctx ) { + Object parent = ctx.currentObject; + Object value; + if( parent instanceof java.util.Map m ) { + value = m.get( fieldName ); + } else { + value = ReflectionCache.getFieldValue( parent, fieldName ); + } + RuntimeContext next = ctx.withCurrentObject( value ); + children.forEach( c -> c.interpret( next ) ); + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderFunction.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderFunction.java index 1506fe693..0bd77f903 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderFunction.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderFunction.java @@ -25,6 +25,9 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.AcceptDispatch; +import oap.template.runtime.ReflectionCache; +import oap.template.runtime.RuntimeContext; import java.lang.reflect.Method; import java.util.List; @@ -68,4 +71,31 @@ public void render( Render render ) { Render newRender = render.withField( funcVariable ).withParentType( type ); children.forEach( a -> a.render( newRender ) ); } + + @Override + public void interpret( RuntimeContext ctx ) { + Class[] paramTypes = method.getParameterTypes(); + Object firstArg = ctx.currentObject; + if( paramTypes.length > 0 && paramTypes[0].equals( String.class ) && !( firstArg instanceof String ) ) { + firstArg = firstArg != null + ? AcceptDispatch.toStringViaAcc( firstArg, new TemplateType( firstArg.getClass() ), ctx.acc ) + : null; + } + + Object[] args = new Object[1 + parameters.size()]; + args[0] = firstArg; + for( int i = 0; i < parameters.size(); i++ ) { + args[i + 1] = ReflectionCache.parseArg( paramTypes[i + 1], parameters.get( i ) ); + } + + Object result; + try { + result = method.invoke( null, args ); + } catch( Exception e ) { + throw new RuntimeException( e ); + } + + RuntimeContext nextCtx = ctx.withCurrentObject( result ).withAcc( ctx.acc ); + children.forEach( c -> c.interpret( nextCtx ) ); + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderIfElse.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderIfElse.java index afa92bf48..012746182 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderIfElse.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderIfElse.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; import java.util.function.Supplier; @@ -81,6 +82,11 @@ public void print( StringBuilder buffer, String prefix, String childrenPrefix ) } } + /** Render the else branch when present, during runtime interpretation. */ + protected void interpretElse( RuntimeContext ctx ) { + if( elseAstRender != null ) elseAstRender.interpret( ctx ); + } + protected abstract String getTrue(); protected abstract String getFalseToString(); diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderMap.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderMap.java index 05feaeca7..cecac1062 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderMap.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderMap.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; @ToString( callSuper = true ) public class AstRenderMap extends AstRender { @@ -38,13 +39,23 @@ public AstRenderMap( String key, TemplateType valueType ) { @Override public void render( Render render ) { - String mapVariable = render.newVariable(); + Render.NewVariable mapVariable = render.newVariable( key ); - render.ntab().append( "%s %s = %s.get( \"%s\" );", - type.getTypeName(), mapVariable, - render.field, render.escapeJava( key ) ); + if( mapVariable.isNew ) { + render.ntab().append( "%s %s = %s.get( \"%s\" );", + type.getTypeName(), mapVariable.name, + render.field, render.escapeJava( key ) ); + } - Render newRender = render.withField( mapVariable ).withParentType( type ); + Render newRender = render.withField( mapVariable.name ).withParentType( type ); children.forEach( a -> a.render( newRender ) ); } + + @Override + @SuppressWarnings( "unchecked" ) + public void interpret( RuntimeContext ctx ) { + Object value = ctx.currentObject instanceof java.util.Map m ? m.get( key ) : null; + RuntimeContext next = ctx.withCurrentObject( value ); + children.forEach( c -> c.interpret( next ) ); + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderMath.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderMath.java index b370674f0..a371a79cc 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderMath.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderMath.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; @ToString( callSuper = true ) public class AstRenderMath extends AstRender { @@ -46,4 +47,37 @@ public void render( Render render ) { var newRender = render.withField( mathVariable ).withParentType( type ); children.forEach( a -> a.render( newRender ) ); } + + @Override + public void interpret( RuntimeContext ctx ) { + Object result = applyMath( operation, ( Number ) ctx.currentObject, number ); + RuntimeContext next = ctx.withCurrentObject( result ); + children.forEach( c -> c.interpret( next ) ); + } + + private static Object applyMath( String op, Number val, String numStr ) { + if( ( val instanceof Integer || val instanceof Long ) && !numStr.contains( "." ) ) { + long lv = val.longValue(); + long n = Long.parseLong( numStr ); + long r = switch( op ) { + case "+" -> lv + n; + case "-" -> lv - n; + case "*" -> lv * n; + case "/" -> lv / n; + case "%" -> lv % n; + default -> throw new IllegalArgumentException( op ); + }; + return val instanceof Integer ? ( int ) r : r; + } + double dv = val.doubleValue(); + double n = Double.parseDouble( numStr ); + return switch( op ) { + case "+" -> dv + n; + case "-" -> dv - n; + case "*" -> dv * n; + case "/" -> dv / n; + case "%" -> dv % n; + default -> throw new IllegalArgumentException( op ); + }; + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderMethod.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderMethod.java index d3517b657..58fb9d493 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderMethod.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderMethod.java @@ -25,6 +25,8 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.ReflectionCache; +import oap.template.runtime.RuntimeContext; import java.util.List; @@ -53,4 +55,11 @@ public void render( Render render ) { var newRender = render.withField( variableName.name ).withParentType( type ); children.forEach( a -> a.render( newRender ) ); } + + @Override + public void interpret( RuntimeContext ctx ) { + Object result = ReflectionCache.invokeMethod( ctx.currentObject, methodName, arguments ); + RuntimeContext next = ctx.withCurrentObject( result ); + children.forEach( c -> c.interpret( next ) ); + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderNullable.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderNullable.java index ad2190a4f..f8773b2d8 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderNullable.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderNullable.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; import java.util.function.Supplier; @@ -53,4 +54,14 @@ protected String getInnerVariable( Supplier newVariable ) { protected String getInnerVariableSetter( String variableName, Render render ) { return null; } + + @Override + public void interpret( RuntimeContext ctx ) { + if( ctx.currentObject != null ) { + children.forEach( c -> c.interpret( ctx ) ); + } else { + if( ctx.tryEmpty != null ) ctx.tryEmpty[0] = true; + interpretElse( ctx ); + } + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderOptional.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderOptional.java index f83d5cc7f..bada36e5b 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderOptional.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderOptional.java @@ -25,7 +25,9 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; +import java.util.Optional; import java.util.function.Supplier; @ToString( callSuper = true ) @@ -53,4 +55,16 @@ protected String getInnerVariable( Supplier newVariable ) { protected String getInnerVariableSetter( String variableName, Render render ) { return "%s %s = %s.get();".formatted( type.getTypeName(), variableName, render.field ); } + + @Override + public void interpret( RuntimeContext ctx ) { + Optional opt = ( Optional ) ctx.currentObject; + if( opt != null && opt.isPresent() ) { + RuntimeContext inner = ctx.withCurrentObject( opt.get() ); + children.forEach( c -> c.interpret( inner ) ); + } else { + if( ctx.tryEmpty != null ) ctx.tryEmpty[0] = true; + interpretElse( ctx ); + } + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderOr.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderOr.java index 41daf371a..e36cbda7b 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderOr.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderOr.java @@ -25,6 +25,8 @@ package oap.template.render; import lombok.ToString; +import oap.template.TemplateAccumulator; +import oap.template.runtime.RuntimeContext; import java.util.ArrayList; import java.util.List; @@ -112,4 +114,28 @@ public void render( Render render ) { Render newRender = r.withField( orVariable ); super.render( newRender ); } + + @Override + @SuppressWarnings( { "unchecked", "rawtypes" } ) + public void interpret( RuntimeContext ctx ) { + TemplateAccumulator orAcc = ctx.acc.newInstance(); + boolean found = false; + for( AstRender orItem : or ) { + TemplateAccumulator tryAcc = ctx.acc.newInstance(); + boolean[] tryEmpty = { false }; + RuntimeContext tryCtx = ctx.withAcc( tryAcc ).withTryEmpty( tryEmpty ); + orItem.interpret( tryCtx ); + if( !tryEmpty[0] ) { + orAcc = tryAcc; + found = true; + break; + } + } + TemplateAccumulator winner = orAcc; + if( found && winner.isNotEmpty() ) { + children.forEach( c -> c.interpret( ctx.withCurrentObject( winner ) ) ); + } else { + interpretElse( ctx ); + } + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderPathNotFound.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderPathNotFound.java index 76ac78100..70254a1bb 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderPathNotFound.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderPathNotFound.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; @ToString( callSuper = true ) public class AstRenderPathNotFound extends AstRender { @@ -46,4 +47,10 @@ public void render( Render render ) { var newRender = render.withField( newVariable ).withParentType( type ); children.forEach( a -> a.render( newRender ) ); } + + @Override + public void interpret( RuntimeContext ctx ) { + RuntimeContext empty = ctx.withCurrentObject( "" ); + children.forEach( c -> c.interpret( empty ) ); + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderPrintField.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderPrintField.java index db1543d0c..ea2fc84ac 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderPrintField.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderPrintField.java @@ -26,6 +26,8 @@ import com.google.common.base.Preconditions; import lombok.ToString; +import oap.template.runtime.AcceptDispatch; +import oap.template.runtime.RuntimeContext; import javax.annotation.Nullable; @@ -45,6 +47,12 @@ public void render( Render render ) { r.append( "%s.accept( %s );", r.templateAccumulatorName, format( castType != null ? new TemplateType( castType.type ) : type, r.field ) ); } + @Override + @SuppressWarnings( "unchecked" ) + public void interpret( RuntimeContext ctx ) { + AcceptDispatch.accept( ctx.acc, ctx.currentObject, type, castType ); + } + @SuppressWarnings( { "checkstyle:ParameterAssignment" } ) private String format( TemplateType castType, String value ) { Preconditions.checkNotNull( value ); diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderPrintValue.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderPrintValue.java index 2af15e044..9d262dda9 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderPrintValue.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderPrintValue.java @@ -26,6 +26,8 @@ import com.google.common.base.Preconditions; import lombok.ToString; +import oap.template.runtime.AcceptDispatch; +import oap.template.runtime.RuntimeContext; import oap.util.Dates; import oap.util.Strings; import org.apache.commons.lang3.StringUtils; @@ -63,6 +65,18 @@ public void render( Render render ) { } } + @Override + @SuppressWarnings( "unchecked" ) + public void interpret( RuntimeContext ctx ) { + String defaultValue = value; + if( defaultValue == null ) defaultValue = ctx.acc.getDefault( type.getTypeClass() ); + if( defaultValue == null ) { + ctx.acc.acceptNull( type.getTypeClass() ); + } else { + AcceptDispatch.acceptDefaultValue( ctx.acc, type, castType, defaultValue ); + } + } + @SuppressWarnings( { "checkstyle:ParameterAssignment" } ) private String format( TemplateType castType, String defaultValue ) { Preconditions.checkNotNull( defaultValue ); diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderRoot.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderRoot.java index 32ced9699..f127762a0 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderRoot.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderRoot.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; @ToString( callSuper = true ) public class AstRenderRoot extends AstRender { @@ -64,4 +65,9 @@ public void render( Render render ) { } }""".stripIndent() ); } + + @Override + public void interpret( RuntimeContext ctx ) { + children.forEach( c -> c.interpret( ctx ) ); + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderSwitchToRoot.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderSwitchToRoot.java index 530dbf8d2..b55acfb79 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderSwitchToRoot.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderSwitchToRoot.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; /** * Redirects render.field to render.rootField so that child nodes resolve @@ -42,4 +43,10 @@ public void render( Render render ) { Render rootRender = render.withField( render.rootField ).withParentType( type ); children.forEach( c -> c.render( rootRender ) ); } + + @Override + public void interpret( RuntimeContext ctx ) { + RuntimeContext rootCtx = ctx.withCurrentObject( ctx.rootObject ); + children.forEach( c -> c.interpret( rootCtx ) ); + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderText.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderText.java index 72a5af281..43bf7d5b5 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderText.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderText.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; @ToString( callSuper = true ) public class AstRenderText extends AstRender { @@ -41,4 +42,9 @@ public void render( Render render ) { .append( "%s.acceptText( \"%s\" );", render.templateAccumulatorName, render.escapeJava( text != null ? text : "" ) ); } + @Override + public void interpret( RuntimeContext ctx ) { + ctx.acc.acceptText( text != null ? text : "" ); + } + } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderTryBlock.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderTryBlock.java index ad9e79d05..c57ad8dc5 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderTryBlock.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderTryBlock.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; @ToString( callSuper = true ) public class AstRenderTryBlock extends AstRender { @@ -61,4 +62,9 @@ public void render( String newFunctionId, String templateAccumulatorName, Render .tabDec() .ntab().append( "};" ); } + + @Override + public void interpret( RuntimeContext ctx ) { + children.forEach( c -> c.interpret( ctx ) ); + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderVarRef.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderVarRef.java index ff70281c9..210e1d38a 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderVarRef.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderVarRef.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; /** * Redirects render.field to the Java variable bound to a named range variable ($varName). @@ -45,4 +46,11 @@ public void render( Render render ) { Render varRender = render.withField( javaVar ).withParentType( type ); children.forEach( c -> c.render( varRender ) ); } + + @Override + public void interpret( RuntimeContext ctx ) { + Object value = ctx.rangeVars.get( varName ); + RuntimeContext next = ctx.withCurrentObject( value ); + children.forEach( c -> c.interpret( next ) ); + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderWith.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderWith.java index 9fd53adf7..57a8f353d 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderWith.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRenderWith.java @@ -25,6 +25,7 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; /** * Inline with: {{ with (field1) field2 | default field3 end }} @@ -50,4 +51,11 @@ public void render( Render render ) { scopeAst.render( render.withScopeVar( sv ) ); bodyAst.render( render.withField( sv ).withParentType( scopeType ) ); } + + @Override + public void interpret( RuntimeContext ctx ) { + Object[] capture = { null }; + scopeAst.interpret( ctx.withScopeCapture( capture ) ); + bodyAst.interpret( ctx.withCurrentObject( capture[0] ) ); + } } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/AstRendererDynamicMap.java b/oap-formats/oap-template/src/main/java/oap/template/render/AstRendererDynamicMap.java index 78eb0ef7c..11efde690 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/AstRendererDynamicMap.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/AstRendererDynamicMap.java @@ -1,8 +1,10 @@ package oap.template.render; import lombok.ToString; +import oap.template.runtime.RuntimeContext; import java.util.ArrayList; +import java.util.Map; @ToString public class AstRendererDynamicMap extends AstRender { @@ -36,6 +38,21 @@ public void render( Render render ) { } } + @Override + public void interpret( RuntimeContext ctx ) { + Object obj = ctx.currentObject; + for( String key : path ) { + if( obj instanceof Map m ) { + obj = m.get( key ); + } else { + obj = null; + break; + } + } + RuntimeContext nextCtx = ctx.withCurrentObject( obj ); + for( AstRender child : children ) child.interpret( nextCtx ); + } + public void addPath( String key ) { this.path.add( key ); } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/Render.java b/oap-formats/oap-template/src/main/java/oap/template/render/Render.java index 942a4c9e3..2e0d30262 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/Render.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/Render.java @@ -31,6 +31,7 @@ import java.util.ArrayDeque; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @@ -171,12 +172,15 @@ public String newVariable() { return "v" + id; } + @SuppressWarnings( "checkstyle:ParameterAssignment" ) public NewVariable newVariable( String name ) { - var fullName = variableNameWithPrefix( name ); - var it = variables.descendingIterator(); + name = name.replaceAll( "[\\s,-?]", "_" ); + + String fullName = variableNameWithPrefix( name ); + Iterator> it = variables.descendingIterator(); while( it.hasNext() ) { - var map = it.next(); + HashSet map = it.next(); if( map.contains( fullName ) ) return new NewVariable( fullName, false ); } diff --git a/oap-formats/oap-template/src/main/java/oap/template/render/TemplateAstUtils.java b/oap-formats/oap-template/src/main/java/oap/template/render/TemplateAstUtils.java index b99c07320..b0498248b 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/render/TemplateAstUtils.java +++ b/oap-formats/oap-template/src/main/java/oap/template/render/TemplateAstUtils.java @@ -34,17 +34,22 @@ import oap.template.TemplateGrammarExpression; import oap.template.TemplateLexerExpression; import oap.template.ThrowingErrorListener; +import oap.template.tree.AndConditionExpr; import oap.template.tree.BlockIfElement; import oap.template.tree.BlockRangeElement; import oap.template.tree.BlockWithElement; +import oap.template.tree.ConditionExpr; import oap.template.tree.Element; import oap.template.tree.Elements; import oap.template.tree.Expr; import oap.template.tree.Expression; import oap.template.tree.ExpressionElement; import oap.template.tree.Exprs; +import oap.template.tree.FieldConditionExpr; import oap.template.tree.Func; import oap.template.tree.IfCondition; +import oap.template.tree.NotConditionExpr; +import oap.template.tree.OrConditionExpr; import oap.template.tree.TextElement; import oap.template.tree.WithCondition; import oap.util.Arrays; @@ -235,7 +240,9 @@ private static AstRender toAst( Expression expression, TemplateType templateType AstRender conditionAst = toConditionAst( ifCondition.condition, templateType, errorStrategy ); AstRender thenCode = toAst( ifCondition.thenCode, null, templateType, rootTemplateType, expressionResultType, castType, defaultValue, builtInFunction, errorStrategy ); - AstRender elseCode = ifCondition.elseCode != null ? toAst( ifCondition.elseCode, null, templateType, rootTemplateType, expressionResultType, castType, defaultValue, builtInFunction, errorStrategy ) : null; + AstRender elseCode = ifCondition.elseCode != null + ? toAst( ifCondition.elseCode, null, templateType, rootTemplateType, expressionResultType, castType, defaultValue, builtInFunction, errorStrategy ) + : null; return new AstRenderBooleanIf( templateType, conditionAst, thenCode, elseCode ); } @@ -264,6 +271,23 @@ private static AstRender toAst( Expression expression, TemplateType templateType } + private static AstRender toConditionAst( ConditionExpr cond, TemplateType templateType, ErrorStrategy errorStrategy ) { + if( cond instanceof FieldConditionExpr f ) { + return toConditionAst( f.fieldPath(), templateType, errorStrategy ); + } else if( cond instanceof AndConditionExpr a ) { + return new AstRenderConditionAnd( templateType, + toConditionAst( a.left(), templateType, errorStrategy ), + toConditionAst( a.right(), templateType, errorStrategy ) ); + } else if( cond instanceof OrConditionExpr o ) { + return new AstRenderConditionOr( templateType, + toConditionAst( o.left(), templateType, errorStrategy ), + toConditionAst( o.right(), templateType, errorStrategy ) ); + } else if( cond instanceof NotConditionExpr n ) { + return new AstRenderConditionNot( templateType, toConditionAst( n.inner(), templateType, errorStrategy ) ); + } + throw new IllegalStateException( "Unknown ConditionExpr: " + cond ); + } + @SuppressWarnings( { "checkstyle:ModifiedControlVariable", "checkstyle:ParameterAssignment" } ) private static AstRender toConditionAst( Exprs conditionExprs, TemplateType templateType, ErrorStrategy errorStrategy ) { try { @@ -285,6 +309,11 @@ private static AstRender toConditionAst( Exprs conditionExprs, TemplateType temp i--; result.add( ast ); currentTemplateType = newType; + } else if( currentTemplateType.isInstanceOf( Map.class ) ) { + TemplateType valueType = currentTemplateType.getActualTypeArguments1( true ); + AstRenderMap ast = new AstRenderMap( expr.name, valueType ); + result.add( ast ); + currentTemplateType = valueType; } else if( !expr.method ) { Class parentClass = currentTemplateType.getTypeClass(); java.lang.reflect.Field field = findField( parentClass, expr.name ); @@ -651,8 +680,8 @@ private static AstRenderRoot toAst( Elements elements, TemplateType templateType lexer.addErrorListener( ThrowingErrorListener.INSTANCE ); grammar.addErrorListener( ThrowingErrorListener.INSTANCE ); } - Exprs conditionExprs = grammar.exprs().ret; - AstRender conditionAst = toConditionAst( conditionExprs, templateType, errorStrategy ); + ConditionExpr conditionExpr = grammar.ifCondition().ret; + AstRender conditionAst = toConditionAst( conditionExpr, templateType, errorStrategy ); AstRenderRoot thenRoot = toAst( b.thenElements, templateType, rootTemplateType, builtInFunction, errorStrategy, rangeVarTypes ); AstRenderRoot elseRoot = b.elseElements != null ? toAst( b.elseElements, templateType, rootTemplateType, builtInFunction, errorStrategy, rangeVarTypes ) diff --git a/oap-formats/oap-template/src/main/java/oap/template/runtime/AcceptDispatch.java b/oap-formats/oap-template/src/main/java/oap/template/runtime/AcceptDispatch.java new file mode 100644 index 000000000..5152fb2b2 --- /dev/null +++ b/oap-formats/oap-template/src/main/java/oap/template/runtime/AcceptDispatch.java @@ -0,0 +1,181 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) Open Application Platform Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package oap.template.runtime; + +import oap.template.TemplateAccumulator; +import oap.template.TemplateAccumulatorString; +import oap.template.render.FieldType; +import oap.template.render.TemplateType; +import oap.util.Dates; +import oap.util.Strings; +import org.joda.time.DateTime; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.List; + +/** + * Routes a runtime {@code value} + {@link TemplateType} to the correct typed + * {@link TemplateAccumulator#accept} overload — doing at runtime what the code-generator + * resolves statically. + */ +@SuppressWarnings( { "rawtypes", "unchecked" } ) +public final class AcceptDispatch { + + private AcceptDispatch() {} + + /** + * Accept a live field value into the accumulator, applying numeric coercion + * when {@code castType} is set (mirrors {@code AstRenderPrintField.format()}). + */ + public static void accept( TemplateAccumulator acc, @Nullable Object value, + TemplateType type, @Nullable FieldType castType ) { + if( value == null ) { + acc.acceptNull( type.getTypeClass() ); + return; + } + if( value instanceof TemplateAccumulator subAcc ) { + acc.accept( subAcc ); + return; + } + if( castType != null ) { + TemplateType effective = new TemplateType( castType.type ); + Class tc = effective.isOptional() ? effective.getActualTypeArguments0().getTypeClass() : effective.getTypeClass(); + dispatchValue( acc, coerce( value, tc ), tc ); + } else { + dispatchValue( acc, value, value.getClass() ); + } + } + + /** + * Accept a literal default value into the accumulator + * (mirrors {@code AstRenderPrintValue.format()}). + */ + public static void acceptDefaultValue( TemplateAccumulator acc, + TemplateType type, @Nullable FieldType castType, + String defaultValue ) { + TemplateType effective = castType != null ? new TemplateType( castType.type ) : type; + Class tc = effective.isOptional() ? effective.getActualTypeArguments0().getTypeClass() : effective.getTypeClass(); + Object parsed = parseDefault( tc, type, defaultValue ); + if( castType != null && parsed instanceof Number n ) parsed = coerce( n, castType.type ); + if( castType != null ) { + acc.accept( parsed ); + } else { + dispatchValue( acc, parsed, parsed != null ? parsed.getClass() : tc ); + } + } + + private static Object coerce( Object value, Class target ) { + if( value instanceof Number n ) { + if( byte.class.equals( target ) || Byte.class.isAssignableFrom( target ) ) return n.byteValue(); + if( short.class.equals( target ) || Short.class.isAssignableFrom( target ) ) return n.shortValue(); + if( int.class.equals( target ) || Integer.class.isAssignableFrom( target ) ) return n.intValue(); + if( long.class.equals( target ) || Long.class.isAssignableFrom( target ) ) return n.longValue(); + if( float.class.equals( target ) || Float.class.isAssignableFrom( target ) ) return n.floatValue(); + if( double.class.equals( target ) || Double.class.isAssignableFrom( target ) ) return n.doubleValue(); + } + return value; + } + + private static void dispatchValue( TemplateAccumulator acc, Object value, Class tc ) { + if( value instanceof TemplateAccumulator subAcc ) { + acc.accept( subAcc ); + return; + } + if( boolean.class.equals( tc ) || Boolean.class.isAssignableFrom( tc ) ) { + acc.accept( ( Boolean ) value ); + } else if( byte.class.equals( tc ) || Byte.class.isAssignableFrom( tc ) ) { + acc.accept( ( ( Number ) value ).byteValue() ); + } else if( short.class.equals( tc ) || Short.class.isAssignableFrom( tc ) ) { + acc.accept( ( ( Number ) value ).shortValue() ); + } else if( int.class.equals( tc ) || Integer.class.isAssignableFrom( tc ) ) { + acc.accept( ( ( Number ) value ).intValue() ); + } else if( long.class.equals( tc ) || Long.class.isAssignableFrom( tc ) ) { + acc.accept( ( ( Number ) value ).longValue() ); + } else if( float.class.equals( tc ) || Float.class.isAssignableFrom( tc ) ) { + acc.accept( ( ( Number ) value ).floatValue() ); + } else if( double.class.equals( tc ) || Double.class.isAssignableFrom( tc ) ) { + acc.accept( ( ( Number ) value ).doubleValue() ); + } else if( Enum.class.isAssignableFrom( tc ) ) { + acc.accept( ( Enum ) value ); + } else if( Collection.class.isAssignableFrom( tc ) ) { + acc.accept( ( Collection ) value ); + } else if( value instanceof DateTime dt ) { + acc.accept( dt ); + } else if( value instanceof String s ) { + acc.accept( s ); + } else { + acc.accept( value ); + } + } + + private static Object parseDefault( Class tc, TemplateType type, String defaultValue ) { + if( String.class.equals( tc ) ) return defaultValue; + if( byte.class.equals( tc ) || Byte.class.isAssignableFrom( tc ) ) + return Byte.parseByte( defaultValue ); + if( short.class.equals( tc ) || Short.class.isAssignableFrom( tc ) ) + return Short.parseShort( defaultValue ); + if( int.class.equals( tc ) || Integer.class.isAssignableFrom( tc ) ) + return Integer.parseInt( defaultValue ); + if( long.class.equals( tc ) || Long.class.isAssignableFrom( tc ) ) + return Long.parseLong( defaultValue ); + if( float.class.equals( tc ) || Float.class.isAssignableFrom( tc ) ) + return Float.parseFloat( defaultValue ); + if( double.class.equals( tc ) || Double.class.isAssignableFrom( tc ) ) + return Double.parseDouble( defaultValue ); + if( boolean.class.equals( tc ) || Boolean.class.isAssignableFrom( tc ) ) + return Boolean.parseBoolean( defaultValue ); + if( Collection.class.isAssignableFrom( tc ) ) return List.of(); + if( Enum.class.isAssignableFrom( tc ) ) { + Class enumClass = ( tc == Enum.class ) ? type.getTypeClass() : tc; + String name = defaultValue.isEmpty() ? Strings.UNKNOWN : defaultValue; + return Enum.valueOf( ( Class ) enumClass, name ); + } + if( Object.class.equals( tc ) ) { + if( "true".equals( defaultValue ) || "false".equals( defaultValue ) ) return Boolean.parseBoolean( defaultValue ); + try { + return Long.parseLong( defaultValue ); + } catch( NumberFormatException ignored ) { } + try { + return Double.parseDouble( defaultValue ); + } catch( NumberFormatException ignored ) { } + return defaultValue; + } + if( DateTime.class.equals( tc ) ) + return Dates.PARSER_MULTIPLE_DATETIME.parseDateTime( defaultValue ); + return defaultValue; + } + + /** + * Convert a live value to its String representation using a temporary + * {@link TemplateAccumulatorString}. Used by function nodes when the first + * parameter expects {@code String} but the current value is not a String. + */ + public static String toStringViaAcc( Object value, TemplateType type, TemplateAccumulator parentAcc ) { + TemplateAccumulatorString tmp = new TemplateAccumulatorString(); + accept( tmp, value, type, null ); + return tmp.get(); + } +} diff --git a/oap-formats/oap-template/src/main/java/oap/template/runtime/ReflectionCache.java b/oap-formats/oap-template/src/main/java/oap/template/runtime/ReflectionCache.java new file mode 100644 index 000000000..939f1281a --- /dev/null +++ b/oap-formats/oap-template/src/main/java/oap/template/runtime/ReflectionCache.java @@ -0,0 +1,129 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) Open Application Platform Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package oap.template.runtime; + +import javax.annotation.Nullable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +/** + * JVM-wide cache of {@link Field} and {@link Method} references, pre-made accessible, + * to minimise reflection overhead in the runtime interpreter. + */ +public final class ReflectionCache { + private static final ConcurrentHashMap FIELD_CACHE = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap METHOD_CACHE = new ConcurrentHashMap<>(); + + private ReflectionCache() {} + + /** + * Read the value of {@code fieldName} on {@code obj}, traversing the class hierarchy. + * Returns {@code null} when {@code obj} is {@code null} or the field cannot be found. + */ + @Nullable + public static Object getFieldValue( @Nullable Object obj, String fieldName ) { + if( obj == null ) return null; + String key = obj.getClass().getName() + '#' + fieldName; + Field f = FIELD_CACHE.computeIfAbsent( key, k -> findField( obj.getClass(), fieldName ) ); + if( f == null ) return null; + try { + return f.get( obj ); + } catch( IllegalAccessException e ) { + throw new RuntimeException( e ); + } + } + + /** + * Invoke a zero-or-more-argument instance method by name, with pre-parsed arguments. + */ + public static Object invokeMethod( Object obj, String methodName, List rawArgs ) { + if( obj == null ) return null; + String key = obj.getClass().getName() + '#' + methodName + '/' + rawArgs.size(); + Method m = METHOD_CACHE.computeIfAbsent( key, k -> findMethod( obj.getClass(), methodName, rawArgs.size() ) ); + if( m == null ) return null; + try { + Object[] args = parseArgs( m.getParameterTypes(), rawArgs ); + return m.invoke( obj, args ); + } catch( Exception e ) { + throw new RuntimeException( e ); + } + } + + /** Parse raw string args to the concrete types expected by the method. */ + public static Object[] parseArgs( Class[] paramTypes, List rawArgs ) { + Object[] args = new Object[rawArgs.size()]; + for( int i = 0; i < rawArgs.size(); i++ ) { + args[i] = parseArg( paramTypes[i], rawArgs.get( i ) ); + } + return args; + } + + /** Parse a single raw argument string to the target Java type. */ + public static Object parseArg( Class targetType, String raw ) { + String s = raw; + if( s.startsWith( "\"" ) && s.endsWith( "\"" ) ) { + s = s.substring( 1, s.length() - 1 ); + if( String.class.equals( targetType ) ) return s; + } + if( int.class.equals( targetType ) || Integer.class.equals( targetType ) ) return Integer.parseInt( s ); + if( long.class.equals( targetType ) || Long.class.equals( targetType ) ) return Long.parseLong( s ); + if( double.class.equals( targetType ) || Double.class.equals( targetType ) ) return Double.parseDouble( s ); + if( float.class.equals( targetType ) || Float.class.equals( targetType ) ) return Float.parseFloat( s ); + if( short.class.equals( targetType ) || Short.class.equals( targetType ) ) return Short.parseShort( s ); + if( byte.class.equals( targetType ) || Byte.class.equals( targetType ) ) return Byte.parseByte( s ); + if( boolean.class.equals( targetType ) || Boolean.class.equals( targetType ) ) return Boolean.parseBoolean( s ); + return s; + } + + @Nullable + private static Field findField( Class clazz, String name ) { + Class c = clazz; + while( c != null ) { + try { + Field f = c.getDeclaredField( name ); + f.setAccessible( true ); + return f; + } catch( NoSuchFieldException e ) { + c = c.getSuperclass(); + } + } + return null; + } + + @Nullable + private static Method findMethod( Class clazz, String name, int argCount ) { + return Arrays.stream( clazz.getMethods() ) + .filter( m -> m.getName().equals( name ) && m.getParameterCount() == argCount ) + .findFirst() + .map( m -> { + m.setAccessible( true ); + return m; + } ) + .orElse( null ); + } +} diff --git a/oap-formats/oap-template/src/main/java/oap/template/runtime/RuntimeContext.java b/oap-formats/oap-template/src/main/java/oap/template/runtime/RuntimeContext.java new file mode 100644 index 000000000..9a150c56d --- /dev/null +++ b/oap-formats/oap-template/src/main/java/oap/template/runtime/RuntimeContext.java @@ -0,0 +1,114 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) Open Application Platform Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package oap.template.runtime; + +import oap.template.TemplateAccumulator; + +import java.util.HashMap; +import java.util.Map; + +/** + * Runtime interpretation context — analogous to {@code Render} for code-generation, + * but carries live Java objects instead of code fragments. + * + *

All with-methods produce a new immutable copy; the accumulator and captures + * are shared mutable references intentionally (they are coordination points). + */ +@SuppressWarnings( "rawtypes" ) +public final class RuntimeContext { + /** The object currently being inspected (analogous to {@code Render.field}). */ + public final Object currentObject; + /** The root input object (analogous to {@code Render.rootField}). */ + public final Object rootObject; + /** The accumulator that receives rendered output. */ + public final TemplateAccumulator acc; + /** Named range-loop variables (e.g. {@code $item}, {@code $k}). */ + public final Map rangeVars; + /** + * One-element array shared with the caller of {@code withBooleanCapture()}. + * {@code AstRenderCaptureBoolean} writes into {@code [0]} when reached. + * {@code null} when not inside a condition-path evaluation. + */ + public final boolean[] booleanCapture; + /** + * One-element array shared with the caller of {@code withScopeCapture()}. + * {@code AstRenderCaptureScope} writes into {@code [0]} when reached. + * {@code null} when not resolving a scope/collection path. + */ + public final Object[] scopeCapture; + /** + * One-element array shared with the caller of {@code withTryEmpty()}. + * Set to {@code true} by {@code AstRenderNullable/Optional} when the null branch is taken. + * {@code null} when not inside an Or-candidate evaluation. + */ + public final boolean[] tryEmpty; + + public RuntimeContext( Object currentObject, Object rootObject, + TemplateAccumulator acc, + Map rangeVars, + boolean[] booleanCapture, + Object[] scopeCapture, + boolean[] tryEmpty ) { + this.currentObject = currentObject; + this.rootObject = rootObject; + this.acc = acc; + this.rangeVars = rangeVars; + this.booleanCapture = booleanCapture; + this.scopeCapture = scopeCapture; + this.tryEmpty = tryEmpty; + } + + /** Create the initial context for interpreting a template against {@code obj}. */ + public static RuntimeContext root( Object obj, TemplateAccumulator acc ) { + return new RuntimeContext( obj, obj, acc, Map.of(), null, null, null ); + } + + public RuntimeContext withCurrentObject( Object obj ) { + return new RuntimeContext( obj, rootObject, acc, rangeVars, booleanCapture, scopeCapture, tryEmpty ); + } + + @SuppressWarnings( "unchecked" ) + public RuntimeContext withAcc( TemplateAccumulator newAcc ) { + return new RuntimeContext( currentObject, rootObject, newAcc, rangeVars, booleanCapture, scopeCapture, tryEmpty ); + } + + public RuntimeContext withRangeVar( String name, Object value ) { + var newVars = new HashMap<>( rangeVars ); + newVars.put( name, value ); + return new RuntimeContext( currentObject, rootObject, acc, newVars, booleanCapture, scopeCapture, tryEmpty ); + } + + public RuntimeContext withBooleanCapture( boolean[] capture ) { + return new RuntimeContext( currentObject, rootObject, acc, rangeVars, capture, scopeCapture, tryEmpty ); + } + + public RuntimeContext withScopeCapture( Object[] capture ) { + return new RuntimeContext( currentObject, rootObject, acc, rangeVars, booleanCapture, capture, tryEmpty ); + } + + public RuntimeContext withTryEmpty( boolean[] tryEmptyFlag ) { + return new RuntimeContext( currentObject, rootObject, acc, rangeVars, booleanCapture, scopeCapture, tryEmptyFlag ); + } +} diff --git a/oap-formats/oap-template/src/main/java/oap/template/tree/AndConditionExpr.java b/oap-formats/oap-template/src/main/java/oap/template/tree/AndConditionExpr.java new file mode 100644 index 000000000..2ea4aa77a --- /dev/null +++ b/oap-formats/oap-template/src/main/java/oap/template/tree/AndConditionExpr.java @@ -0,0 +1,27 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) Open Application Platform Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package oap.template.tree; + +public record AndConditionExpr( ConditionExpr left, ConditionExpr right ) implements ConditionExpr {} diff --git a/oap-formats/oap-template/src/main/java/oap/template/tree/ConditionExpr.java b/oap-formats/oap-template/src/main/java/oap/template/tree/ConditionExpr.java new file mode 100644 index 000000000..a94d826e1 --- /dev/null +++ b/oap-formats/oap-template/src/main/java/oap/template/tree/ConditionExpr.java @@ -0,0 +1,27 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) Open Application Platform Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package oap.template.tree; + +public sealed interface ConditionExpr permits FieldConditionExpr, AndConditionExpr, OrConditionExpr, NotConditionExpr {} diff --git a/oap-formats/oap-template/src/main/java/oap/template/tree/Expression.java b/oap-formats/oap-template/src/main/java/oap/template/tree/Expression.java index 87ccc16df..0ae50d04d 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/tree/Expression.java +++ b/oap-formats/oap-template/src/main/java/oap/template/tree/Expression.java @@ -66,7 +66,7 @@ public String print() { if( castType != null ) sb.append( "CAST " ).append( castType ).append( '\n' ); if( defaultValue != null ) sb.append( "DEFAULT '" ).append( defaultValue ).append( "'\n" ); if( ifCondition != null ) { - sb.append( "IF\n" ).append( "└── " ).append( ifCondition.condition.print() ).append( '\n' ); + sb.append( "IF\n" ).append( "└── " ).append( ifCondition.condition ).append( '\n' ); sb.append( "THEN\n" ).append( "└── " ).append( ifCondition.thenCode.print() ).append( '\n' ); if( ifCondition.elseCode != null ) { sb.append( "ELSE\n" ).append( "└── " ).append( ifCondition.elseCode.print() ).append( '\n' ); diff --git a/oap-formats/oap-template/src/main/java/oap/template/tree/FieldConditionExpr.java b/oap-formats/oap-template/src/main/java/oap/template/tree/FieldConditionExpr.java new file mode 100644 index 000000000..14c7a537e --- /dev/null +++ b/oap-formats/oap-template/src/main/java/oap/template/tree/FieldConditionExpr.java @@ -0,0 +1,27 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) Open Application Platform Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package oap.template.tree; + +public record FieldConditionExpr( Exprs fieldPath ) implements ConditionExpr {} diff --git a/oap-formats/oap-template/src/main/java/oap/template/tree/IfCondition.java b/oap-formats/oap-template/src/main/java/oap/template/tree/IfCondition.java index c5f6f391f..ad1211edf 100644 --- a/oap-formats/oap-template/src/main/java/oap/template/tree/IfCondition.java +++ b/oap-formats/oap-template/src/main/java/oap/template/tree/IfCondition.java @@ -3,11 +3,11 @@ import javax.annotation.Nullable; public class IfCondition { - public final Exprs condition; + public final ConditionExpr condition; public final Exprs thenCode; public final Exprs elseCode; - public IfCondition( Exprs condition, Exprs thenCode, @Nullable Exprs elseCode ) { + public IfCondition( ConditionExpr condition, Exprs thenCode, @Nullable Exprs elseCode ) { this.condition = condition; this.thenCode = thenCode; this.elseCode = elseCode; diff --git a/oap-formats/oap-template/src/main/java/oap/template/tree/NotConditionExpr.java b/oap-formats/oap-template/src/main/java/oap/template/tree/NotConditionExpr.java new file mode 100644 index 000000000..5b688d8b7 --- /dev/null +++ b/oap-formats/oap-template/src/main/java/oap/template/tree/NotConditionExpr.java @@ -0,0 +1,27 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) Open Application Platform Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package oap.template.tree; + +public record NotConditionExpr( ConditionExpr inner ) implements ConditionExpr {} diff --git a/oap-formats/oap-template/src/main/java/oap/template/tree/OrConditionExpr.java b/oap-formats/oap-template/src/main/java/oap/template/tree/OrConditionExpr.java new file mode 100644 index 000000000..b341b9739 --- /dev/null +++ b/oap-formats/oap-template/src/main/java/oap/template/tree/OrConditionExpr.java @@ -0,0 +1,27 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) Open Application Platform Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package oap.template.tree; + +public record OrConditionExpr( ConditionExpr left, ConditionExpr right ) implements ConditionExpr {} diff --git a/oap-formats/oap-template/src/test/java/oap/template/AbstractTemplateEngineTest.java b/oap-formats/oap-template/src/test/java/oap/template/AbstractTemplateEngineTest.java index d7f780ac3..5a8f00d29 100644 --- a/oap-formats/oap-template/src/test/java/oap/template/AbstractTemplateEngineTest.java +++ b/oap-formats/oap-template/src/test/java/oap/template/AbstractTemplateEngineTest.java @@ -1,11 +1,16 @@ package oap.template; +import oap.reflect.TypeRef; import oap.testng.Fixtures; import oap.testng.TestDirectoryFixture; import oap.util.Dates; import org.testng.annotations.BeforeMethod; import java.lang.reflect.Method; +import java.util.Map; +import java.util.function.Consumer; + +import oap.template.render.AstRender; public abstract class AbstractTemplateEngineTest extends Fixtures { protected final TestDirectoryFixture testDirectoryFixture; @@ -25,4 +30,50 @@ public void beforeCMethod() { public void nameBefore( Method method ) { testMethodName = method.getName(); } + + /** Override to {@code true} in subclasses that run against the runtime interpreter. */ + protected boolean useRuntime() { + return false; + } + + protected > + Template getTemplate( String name, TypeRef type, String template, TA acc, + Consumer postProcess ) { + return useRuntime() + ? engine.getRuntimeTemplate( name, type, template, acc, postProcess ) + : engine.getTemplate( name, type, template, acc, postProcess ); + } + + protected > + Template getTemplate( String name, TypeRef type, String template, TA acc, + Map aliases, Consumer postProcess ) { + return useRuntime() + ? engine.getRuntimeTemplate( name, type, template, acc, aliases, postProcess ) + : engine.getTemplate( name, type, template, acc, aliases, postProcess ); + } + + protected > + Template getTemplate( String name, TypeRef type, String template, TA acc, + ErrorStrategy errorStrategy, Consumer postProcess ) { + return useRuntime() + ? engine.getRuntimeTemplate( name, type, template, acc, errorStrategy, postProcess ) + : engine.getTemplate( name, type, template, acc, errorStrategy, postProcess ); + } + + protected > + Template getTemplate( String name, TypeRef type, String template, TA acc, + Map aliases, ErrorStrategy errorStrategy ) { + return useRuntime() + ? engine.getRuntimeTemplate( name, type, template, acc, aliases, errorStrategy ) + : engine.getTemplate( name, type, template, acc, aliases, errorStrategy ); + } + + protected > + Template getTemplate( String name, TypeRef type, String template, TA acc, + Map aliases, ErrorStrategy errorStrategy, + Consumer postProcess ) { + return useRuntime() + ? engine.getRuntimeTemplate( name, type, template, acc, aliases, errorStrategy, postProcess ) + : engine.getTemplate( name, type, template, acc, aliases, errorStrategy, postProcess ); + } } diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConcatenationRuntimeTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConcatenationRuntimeTest.java new file mode 100644 index 000000000..0523f1c21 --- /dev/null +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConcatenationRuntimeTest.java @@ -0,0 +1,8 @@ +package oap.template; + +public class TemplateEngineConcatenationRuntimeTest extends TemplateEngineConcatenationTest { + @Override + protected boolean useRuntime() { + return true; + } +} diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConcatenationTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConcatenationTest.java index bed54cce3..2bbbb97ff 100644 --- a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConcatenationTest.java +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConcatenationTest.java @@ -39,7 +39,7 @@ public void testConcatenation() { c.field = "f1"; c.field2 = "f2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${{field,\"x\",field2}}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${{field,\"x\",field2}}", STRING, null ).render( c ).get() ) .isEqualTo( "f1xf2" ); } @@ -49,7 +49,7 @@ public void testConcatenationWithNumber() { c.intField = 3; c.field2 = "f2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${{intField,\"x\",field2}}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${{intField,\"x\",field2}}", STRING, null ).render( c ).get() ) .isEqualTo( "3xf2" ); } @@ -61,7 +61,7 @@ public void testNestedConcatenation() { c1.field = "f1"; c1.field2 = "f2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${child{field,\"x\",field2}}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${child{field,\"x\",field2}}", STRING, null ).render( c ).get() ) .isEqualTo( "f1xf2" ); } @@ -73,7 +73,7 @@ public void testNestedConcatenationWithDot() { c1.field2 = "f1"; c1.field22 = "f2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${child2.{field2,\"x\",field22}}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${child2.{field2,\"x\",field22}}", STRING, null ).render( c ).get() ) .isEqualTo( "f1xf2" ); } @@ -89,7 +89,7 @@ public void testNestedNullableConcatenationWithDot() { c11.field2 = "f1"; c11.intField = 5; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${childNullable.childNullable.{field2,\"x\",intField}??''}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${childNullable.childNullable.{field2,\"x\",intField}??''}", STRING, null ).render( c ).get() ) .isEqualTo( "f1x5" ); } @@ -105,7 +105,7 @@ public void testNestedOptConcatenationWithDot() { c11.field2 = "f1"; c11.intField = 5; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${childOpt.childOpt.{field2,\"x\",intField}??''}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${childOpt.childOpt.{field2,\"x\",intField}??''}", STRING, null ).render( c ).get() ) .isEqualTo( "f1x5" ); } } diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConditionRuntimeTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConditionRuntimeTest.java new file mode 100644 index 000000000..6c2adb3d9 --- /dev/null +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConditionRuntimeTest.java @@ -0,0 +1,8 @@ +package oap.template; + +public class TemplateEngineConditionRuntimeTest extends TemplateEngineConditionTest { + @Override + protected boolean useRuntime() { + return true; + } +} diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConditionTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConditionTest.java index e21326fac..7e898bded 100644 --- a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConditionTest.java +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConditionTest.java @@ -27,6 +27,8 @@ import oap.reflect.TypeRef; import org.testng.annotations.Test; +import java.util.HashMap; + import static oap.template.ErrorStrategy.ERROR; import static oap.template.TemplateAccumulators.STRING; import static org.assertj.core.api.Assertions.assertThat; @@ -38,7 +40,7 @@ public void testIfConditionTrue() { TestTemplateClass c = new TestTemplateClass(); c.field = "val"; c.booleanField = true; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ if booleanField then field end }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ if booleanField then field end }}", STRING, null ).render( c ).get() ) .isEqualTo( "val" ); } @@ -47,7 +49,7 @@ public void testIfConditionFalse() { TestTemplateClass c = new TestTemplateClass(); c.field = "val"; c.booleanField = false; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ if booleanField then field end }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ if booleanField then field end }}", STRING, null ).render( c ).get() ) .isEqualTo( "" ); } @@ -57,7 +59,7 @@ public void testIfElseConditionFalse() { c.field = "val"; c.field2 = "val2"; c.booleanField = false; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ if booleanField then field else field2 end }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ if booleanField then field else field2 end }}", STRING, null ).render( c ).get() ) .isEqualTo( "val2" ); } @@ -67,11 +69,11 @@ public void testIfConditionNullableObject() { c.field = "val"; c.booleanObjectField = true; - assertThat( engine.getTemplate( testMethodName + "True", new TypeRef() {}, "{{ if booleanObjectField then field end }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName + "True", new TypeRef() {}, "{{ if booleanObjectField then field end }}", STRING, null ).render( c ).get() ) .isEqualTo( "val" ); c.booleanObjectField = null; - assertThat( engine.getTemplate( testMethodName + "Null", new TypeRef() {}, "{{ if booleanObjectField then field end }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName + "Null", new TypeRef() {}, "{{ if booleanObjectField then field end }}", STRING, null ).render( c ).get() ) .isEqualTo( "" ); } @@ -80,7 +82,7 @@ public void testIfConditionWithText() { TestTemplateClass c = new TestTemplateClass(); c.field = "val"; c.booleanField = true; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "prefix-{{ if booleanField then field end }}-suffix", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "prefix-{{ if booleanField then field end }}-suffix", STRING, null ).render( c ).get() ) .isEqualTo( "prefix-val-suffix" ); } @@ -88,7 +90,7 @@ public void testIfConditionWithText() { public void testIfConditionWithDefaultValue() { TestTemplateClass c = new TestTemplateClass(); c.booleanField = true; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ if booleanField then field end ?? 'default' }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ if booleanField then field end ?? 'default' }}", STRING, null ).render( c ).get() ) .isEqualTo( "default" ); } @@ -97,7 +99,7 @@ public void testBlockIfTrue() { TestTemplateClass c = new TestTemplateClass(); c.booleanField = true; c.field = "hello"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% if booleanField }}{{ field }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "hello" ); } @@ -107,7 +109,7 @@ public void testBlockIfFalse() { TestTemplateClass c = new TestTemplateClass(); c.booleanField = false; c.field = "hello"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% if booleanField }}{{ field }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "" ); } @@ -118,7 +120,7 @@ public void testBlockIfElseTrue() { c.booleanField = true; c.field = "then-val"; c.field2 = "else-val"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% if booleanField }}{{ field }}{{% else }}{{ field2 }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "then-val" ); } @@ -129,7 +131,17 @@ public void testBlockIfElseFalse() { c.booleanField = false; c.field = "then-val"; c.field2 = "else-val"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, + "{{% if booleanField }}{{ field }}{{% else }}{{ field2 }}{{% end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "else-val" ); + } + + @Test + public void testBlockIfElseFalseMap() { + HashMap c = new HashMap<>(); + c.put( "field", "then-val" ); + c.put( "field2", "else-val" ); + assertThat( getTemplate( testMethodName, new TypeRef>() {}, "{{% if booleanField }}{{ field }}{{% else }}{{ field2 }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "else-val" ); } @@ -139,7 +151,7 @@ public void testBlockIfNullableBoolTrue() { TestTemplateClass c = new TestTemplateClass(); c.booleanObjectField = true; c.field = "yes"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% if booleanObjectField }}{{ field }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "yes" ); } @@ -149,7 +161,7 @@ public void testBlockIfNullableBoolNull() { TestTemplateClass c = new TestTemplateClass(); c.booleanObjectField = null; c.field = "yes"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% if booleanObjectField }}{{ field }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "" ); } @@ -159,7 +171,7 @@ public void testBlockIfWithSurroundingText() { TestTemplateClass c = new TestTemplateClass(); c.booleanField = true; c.field = "world"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "Hello {{% if booleanField }}{{ field }}{{% end }} done", STRING, null ).render( c ).get() ) .isEqualTo( "Hello world done" ); } @@ -170,7 +182,7 @@ public void testBlockIfNestedPath() { c.child = new TestTemplateClass(); c.child.booleanField = true; c.child.field = "nested"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% if child.booleanField }}{{ child.field }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "nested" ); } @@ -180,7 +192,7 @@ public void testBlockIfMultiLineBody() { TestTemplateClass c = new TestTemplateClass(); c.booleanField = true; c.field = "myval"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% if booleanField }}\n value={{ field }}\n{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "\n value=myval\n" ); } @@ -192,7 +204,7 @@ public void testBlockIfNested() { c.child = new TestTemplateClass(); c.child.booleanField = true; c.child.field = "deep"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% if booleanField %}}{{% if child.booleanField }}{{ child.field }}{{% end }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "deep" ); } @@ -200,9 +212,114 @@ public void testBlockIfNested() { @Test public void testBlockIfUnknownFieldThrows() { assertThatThrownBy( () -> - engine.getTemplate( testMethodName, new TypeRef() {}, + getTemplate( testMethodName, new TypeRef() {}, "{{% if unknownField }}x{{% end }}", STRING, ERROR, null ) ) .isInstanceOf( TemplateException.class ); } + @Test + public void testBlockIfAnd() { + TestTemplateClass c = new TestTemplateClass(); + c.booleanField = true; + c.booleanObjectField = true; + assertThat( getTemplate( testMethodName, new TypeRef() {}, + "{{% if booleanField and booleanObjectField }}yes{{% else }}no{{% end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "yes" ); + } + + @Test + public void testBlockIfAndString() { + TestTemplateClass c = new TestTemplateClass(); + c.field = "1"; + c.field2 = "2"; + assertThat( getTemplate( testMethodName + "Both", new TypeRef() {}, + "{{% if field and field2 }}yes{{% else }}no{{% end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "yes" ); + + c.field2 = ""; + assertThat( getTemplate( testMethodName + "SecondEmpty", new TypeRef() {}, + "{{% if field and field2 }}yes{{% else }}no{{% end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "no" ); + + c.field = null; + c.field2 = "2"; + assertThat( getTemplate( testMethodName + "FirstNull", new TypeRef() {}, + "{{% if field or field2 }}yes{{% else }}no{{% end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "yes" ); + + c.field = "1"; + assertThat( getTemplate( testMethodName + "Single", new TypeRef() {}, + "{{% if field }}yes{{% else }}no{{% end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "yes" ); + } + + @Test + public void testBlockIfAndFalse() { + TestTemplateClass c = new TestTemplateClass(); + c.booleanField = true; + c.booleanObjectField = false; + assertThat( getTemplate( testMethodName, new TypeRef() {}, + "{{% if booleanField and booleanObjectField }}yes{{% else }}no{{% end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "no" ); + } + + @Test + public void testBlockIfOr() { + TestTemplateClass c = new TestTemplateClass(); + c.booleanField = false; + c.booleanObjectField = true; + assertThat( getTemplate( testMethodName, new TypeRef() {}, + "{{% if booleanField or booleanObjectField }}yes{{% else }}no{{% end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "yes" ); + } + + @Test + public void testBlockIfOrFalse() { + TestTemplateClass c = new TestTemplateClass(); + c.booleanField = false; + c.booleanObjectField = false; + assertThat( getTemplate( testMethodName, new TypeRef() {}, + "{{% if booleanField or booleanObjectField }}yes{{% else }}no{{% end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "no" ); + } + + @Test + public void testBlockIfNot() { + TestTemplateClass c = new TestTemplateClass(); + c.booleanField = false; + assertThat( getTemplate( testMethodName, new TypeRef() {}, + "{{% if not booleanField }}yes{{% else }}no{{% end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "yes" ); + } + + @Test + public void testBlockIfBangNot() { + TestTemplateClass c = new TestTemplateClass(); + c.booleanField = true; + assertThat( getTemplate( testMethodName, new TypeRef() {}, + "{{% if !booleanField }}yes{{% else }}no{{% end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "no" ); + } + + @Test + public void testBlockIfComplex() { + TestTemplateClass c = new TestTemplateClass(); + c.booleanField = true; + c.booleanObjectField = true; + c.field = "check"; + assertThat( getTemplate( testMethodName, new TypeRef() {}, + "{{% if (booleanField and booleanObjectField) and not booleanField }}yes{{% else }}no{{% end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "no" ); + } + + @Test + public void testBlockIfComplexTrue() { + TestTemplateClass c = new TestTemplateClass(); + c.booleanField = true; + c.booleanObjectField = true; + assertThat( getTemplate( testMethodName, new TypeRef() {}, + "{{% if (booleanField and booleanObjectField) and not booleanObjectField }}yes{{% else }}no{{% end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "no" ); + } + } diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineEnumRuntimeTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineEnumRuntimeTest.java new file mode 100644 index 000000000..cd276ab7d --- /dev/null +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineEnumRuntimeTest.java @@ -0,0 +1,8 @@ +package oap.template; + +public class TemplateEngineEnumRuntimeTest extends TemplateEngineEnumTest { + @Override + protected boolean useRuntime() { + return true; + } +} diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineEnumTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineEnumTest.java index 2bf652d98..a5b4fdcda 100644 --- a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineEnumTest.java +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineEnumTest.java @@ -37,7 +37,7 @@ public class TemplateEngineEnumTest extends AbstractTemplateEngineTest { public void testEnumField() { var c = new TestTemplateClass(); c.enumFieldWithoutDefaultValue = TestTemplateEnumWithoutDefaultValue.VAL1; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${enumFieldWithoutDefaultValue}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${enumFieldWithoutDefaultValue}", STRING, null ).render( c ).get() ) .isEqualTo( "VAL1" ); } @@ -45,7 +45,7 @@ public void testEnumField() { public void testEnumFieldDefault() { var c = new TestTemplateClass(); c.enumField = null; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${enumField??'VAL2'}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${enumField??'VAL2'}", STRING, null ).render( c ).get() ) .isEqualTo( "VAL2" ); } @@ -53,7 +53,7 @@ public void testEnumFieldDefault() { public void testEnumFieldWithoutDefault() { var c = new TestTemplateClass(); c.enumField = null; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${enumField}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${enumField}", STRING, null ).render( c ).get() ) .isEqualTo( "" ); } @@ -61,7 +61,7 @@ public void testEnumFieldWithoutDefault() { public void testEnumFieldDefaultEmptyAsUNKNOWN() { var c = new TestTemplateClass(); c.enumField = null; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${enumField??''}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${enumField??''}", STRING, null ).render( c ).get() ) .isEqualTo( "UNKNOWN" ); } @@ -69,7 +69,7 @@ public void testEnumFieldDefaultEmptyAsUNKNOWN() { public void testEnumFieldNonNull() { var c = new TestTemplateClass(); c.nonNullEnumField = TestTemplateEnum.VAL2; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${nonNullEnumField}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${nonNullEnumField}", STRING, null ).render( c ).get() ) .isEqualTo( "VAL2" ); } @@ -77,7 +77,7 @@ public void testEnumFieldNonNull() { public void testListEnum() { var c = new TestTemplateClass(); c.listEnum = List.of( TestTemplateEnum.VAL2, TestTemplateEnum.VAL1 ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${listEnum}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${listEnum}", STRING, null ).render( c ).get() ) .isEqualTo( "['VAL2','VAL1']" ); } } diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineFunctionsRuntimeTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineFunctionsRuntimeTest.java new file mode 100644 index 000000000..3c9e6c1ea --- /dev/null +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineFunctionsRuntimeTest.java @@ -0,0 +1,8 @@ +package oap.template; + +public class TemplateEngineFunctionsRuntimeTest extends TemplateEngineFunctionsTest { + @Override + protected boolean useRuntime() { + return true; + } +} diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineFunctionsTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineFunctionsTest.java index 8a5dcb46b..403556db6 100644 --- a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineFunctionsTest.java +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineFunctionsTest.java @@ -39,16 +39,16 @@ public class TemplateEngineFunctionsTest extends AbstractTemplateEngineTest { public void testMethod() { TestTemplateClass c = new TestTemplateClass(); c.field = "val2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${fieldM()}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${fieldM()}", STRING, null ).render( c ).get() ) .isEqualTo( "val2" ); } @Test public void testMethodDefault() { TestTemplateClass c = new TestTemplateClass(); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${fieldM()??'d'}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${fieldM()??'d'}", STRING, null ).render( c ).get() ) .isEqualTo( "d" ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${childM().field??'d'}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${childM().field??'d'}", STRING, null ).render( c ).get() ) .isEqualTo( "d" ); } @@ -56,7 +56,7 @@ public void testMethodDefault() { public void testMethodWithIntParameter() { TestTemplateClass c = new TestTemplateClass(); c.field = "val2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${fieldMInt(1 )}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${fieldMInt(1 )}", STRING, null ).render( c ).get() ) .isEqualTo( "val2-1" ); } @@ -64,7 +64,7 @@ public void testMethodWithIntParameter() { public void testMethodWithNegativeIntParameter() { TestTemplateClass c = new TestTemplateClass(); c.field = "val2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${fieldMInt( -1)}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${fieldMInt( -1)}", STRING, null ).render( c ).get() ) .isEqualTo( "val2--1" ); } @@ -72,7 +72,7 @@ public void testMethodWithNegativeIntParameter() { public void testMethodWithFloatParameter() { TestTemplateClass c = new TestTemplateClass(); c.field = "val2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${fieldMDouble(1.2 )}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${fieldMDouble(1.2 )}", STRING, null ).render( c ).get() ) .isEqualTo( "val2-1.2" ); } @@ -80,33 +80,33 @@ public void testMethodWithFloatParameter() { public void testMethodWithStringParameter() { TestTemplateClass c = new TestTemplateClass(); c.field = "val2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "${fieldMString( 'str')}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "${fieldMString( 'str')}", STRING, null ).render( c ).get() ) .isEqualTo( "val2-str" ); } @Test public void testFunctionUrlencode() { - assertThat( engine.getTemplate( "testFunctionUrlencode0", new TypeRef>() {}, "id=${v; urlencode(0)}", STRING, null ).render( Map.of( "v", "a i/d" ) ).get() ) + assertThat( getTemplate( "testFunctionUrlencode0", new TypeRef>() {}, "id=${v; urlencode(0)}", STRING, null ).render( Map.of( "v", "a i/d" ) ).get() ) .isEqualTo( "id=a i/d" ); - assertThat( engine.getTemplate( "testFunctionUrlencode1", new TypeRef>() {}, "id=${v; urlencode( 1)}", STRING, null ).render( Map.of( "v", "a i/d" ) ).get() ) + assertThat( getTemplate( "testFunctionUrlencode1", new TypeRef>() {}, "id=${v; urlencode( 1)}", STRING, null ).render( Map.of( "v", "a i/d" ) ).get() ) .isEqualTo( "id=a+i%2Fd" ); - assertThat( engine.getTemplate( "testFunctionUrlencode", new TypeRef>() {}, "id=${ v ; urlencode() }", STRING, null ).render( Map.of( "v", "a i/d" ) ).get() ) + assertThat( getTemplate( "testFunctionUrlencode", new TypeRef>() {}, "id=${ v ; urlencode() }", STRING, null ).render( Map.of( "v", "a i/d" ) ).get() ) .isEqualTo( "id=a+i%2Fd" ); - assertThat( engine.getTemplate( "testFunctionUrlencode2", new TypeRef>() {}, "id=${v; urlencode ( 2 )}", STRING, null ).render( Map.of( "v", "a i/d" ) ).get() ) + assertThat( getTemplate( "testFunctionUrlencode2", new TypeRef>() {}, "id=${v; urlencode ( 2 )}", STRING, null ).render( Map.of( "v", "a i/d" ) ).get() ) .isEqualTo( "id=a%2Bi%252Fd" ); - assertThat( engine.getTemplate( "testFunctionUrlencode", new TypeRef>() {}, "id=${ v ; urlencodePercent() }", STRING, null ).render( Map.of( "v", "a i/d" ) ).get() ) + assertThat( getTemplate( "testFunctionUrlencode", new TypeRef>() {}, "id=${ v ; urlencodePercent() }", STRING, null ).render( Map.of( "v", "a i/d" ) ).get() ) .isEqualTo( "id=a%20i%2Fd" ); } @Test public void testFunctionUrlencodeCollection() { - assertThat( engine.getTemplate( "testFunctionUrlencodeList", new TypeRef>>() {}, "id=${v; urlencode()}", STRING, null ).render( Map.of( "v", List.of( "a i/d", "X" ) ) ).get() ) + assertThat( getTemplate( "testFunctionUrlencodeList", new TypeRef>>() {}, "id=${v; urlencode()}", STRING, null ).render( Map.of( "v", List.of( "a i/d", "X" ) ) ).get() ) .isEqualTo( "id=%5B%27a+i%2Fd%27%2C%27X%27%5D" ); } @Test public void testFunctionToUpperCase() { - assertThat( engine.getTemplate( testMethodName, new TypeRef>() {}, "id=${v; toUpperCase()}", STRING, null ).render( Map.of( "v", "a i/d" ) ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef>() {}, "id=${v; toUpperCase()}", STRING, null ).render( Map.of( "v", "a i/d" ) ).get() ) .isEqualTo( "id=A I/D" ); } @@ -114,21 +114,21 @@ public void testFunctionToUpperCase() { public void testTypes() { Map map = Map.of( "v", Map.of( "d", 1.1d, "s1", Map.of( "s2", "str" ) ) ); - assertThat( engine.getTemplate( testMethodName, new TypeRef>() {}, "${v.d ?? 0.0}", OBJECT, null ).render( map ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef>() {}, "${v.d ?? 0.0}", OBJECT, null ).render( map ).get() ) .isEqualTo( 1.1d ); - assertThat( engine.getTemplate( testMethodName, new TypeRef>() {}, "${v.c ?? 0.1}", OBJECT, null ).render( map ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef>() {}, "${v.c ?? 0.1}", OBJECT, null ).render( map ).get() ) .isEqualTo( 0.1d ); - assertThat( engine.getTemplate( testMethodName, new TypeRef>() {}, "${v.d ?? 0.0}", STRING, null ).render( map ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef>() {}, "${v.d ?? 0.0}", STRING, null ).render( map ).get() ) .isEqualTo( "1.1" ); - assertThat( engine.getTemplate( testMethodName, new TypeRef>() {}, "${v.d ?? 0.0}", OBJECT, null ).render( map ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef>() {}, "${v.d ?? 0.0}", OBJECT, null ).render( map ).get() ) .isEqualTo( 1.1d ); - assertThat( engine.getTemplate( testMethodName, new TypeRef>() {}, "${v.c ?? 0.1}", OBJECT, null ).render( map ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef>() {}, "${v.c ?? 0.1}", OBJECT, null ).render( map ).get() ) .isEqualTo( 0.1d ); - assertThat( engine.getTemplate( testMethodName, new TypeRef>() {}, "${v.d ?? 0.0}", STRING, null ).render( map ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef>() {}, "${v.d ?? 0.0}", STRING, null ).render( map ).get() ) .isEqualTo( "1.1" ); - assertThat( engine.getTemplate( testMethodName, new TypeRef>() {}, "${v.s1.s2 ?? ''}", STRING, null ).render( map ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef>() {}, "${v.s1.s2 ?? ''}", STRING, null ).render( map ).get() ) .isEqualTo( "str" ); } @@ -136,9 +136,9 @@ public void testTypes() { public void testAlias() { TestTemplateClass c = new TestTemplateClass(); c.intField = 10; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ intField ; testInc() }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ intField ; testInc() }}", STRING, null ).render( c ).get() ) .isEqualTo( "11" ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ intField ; testIncAlias() }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ intField ; testIncAlias() }}", STRING, null ).render( c ).get() ) .isEqualTo( "11" ); } } diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineOrRuntimeTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineOrRuntimeTest.java new file mode 100644 index 000000000..c61d1d8c9 --- /dev/null +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineOrRuntimeTest.java @@ -0,0 +1,8 @@ +package oap.template; + +public class TemplateEngineOrRuntimeTest extends TemplateEngineOrTest { + @Override + protected boolean useRuntime() { + return true; + } +} diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineOrTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineOrTest.java index 79f0b2cdb..aed4c88f1 100644 --- a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineOrTest.java +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineOrTest.java @@ -38,7 +38,7 @@ public void testOrEmptyString() { TestTemplateClass c = new TestTemplateClass(); c.field2 = "f2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ field | default field2 }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ field | default field2 }}", STRING, null ).render( c ).get() ) .isEqualTo( "f2" ); } @@ -46,7 +46,7 @@ public void testOrEmptyString() { public void testOrNull() { TestTemplateClass c = new TestTemplateClass(); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ field | default field2 }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ field | default field2 }}", STRING, null ).render( c ).get() ) .isEqualTo( "" ); } @@ -55,7 +55,7 @@ public void testOrCollections() { TestTemplateClass c = new TestTemplateClass(); c.list2 = List.of( 2, 3 ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ list | default list2 }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ list | default list2 }}", STRING, null ).render( c ).get() ) .isEqualTo( "[2,3]" ); } } diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineRangeRuntimeTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineRangeRuntimeTest.java new file mode 100644 index 000000000..30dce6b09 --- /dev/null +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineRangeRuntimeTest.java @@ -0,0 +1,8 @@ +package oap.template; + +public class TemplateEngineRangeRuntimeTest extends TemplateEngineRangeTest { + @Override + protected boolean useRuntime() { + return true; + } +} diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineRangeTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineRangeTest.java index ad6f8394c..ef09022d7 100644 --- a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineRangeTest.java +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineRangeTest.java @@ -25,30 +25,12 @@ package oap.template; import oap.reflect.TypeRef; -import oap.testng.Fixtures; -import oap.util.Dates; -import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import java.lang.reflect.Method; - import static oap.template.TemplateAccumulators.STRING; import static org.assertj.core.api.Assertions.assertThat; -public class TemplateEngineRangeTest extends Fixtures { - private TemplateEngine engine; - private String testMethodName; - - @BeforeMethod - public void beforeMethod() { - engine = new TemplateEngine( Dates.d( 10 ) ); - } - - @BeforeMethod - public void nameBefore( Method method ) { - testMethodName = method.getName(); - } - +public class TemplateEngineRangeTest extends AbstractTemplateEngineTest { private TestTemplateClass root( String... fieldValues ) { TestTemplateClass c = new TestTemplateClass(); for( String fv : fieldValues ) { @@ -62,7 +44,7 @@ private TestTemplateClass root( String... fieldValues ) { @Test public void testRangeImplicitScope() { TestTemplateClass c = root( "a", "b", "c" ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% range listItems }}{{ field }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "abc" ); } @@ -70,7 +52,7 @@ public void testRangeImplicitScope() { @Test public void testRangeNamedItem() { TestTemplateClass c = root( "x", "y" ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% range $item := listItems }}{{ $item.field }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "xy" ); } @@ -78,7 +60,7 @@ public void testRangeNamedItem() { @Test public void testRangeNamedIndexItem() { TestTemplateClass c = root( "a", "b", "c" ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% range $i,$item := listItems }}{{ $i }}:{{ $item.field }} {{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "0:a 1:b 2:c " ); } @@ -89,7 +71,7 @@ public void testRangeMap() { TestTemplateClass v1 = new TestTemplateClass(); v1.field = "val1"; c.mapItems.put( "k1", v1 ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% range $k,$v := mapItems }}{{ $k }}={{ $v.field }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "k1=val1" ); } @@ -97,7 +79,7 @@ public void testRangeMap() { @Test public void testRangeElseEmpty() { TestTemplateClass c = new TestTemplateClass(); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% range listItems }}{{ field }}{{% else }}empty{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "empty" ); } @@ -105,7 +87,7 @@ public void testRangeElseEmpty() { @Test public void testRangeElseNonEmpty() { TestTemplateClass c = root( "v" ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% range listItems }}{{ field }}{{% else }}empty{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "v" ); } @@ -113,7 +95,7 @@ public void testRangeElseNonEmpty() { @Test public void testRangeIntervalLiteral() { TestTemplateClass c = new TestTemplateClass(); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% range $k := 1 .. 3 }}{{ $k }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "123" ); } @@ -121,7 +103,7 @@ public void testRangeIntervalLiteral() { @Test public void testRangeIntervalWithStep() { TestTemplateClass c = new TestTemplateClass(); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% range $k := 1 .. 5 step 2 }}{{ $k }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "135" ); } @@ -132,7 +114,7 @@ public void testRangeIntervalFieldBased() { c.rangeStart = 2; c.rangeEnd = 4; c.rangeStep = 1; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% range $k := rangeStart .. rangeEnd step rangeStep }}{{ $k }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "234" ); } diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineRuntimeTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineRuntimeTest.java new file mode 100644 index 000000000..b805a84d0 --- /dev/null +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineRuntimeTest.java @@ -0,0 +1,8 @@ +package oap.template; + +public class TemplateEngineRuntimeTest extends TemplateEngineTest { + @Override + protected boolean useRuntime() { + return true; + } +} diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTest.java index 43875868f..680e0524a 100644 --- a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTest.java +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTest.java @@ -48,7 +48,7 @@ public class TemplateEngineTest extends AbstractTemplateEngineTest { @Test public void testRenderStringText() { - assertThat( engine.getTemplate( testMethodName, new TypeRef>() {}, "sdkjf hdkfgj d$...{}", STRING, null ).render( null ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef>() {}, "sdkjf hdkfgj d$...{}", STRING, null ).render( null ).get() ) .isEqualTo( "sdkjf hdkfgj d$...{}" ); } @@ -57,7 +57,7 @@ public void testWithoutDefaultValue() { TestTemplateClass c = new TestTemplateClass(); c.childNullable = new TestTemplateClass(); c.childNullable.longField = 0; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{childNullable.longField}}", OBJECT, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{childNullable.longField}}", OBJECT, null ).render( c ).get() ) .isEqualTo( 0L ); } @@ -66,7 +66,7 @@ public void testEscapeVariables() { TestTemplateClass c = new TestTemplateClass(); c.field = "1"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ field }}\t{{ field }}", new TestTemplateAccumulatorString(), null ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ field }}\t{{ field }}", new TestTemplateAccumulatorString(), null ) .render( c ).get() ).isEqualTo( "12\t12" ); } @@ -75,19 +75,19 @@ public void testEscapeExpression() { TestTemplateClass c = new TestTemplateClass(); c.field = "1"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "$${field}", new TestTemplateAccumulatorString(), null ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "$${field}", new TestTemplateAccumulatorString(), null ) .render( c ).get() ).isEqualTo( "${field}" ); } @Test public void testMapProperty() { - assertThat( engine.getTemplate( testMethodName, new TypeRef>() {}, "{{ prop }}", STRING, null ).render( Map.of( "prop", "val" ) ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef>() {}, "{{ prop }}", STRING, null ).render( Map.of( "prop", "val" ) ).get() ) .isEqualTo( "val" ); } @Test public void testEscapeClassName() { - assertThat( engine.getTemplate( "111-" + testMethodName + "-? ()?пп1", new TypeRef>() {}, "{{ prop }}", STRING, null ).render( Map.of( "prop", "val" ) ).get() ) + assertThat( getTemplate( "111-" + testMethodName + "-? ()?пп1", new TypeRef>() {}, "{{ prop }}", STRING, null ).render( Map.of( "prop", "val" ) ).get() ) .isEqualTo( "val" ); } @@ -95,7 +95,7 @@ public void testEscapeClassName() { public void testField() { TestTemplateClass c = new TestTemplateClass(); c.field = "val1"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ field }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ field }}", STRING, null ).render( c ).get() ) .isEqualTo( "val1" ); } @@ -103,9 +103,9 @@ public void testField() { public void testFieldWithJsonProperty() { TestTemplateClass c = new TestTemplateClass(); c.jsonTest = "val1"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ jsonTest }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ jsonTest }}", STRING, null ).render( c ).get() ) .isEqualTo( "val1" ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ jsonTestNew }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ jsonTestNew }}", STRING, null ).render( c ).get() ) .isEqualTo( "val1" ); } @@ -113,11 +113,11 @@ public void testFieldWithJsonProperty() { public void testFieldWithJsonAlias() { TestTemplateClass c = new TestTemplateClass(); c.jsonTest = "val1"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ jsonTest }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ jsonTest }}", STRING, null ).render( c ).get() ) .isEqualTo( "val1" ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ jsonTestAlias1 }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ jsonTestAlias1 }}", STRING, null ).render( c ).get() ) .isEqualTo( "val1" ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ jsonTestAlias2 }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ jsonTestAlias2 }}", STRING, null ).render( c ).get() ) .isEqualTo( "val1" ); } @@ -125,14 +125,14 @@ public void testFieldWithJsonAlias() { public void testEnumField() { TestTemplateClass c = new TestTemplateClass(); c.enumField = TestTemplateEnum.VAL1; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ enumField }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ enumField }}", STRING, null ).render( c ).get() ) .isEqualTo( "VAL1" ); } @Test public void testEnumFieldDefaultValue() { TestTemplateClass c = new TestTemplateClass(); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ child.enumField ?? 'UNKNOWN' }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ child.enumField ?? 'UNKNOWN' }}", STRING, null ).render( c ).get() ) .isEqualTo( "UNKNOWN" ); } @@ -140,14 +140,14 @@ public void testEnumFieldDefaultValue() { public void testListField() { TestTemplateClass c = new TestTemplateClass(); c.list = List.of( 1, 2, 3 ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ list }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ list }}", STRING, null ).render( c ).get() ) .isEqualTo( "[1,2,3]" ); } @Test public void testListFieldWithoutDefault() { TestTemplateClass c = new TestTemplateClass(); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ list }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ list }}", STRING, null ).render( c ).get() ) .isEqualTo( "[]" ); } @@ -155,7 +155,7 @@ public void testListFieldWithoutDefault() { public void testListString() { TestTemplateClass c = new TestTemplateClass(); c.listString = List.of( "1", "'", "\\" ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ listString }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ listString }}", STRING, null ).render( c ).get() ) .isEqualTo( "['1','\\'','\\\\']" ); } @@ -163,7 +163,7 @@ public void testListString() { public void testListEnum() { TestTemplateClass c = new TestTemplateClass(); c.listEnum = List.of( TestTemplateEnum.VAL2, TestTemplateEnum.VAL1 ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ listEnum }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ listEnum }}", STRING, null ).render( c ).get() ) .isEqualTo( "['VAL2','VAL1']" ); } @@ -171,7 +171,7 @@ public void testListEnum() { public void testListFieldDefaultValue() { TestTemplateClass c = new TestTemplateClass(); c.list = null; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ list ?? [] }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ list ?? [] }}", STRING, null ).render( c ).get() ) .isEqualTo( "[]" ); } @@ -181,7 +181,7 @@ public void testChain() { TestTemplateClass c2 = new TestTemplateClass(); c1.child = c2; c2.field = "val3"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ child.field }}", STRING, null ).render( c1 ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ child.field }}", STRING, null ).render( c1 ).get() ) .isEqualTo( "val3" ); } @@ -190,7 +190,7 @@ public void testOrEmptyString() { TestTemplateClass c = new TestTemplateClass(); c.field2 = "f2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ field | default field2 }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ field | default field2 }}", STRING, null ).render( c ).get() ) .isEqualTo( "f2" ); } @@ -199,7 +199,7 @@ public void testOrCollections() { TestTemplateClass c = new TestTemplateClass(); c.list2 = List.of( 2, 3 ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ list | default list2 }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ list | default list2 }}", STRING, null ).render( c ).get() ) .isEqualTo( "[2,3]" ); } @@ -208,11 +208,11 @@ public void testOptional() { TestTemplateClass c = new TestTemplateClass(); c.fieldOpt = Optional.of( "o" ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ fieldOpt }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ fieldOpt }}", STRING, null ).render( c ).get() ) .isEqualTo( "o" ); c.fieldOpt = Optional.empty(); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ fieldOpt }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ fieldOpt }}", STRING, null ).render( c ).get() ) .isEqualTo( "" ); } @@ -224,11 +224,11 @@ public void testChildOptional() { c.intField = 10; cp.childOpt = Optional.of( c ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ childOpt.fieldOpt }}-{{ childOpt.intField }}", STRING, Map.of(), IGNORE ).render( cp ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ childOpt.fieldOpt }}-{{ childOpt.intField }}", STRING, Map.of(), IGNORE ).render( cp ).get() ) .isEqualTo( "o-10" ); cp.childOpt = Optional.empty(); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ childOpt.fieldOpt }}", STRING, null ).render( cp ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ childOpt.fieldOpt }}", STRING, null ).render( cp ).get() ) .isEqualTo( "" ); } @@ -237,11 +237,11 @@ public void testNullable() { TestTemplateClass c = new TestTemplateClass(); c.fieldNullable = "o"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ fieldNullable }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ fieldNullable }}", STRING, null ).render( c ).get() ) .isEqualTo( "o" ); c.fieldNullable = null; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ fieldNullable }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ fieldNullable }}", STRING, null ).render( c ).get() ) .isEqualTo( "" ); } @@ -252,23 +252,23 @@ public void testChildNullable() { c.fieldNullable = "o"; cp.childNullable = c; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ childNullable.fieldNullable ?? '' }}", STRING, null ).render( cp ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ childNullable.fieldNullable ?? '' }}", STRING, null ).render( cp ).get() ) .isEqualTo( "o" ); cp.childNullable = null; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ childNullable.fieldNullable ?? '' }}", STRING, null ).render( cp ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ childNullable.fieldNullable ?? '' }}", STRING, null ).render( cp ).get() ) .isEqualTo( "" ); } @Test public void testDefaultString() { - assertThat( engine.getTemplate( testMethodName, new TypeRef>() {}, "{{ bbb ?? 'test' }}", STRING, null ).render( Map.of( "prop", "val" ) ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef>() {}, "{{ bbb ?? 'test' }}", STRING, null ).render( Map.of( "prop", "val" ) ).get() ) .isEqualTo( "test" ); } @Test public void testDefaultInt() { - assertThat( engine.getTemplate( testMethodName, new TypeRef>() {}, "{{ bbb ?? -1 }}", STRING, null ).render( Map.of( "prop", 1 ) ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef>() {}, "{{ bbb ?? -1 }}", STRING, null ).render( Map.of( "prop", 1 ) ).get() ) .isEqualTo( "-1" ); } @@ -278,21 +278,21 @@ public void testDefaultBoolean() { c.childNullable = null; c.childOpt = Optional.empty(); - assertThat( engine.getTemplate( testMethodName + "True", new TypeRef() {}, "{{ childNullable.booleanObjectField ?? true }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName + "True", new TypeRef() {}, "{{ childNullable.booleanObjectField ?? true }}", STRING, null ).render( c ).get() ) .isEqualTo( "true" ); - assertThat( engine.getTemplate( testMethodName + "True", new TypeRef() {}, "{{ childOpt.booleanObjectField ?? true }}", STRING, Map.of(), IGNORE ).render( c ).get() ) + assertThat( getTemplate( testMethodName + "True", new TypeRef() {}, "{{ childOpt.booleanObjectField ?? true }}", STRING, Map.of(), IGNORE ).render( c ).get() ) .isEqualTo( "true" ); } @Test public void testDefaultDouble() { - assertThat( engine.getTemplate( testMethodName, new TypeRef>() {}, "{{ bbb ?? 0.0 }}", STRING, null ).render( Map.of( "prop", 1.1 ) ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef>() {}, "{{ bbb ?? 0.0 }}", STRING, null ).render( Map.of( "prop", 1.1 ) ).get() ) .isEqualTo( "0.0" ); } @Test public void testMix() { - assertThat( engine.getTemplate( testMethodName, new TypeRef>() {}, "-{{ prop }}-{{ b }}-", STRING, null ).render( Map.of( "prop", "val", "b", "b1" ) ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef>() {}, "-{{ prop }}-{{ b }}-", STRING, null ).render( Map.of( "prop", "val", "b", "b1" ) ).get() ) .isEqualTo( "-val-b1-" ); } @@ -307,7 +307,7 @@ public void testAliases() { c2.field = "val3"; c3.field2 = "f2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ child.field }}", STRING, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ child.field }}", STRING, Map.of( "child.field", "child2.field2" ), ERROR ).render( c1 ).get() ) .isEqualTo( "f2" ); } @@ -318,10 +318,10 @@ public void testDiskCache() { c1.field = "1"; c1.field2 = "2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ field }}", STRING, ERROR, null ).render( c1 ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ field }}", STRING, ERROR, null ).render( c1 ).get() ) .isEqualTo( "1" ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ field2 }}", STRING, ERROR, null ).render( c1 ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ field2 }}", STRING, ERROR, null ).render( c1 ).get() ) .isEqualTo( "2" ); TemplateEngine engine2 = new TemplateEngine( testDirectoryFixture.testDirectory(), Dates.d( 10 ) ); @@ -356,7 +356,7 @@ private void replace( String fileName ) throws IOException { @Test public void testErrorSyntax() { - assertThatThrownBy( () -> engine.getTemplate( testMethodName, new TypeRef>() {}, "id={{ v; toUpperCase()", STRING, ERROR, null ) ) + assertThatThrownBy( () -> getTemplate( testMethodName, new TypeRef>() {}, "id={{ v; toUpperCase()", STRING, ERROR, null ) ) .isInstanceOf( TemplateException.class ); } @@ -364,7 +364,7 @@ public void testErrorSyntax() { public void testExt() { TestTemplateClass c = new TestTemplateClass(); c.ext2 = new TestTemplateClassExt( "ev" ); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ ext.a | default ext2.a }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ ext.a | default ext2.a }}", STRING, null ).render( c ).get() ) .isEqualTo( "ev" ); } @@ -372,7 +372,7 @@ public void testExt() { public void testDefaultExt() { TestTemplateClass c = new TestTemplateClass(); c.ext3.a = "123"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ ext2.a | default ext3.a }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ ext2.a | default ext3.a }}", STRING, null ).render( c ).get() ) .isEqualTo( "123" ); } @@ -382,7 +382,7 @@ public void testConcatenation() { c.field = "f1"; c.field2 = "f2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ {field,\"x\",field2} }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ {field,\"x\",field2} }}", STRING, null ).render( c ).get() ) .isEqualTo( "f1xf2" ); } @@ -394,7 +394,7 @@ public void testNestedConcatenation() { c1.field = "f1"; c1.field2 = "f2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ child{field,\"x\",field2} }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ child{field,\"x\",field2} }}", STRING, null ).render( c ).get() ) .isEqualTo( "f1xf2" ); } @@ -406,7 +406,7 @@ public void testNestedConcatenationWithDot() { c1.field2 = "f1"; c1.field22 = "f2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ child2.{field2,\"x\",field22} }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ child2.{field2,\"x\",field22} }}", STRING, null ).render( c ).get() ) .isEqualTo( "f1xf2" ); } @@ -415,7 +415,7 @@ public void testSum() { TestTemplateClass c = new TestTemplateClass(); c.intField = 123; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ intField + 12.45 }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ intField + 12.45 }}", STRING, null ).render( c ).get() ) .isEqualTo( "135.45" ); } @@ -423,7 +423,7 @@ public void testSum() { public void testSumDefault() { TestTemplateClass c = new TestTemplateClass(); - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ intObjectField + 12.45 ?? 5 }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ intObjectField + 12.45 ?? 5 }}", STRING, null ).render( c ).get() ) .isEqualTo( "5" ); } @@ -432,13 +432,13 @@ public void testComment() { TestTemplateClass c = new TestTemplateClass(); c.intField = 123; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ /* intField */intField }}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ /* intField */intField }}", STRING, null ).render( c ).get() ) .isEqualTo( "123" ); } @Test public void testErrorSyntaxMsg() { - assertThatThrownBy( () -> engine.getTemplate( testMethodName, new TypeRef>() {}, "id={{ unknownField.unknownField }}", STRING, ERROR, null ) ) + assertThatThrownBy( () -> getTemplate( testMethodName, new TypeRef>() {}, "id={{ unknownField.unknownField }}", STRING, ERROR, null ) ) .isInstanceOf( TemplateException.class ) .hasMessageContaining( "unknownField.unknownField" ); } @@ -452,7 +452,7 @@ public void testPrimitiveAsObject() { templateClass.intField = 1; templateClass.intObjectField = 2; - String str = engine.getTemplate( testMethodName, new TypeRef() {}, + String str = getTemplate( testMethodName, new TypeRef() {}, "booleanField:{{ booleanField }},booleanObjectField:{{ booleanObjectField }},intField:{{ intField }},intObjectField:{{ intObjectField }}", templateAccumulator, ERROR, null ).render( templateClass ).get(); @@ -466,7 +466,7 @@ public void testPrimitiveAsObjectDefaultValue() { TestPrimitiveTemplateAccumulatorString templateAccumulator = new TestPrimitiveTemplateAccumulatorString(); TestTemplateClass templateClass = new TestTemplateClass(); - String str = engine.getTemplate( testMethodName, new TypeRef() {}, + String str = getTemplate( testMethodName, new TypeRef() {}, "booleanField:{{ booleanField ?? true }},booleanObjectField:{{ booleanObjectField ?? true }}" + ",byteField:{{ byteField ?? 1 }},byteObjectField:{{ byteObjectField ?? 1 }}" + ",shortField:{{ shortField ?? 1 }},shortObjectField:{{ shortObjectField ?? 1 }}" @@ -493,7 +493,7 @@ public void testCacheClassFormatError() throws IOException { TestTemplateClass c = new TestTemplateClass(); c.field = "1"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, "{{ field }}\t{{ field }}", new TestTemplateAccumulatorString(), null ) + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ field }}\t{{ field }}", new TestTemplateAccumulatorString(), null ) .render( c ).get() ).isEqualTo( "12\t12" ); FileUtils.write( testDirectoryFixture.testPath( "oap.template.testCacheClassFormatError.class" ).toFile(), "", UTF_8 ); diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTrimRuntimeTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTrimRuntimeTest.java new file mode 100644 index 000000000..9d95ec282 --- /dev/null +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTrimRuntimeTest.java @@ -0,0 +1,8 @@ +package oap.template; + +public class TemplateEngineTrimRuntimeTest extends TemplateEngineTrimTest { + @Override + protected boolean useRuntime() { + return true; + } +} diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTrimTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTrimTest.java index 781ba33e0..b4c61fefc 100644 --- a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTrimTest.java +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTrimTest.java @@ -25,42 +25,17 @@ package oap.template; import oap.reflect.TypeRef; -import oap.testng.Fixtures; -import oap.testng.TestDirectoryFixture; -import oap.util.Dates; -import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import java.lang.reflect.Method; - import static oap.template.TemplateAccumulators.STRING; import static org.assertj.core.api.Assertions.assertThat; -public class TemplateEngineTrimTest extends Fixtures { - private final TestDirectoryFixture testDirectoryFixture; - private TemplateEngine engine; - private String testMethodName; - - public TemplateEngineTrimTest() { - testDirectoryFixture = fixture( new TestDirectoryFixture() ); - } - - @BeforeMethod - public void beforeCMethod() { - engine = new TemplateEngine( Dates.d( 10 ) ); - } - - @BeforeMethod - public void nameBefore( Method method ) { - testMethodName = method.getName(); - } - - +public class TemplateEngineTrimTest extends AbstractTemplateEngineTest { @Test public void testTrimLeft() { TestTemplateClass c = new TestTemplateClass(); c.field = "test"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "aa {{- field }}", STRING, null ).render( c ).get() ) .isEqualTo( "aatest" ); } @@ -69,7 +44,7 @@ public void testTrimLeft() { public void testTrimRight() { TestTemplateClass c = new TestTemplateClass(); c.field = "test"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ field -}} bb", STRING, null ).render( c ).get() ) .isEqualTo( "testbb" ); } @@ -78,7 +53,7 @@ public void testTrimRight() { public void testTrimBoth() { TestTemplateClass c = new TestTemplateClass(); c.field = "test"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "aa {{- field -}} \nbb", STRING, null ).render( c ).get() ) .isEqualTo( "aatestbb" ); } @@ -87,7 +62,7 @@ public void testTrimBoth() { public void testTrimMultipleSpaces() { TestTemplateClass c = new TestTemplateClass(); c.field = "test"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "aa \t{{- field -}}\t\n bb", STRING, null ).render( c ).get() ) .isEqualTo( "aatestbb" ); } @@ -96,7 +71,7 @@ public void testTrimMultipleSpaces() { public void testTrimNoAdjacentText() { TestTemplateClass c = new TestTemplateClass(); c.field = "test"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{- field -}}", STRING, null ).render( c ).get() ) .isEqualTo( "test" ); } @@ -106,7 +81,7 @@ public void testBlockIfLTrim() { TestTemplateClass c = new TestTemplateClass(); c.booleanField = true; c.field = "world"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "aa\n{{%- if booleanField }}{{ field }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "aaworld" ); } diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTypesRuntimeTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTypesRuntimeTest.java new file mode 100644 index 000000000..ad50068cc --- /dev/null +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTypesRuntimeTest.java @@ -0,0 +1,8 @@ +package oap.template; + +public class TemplateEngineTypesRuntimeTest extends TemplateEngineTypesTest { + @Override + protected boolean useRuntime() { + return true; + } +} diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTypesTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTypesTest.java index b04d2d54e..69c501046 100644 --- a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTypesTest.java +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineTypesTest.java @@ -44,13 +44,13 @@ public void testTypes() { templateClass.intField = 1; templateClass.intObjectField = 2; - var str = engine.getTemplate( testMethodName, new TypeRef() {}, + var str = getTemplate( testMethodName, new TypeRef() {}, "booleanField:${booleanField},booleanObjectField:${booleanObjectField},intField:${intField},intObjectField:${intObjectField}", templateAccumulator, ERROR, null ).render( templateClass ).get(); assertThat( str ).isEqualTo( "booleanField:true_b,booleanObjectField:true_b,intField:1_i,intObjectField:2_i" ); - assertThatThrownBy( () -> engine.getTemplate( testMethodName, new TypeRef() {}, + assertThatThrownBy( () -> getTemplate( testMethodName, new TypeRef() {}, "booleanField:${booleanField}", templateAccumulator, ERROR, null ).render( templateClass ) ) .isInstanceOf( TemplateException.class ) @@ -64,7 +64,7 @@ public void testObjectReference() { templateClass.child = new TestTemplateClass(); templateClass.child.intField = 100; - var str = engine.getTemplate( testMethodName, new TypeRef() {}, + var str = getTemplate( testMethodName, new TypeRef() {}, "child.intField:${child.intField}", templateAccumulator, ERROR, null ).render( templateClass ).get(); @@ -80,7 +80,7 @@ public void testObjectReferenceWithConcatenation() { templateClass.child.child.field = "v1"; templateClass.child.child.field2 = "v2"; - var str = engine.getTemplate( testMethodName, new TypeRef() {}, + var str = getTemplate( testMethodName, new TypeRef() {}, "child.child.{field,\"x\",field2}:${child.child.{field,\"x\",field2}}", templateAccumulator, ERROR, null ).render( templateClass ).get(); @@ -94,7 +94,7 @@ public void testNullableObjectReference() { templateClass.childNullable = new TestTemplateClass(); templateClass.childNullable.intField = 100; - var str = engine.getTemplate( testMethodName, new TypeRef() {}, + var str = getTemplate( testMethodName, new TypeRef() {}, "childNullable.intField:${childNullable.intField}", templateAccumulator, ERROR, null ).render( templateClass ).get(); @@ -107,7 +107,7 @@ public void testDefaultBoolean() { c.childNullable = null; c.childOpt = Optional.empty(); - assertThat( engine.getTemplate( testMethodName + "True", new TypeRef() {}, "${childNullable.booleanObjectField??true}", STRING, null ).render( c ).get() ) + assertThat( getTemplate( testMethodName + "True", new TypeRef() {}, "${childNullable.booleanObjectField??true}", STRING, null ).render( c ).get() ) .isEqualTo( "true" ); } } diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineWithRuntimeTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineWithRuntimeTest.java new file mode 100644 index 000000000..c2f25231d --- /dev/null +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineWithRuntimeTest.java @@ -0,0 +1,8 @@ +package oap.template; + +public class TemplateEngineWithRuntimeTest extends TemplateEngineWithTest { + @Override + protected boolean useRuntime() { + return true; + } +} diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineWithTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineWithTest.java index a0f02e2a2..4a391e7ca 100644 --- a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineWithTest.java +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineWithTest.java @@ -25,38 +25,20 @@ package oap.template; import oap.reflect.TypeRef; -import oap.testng.Fixtures; -import oap.util.Dates; -import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import java.lang.reflect.Method; - import static oap.template.ErrorStrategy.ERROR; import static oap.template.TemplateAccumulators.STRING; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -public class TemplateEngineWithTest extends Fixtures { - private TemplateEngine engine; - private String testMethodName; - - @BeforeMethod - public void beforeMethod() { - engine = new TemplateEngine( Dates.d( 10 ) ); - } - - @BeforeMethod - public void nameBefore( Method method ) { - testMethodName = method.getName(); - } - +public class TemplateEngineWithTest extends AbstractTemplateEngineTest { @Test public void testInlineWithField() { TestTemplateClass c = new TestTemplateClass(); c.child = new TestTemplateClass(); c.child.field = "val"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ with (child) field end }}", STRING, null ).render( c ).get() ) .isEqualTo( "val" ); } @@ -67,7 +49,7 @@ public void testInlineWithFallback() { c.child = new TestTemplateClass(); c.child.field = null; c.child.field2 = "fb"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ with (child) field | default field2 end }}", STRING, null ).render( c ).get() ) .isEqualTo( "fb" ); } @@ -76,7 +58,7 @@ public void testInlineWithFallback() { public void testInlineWithNullScope() { TestTemplateClass c = new TestTemplateClass(); c.child = null; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ with (child) field end }}", STRING, null ).render( c ).get() ) .isEqualTo( "" ); } @@ -86,7 +68,7 @@ public void testBlockWithBasic() { TestTemplateClass c = new TestTemplateClass(); c.child = new TestTemplateClass(); c.child.field = "val"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% with child }}{{ field }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "val" ); } @@ -96,7 +78,7 @@ public void testBlockWithTextAroundExpr() { TestTemplateClass c = new TestTemplateClass(); c.child = new TestTemplateClass(); c.child.field = "val"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% with child }}A{{ field }}B{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "AvalB" ); } @@ -105,7 +87,7 @@ public void testBlockWithTextAroundExpr() { public void testBlockWithNullScopeSkipsBody() { TestTemplateClass c = new TestTemplateClass(); c.child = null; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% with child }}{{ field }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "" ); } @@ -116,7 +98,7 @@ public void testBlockWithMultipleFields() { c.child = new TestTemplateClass(); c.child.field = "f1"; c.child.field2 = "f2"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% with child }}{{ field }}-{{ field2 }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "f1-f2" ); } @@ -127,7 +109,7 @@ public void testBlockWithRootScope() { c.field = "root-val"; c.child = new TestTemplateClass(); c.child.field = "scoped-val"; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% with child }}{{ $.field }}{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "root-val" ); } @@ -138,7 +120,7 @@ public void testInlineWithRootScopeFallback() { c.field = "root-val"; c.child = new TestTemplateClass(); c.child.field = null; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ with (child) field | default $.field end }}", STRING, null ).render( c ).get() ) .isEqualTo( "root-val" ); } @@ -147,7 +129,7 @@ public void testInlineWithRootScopeFallback() { public void testBlockWithNullScopeUsesDefault() { TestTemplateClass c = new TestTemplateClass(); c.child = null; - assertThat( engine.getTemplate( testMethodName, new TypeRef() {}, + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{% with child }}A{{ field2 ?? 'a' }}B{{% end }}", STRING, null ).render( c ).get() ) .isEqualTo( "AaB" ); } @@ -155,7 +137,7 @@ public void testBlockWithNullScopeUsesDefault() { @Test public void testBlockWithUnknownFieldThrows() { assertThatThrownBy( () -> - engine.getTemplate( testMethodName, new TypeRef() {}, + getTemplate( testMethodName, new TypeRef() {}, "{{% with unknownField }}x{{% end }}", STRING, ERROR, null ) ) .isInstanceOf( TemplateException.class ); } diff --git a/oap-formats/pom.xml b/oap-formats/pom.xml index 36e8847cf..6b5864bc7 100644 --- a/oap-formats/pom.xml +++ b/oap-formats/pom.xml @@ -15,6 +15,7 @@ oap-tsv oap-json oap-template + oap-template-test oap-logstream \ No newline at end of file diff --git a/pom.xml b/pom.xml index df1e831c8..c0eb4255b 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ - 25.5.6 + 25.5.7 25.0.1 25.0.0 From d04e2c827821a6ced527733e11b4c872ce15405e Mon Sep 17 00:00:00 2001 From: "igor.petrenko" Date: Wed, 22 Apr 2026 13:20:17 +0300 Subject: [PATCH 2/4] CE-148 oap-template: interpreter mode --- .../src/main/java/oap/logstream/LogIdTemplate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/LogIdTemplate.java b/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/LogIdTemplate.java index 4f204326d..ce4cf3991 100644 --- a/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/LogIdTemplate.java +++ b/oap-formats/oap-logstream/oap-logstream/src/main/java/oap/logstream/LogIdTemplate.java @@ -66,7 +66,7 @@ public String render( TemplateEngine templateEngine, String template, DateTime t context.putAll( variables ); - return templateEngine.getTemplate( "LogIdTemplate", new TypeRef>() {}, template, TemplateAccumulators.STRING, _ -> {} ).render( context ).get(); + return templateEngine.getRuntimeTemplate( "LogIdTemplate", new TypeRef>() {}, template, TemplateAccumulators.STRING, _ -> {} ).render( context ).get(); } public void init( Map context, DateTime time, Timestamp timestamp, int version, String hostname ) { From 37506b70135f2c832789fbf74bd7562874b65eba Mon Sep 17 00:00:00 2001 From: "igor.petrenko" Date: Wed, 22 Apr 2026 14:11:36 +0300 Subject: [PATCH 3/4] CE-148 oap-template: interpreter mode --- .../test/java/oap/logstream/LoggerTest.java | 1 - oap-formats/oap-template/README.md | 130 ++++++++++++++++-- .../template/TemplateEngineConditionTest.java | 75 ++++++++++ 3 files changed, 194 insertions(+), 12 deletions(-) diff --git a/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/LoggerTest.java b/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/LoggerTest.java index 6c689533f..0f220d099 100644 --- a/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/LoggerTest.java +++ b/oap-formats/oap-logstream/oap-logstream-test/src/test/java/oap/logstream/LoggerTest.java @@ -33,7 +33,6 @@ import oap.logstream.net.server.SocketLoggerServer; import oap.message.client.MessageSender; import oap.message.server.MessageHttpHandler; -import oap.template.TemplateEngine; import oap.template.TemplateEngineFixture; import oap.template.Types; import oap.testng.Fixtures; diff --git a/oap-formats/oap-template/README.md b/oap-formats/oap-template/README.md index aed76cafa..6ea9d0200 100644 --- a/oap-formats/oap-template/README.md +++ b/oap-formats/oap-template/README.md @@ -16,7 +16,10 @@ A compile-time template engine for the OAP framework. Each unique template strin - [Concatenation](#concatenation) - [Math](#math) - [If / then / else (inline)](#if--then--else-inline) + - [Compound conditions (inline)](#compound-conditions-inline) - [If / else / end (block)](#if--else--end-block) + - [Compound conditions](#compound-conditions) + - [Truthiness semantics](#truthiness-semantics) - [With scope (inline)](#with-scope-inline) - [With scope (block)](#with-scope-block) - [Pipe-to-function](#pipe-to-function) @@ -26,6 +29,7 @@ A compile-time template engine for the OAP framework. Each unique template strin - [Custom Functions](#custom-functions) - [Output Accumulators](#output-accumulators) - [Using the Engine in Java](#using-the-engine-in-java) +- [Runtime Interpreter Mode](#runtime-interpreter-mode) - [OAP Module Integration](#oap-module-integration) - [Aliases](#aliases) - [Error Handling](#error-handling) @@ -60,17 +64,25 @@ Template string + TypeRef + Accumulator TemplateAstUtils.toAst() ← walks the type hierarchy via reflection, resolves fields/methods, builds AstRender nodes │ - ▼ - Render (code generation) ← emits a Java source file - │ - ▼ - MemoryClassLoaderJava ← compiles and loads the generated class + ├─── getTemplate() ──────────────────────────────────────────────────────┐ + │ │ + ▼ │ + Render (code generation) ← emits a Java source file │ + │ │ + ▼ │ + MemoryClassLoaderJava ← compiles and loads the generated class │ + │ │ + ▼ │ + Guava Cache ←→ optional disk cache │ + │ │ + ▼ │ + template.render(obj) ← calls compiled TriConsumer directly │ + │ + └─── getRuntimeTemplate() ───────────────────────────────────────────────┘ │ ▼ - Guava Cache ←→ optional disk cache - │ - ▼ - template.render(obj) ← calls compiled TriConsumer directly + AstRender tree interpreted via reflection (RuntimeContext) + No compilation, no cache — each render walks the AST directly ``` Field resolution honours `@JsonProperty` and `@JsonAlias` annotations as alternate names. `@Nullable` / `@Nonnull` control null-check code generation. @@ -235,7 +247,7 @@ Operators: `+`, `-`, `*`, `/`, `%`. The right-hand operand must be a numeric lit {{ if booleanField then field else field2 end }} ``` -The condition must be a `boolean` field or a nullable `Boolean` object. A null `Boolean` is treated as false. +The condition can be any field path or a compound boolean expression (see below). Truthiness is determined by the field's type — see [Truthiness semantics](#truthiness-semantics). Can be combined with a default value: @@ -243,6 +255,19 @@ Can be combined with a default value: {{ if isPremium then premiumField end ?? 'standard' }} ``` +#### Compound conditions (inline) + +The same `and`, `or`, `not` / `!`, and parenthesised grouping supported by block-if are available in inline if. Operator precedence: `not` / `!` → `and` → `or`. + +``` +{{ if active and not user.isBanned then user.name end }} +{{ if flagA or flagB then field else field2 end }} +{{ if !booleanField then fallback end }} +{{ if (a and b) or c then field end }} +``` + +Field types follow the same truthiness rules as block-if — a `String` is truthy when non-empty, a `Collection` or `Map` when non-empty, an array when `length > 0`, any other non-null value is truthy, and `null` is always false. + ### If / else / end (block) Block-level conditionals span multiple lines and can contain arbitrary template content (plain text and expression blocks) in each branch. @@ -265,7 +290,7 @@ With an else branch: **Rules:** -- The condition is a field path (e.g. `booleanField`, `child.active`). It must resolve to a `boolean` primitive or a nullable `Boolean` object. A null `Boolean` is treated as `false`. +- The condition is a field path (e.g. `booleanField`, `child.active`) or a compound boolean expression (see below). Any field type is allowed; truthiness is determined by the field's type (see [Truthiness semantics](#truthiness-semantics)). - Each branch is a full template body — any mix of literal text and `{{ expr }}` / `${ expr }` expression blocks. - The `{{% else }}` branch is optional. - Blocks can be nested inside each other's branches. @@ -291,6 +316,51 @@ Nested example: {{% end }} ``` +#### Compound conditions + +Block-if conditions support `and`, `or`, `not` / `!` operators and parenthesised grouping. Operator precedence (highest to lowest): `not` / `!` → `and` → `or`. + +| Operator | Syntax | Example | +|---|---|---| +| AND | `and` | `{{% if active and user.isPremium }}` | +| OR | `or` | `{{% if flagA or flagB }}` | +| NOT | `not` | `{{% if not booleanField }}` | +| NOT | `!` | `{{% if !booleanField }}` | +| Grouping | `( … )` | `{{% if (a and b) or c }}` | + +``` +{{% if active and not user.isBanned }} + Welcome, {{ user.name }}! +{{% end }} + +{{% if (flagA and flagB) or flagC }} + condition met +{{% end }} +``` + +Operators can be applied to any field type — truthiness is evaluated per type before combining. + +#### Truthiness semantics + +Any field type may appear in a `{{% if … }}` condition. The field value is coerced to a boolean as follows: + +| Field type | Truthy when | +|---|---| +| `boolean` | value is `true` | +| `Boolean` | non-null and `true` | +| `String` | non-null and non-empty | +| `Collection` | non-null and non-empty | +| `Map` | non-null and non-empty | +| array | non-null and `length > 0` | +| any other type | non-null | +| `null` | always `false` | + +``` +{{% if name }}Hello, {{ name }}!{{% end %}} +{{% if tags }}Tags: {{ tags }}{{% end %}} +{{% if name and tags }}{{ name }} has tags{{% end %}} +``` + ### With scope (inline) `{{ with (scopePath) bodyExpr end }}` — evaluates `bodyExpr` relative to the object resolved by `scopePath`. At compile time the scope path is prepended to each body expression, so this is purely syntactic sugar for chained field access. @@ -538,6 +608,44 @@ engine.getTemplate( name, type, tmpl, acc, ast -> log.debug( ast.print() ) ); --- +## Runtime Interpreter Mode + +By default `getTemplate` generates a Java class, compiles it in memory, and caches it — the compiled code runs at near-native speed on subsequent calls. An alternative path, `getRuntimeTemplate`, interprets the same AST directly via reflection without any code generation or compilation. + +**When to use:** + +- Environments where dynamic classloading or bytecode generation is restricted (e.g. OSGi containers, some native-image builds) +- Short-lived or one-shot templates where paying the compile cost once is not worth it +- Unit tests that need to verify template logic without the JIT warm-up noise + +**API** — mirrors `getTemplate` exactly; replace the method name: + +```java +// Compile-time path (default): +Template template = + engine.getTemplate( "myTemplate", new TypeRef() {}, "id={{ id }}", STRING, null ); + +// Runtime interpreter path: +Template template = + engine.getRuntimeTemplate( "myTemplate", new TypeRef() {}, "id={{ id }}", STRING ); +``` + +All overloads accepting `aliases`, `ErrorStrategy`, and `postProcess` are available on both methods. + +**Rendering** is identical — call `template.render(obj)` the same way: + +```java +String result = template.render( bean ).get(); +``` + +**Limitations compared to `getTemplate`:** + +- No disk cache — the AST is always re-walked on each `render` call (though the AST itself is built once and can be cached). +- No compile-time Micrometer metrics. +- Throughput is lower for high-frequency rendering; prefer `getTemplate` in production hot paths. + +--- + ## OAP Module Integration The module registers a pre-wired service `oap-template-engine`: diff --git a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConditionTest.java b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConditionTest.java index 7e898bded..db994e997 100644 --- a/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConditionTest.java +++ b/oap-formats/oap-template/src/test/java/oap/template/TemplateEngineConditionTest.java @@ -94,6 +94,81 @@ public void testIfConditionWithDefaultValue() { .isEqualTo( "default" ); } + @Test + public void testIfConditionAnd() { + TestTemplateClass c = new TestTemplateClass(); + c.field = "val"; + c.booleanField = true; + c.booleanObjectField = true; + assertThat( getTemplate( testMethodName + "BothTrue", new TypeRef() {}, "{{ if booleanField and booleanObjectField then field end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "val" ); + + c.booleanObjectField = false; + assertThat( getTemplate( testMethodName + "SecondFalse", new TypeRef() {}, "{{ if booleanField and booleanObjectField then field end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "" ); + } + + @Test + public void testIfConditionOr() { + TestTemplateClass c = new TestTemplateClass(); + c.field = "val"; + c.booleanField = false; + c.booleanObjectField = true; + assertThat( getTemplate( testMethodName + "SecondTrue", new TypeRef() {}, "{{ if booleanField or booleanObjectField then field end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "val" ); + + c.booleanObjectField = false; + assertThat( getTemplate( testMethodName + "BothFalse", new TypeRef() {}, "{{ if booleanField or booleanObjectField then field end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "" ); + } + + @Test + public void testIfConditionNot() { + TestTemplateClass c = new TestTemplateClass(); + c.field = "val"; + c.booleanField = false; + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ if not booleanField then field end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "val" ); + } + + @Test + public void testIfConditionBangNot() { + TestTemplateClass c = new TestTemplateClass(); + c.field = "val"; + c.booleanField = true; + assertThat( getTemplate( testMethodName, new TypeRef() {}, "{{ if !booleanField then field end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "" ); + } + + @Test + public void testIfConditionAndString() { + TestTemplateClass c = new TestTemplateClass(); + c.field = "hello"; + c.field2 = "world"; + assertThat( getTemplate( testMethodName + "BothNonEmpty", new TypeRef() {}, "{{ if field and field2 then field end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "hello" ); + + c.field2 = ""; + assertThat( getTemplate( testMethodName + "SecondEmpty", new TypeRef() {}, "{{ if field and field2 then field end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "" ); + + c.field = null; + c.field2 = "world"; + assertThat( getTemplate( testMethodName + "FirstNullOrSecond", new TypeRef() {}, "{{ if field or field2 then field2 end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "world" ); + } + + @Test + public void testIfConditionComplex() { + TestTemplateClass c = new TestTemplateClass(); + c.field = "val"; + c.booleanField = true; + c.booleanObjectField = true; + assertThat( getTemplate( testMethodName, new TypeRef() {}, + "{{ if (booleanField and booleanObjectField) and not booleanField then field end }}", STRING, null ).render( c ).get() ) + .isEqualTo( "" ); + } + @Test public void testBlockIfTrue() { TestTemplateClass c = new TestTemplateClass(); From cfcadbb3140448df01e39f4b6383bd6ed44b4ed8 Mon Sep 17 00:00:00 2001 From: "igor.petrenko" Date: Wed, 22 Apr 2026 14:20:17 +0300 Subject: [PATCH 4/4] CE-148 oap-template: interpreter mode --- oap-formats/oap-template/README.md | 98 ++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/oap-formats/oap-template/README.md b/oap-formats/oap-template/README.md index 6ea9d0200..300cde1bc 100644 --- a/oap-formats/oap-template/README.md +++ b/oap-formats/oap-template/README.md @@ -22,6 +22,7 @@ A compile-time template engine for the OAP framework. Each unique template strin - [Truthiness semantics](#truthiness-semantics) - [With scope (inline)](#with-scope-inline) - [With scope (block)](#with-scope-block) + - [Range (block)](#range-block) - [Pipe-to-function](#pipe-to-function) - [Cast types](#cast-types) - [Block comments](#block-comments) @@ -428,6 +429,103 @@ Renders `AnoneB` when `child` is null. Renders `A` + field value + `B` when `chi - Blocks may be nested inside other block constructs (`{{% if … }}`, other `{{% with … }}`). - The `{{% end }}` tag closes the nearest open block. +### Range (block) + +Block-level iteration over a `Collection`, `Map`, or a numeric interval. The body is rendered once per element; an optional `{{% else %}}` branch renders when the source is empty or null. The `{{% end %}}` tag closes the block. + +#### Implicit scope (list) + +``` +{{% range .list }} + {{ field }} +{{% end }} +``` + +The body scope becomes the current list item — fields are accessed directly without any variable prefix, exactly as if the item were the root object. + +``` +{{% range .items }}{{ name }}, {{ price }}{{% end %}} +``` + +#### Named item (list) + +``` +{{% range $item := .list }} + {{ $item.field }} +{{% end }} +``` + +The body stays in the original root scope. The current item is bound to `$item` and accessed via `$item.fieldName`. + +#### Named index + item (list) + +``` +{{% range $i,$item := .list }} + {{ $i }}: {{ $item.field }} +{{% end %}} +``` + +`$i` is a 0-based integer index; `$item` is the current element. Both variables are available anywhere in the body. + +#### Named key + value (map) + +``` +{{% range $k,$v := .mapField }} + {{ $k }}={{ $v.field }} +{{% end %}} +``` + +`$k` is the map key; `$v` is the map value. The value type is derived from the map's declared generic type. + +#### Numeric interval + +``` +{{% range $k := 1 .. 5 }}{{ $k }}{{% end %}} +``` + +Iterates from `from` to `to` **inclusive**, incrementing by 1. `$k` holds the current integer value. + +With an explicit step: + +``` +{{% range $k := 1 .. 9 step 2 }}{{ $k }} {{% end %}} +``` + +Renders `1 3 5 7 9 `. + +Bounds and step can also be field names resolved at render time: + +``` +{{% range $k := rangeStart .. rangeEnd step rangeStep }}{{ $k }}{{% end %}} +``` + +#### Else branch + +All range forms accept an optional `{{% else %}}` branch. It renders when the collection or map is empty or null, or when the interval produces no iterations. + +``` +{{% range $item := .list }} + {{ $item.name }} +{{% else }} + (no items) +{{% end %}} +``` + +#### Rules + +| Form | Syntax | Body variables | Notes | +|---|---|---|---| +| Implicit scope | `{{% range .list }}` | none — item fields accessible directly | Scope shifts to item type | +| Named item | `{{% range $item := .list }}` | `$item` | Root scope preserved | +| Named index + item | `{{% range $i,$item := .list }}` | `$i` (int, 0-based), `$item` | Root scope preserved | +| Named key + value | `{{% range $k,$v := .map }}` | `$k` (key), `$v` (value) | Map type inferred from field generic | +| Numeric interval | `{{% range $k := from .. to }}` | `$k` (int) | Default step 1; inclusive | +| Numeric interval + step | `{{% range $k := from .. to step N }}` | `$k` (int) | `N` can be a literal or field name | + +- Ranges can be nested; each level has its own variable scope. +- `$.fieldName` inside the body always resolves from the original root object, regardless of nesting. +- The `{{% end %}}` tag closes the nearest open block. + ### Pipe-to-function `{{ field ; funcName() }}` — the field value is passed as the first argument to the named function. Additional arguments follow inside the parentheses.