This is an automated email from the ASF dual-hosted git repository.
aradzinski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft.git
The following commit(s) were added to refs/heads/master by this push:
new 5fa2579 WIP
5fa2579 is described below
commit 5fa2579d1db5bb9b38e596bdbaa8f0071c15ec5a
Author: Aaron Radzinski <[email protected]>
AuthorDate: Tue Oct 5 13:20:53 2021 -0700
WIP
---
nlpcraft/pom.xml | 4 +
.../nlpcraft/common/makro/NCMacroCompiler.scala | 242 ++++++++
.../nlpcraft/common/makro/NCMacroJavaParser.java | 77 +++
.../common/makro/NCMacroJavaParserTrait.java | 59 ++
.../nlpcraft/common/makro/NCMacroParser.scala | 197 +++++++
.../nlpcraft/common/makro/antlr4/NCMacroDsl.g4 | 82 +++
.../nlpcraft/common/makro/antlr4/NCMacroDsl.interp | 47 ++
.../nlpcraft/common/makro/antlr4/NCMacroDsl.tokens | 22 +
.../makro/antlr4/NCMacroDslBaseListener.java | 135 +++++
.../common/makro/antlr4/NCMacroDslLexer.interp | 62 ++
.../common/makro/antlr4/NCMacroDslLexer.java | 148 +++++
.../common/makro/antlr4/NCMacroDslLexer.tokens | 22 +
.../common/makro/antlr4/NCMacroDslListener.java | 90 +++
.../common/makro/antlr4/NCMacroDslParser.java | 641 +++++++++++++++++++++
.../org/apache/nlpcraft/common/util/NCUtils.scala | 16 +-
pom.xml | 12 +
16 files changed, 1855 insertions(+), 1 deletion(-)
diff --git a/nlpcraft/pom.xml b/nlpcraft/pom.xml
index 8bd3382..94a9ea2 100644
--- a/nlpcraft/pom.xml
+++ b/nlpcraft/pom.xml
@@ -84,6 +84,10 @@
Other dependencies.
===================
-->
+ <dependency>
+ <groupId>org.antlr</groupId>
+ <artifactId>antlr4-runtime</artifactId>
+ </dependency>
<!--
JUnit & ScalaTest dependencies.
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/NCMacroCompiler.scala
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/NCMacroCompiler.scala
new file mode 100644
index 0000000..87f0f45
--- /dev/null
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/NCMacroCompiler.scala
@@ -0,0 +1,242 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.nlpcraft.common.makro
+
+import com.typesafe.scalalogging.LazyLogging
+import org.antlr.v4.runtime.tree.ParseTreeWalker
+import org.antlr.v4.runtime.*
+import org.apache.nlpcraft.common.*
+import org.apache.nlpcraft.common.ansi.NCAnsi.*
+import org.apache.nlpcraft.common.antlr4.*
+import org.apache.nlpcraft.common.makro.NCMacroCompiler.FiniteStateMachine
+import org.apache.nlpcraft.common.makro.antlr4.*
+import org.apache.nlpcraft.common.util.NCUtils
+
+import scala.collection.mutable
+
+/**
+ *
+ */
+object NCMacroCompiler extends LazyLogging:
+ private final val MAX_SYN = 10000
+ private final val MAX_QTY = 100
+
+ /**
+ *
+ * @param buffer
+ * @param isGroup
+ */
+ case class StackItem (
+ var buffer: mutable.Buffer[String],
+ isGroup: Boolean
+ )
+
+ /**
+ *
+ * @param parser
+ * @param in
+ */
+ class FiniteStateMachine(parser: NCMacroDslParser, in: String) extends
NCMacroDslBaseListener:
+ private val stack = new mutable.Stack[StackItem]
+ private var expandedSyns: Set[String] = _
+ private var min = 1
+ private var max = 1
+
+ /**
+ *
+ * @param optS
+ * @param s
+ * @return
+ */
+ private def concat(optS: String, s: String): String = if
(optS.isEmpty) s else optS + " " + s
+
+ /**
+ *
+ * @param errMsg
+ * @param ctx
+ * @return
+ */
+ private def compilerError(errMsg: String)(implicit ctx:
ParserRuleContext): NCException =
+ val tok = ctx.stop
+ new NCException(mkCompilerError(errMsg, tok.getLine,
tok.getCharPositionInLine, in))
+
+ /**
+ *
+ * @param buf
+ * @param ctx
+ */
+ private def checkMaxSyn(buf: mutable.Buffer[String])(implicit ctx:
ParserRuleContext): Unit =
+ if (buf.size > MAX_SYN)
+ throw compilerError(s"Exceeded max number ($MAX_SYN) of macro
expansions: ${buf.size}")
+
+ override def enterExpr(ctx: NCMacroDslParser.ExprContext): Unit =
+ val buf = mutable.Buffer.empty[String]
+ // NOTE: do not allow expression's buffer to be empty.
+ // Add harmless empty string.
+ buf += ""
+ stack.push(StackItem(buf, isGroup = false))
+
+ override def enterGroup(ctx: NCMacroDslParser.GroupContext): Unit =
+ // NOTE: group cannot be empty based on the BNF grammar.
+ stack.push(StackItem(mutable.Buffer.empty[String], isGroup = true))
+
+ override def exitExpr(ctx: NCMacroDslParser.ExprContext): Unit =
+ implicit val evidence: ParserRuleContext = ctx
+
+ if stack.size > 1 then
+ val expr = stack.pop()
+ val prn = stack.top
+ checkMaxSyn(expr.buffer)
+ require(expr.buffer.nonEmpty)
+
+ if prn.isGroup then
+ prn.buffer ++= expr.buffer
+ else
+ prn.buffer = for (z <- expr.buffer; i <-
prn.buffer.indices) yield concat(prn.buffer(i), z)
+
+ override def exitMinMax(ctx: NCMacroDslParser.MinMaxContext): Unit =
+ implicit val evidence: ParserRuleContext = ctx
+
+ if ctx.minMaxShortcut() != null then
+ ctx.minMaxShortcut().getText match
+ case "?" => min = 0; max = 1
+ case c => throw compilerError(s"Invalid min/max shortcut
'$c' in: ${ctx.getText}")
+ else if ctx.MINMAX() != null then
+ var s = ctx.MINMAX().getText
+ val orig = s
+
+ s = s.substring(1, s.length - 1)
+ val comma = s.indexOf(',')
+ if comma == -1 || comma == 0 || comma == s.length - 1 then
+ throw compilerError(s"Invalid min/max quantifier: $orig")
+
+ try
+ min = java.lang.Integer.parseInt(s.substring(0,
comma).trim)
+ catch
+ case _: NumberFormatException => throw
compilerError(s"Invalid min quantifier: $orig")
+
+ try
+ max = java.lang.Integer.parseInt(s.substring(comma +
1).trim)
+ catch
+ case _: NumberFormatException => throw
compilerError(s"Invalid max quantifier: $orig")
+
+ if min < 0 || max < 0 || min > max || max == 0 || max > MAX_QTY
then
+ throw compilerError(s"[$min,$max] quantifiers should be 'max
>= min, min >= 0, max > 0, max <= $MAX_QTY'.")
+
+ override def exitGroup(ctx: NCMacroDslParser.GroupContext): Unit =
+ given evidence: ParserRuleContext = ctx
+ val grp = stack.pop()
+ // Remove dups.
+ grp.buffer = grp.buffer.distinct
+ checkMaxSyn(grp.buffer)
+ require(grp.isGroup)
+ val prn = stack.top
+ prn.buffer = prn.buffer.flatMap {
+ s => (for (z <- grp.buffer; i <- min to max) yield concat(s,
s"$z " * i).trim).toSet
+ }
+ // Reset.
+ min = 1
+ max = 1
+
+ override def exitSyn(ctx: NCMacroDslParser.SynContext): Unit =
+ val syn = (
+ if (ctx.TXT() != null) ctx.TXT()
+ else if (ctx.REGEX_TXT() != null) ctx.REGEX_TXT()
+ else ctx.IDL_TXT()
+ ).getText
+
+ val buf = stack.top.buffer
+ require(buf.nonEmpty)
+ for (i <- buf.indices) buf.update(i, concat(buf(i), syn))
+
+ override def exitList(ctx: NCMacroDslParser.ListContext): Unit = if
ctx.UNDERSCORE() != null then stack.top.buffer += ""
+ override def exitMakro(ctx: NCMacroDslParser.MakroContext): Unit =
expandedSyns = stack.pop().buffer.map(_.trim).toSet
+
+ /**
+ *
+ * @return
+ */
+ def getExpandedMacro: Set[String] =
+ require(expandedSyns != null)
+ expandedSyns
+
+ /**
+ * Custom error handler.
+ */
+ class CompilerErrorListener(in: String) extends BaseErrorListener:
+ /**
+ *
+ * @param recognizer
+ * @param offendingSymbol
+ * @param line
+ * @param charPos
+ * @param msg
+ * @param e
+ */
+ override def syntaxError(
+ recognizer: Recognizer[_, _],
+ offendingSymbol: scala.Any,
+ line: Int, // 1, 2, ...
+ charPos: Int, // 1, 2, ...
+ msg: String,
+ e: RecognitionException): Unit = throw new
NCException(mkCompilerError(msg, line, charPos - 1, in))
+
+ /**
+ *
+ * @param line
+ * @param charPos
+ * @param in
+ * @param msg
+ */
+ private def mkCompilerError(
+ msg: String,
+ line: Int, // 1, 2, ...
+ charPos: Int, // 0, 1, 2, ...
+ in: String
+ ): String =
+ val hldr = NCCompilerUtils.mkErrorHolder(in, charPos)
+ val aMsg = NCUtils.decapitalize(msg) match
+ case s: String if s.last == '.' => s
+ case s: String => s + '.'
+ s"Macro compiler error at line $line - $aMsg\n" +
+ s" |-- ${c("Macro:")} ${hldr.origStr}\n" +
+ s" +-- ${c("Error:")} ${hldr.ptrStr}"
+
+ /**
+ *
+ * @param in Macro to expand.
+ * @return Expanded macro as a set of finite strings.
+ */
+ def compile(in: String): Set[String] =
+ // ANTLR4 armature.
+ val lexer = new NCMacroDslLexer(CharStreams.fromString(in))
+ val stream = new CommonTokenStream(lexer)
+ val parser = new NCMacroDslParser(stream)
+
+ // Set custom error handlers.
+ lexer.removeErrorListeners()
+ parser.removeErrorListeners()
+ lexer.addErrorListener(new CompilerErrorListener(in))
+ parser.addErrorListener(new CompilerErrorListener(in))
+
+ // State automata.
+ val fsm = new FiniteStateMachine(parser, in)
+ // Parse the input DSL and walk built AST.
+ (new ParseTreeWalker).walk(fsm, parser.makro())
+ // Return the expanded macro.
+ fsm.getExpandedMacro
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/NCMacroJavaParser.java
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/NCMacroJavaParser.java
new file mode 100644
index 0000000..d10aa2d
--- /dev/null
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/NCMacroJavaParser.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.nlpcraft.common.makro;
+
+import java.util.Set;
+
+/**
+ * Java adapter for macro parser (so that Java reflection could work).
+ */
+public class NCMacroJavaParser implements NCMacroJavaParserTrait {
+ private final NCMacroParser impl = new NCMacroParser();
+
+ /**
+ * Expands given macro DSL string.
+ *
+ * @param s Macro DSL string to expand.
+ * @return Set of macro expansions for a given macro DSL string.
+ */
+ public Set<String> expand(String s) {
+ return impl.expandJava(s);
+ }
+
+ /**
+ * Adds or overrides given macro.
+ *
+ * @param name Macro name (typically an upper case string).
+ * It must start with '<' and end with '>' symbol.
+ * @param macro Value of the macro (any arbitrary string).
+ * @return {@code true} if an existing macro was overridden, {@code false}
otherwise.
+ */
+ public boolean addMacro(String name, String macro) {
+ boolean f = impl.hasMacro(name);
+
+ impl.addMacro(name, macro);
+
+ return f;
+ }
+
+ /**
+ * Removes macro.
+ *
+ * @param name Name of the macro to remove.
+ * @return {@code true} if given macro was indeed found and removed,
{@code false} otherwise.
+ */
+ public boolean removeMacro(String name) {
+ boolean f = impl.hasMacro(name);
+
+ impl.removeMacro(name);
+
+ return f;
+ }
+
+ /**
+ * Tests whether this processor has given macro.
+ *
+ * @param name Name of the macro to test.
+ * @return {@code true} if macro was found, {@code false} otherwise.
+ */
+ public boolean hasMacro(String name) {
+ return impl.hasMacro(name);
+ }
+}
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/NCMacroJavaParserTrait.java
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/NCMacroJavaParserTrait.java
new file mode 100644
index 0000000..58d5452
--- /dev/null
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/NCMacroJavaParserTrait.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.nlpcraft.common.makro;
+
+import java.util.Set;
+
+/**
+ * Necessary plug for Javadoc to work on mixed Java/Scala project.
+ */
+public interface NCMacroJavaParserTrait {
+ /**
+ * Expands given macro DSL string.
+ *
+ * @param s Macro DSL string to expand.
+ * @return Set of macro expansions for a given macro DSL string.
+ */
+ Set<String> expand(String s);
+
+ /**
+ * Adds or overrides given macro.
+ *
+ * @param name Macro name (typically an upper case string).
+ * It must start with '<' and end with '>' symbol.
+ * @param macro Value of the macro (any arbitrary string).
+ * @return {@code true} if an existing macro was overridden, {@code false}
otherwise.
+ */
+ boolean addMacro(String name, String macro);
+
+ /**
+ * Removes macro.
+ *
+ * @param name Name of the macro to remove.
+ * @return {@code true} if given macro was indeed found and removed,
{@code false} otherwise.
+ */
+ boolean removeMacro(String name);
+
+ /**
+ * Tests whether this processor has given macro.
+ *
+ * @param name Name of the macro to test.
+ * @return {@code true} if macro was found, {@code false} otherwise.
+ */
+ boolean hasMacro(String name);
+}
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/NCMacroParser.scala
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/NCMacroParser.scala
new file mode 100644
index 0000000..11c7cc1
--- /dev/null
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/NCMacroParser.scala
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.nlpcraft.common.makro
+
+import org.apache.nlpcraft.common.*
+import org.apache.nlpcraft.common.util.NCUtils
+
+import scala.jdk.CollectionConverters.*
+
+object NCMacroParser:
+ private final val ESC_CHARS = """{}\<>_[]|,"""
+ private final val MACRO_REGEX = s"<[A-Za-z0-9-_]+>".r
+ private final val BROKEN_MACRO_REGEX1 = s"<[A-Za-z0-9-_]+".r
+ private final val BROKEN_MACRO_REGEX2 = s"[A-Za-z0-9-_]+>".r
+
+ /**
+ * Constructor.
+ *
+ * @param macros Set of macros to add.
+ */
+ def apply(macros: List[(String, String)]): NCMacroParser =
+ apply(macros: _*)
+
+ /**
+ * Constructor.
+ *
+ * @param macros Set of macros to add.
+ */
+ def apply(macros: Map[String, String]): NCMacroParser =
+ apply(macros.toSeq: _*)
+
+ /**
+ * Constructor.
+ *
+ * @param macros Set of macros to add.
+ */
+ def apply(macros: (String, String)*): NCMacroParser =
+ val obj = new NCMacroParser
+ macros.foreach(m => obj.addMacro(m._1, m._2))
+ obj
+
+
+/**
+ * Provides generic support for text expansion using macros and options
groups.
+ *
+ * Syntax:
+ * - all macros should start with '<' and end with '>'.
+ * - '{A|{B}}' denotes either 'A' or 'B'.
+ * - '{A|B|_}' denotes either 'A', or 'B' or nothing ('_').
+ * - '{A}[1,2]' denotes 'A' or 'A A'.
+ * - '{A}[0,1]' denotes 'A' or nothing (just like '{A|_}').
+ * - '\' should be used for escaping any of '{}\_[]|,' special symbols.
+ * - Excessive pairs'{' and '}' are ignored
+ *
+ * Examples:
+ * "A {B|C}[1,2] D" => "A B D", "A C D", "A B B D", "A C C D"
+ * "A \{B\|C\} D" => "A {B|C} D"
+ * "A {B|_} D" => "A D", "A B D"
+ * "A {_|B|C} {D}[1,2]" => "A D", "A B D", "A C D", "A D D", "A B D D",
"A C D D"
+ * "A <MACRO>" => "A ..." based on <MACRO> content.
+ * "A {<MACRO>|_}" => "A", "A ..." based on <MACRO> content.
+ *
+ * NOTE: Macros cannot be recursive.
+ * NOTE: Macros and '{...}' options groups can be nested.
+ */
+class NCMacroParser:
+ import NCMacroParser.*
+
+ private val macros = new java.util.concurrent.ConcurrentHashMap[String,
String]().asScala
+
+ /**
+ * Trims all duplicate spaces.
+ *
+ * @param s
+ * @return
+ */
+ private def trimDupSpaces(s: String) = NCUtils.splitTrimFilter(s, "
").mkString(" ")
+
+ /**
+ *
+ * @param s
+ * @return
+ */
+ private def processEscapes(s: String): String =
+ val len = s.length()
+ val buf = new StringBuilder()
+ var i = 0
+ var isEscape = false
+
+ while (i < len)
+ val ch = s.charAt(i)
+ if ch == '\\' && !isEscape then
+ isEscape = true
+ else
+ if isEscape && !ESC_CHARS.contains(ch) then buf += '\\'
+ buf += ch
+ isEscape = false
+ i += 1
+ buf.toString
+
+ /**
+ * Expand given string.
+ *
+ * @param txt Text to expand.
+ */
+ @throws[NCException]
+ def expand(txt: String): Seq[String] =
+ require(txt != null)
+
+ var s = txt
+
+ // Grab 1st macro match, if any.
+ var m = MACRO_REGEX.findFirstMatchIn(s)
+
+ // Expand macros including nested ones.
+ while (m.isDefined)
+ val ms = m.get.toString()
+ if !macros.keySet.contains(ms) then throw new
NCException(s"Unknown macro [macro=$ms, txt=$txt]")
+ // Expand all registered macros.
+ for ((k, v) <- macros) s = s.replace(k, v)
+ // Grab another macro match, if any.
+ m = MACRO_REGEX.findFirstMatchIn(s)
+
+ // Check for potentially invalid macros syntax.
+ if BROKEN_MACRO_REGEX1.findFirstIn(s).isDefined ||
BROKEN_MACRO_REGEX2.findFirstIn(s).isDefined then
+ throw new NCException(s"Suspicious or invalid macro in: $txt")
+
+ NCUtils.distinct(NCMacroCompiler.compile(s).toList map trimDupSpaces
map processEscapes)
+
+ /**
+ * Expand given string.
+ *
+ * @param txt Text to expand.
+ */
+ @throws[NCException]
+ def expandJava(txt: String): java.util.Set[String] =
+ expand(txt).toSet.asJava
+
+ /**
+ * Checks macro name.
+ *
+ * @param name Macro name.
+ */
+ private def checkName(name: String): Unit =
+ if name.head != '<' then throw new NCException(s"Missing macro '<'
opening: $name")
+ if name.last != '>' then throw new NCException(s"Missing macro '>'
closing: $name")
+
+ /**
+ * Adds or overrides given macro.
+ *
+ * @param name Macro name (typically an upper case string).
+ * It must start with '<' and end with '>'.
+ * @param str Value of the macro (any arbitrary string).
+ */
+ @throws[NCException]
+ def addMacro(name: String, str: String): Unit =
+ require(name != null)
+ require(str != null)
+
+ checkName(name)
+ // Check for recursion.
+ if str.contains(name) then throw new NCException(s"Recursion is not
supported, macro: $name")
+ macros += name -> str
+
+ /**
+ * Removes macro.
+ *
+ * @param name Macro name (typically an upper case string).
+ * It must start with '<' and end with '>'.
+ */
+ @throws[NCException]
+ def removeMacro(name: String): Unit =
+ require(name != null)
+ macros -= name
+
+ /**
+ * Checks whether or not macro with given name exists or not.
+ *
+ * @param name Name.
+ */
+ def hasMacro(name: String): Boolean = macros.contains(name)
+
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDsl.g4
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDsl.g4
new file mode 100644
index 0000000..c6ee2a1
--- /dev/null
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDsl.g4
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+grammar NCMacroDsl;
+
+// Parser.
+makro: expr EOF;
+expr
+ : item
+ | expr item
+ ;
+item: syn | group;
+syn : (TXT | REGEX_TXT | IDL_TXT);
+group: LCURLY list RCURLY minMax?;
+list
+ : expr
+ | list VERT expr
+ | list VERT UNDERSCORE
+ | UNDERSCORE VERT list
+ ;
+minMax
+ : minMaxShortcut
+ | MINMAX
+ ;
+minMaxShortcut
+ : QUESTION
+ ;
+
+// Lexer.
+LCURLY: '{';
+RCURLY: '}';
+VERT: '|';
+COMMA: ',';
+UNDERSCORE: '_';
+LBR: '[';
+RBR: ']';
+QUESTION: '?';
+fragment ESC_CHAR: [{}\\_[\]|,/];
+fragment ESC: '\\' ESC_CHAR;
+fragment TXT_CHAR
+ : [~!@#$%^&*?()+._]
+ | [-=<>/\\;:`'",]
+ | 'A'..'Z'
+ | 'a'..'z'
+ | '0'..'9'
+ | '\u0300'..'\u036F'
+ | '\u00A0'..'\u00FF' /* Latin-1 Supplement. */
+ | '\u0100'..'\u017F' /* Latin Extended-A. */
+ | '\u0180'..'\u024F' /* Latin Extended-B. */
+ | '\u1E02'..'\u1EF3' /* Latin Extended Additional. */
+ | '\u0259'..'\u0292' /* IPA Extensions. */
+ | '\u02B0'..'\u02FF' /* Spacing modifier letters. */
+ | '\u203F'..'\u2040'
+ | '\u1F01'..'\u1FFF' /* Greek Extended. */
+ | '\u0400'..'\u04FF' /* Cyrillic. */
+ | '\u200C'..'\u200D'
+ | '\u2070'..'\u218F'
+ | '\u2C00'..'\u2FEF'
+ | '\u3001'..'\uD7FF'
+ | '\uF900'..'\uFDCF'
+ | '\uFDF0'..'\uFFFD'
+ ; // Ignoring ['\u10000-'\uEFFFF].
+REGEX_TXT: '//' .*? '//';
+IDL_TXT: '^^' .*? '^^';
+TXT: (TXT_CHAR | ESC)+;
+MINMAX: '[' [ 0-9,]+ ']';
+WS: [ \r\t\u000C\n]+ -> skip ;
+ERR_CHAR: .;
\ No newline at end of file
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDsl.interp
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDsl.interp
new file mode 100644
index 0000000..b85d8dd
--- /dev/null
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDsl.interp
@@ -0,0 +1,47 @@
+token literal names:
+null
+'{'
+'}'
+'|'
+','
+'_'
+'['
+']'
+'?'
+null
+null
+null
+null
+null
+null
+
+token symbolic names:
+null
+LCURLY
+RCURLY
+VERT
+COMMA
+UNDERSCORE
+LBR
+RBR
+QUESTION
+REGEX_TXT
+IDL_TXT
+TXT
+MINMAX
+WS
+ERR_CHAR
+
+rule names:
+makro
+expr
+item
+syn
+group
+list
+minMax
+minMaxShortcut
+
+
+atn:
+[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 16, 68, 4, 2,
9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8,
4, 9, 9, 9, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 27, 10, 3,
12, 3, 14, 3, 30, 11, 3, 3, 4, 3, 4, 5, 4, 34, 10, 4, 3, 5, 3, 5, 3, 6, 3, 6,
3, 6, 3, 6, 5, 6, 42, 10, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 49, 10, 7, 3,
7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 57, 10, 7, 12, 7, 14, 7, 60, 11, 7, 3,
8, 3, 8, 5, 8, 64, 10, 8, [...]
\ No newline at end of file
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDsl.tokens
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDsl.tokens
new file mode 100644
index 0000000..319aa8e
--- /dev/null
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDsl.tokens
@@ -0,0 +1,22 @@
+LCURLY=1
+RCURLY=2
+VERT=3
+COMMA=4
+UNDERSCORE=5
+LBR=6
+RBR=7
+QUESTION=8
+REGEX_TXT=9
+IDL_TXT=10
+TXT=11
+MINMAX=12
+WS=13
+ERR_CHAR=14
+'{'=1
+'}'=2
+'|'=3
+','=4
+'_'=5
+'['=6
+']'=7
+'?'=8
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslBaseListener.java
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslBaseListener.java
new file mode 100644
index 0000000..7bd6836
--- /dev/null
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslBaseListener.java
@@ -0,0 +1,135 @@
+// Generated from C:/Users/Nikita
Ivanov/Documents/GitHub/incubator-nlpcraft/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4\NCMacroDsl.g4
by ANTLR 4.9.1
+package org.apache.nlpcraft.common.makro.antlr4;
+
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.tree.ErrorNode;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+/**
+ * This class provides an empty implementation of {@link NCMacroDslListener},
+ * which can be extended to create a listener which only needs to handle a
subset
+ * of the available methods.
+ */
+public class NCMacroDslBaseListener implements NCMacroDslListener {
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void enterMakro(NCMacroDslParser.MakroContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void exitMakro(NCMacroDslParser.MakroContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void enterExpr(NCMacroDslParser.ExprContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void exitExpr(NCMacroDslParser.ExprContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void enterItem(NCMacroDslParser.ItemContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void exitItem(NCMacroDslParser.ItemContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void enterSyn(NCMacroDslParser.SynContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void exitSyn(NCMacroDslParser.SynContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void enterGroup(NCMacroDslParser.GroupContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void exitGroup(NCMacroDslParser.GroupContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void enterList(NCMacroDslParser.ListContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void exitList(NCMacroDslParser.ListContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void enterMinMax(NCMacroDslParser.MinMaxContext ctx) {
}
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void exitMinMax(NCMacroDslParser.MinMaxContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void
enterMinMaxShortcut(NCMacroDslParser.MinMaxShortcutContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void
exitMinMaxShortcut(NCMacroDslParser.MinMaxShortcutContext ctx) { }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void enterEveryRule(ParserRuleContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void exitEveryRule(ParserRuleContext ctx) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void visitTerminal(TerminalNode node) { }
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default implementation does nothing.</p>
+ */
+ @Override public void visitErrorNode(ErrorNode node) { }
+}
\ No newline at end of file
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslLexer.interp
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslLexer.interp
new file mode 100644
index 0000000..e7fb0fe
--- /dev/null
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslLexer.interp
@@ -0,0 +1,62 @@
+token literal names:
+null
+'{'
+'}'
+'|'
+','
+'_'
+'['
+']'
+'?'
+null
+null
+null
+null
+null
+null
+
+token symbolic names:
+null
+LCURLY
+RCURLY
+VERT
+COMMA
+UNDERSCORE
+LBR
+RBR
+QUESTION
+REGEX_TXT
+IDL_TXT
+TXT
+MINMAX
+WS
+ERR_CHAR
+
+rule names:
+LCURLY
+RCURLY
+VERT
+COMMA
+UNDERSCORE
+LBR
+RBR
+QUESTION
+ESC_CHAR
+ESC
+TXT_CHAR
+REGEX_TXT
+IDL_TXT
+TXT
+MINMAX
+WS
+ERR_CHAR
+
+channel names:
+DEFAULT_TOKEN_CHANNEL
+HIDDEN
+
+mode names:
+DEFAULT_MODE
+
+atn:
+[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 16, 108, 8, 1,
4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8,
9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4,
14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 3, 2, 3, 2,
3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9,
3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 12, 5, 12, 60, 10, 12, 3, 13, 3,
13, 3, 13, 3, 13, 7, 13, [...]
\ No newline at end of file
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslLexer.java
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslLexer.java
new file mode 100644
index 0000000..31e2d67
--- /dev/null
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslLexer.java
@@ -0,0 +1,148 @@
+// Generated from C:/Users/Nikita
Ivanov/Documents/GitHub/incubator-nlpcraft/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4\NCMacroDsl.g4
by ANTLR 4.9.1
+package org.apache.nlpcraft.common.makro.antlr4;
+import org.antlr.v4.runtime.Lexer;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenStream;
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.atn.*;
+import org.antlr.v4.runtime.dfa.DFA;
+import org.antlr.v4.runtime.misc.*;
+
+@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
+public class NCMacroDslLexer extends Lexer {
+ static { RuntimeMetaData.checkVersion("4.9.1",
RuntimeMetaData.VERSION); }
+
+ protected static final DFA[] _decisionToDFA;
+ protected static final PredictionContextCache _sharedContextCache =
+ new PredictionContextCache();
+ public static final int
+ LCURLY=1, RCURLY=2, VERT=3, COMMA=4, UNDERSCORE=5, LBR=6,
RBR=7, QUESTION=8,
+ REGEX_TXT=9, IDL_TXT=10, TXT=11, MINMAX=12, WS=13, ERR_CHAR=14;
+ public static String[] channelNames = {
+ "DEFAULT_TOKEN_CHANNEL", "HIDDEN"
+ };
+
+ public static String[] modeNames = {
+ "DEFAULT_MODE"
+ };
+
+ private static String[] makeRuleNames() {
+ return new String[] {
+ "LCURLY", "RCURLY", "VERT", "COMMA", "UNDERSCORE",
"LBR", "RBR", "QUESTION",
+ "ESC_CHAR", "ESC", "TXT_CHAR", "REGEX_TXT", "IDL_TXT",
"TXT", "MINMAX",
+ "WS", "ERR_CHAR"
+ };
+ }
+ public static final String[] ruleNames = makeRuleNames();
+
+ private static String[] makeLiteralNames() {
+ return new String[] {
+ null, "'{'", "'}'", "'|'", "','", "'_'", "'['", "']'",
"'?'"
+ };
+ }
+ private static final String[] _LITERAL_NAMES = makeLiteralNames();
+ private static String[] makeSymbolicNames() {
+ return new String[] {
+ null, "LCURLY", "RCURLY", "VERT", "COMMA",
"UNDERSCORE", "LBR", "RBR",
+ "QUESTION", "REGEX_TXT", "IDL_TXT", "TXT", "MINMAX",
"WS", "ERR_CHAR"
+ };
+ }
+ private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames();
+ public static final Vocabulary VOCABULARY = new
VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
+
+ /**
+ * @deprecated Use {@link #VOCABULARY} instead.
+ */
+ @Deprecated
+ public static final String[] tokenNames;
+ static {
+ tokenNames = new String[_SYMBOLIC_NAMES.length];
+ for (int i = 0; i < tokenNames.length; i++) {
+ tokenNames[i] = VOCABULARY.getLiteralName(i);
+ if (tokenNames[i] == null) {
+ tokenNames[i] = VOCABULARY.getSymbolicName(i);
+ }
+
+ if (tokenNames[i] == null) {
+ tokenNames[i] = "<INVALID>";
+ }
+ }
+ }
+
+ @Override
+ @Deprecated
+ public String[] getTokenNames() {
+ return tokenNames;
+ }
+
+ @Override
+
+ public Vocabulary getVocabulary() {
+ return VOCABULARY;
+ }
+
+
+ public NCMacroDslLexer(CharStream input) {
+ super(input);
+ _interp = new
LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
+ }
+
+ @Override
+ public String getGrammarFileName() { return "NCMacroDsl.g4"; }
+
+ @Override
+ public String[] getRuleNames() { return ruleNames; }
+
+ @Override
+ public String getSerializedATN() { return _serializedATN; }
+
+ @Override
+ public String[] getChannelNames() { return channelNames; }
+
+ @Override
+ public String[] getModeNames() { return modeNames; }
+
+ @Override
+ public ATN getATN() { return _ATN; }
+
+ public static final String _serializedATN =
+
"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\20l\b\1\4\2\t\2\4"+
+
"\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t"+
+
"\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+
+
"\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6\3\7\3\7\3\b\3\b\3\t\3\t\3\n\3"+
+
"\n\3\13\3\13\3\13\3\f\5\f<\n\f\3\r\3\r\3\r\3\r\7\rB\n\r\f\r\16\rE\13\r"+
+
"\3\r\3\r\3\r\3\16\3\16\3\16\3\16\7\16N\n\16\f\16\16\16Q\13\16\3\16\3\16"+
+
"\3\16\3\17\3\17\6\17X\n\17\r\17\16\17Y\3\20\3\20\6\20^\n\20\r\20\16\20"+
+
"_\3\20\3\20\3\21\6\21e\n\21\r\21\16\21f\3\21\3\21\3\22\3\22\4CO\2\23\3"+
+
"\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\2\25\2\27\2\31\13\33\f\35\r\37\16"+
+
"!\17#\20\3\2\6\7\2..\61\61]_aa}\177\23\2#\\^^`|\u0080\u0080\u00a2\u0251"+
+
"\u025b\u0294\u02b2\u0371\u0402\u0501\u1e04\u1ef5\u1f03\u2001\u200e\u200f"+
+
"\u2041\u2042\u2072\u2191\u2c02\u2ff1\u3003\ud801\uf902\ufdd1\ufdf2\uffff"+
+
"\5\2\"\"..\62;\5\2\13\f\16\17\"\"\2n\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2"+
+
"\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\31"+
+
"\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2"+
+
"\3%\3\2\2\2\5\'\3\2\2\2\7)\3\2\2\2\t+\3\2\2\2\13-\3\2\2\2\r/\3\2\2\2\17"+
+
"\61\3\2\2\2\21\63\3\2\2\2\23\65\3\2\2\2\25\67\3\2\2\2\27;\3\2\2\2\31="+
+
"\3\2\2\2\33I\3\2\2\2\35W\3\2\2\2\37[\3\2\2\2!d\3\2\2\2#j\3\2\2\2%&\7}"+
+
"\2\2&\4\3\2\2\2\'(\7\177\2\2(\6\3\2\2\2)*\7~\2\2*\b\3\2\2\2+,\7.\2\2,"+
+
"\n\3\2\2\2-.\7a\2\2.\f\3\2\2\2/\60\7]\2\2\60\16\3\2\2\2\61\62\7_\2\2\62"+
+
"\20\3\2\2\2\63\64\7A\2\2\64\22\3\2\2\2\65\66\t\2\2\2\66\24\3\2\2\2\67"+
+
"8\7^\2\289\5\23\n\29\26\3\2\2\2:<\t\3\2\2;:\3\2\2\2<\30\3\2\2\2=>\7\61"+
+
"\2\2>?\7\61\2\2?C\3\2\2\2@B\13\2\2\2A@\3\2\2\2BE\3\2\2\2CD\3\2\2\2CA\3"+
+
"\2\2\2DF\3\2\2\2EC\3\2\2\2FG\7\61\2\2GH\7\61\2\2H\32\3\2\2\2IJ\7`\2\2"+
+
"JK\7`\2\2KO\3\2\2\2LN\13\2\2\2ML\3\2\2\2NQ\3\2\2\2OP\3\2\2\2OM\3\2\2\2"+
+
"PR\3\2\2\2QO\3\2\2\2RS\7`\2\2ST\7`\2\2T\34\3\2\2\2UX\5\27\f\2VX\5\25\13"+
+
"\2WU\3\2\2\2WV\3\2\2\2XY\3\2\2\2YW\3\2\2\2YZ\3\2\2\2Z\36\3\2\2\2[]\7]"+
+
"\2\2\\^\t\4\2\2]\\\3\2\2\2^_\3\2\2\2_]\3\2\2\2_`\3\2\2\2`a\3\2\2\2ab\7"+
+ "_\2\2b
\3\2\2\2ce\t\5\2\2dc\3\2\2\2ef\3\2\2\2fd\3\2\2\2fg\3\2\2\2gh\3"+
+
"\2\2\2hi\b\21\2\2i\"\3\2\2\2jk\13\2\2\2k$\3\2\2\2\n\2;COWY_f\3\b\2\2";
+ public static final ATN _ATN =
+ new ATNDeserializer().deserialize(_serializedATN.toCharArray());
+ static {
+ _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
+ for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
+ _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i),
i);
+ }
+ }
+}
\ No newline at end of file
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslLexer.tokens
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslLexer.tokens
new file mode 100644
index 0000000..319aa8e
--- /dev/null
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslLexer.tokens
@@ -0,0 +1,22 @@
+LCURLY=1
+RCURLY=2
+VERT=3
+COMMA=4
+UNDERSCORE=5
+LBR=6
+RBR=7
+QUESTION=8
+REGEX_TXT=9
+IDL_TXT=10
+TXT=11
+MINMAX=12
+WS=13
+ERR_CHAR=14
+'{'=1
+'}'=2
+'|'=3
+','=4
+'_'=5
+'['=6
+']'=7
+'?'=8
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslListener.java
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslListener.java
new file mode 100644
index 0000000..eb0821d
--- /dev/null
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslListener.java
@@ -0,0 +1,90 @@
+// Generated from C:/Users/Nikita
Ivanov/Documents/GitHub/incubator-nlpcraft/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4\NCMacroDsl.g4
by ANTLR 4.9.1
+package org.apache.nlpcraft.common.makro.antlr4;
+import org.antlr.v4.runtime.tree.ParseTreeListener;
+
+/**
+ * This interface defines a complete listener for a parse tree produced by
+ * {@link NCMacroDslParser}.
+ */
+public interface NCMacroDslListener extends ParseTreeListener {
+ /**
+ * Enter a parse tree produced by {@link NCMacroDslParser#makro}.
+ * @param ctx the parse tree
+ */
+ void enterMakro(NCMacroDslParser.MakroContext ctx);
+ /**
+ * Exit a parse tree produced by {@link NCMacroDslParser#makro}.
+ * @param ctx the parse tree
+ */
+ void exitMakro(NCMacroDslParser.MakroContext ctx);
+ /**
+ * Enter a parse tree produced by {@link NCMacroDslParser#expr}.
+ * @param ctx the parse tree
+ */
+ void enterExpr(NCMacroDslParser.ExprContext ctx);
+ /**
+ * Exit a parse tree produced by {@link NCMacroDslParser#expr}.
+ * @param ctx the parse tree
+ */
+ void exitExpr(NCMacroDslParser.ExprContext ctx);
+ /**
+ * Enter a parse tree produced by {@link NCMacroDslParser#item}.
+ * @param ctx the parse tree
+ */
+ void enterItem(NCMacroDslParser.ItemContext ctx);
+ /**
+ * Exit a parse tree produced by {@link NCMacroDslParser#item}.
+ * @param ctx the parse tree
+ */
+ void exitItem(NCMacroDslParser.ItemContext ctx);
+ /**
+ * Enter a parse tree produced by {@link NCMacroDslParser#syn}.
+ * @param ctx the parse tree
+ */
+ void enterSyn(NCMacroDslParser.SynContext ctx);
+ /**
+ * Exit a parse tree produced by {@link NCMacroDslParser#syn}.
+ * @param ctx the parse tree
+ */
+ void exitSyn(NCMacroDslParser.SynContext ctx);
+ /**
+ * Enter a parse tree produced by {@link NCMacroDslParser#group}.
+ * @param ctx the parse tree
+ */
+ void enterGroup(NCMacroDslParser.GroupContext ctx);
+ /**
+ * Exit a parse tree produced by {@link NCMacroDslParser#group}.
+ * @param ctx the parse tree
+ */
+ void exitGroup(NCMacroDslParser.GroupContext ctx);
+ /**
+ * Enter a parse tree produced by {@link NCMacroDslParser#list}.
+ * @param ctx the parse tree
+ */
+ void enterList(NCMacroDslParser.ListContext ctx);
+ /**
+ * Exit a parse tree produced by {@link NCMacroDslParser#list}.
+ * @param ctx the parse tree
+ */
+ void exitList(NCMacroDslParser.ListContext ctx);
+ /**
+ * Enter a parse tree produced by {@link NCMacroDslParser#minMax}.
+ * @param ctx the parse tree
+ */
+ void enterMinMax(NCMacroDslParser.MinMaxContext ctx);
+ /**
+ * Exit a parse tree produced by {@link NCMacroDslParser#minMax}.
+ * @param ctx the parse tree
+ */
+ void exitMinMax(NCMacroDslParser.MinMaxContext ctx);
+ /**
+ * Enter a parse tree produced by {@link
NCMacroDslParser#minMaxShortcut}.
+ * @param ctx the parse tree
+ */
+ void enterMinMaxShortcut(NCMacroDslParser.MinMaxShortcutContext ctx);
+ /**
+ * Exit a parse tree produced by {@link
NCMacroDslParser#minMaxShortcut}.
+ * @param ctx the parse tree
+ */
+ void exitMinMaxShortcut(NCMacroDslParser.MinMaxShortcutContext ctx);
+}
\ No newline at end of file
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslParser.java
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslParser.java
new file mode 100644
index 0000000..eef5f94
--- /dev/null
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4/NCMacroDslParser.java
@@ -0,0 +1,641 @@
+// Generated from C:/Users/Nikita
Ivanov/Documents/GitHub/incubator-nlpcraft/nlpcraft/src/main/scala/org/apache/nlpcraft/common/makro/antlr4\NCMacroDsl.g4
by ANTLR 4.9.1
+package org.apache.nlpcraft.common.makro.antlr4;
+import org.antlr.v4.runtime.atn.*;
+import org.antlr.v4.runtime.dfa.DFA;
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.misc.*;
+import org.antlr.v4.runtime.tree.*;
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
+public class NCMacroDslParser extends Parser {
+ static { RuntimeMetaData.checkVersion("4.9.1",
RuntimeMetaData.VERSION); }
+
+ protected static final DFA[] _decisionToDFA;
+ protected static final PredictionContextCache _sharedContextCache =
+ new PredictionContextCache();
+ public static final int
+ LCURLY=1, RCURLY=2, VERT=3, COMMA=4, UNDERSCORE=5, LBR=6,
RBR=7, QUESTION=8,
+ REGEX_TXT=9, IDL_TXT=10, TXT=11, MINMAX=12, WS=13, ERR_CHAR=14;
+ public static final int
+ RULE_makro = 0, RULE_expr = 1, RULE_item = 2, RULE_syn = 3,
RULE_group = 4,
+ RULE_list = 5, RULE_minMax = 6, RULE_minMaxShortcut = 7;
+ private static String[] makeRuleNames() {
+ return new String[] {
+ "makro", "expr", "item", "syn", "group", "list",
"minMax", "minMaxShortcut"
+ };
+ }
+ public static final String[] ruleNames = makeRuleNames();
+
+ private static String[] makeLiteralNames() {
+ return new String[] {
+ null, "'{'", "'}'", "'|'", "','", "'_'", "'['", "']'",
"'?'"
+ };
+ }
+ private static final String[] _LITERAL_NAMES = makeLiteralNames();
+ private static String[] makeSymbolicNames() {
+ return new String[] {
+ null, "LCURLY", "RCURLY", "VERT", "COMMA",
"UNDERSCORE", "LBR", "RBR",
+ "QUESTION", "REGEX_TXT", "IDL_TXT", "TXT", "MINMAX",
"WS", "ERR_CHAR"
+ };
+ }
+ private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames();
+ public static final Vocabulary VOCABULARY = new
VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
+
+ /**
+ * @deprecated Use {@link #VOCABULARY} instead.
+ */
+ @Deprecated
+ public static final String[] tokenNames;
+ static {
+ tokenNames = new String[_SYMBOLIC_NAMES.length];
+ for (int i = 0; i < tokenNames.length; i++) {
+ tokenNames[i] = VOCABULARY.getLiteralName(i);
+ if (tokenNames[i] == null) {
+ tokenNames[i] = VOCABULARY.getSymbolicName(i);
+ }
+
+ if (tokenNames[i] == null) {
+ tokenNames[i] = "<INVALID>";
+ }
+ }
+ }
+
+ @Override
+ @Deprecated
+ public String[] getTokenNames() {
+ return tokenNames;
+ }
+
+ @Override
+
+ public Vocabulary getVocabulary() {
+ return VOCABULARY;
+ }
+
+ @Override
+ public String getGrammarFileName() { return "NCMacroDsl.g4"; }
+
+ @Override
+ public String[] getRuleNames() { return ruleNames; }
+
+ @Override
+ public String getSerializedATN() { return _serializedATN; }
+
+ @Override
+ public ATN getATN() { return _ATN; }
+
+ public NCMacroDslParser(TokenStream input) {
+ super(input);
+ _interp = new
ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
+ }
+
+ public static class MakroContext extends ParserRuleContext {
+ public ExprContext expr() {
+ return getRuleContext(ExprContext.class,0);
+ }
+ public TerminalNode EOF() { return
getToken(NCMacroDslParser.EOF, 0); }
+ public MakroContext(ParserRuleContext parent, int
invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_makro; }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof NCMacroDslListener )
((NCMacroDslListener)listener).enterMakro(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof NCMacroDslListener )
((NCMacroDslListener)listener).exitMakro(this);
+ }
+ }
+
+ public final MakroContext makro() throws RecognitionException {
+ MakroContext _localctx = new MakroContext(_ctx, getState());
+ enterRule(_localctx, 0, RULE_makro);
+ try {
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(16);
+ expr(0);
+ setState(17);
+ match(EOF);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ public static class ExprContext extends ParserRuleContext {
+ public ItemContext item() {
+ return getRuleContext(ItemContext.class,0);
+ }
+ public ExprContext expr() {
+ return getRuleContext(ExprContext.class,0);
+ }
+ public ExprContext(ParserRuleContext parent, int invokingState)
{
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_expr; }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof NCMacroDslListener )
((NCMacroDslListener)listener).enterExpr(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof NCMacroDslListener )
((NCMacroDslListener)listener).exitExpr(this);
+ }
+ }
+
+ public final ExprContext expr() throws RecognitionException {
+ return expr(0);
+ }
+
+ private ExprContext expr(int _p) throws RecognitionException {
+ ParserRuleContext _parentctx = _ctx;
+ int _parentState = getState();
+ ExprContext _localctx = new ExprContext(_ctx, _parentState);
+ ExprContext _prevctx = _localctx;
+ int _startState = 2;
+ enterRecursionRule(_localctx, 2, RULE_expr, _p);
+ try {
+ int _alt;
+ enterOuterAlt(_localctx, 1);
+ {
+ {
+ setState(20);
+ item();
+ }
+ _ctx.stop = _input.LT(-1);
+ setState(26);
+ _errHandler.sync(this);
+ _alt = getInterpreter().adaptivePredict(_input,0,_ctx);
+ while ( _alt!=2 &&
_alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
+ if ( _alt==1 ) {
+ if ( _parseListeners!=null )
triggerExitRuleEvent();
+ _prevctx = _localctx;
+ {
+ {
+ _localctx = new ExprContext(_parentctx,
_parentState);
+ pushNewRecursionContext(_localctx,
_startState, RULE_expr);
+ setState(22);
+ if (!(precpred(_ctx, 1))) throw new
FailedPredicateException(this, "precpred(_ctx, 1)");
+ setState(23);
+ item();
+ }
+ }
+ }
+ setState(28);
+ _errHandler.sync(this);
+ _alt =
getInterpreter().adaptivePredict(_input,0,_ctx);
+ }
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ unrollRecursionContexts(_parentctx);
+ }
+ return _localctx;
+ }
+
+ public static class ItemContext extends ParserRuleContext {
+ public SynContext syn() {
+ return getRuleContext(SynContext.class,0);
+ }
+ public GroupContext group() {
+ return getRuleContext(GroupContext.class,0);
+ }
+ public ItemContext(ParserRuleContext parent, int invokingState)
{
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_item; }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof NCMacroDslListener )
((NCMacroDslListener)listener).enterItem(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof NCMacroDslListener )
((NCMacroDslListener)listener).exitItem(this);
+ }
+ }
+
+ public final ItemContext item() throws RecognitionException {
+ ItemContext _localctx = new ItemContext(_ctx, getState());
+ enterRule(_localctx, 4, RULE_item);
+ try {
+ setState(31);
+ _errHandler.sync(this);
+ switch (_input.LA(1)) {
+ case REGEX_TXT:
+ case IDL_TXT:
+ case TXT:
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(29);
+ syn();
+ }
+ break;
+ case LCURLY:
+ enterOuterAlt(_localctx, 2);
+ {
+ setState(30);
+ group();
+ }
+ break;
+ default:
+ throw new NoViableAltException(this);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ public static class SynContext extends ParserRuleContext {
+ public TerminalNode TXT() { return
getToken(NCMacroDslParser.TXT, 0); }
+ public TerminalNode REGEX_TXT() { return
getToken(NCMacroDslParser.REGEX_TXT, 0); }
+ public TerminalNode IDL_TXT() { return
getToken(NCMacroDslParser.IDL_TXT, 0); }
+ public SynContext(ParserRuleContext parent, int invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_syn; }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof NCMacroDslListener )
((NCMacroDslListener)listener).enterSyn(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof NCMacroDslListener )
((NCMacroDslListener)listener).exitSyn(this);
+ }
+ }
+
+ public final SynContext syn() throws RecognitionException {
+ SynContext _localctx = new SynContext(_ctx, getState());
+ enterRule(_localctx, 6, RULE_syn);
+ int _la;
+ try {
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(33);
+ _la = _input.LA(1);
+ if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L <<
REGEX_TXT) | (1L << IDL_TXT) | (1L << TXT))) != 0)) ) {
+ _errHandler.recoverInline(this);
+ }
+ else {
+ if ( _input.LA(1)==Token.EOF ) matchedEOF =
true;
+ _errHandler.reportMatch(this);
+ consume();
+ }
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ public static class GroupContext extends ParserRuleContext {
+ public TerminalNode LCURLY() { return
getToken(NCMacroDslParser.LCURLY, 0); }
+ public ListContext list() {
+ return getRuleContext(ListContext.class,0);
+ }
+ public TerminalNode RCURLY() { return
getToken(NCMacroDslParser.RCURLY, 0); }
+ public MinMaxContext minMax() {
+ return getRuleContext(MinMaxContext.class,0);
+ }
+ public GroupContext(ParserRuleContext parent, int
invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_group; }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof NCMacroDslListener )
((NCMacroDslListener)listener).enterGroup(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof NCMacroDslListener )
((NCMacroDslListener)listener).exitGroup(this);
+ }
+ }
+
+ public final GroupContext group() throws RecognitionException {
+ GroupContext _localctx = new GroupContext(_ctx, getState());
+ enterRule(_localctx, 8, RULE_group);
+ try {
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(35);
+ match(LCURLY);
+ setState(36);
+ list(0);
+ setState(37);
+ match(RCURLY);
+ setState(39);
+ _errHandler.sync(this);
+ switch (
getInterpreter().adaptivePredict(_input,2,_ctx) ) {
+ case 1:
+ {
+ setState(38);
+ minMax();
+ }
+ break;
+ }
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ public static class ListContext extends ParserRuleContext {
+ public ExprContext expr() {
+ return getRuleContext(ExprContext.class,0);
+ }
+ public TerminalNode UNDERSCORE() { return
getToken(NCMacroDslParser.UNDERSCORE, 0); }
+ public TerminalNode VERT() { return
getToken(NCMacroDslParser.VERT, 0); }
+ public ListContext list() {
+ return getRuleContext(ListContext.class,0);
+ }
+ public ListContext(ParserRuleContext parent, int invokingState)
{
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_list; }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof NCMacroDslListener )
((NCMacroDslListener)listener).enterList(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof NCMacroDslListener )
((NCMacroDslListener)listener).exitList(this);
+ }
+ }
+
+ public final ListContext list() throws RecognitionException {
+ return list(0);
+ }
+
+ private ListContext list(int _p) throws RecognitionException {
+ ParserRuleContext _parentctx = _ctx;
+ int _parentState = getState();
+ ListContext _localctx = new ListContext(_ctx, _parentState);
+ ListContext _prevctx = _localctx;
+ int _startState = 10;
+ enterRecursionRule(_localctx, 10, RULE_list, _p);
+ try {
+ int _alt;
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(46);
+ _errHandler.sync(this);
+ switch (_input.LA(1)) {
+ case LCURLY:
+ case REGEX_TXT:
+ case IDL_TXT:
+ case TXT:
+ {
+ setState(42);
+ expr(0);
+ }
+ break;
+ case UNDERSCORE:
+ {
+ setState(43);
+ match(UNDERSCORE);
+ setState(44);
+ match(VERT);
+ setState(45);
+ list(1);
+ }
+ break;
+ default:
+ throw new NoViableAltException(this);
+ }
+ _ctx.stop = _input.LT(-1);
+ setState(56);
+ _errHandler.sync(this);
+ _alt = getInterpreter().adaptivePredict(_input,5,_ctx);
+ while ( _alt!=2 &&
_alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
+ if ( _alt==1 ) {
+ if ( _parseListeners!=null )
triggerExitRuleEvent();
+ _prevctx = _localctx;
+ {
+ setState(54);
+ _errHandler.sync(this);
+ switch (
getInterpreter().adaptivePredict(_input,4,_ctx) ) {
+ case 1:
+ {
+ _localctx = new
ListContext(_parentctx, _parentState);
+
pushNewRecursionContext(_localctx, _startState, RULE_list);
+ setState(48);
+ if (!(precpred(_ctx, 3))) throw
new FailedPredicateException(this, "precpred(_ctx, 3)");
+ setState(49);
+ match(VERT);
+ setState(50);
+ expr(0);
+ }
+ break;
+ case 2:
+ {
+ _localctx = new
ListContext(_parentctx, _parentState);
+
pushNewRecursionContext(_localctx, _startState, RULE_list);
+ setState(51);
+ if (!(precpred(_ctx, 2))) throw
new FailedPredicateException(this, "precpred(_ctx, 2)");
+ setState(52);
+ match(VERT);
+ setState(53);
+ match(UNDERSCORE);
+ }
+ break;
+ }
+ }
+ }
+ setState(58);
+ _errHandler.sync(this);
+ _alt =
getInterpreter().adaptivePredict(_input,5,_ctx);
+ }
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ unrollRecursionContexts(_parentctx);
+ }
+ return _localctx;
+ }
+
+ public static class MinMaxContext extends ParserRuleContext {
+ public MinMaxShortcutContext minMaxShortcut() {
+ return getRuleContext(MinMaxShortcutContext.class,0);
+ }
+ public TerminalNode MINMAX() { return
getToken(NCMacroDslParser.MINMAX, 0); }
+ public MinMaxContext(ParserRuleContext parent, int
invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return RULE_minMax; }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof NCMacroDslListener )
((NCMacroDslListener)listener).enterMinMax(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof NCMacroDslListener )
((NCMacroDslListener)listener).exitMinMax(this);
+ }
+ }
+
+ public final MinMaxContext minMax() throws RecognitionException {
+ MinMaxContext _localctx = new MinMaxContext(_ctx, getState());
+ enterRule(_localctx, 12, RULE_minMax);
+ try {
+ setState(61);
+ _errHandler.sync(this);
+ switch (_input.LA(1)) {
+ case QUESTION:
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(59);
+ minMaxShortcut();
+ }
+ break;
+ case MINMAX:
+ enterOuterAlt(_localctx, 2);
+ {
+ setState(60);
+ match(MINMAX);
+ }
+ break;
+ default:
+ throw new NoViableAltException(this);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ public static class MinMaxShortcutContext extends ParserRuleContext {
+ public TerminalNode QUESTION() { return
getToken(NCMacroDslParser.QUESTION, 0); }
+ public MinMaxShortcutContext(ParserRuleContext parent, int
invokingState) {
+ super(parent, invokingState);
+ }
+ @Override public int getRuleIndex() { return
RULE_minMaxShortcut; }
+ @Override
+ public void enterRule(ParseTreeListener listener) {
+ if ( listener instanceof NCMacroDslListener )
((NCMacroDslListener)listener).enterMinMaxShortcut(this);
+ }
+ @Override
+ public void exitRule(ParseTreeListener listener) {
+ if ( listener instanceof NCMacroDslListener )
((NCMacroDslListener)listener).exitMinMaxShortcut(this);
+ }
+ }
+
+ public final MinMaxShortcutContext minMaxShortcut() throws
RecognitionException {
+ MinMaxShortcutContext _localctx = new
MinMaxShortcutContext(_ctx, getState());
+ enterRule(_localctx, 14, RULE_minMaxShortcut);
+ try {
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(63);
+ match(QUESTION);
+ }
+ }
+ catch (RecognitionException re) {
+ _localctx.exception = re;
+ _errHandler.reportError(this, re);
+ _errHandler.recover(this, re);
+ }
+ finally {
+ exitRule();
+ }
+ return _localctx;
+ }
+
+ public boolean sempred(RuleContext _localctx, int ruleIndex, int
predIndex) {
+ switch (ruleIndex) {
+ case 1:
+ return expr_sempred((ExprContext)_localctx, predIndex);
+ case 5:
+ return list_sempred((ListContext)_localctx, predIndex);
+ }
+ return true;
+ }
+ private boolean expr_sempred(ExprContext _localctx, int predIndex) {
+ switch (predIndex) {
+ case 0:
+ return precpred(_ctx, 1);
+ }
+ return true;
+ }
+ private boolean list_sempred(ListContext _localctx, int predIndex) {
+ switch (predIndex) {
+ case 1:
+ return precpred(_ctx, 3);
+ case 2:
+ return precpred(_ctx, 2);
+ }
+ return true;
+ }
+
+ public static final String _serializedATN =
+
"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\20D\4\2\t\2\4\3\t"+
+
"\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\3\2\3\2\3\2\3\3\3\3"+
+
"\3\3\3\3\3\3\7\3\33\n\3\f\3\16\3\36\13\3\3\4\3\4\5\4\"\n\4\3\5\3\5\3\6"+
+
"\3\6\3\6\3\6\5\6*\n\6\3\7\3\7\3\7\3\7\3\7\5\7\61\n\7\3\7\3\7\3\7\3\7\3"+
+
"\7\3\7\7\79\n\7\f\7\16\7<\13\7\3\b\3\b\5\b@\n\b\3\t\3\t\3\t\2\4\4\f\n"+
+
"\2\4\6\b\n\f\16\20\2\3\3\2\13\r\2B\2\22\3\2\2\2\4\25\3\2\2\2\6!\3\2\2"+
+
"\2\b#\3\2\2\2\n%\3\2\2\2\f\60\3\2\2\2\16?\3\2\2\2\20A\3\2\2\2\22\23\5"+
+
"\4\3\2\23\24\7\2\2\3\24\3\3\2\2\2\25\26\b\3\1\2\26\27\5\6\4\2\27\34\3"+
+
"\2\2\2\30\31\f\3\2\2\31\33\5\6\4\2\32\30\3\2\2\2\33\36\3\2\2\2\34\32\3"+
+ "\2\2\2\34\35\3\2\2\2\35\5\3\2\2\2\36\34\3\2\2\2\37\"\5\b\5\2
\"\5\n\6"+
+ "\2!\37\3\2\2\2!
\3\2\2\2\"\7\3\2\2\2#$\t\2\2\2$\t\3\2\2\2%&\7\3\2\2&\'"+
+
"\5\f\7\2\')\7\4\2\2(*\5\16\b\2)(\3\2\2\2)*\3\2\2\2*\13\3\2\2\2+,\b\7\1"+
+
"\2,\61\5\4\3\2-.\7\7\2\2./\7\5\2\2/\61\5\f\7\3\60+\3\2\2\2\60-\3\2\2\2"+
+
"\61:\3\2\2\2\62\63\f\5\2\2\63\64\7\5\2\2\649\5\4\3\2\65\66\f\4\2\2\66"+
+
"\67\7\5\2\2\679\7\7\2\28\62\3\2\2\28\65\3\2\2\29<\3\2\2\2:8\3\2\2\2:;"+
+
"\3\2\2\2;\r\3\2\2\2<:\3\2\2\2=@\5\20\t\2>@\7\16\2\2?=\3\2\2\2?>\3\2\2"+
+ "\2@\17\3\2\2\2AB\7\n\2\2B\21\3\2\2\2\t\34!)\608:?";
+ public static final ATN _ATN =
+ new ATNDeserializer().deserialize(_serializedATN.toCharArray());
+ static {
+ _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
+ for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
+ _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i),
i);
+ }
+ }
+}
\ No newline at end of file
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/util/NCUtils.scala
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/util/NCUtils.scala
index f9d8385..479ebb5 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/util/NCUtils.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/util/NCUtils.scala
@@ -644,4 +644,18 @@ object NCUtils extends LazyLogging:
if a != null then
ignoring(classOf[Exception]) {
a.close()
- }
\ No newline at end of file
+ }
+
+ /**
+ *
+ * @param s
+ * @return
+ */
+ def decapitalize(s: String): String = s"${s.head.toLower}${s.tail}"
+
+ /**
+ *
+ * @param s
+ * @return
+ */
+ def capitalize(s: String): String = s"${s.head.toUpper}${s.tail}"
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 25713ab..9f93030 100644
--- a/pom.xml
+++ b/pom.xml
@@ -96,6 +96,7 @@
<maven.install.plugin.ver>2.5.2</maven.install.plugin.ver>
<maven.source.plugin.ver>3.0.1</maven.source.plugin.ver>
<maven.clean.plugin.ver>3.1.0</maven.clean.plugin.ver>
+ <org.antlr4.ver>4.9</org.antlr4.ver>
<jline.ver>3.20.0</jline.ver>
<commons.lang3.ver>3.12.0</commons.lang3.ver>
<scala3.ref.ver>1.0.0</scala3.ref.ver>
@@ -148,6 +149,17 @@
</dependency>
<!--
+ Other dependencies.
+ ==================
+ -->
+
+ <dependency>
+ <groupId>org.antlr</groupId>
+ <artifactId>antlr4-runtime</artifactId>
+ <version>${org.antlr4.ver}</version>
+ </dependency>
+
+ <!--
JLine dependencies.
==================
-->