This is an automated email from the ASF dual-hosted git repository.

aradzinski pushed a commit to branch NLPCRAFT-474
in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft.git


The following commit(s) were added to refs/heads/NLPCRAFT-474 by this push:
     new 64ec9c4  WIP
64ec9c4 is described below

commit 64ec9c459b0196c0eed1014c09c5ac51a0178c3d
Author: Aaron Radzinski <[email protected]>
AuthorDate: Mon Jan 24 17:46:47 2022 -0800

    WIP
---
 nlpcraft/pom.xml                                   |   5 +
 .../nlpcraft/internal/intent/NCIDLContext.scala    |   9 +-
 .../{NCIDLContext.scala => NCIDLEntity.scala}      |  30 +-
 .../intent/compiler/NCIDLCodeGenerator.scala       | 593 +++++++--------------
 .../internal/intent/compiler/antlr4/NCIDL.g4       |   3 +
 pom.xml                                            |   7 +
 6 files changed, 221 insertions(+), 426 deletions(-)

diff --git a/nlpcraft/pom.xml b/nlpcraft/pom.xml
index 2c75806..9f4a02a 100644
--- a/nlpcraft/pom.xml
+++ b/nlpcraft/pom.xml
@@ -95,6 +95,11 @@
         </dependency>
 
         <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-collections4</artifactId>
+        </dependency>
+
+        <dependency>
             <groupId>commons-codec</groupId>
             <artifactId>commons-codec</artifactId>
         </dependency>
diff --git 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/NCIDLContext.scala
 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/NCIDLContext.scala
index 865e05e..cd6d6d0 100644
--- 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/NCIDLContext.scala
+++ 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/NCIDLContext.scala
@@ -23,7 +23,8 @@ import scala.collection.mutable
 
 /**
   *
-  * @param ents Entities.
+  * @param mdlCf Model configuration.
+  * @param ents Detected entities.
   * @param intentMeta Intent metadata.
   * @param convMeta Conversation metadata.
   * @param fragMeta Fragment (argument) metadata passed during intent fragment 
reference.
@@ -31,11 +32,13 @@ import scala.collection.mutable
   * @param vars Intent variable storage.
   */
 case class NCIDLContext(
-    ents: Seq[NCEntity] = Seq.empty,
+    mdlCf: NCModelConfig,
+    private val ents: Seq[NCEntity] = Seq.empty,
     intentMeta: Map[String, Object] = Map.empty,
     convMeta: Map[String, Object] = Map.empty,
     fragMeta: Map[String, Object] = Map.empty,
     req: NCRequest,
     vars: mutable.Map[String, NCIDLFunction] = mutable.HashMap.empty
-)
+):
+    lazy val entities: Seq[NCIDLEntity] = ents.zipWithIndex.map((ent, idx) => 
NCIDLEntity(ent, idx))
 
diff --git 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/NCIDLContext.scala
 b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/NCIDLEntity.scala
similarity index 59%
copy from 
nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/NCIDLContext.scala
copy to 
nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/NCIDLEntity.scala
index 865e05e..f779938 100644
--- 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/NCIDLContext.scala
+++ 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/NCIDLEntity.scala
@@ -18,24 +18,22 @@
 package org.apache.nlpcraft.internal.intent
 
 import org.apache.nlpcraft.*
-
-import scala.collection.mutable
+import scala.jdk.CollectionConverters.*
+import java.util
+//import java.util.{Collections, List, Set}
 
 /**
   *
-  * @param ents Entities.
-  * @param intentMeta Intent metadata.
-  * @param convMeta Conversation metadata.
-  * @param fragMeta Fragment (argument) metadata passed during intent fragment 
reference.
-  * @param req Server request holder.
-  * @param vars Intent variable storage.
+  * @param ent
+  * @param idx
   */
-case class NCIDLContext(
-    ents: Seq[NCEntity] = Seq.empty,
-    intentMeta: Map[String, Object] = Map.empty,
-    convMeta: Map[String, Object] = Map.empty,
-    fragMeta: Map[String, Object] = Map.empty,
-    req: NCRequest,
-    vars: mutable.Map[String, NCIDLFunction] = mutable.HashMap.empty
-)
+class NCIDLEntity(ent: NCEntity, idx: Int) extends NCPropertyMapAdapter with 
NCEntity:
+    private lazy val txt = ent.getTokens.asScala.map(_.getText).mkString(" ")
+
+    override def getTokens: util.List[NCToken] = ent.getTokens
+    override def getRequestId: String = ent.getRequestId
+    override def getGroups: util.Set[String] = ent.getGroups
+    override def getId: String = ent.getId
 
+    def getText: String = txt
+    def getIndex: Int = idx
diff --git 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/compiler/NCIDLCodeGenerator.scala
 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/compiler/NCIDLCodeGenerator.scala
index 7c86730..fd53633 100644
--- 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/compiler/NCIDLCodeGenerator.scala
+++ 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/compiler/NCIDLCodeGenerator.scala
@@ -22,7 +22,7 @@ import org.apache.nlpcraft.*
 import org.apache.nlpcraft.internal.util.*
 import org.antlr.v4.runtime.{ParserRuleContext => PRC}
 import org.antlr.v4.runtime.tree.{TerminalNode => TN}
-import org.apache.commons.collections.CollectionUtils
+import org.apache.commons.collections4.CollectionUtils
 import org.apache.nlpcraft.internal.intent.*
 import org.apache.nlpcraft.internal.intent.{NCIDLStackItem => Z}
 
@@ -130,13 +130,13 @@ trait NCIDLCodeGenerator:
     def isJColl(v: Object): Boolean = v.isInstanceOf[JColl[_]]
     def isMap(v: Object): Boolean = v.isInstanceOf[JMap[_, _]]
     def isStr(v: Object): Boolean = v.isInstanceOf[String]
-    def isToken(v: Object): Boolean = v.isInstanceOf[NCToken]
+    def isEntity(v: Object): Boolean = v.isInstanceOf[NCIDLEntity]
 
     def asList(v: Object): JList[_] = v.asInstanceOf[JList[_]]
     def asJColl(v: Object): JColl[_] = v.asInstanceOf[JColl[_]]
     def asMap(v: Object): JMap[_, _] = v.asInstanceOf[JMap[_, _]]
     def asStr(v: Object): String = v.asInstanceOf[String]
-    def asToken(v: Object): NCToken = v.asInstanceOf[NCToken]
+    def asEntity(v: Object): NCIDLEntity = v.asInstanceOf[NCIDLEntity]
     def asBool(v: Object): Boolean = v.asInstanceOf[Boolean]
 
     // Runtime errors.
@@ -343,24 +343,16 @@ trait NCIDLCodeGenerator:
         val (x1, x2) = pop2()(stack, ctx)
 
         stack.push(() => {
-            val (op, flag) = if (and != null) ("&&", false) else ("||", true)
-
+            val (op, flag) = if and != null then ("&&", false) else ("||", 
true)
             val Z(v1, n1) = x1()
-
-            if (!isBool(v1))
-                throw rtBinaryOpError(op, v1, x2().value)
+            if !isBool(v1) then throw rtBinaryOpError(op, v1, x2().value)
 
             // NOTE: check v1 first and only if it is {true|false} check the 
v2.
-            if (asBool(v1) == flag)
-                Z(flag, n1)
-            else {
+            if asBool(v1) == flag then Z(flag, n1)
+            else
                 val Z(v2, n2) = x2()
-
-                if (!isBool(v2))
-                    throw rtBinaryOpError(op, v2, v1)
-
+                if !isBool(v2) then throw rtBinaryOpError(op, v2, v1)
                 Z(asBool(v2), n1 + n2)
-            }
         })
     }
 
@@ -373,32 +365,28 @@ trait NCIDLCodeGenerator:
     def parseEqNeqExpr(eq: TN, neq: TN)(implicit ctx: PRC): SI = (_, stack: S, 
_) => {
         val (x1, x2) = pop2()(stack, ctx)
 
-        def doEq(v1: Object, v2: Object): Boolean = {
+        def doEq(v1: Object, v2: Object): Boolean =
             //noinspection ComparingUnrelatedTypes
-            if (v1 eq v2) true
-            else if (v1 == null && v2 == null) true
-            else if ((v1 == null && v2 != null) || (v1 != null && v2 == null)) 
false
-            else if (isInt(v1) && isInt(v2)) asInt(v1) == asInt(v2)
-            else if (isReal(v1) && isReal(v2)) asReal(v1) == asReal(v2)
-            else if (isBool(v1) && isBool(v2)) asBool(v1) == asBool(v2)
-            else if (isStr(v1) && isStr(v2)) asStr(v1) == asStr(v2)
-            else if (isList(v1) && isList(v2)) 
CollectionUtils.isEqualCollection(asList(v1), asList(v2))
-            else if ((isInt(v1) && isReal(v2)) || (isReal(v1) && isInt(v2))) 
asReal(v1) == asReal(v2)
+            if v1 eq v2 then true
+            else if v1 == null && v2 == null then true
+            else if (v1 == null && v2 != null) || (v1 != null && v2 == null) 
then false
+            else if isInt(v1) && isInt(v2) then asInt(v1) == asInt(v2)
+            else if isReal(v1) && isReal(v2) then asReal(v1) == asReal(v2)
+            else if isBool(v1) && isBool(v2) then asBool(v1) == asBool(v2)
+            else if isStr(v1) && isStr(v2) then asStr(v1) == asStr(v2)
+            else if isList(v1) && isList(v2) then 
CollectionUtils.isEqualCollection(asList(v1), asList(v2))
+            else if (isInt(v1) && isReal(v2)) || (isReal(v1) && isInt(v2)) 
then asReal(v1) == asReal(v2)
             else
                 v1.equals(v2)
-        }
 
         stack.push(() => {
             val (v1, v2, n) = extract2(x1, x2)
 
             val f =
-                if (eq != null)
-                    doEq(v1, v2)
-                else {
+                if eq != null then doEq(v1, v2)
+                else
                     assert(neq != null)
-
                     !doEq(v1, v2)
-                }
 
             Z(f, n)
         })
@@ -412,32 +400,31 @@ trait NCIDLCodeGenerator:
     def parsePlusMinusExpr(plus: TN, minus: TN)(implicit ctx: PRC): SI = (_, 
stack: S, _) => {
         val (x1, x2) = pop2()(stack, ctx)
 
-        if (plus != null)
+        if plus != null then
             stack.push(() => {
                 val (v1, v2, n) = extract2(x1, x2)
 
-                if (isStr(v1) && isStr(v2)) Z(asStr(v1) + asStr(v2), n)
-                else if (isInt(v1) && isInt(v2)) Z(asInt(v1) + asInt(v2), n)
-                else if (isInt(v1) && isReal(v2)) Z(asInt(v1) + asReal(v2), n)
-                else if (isReal(v1) && isInt(v2)) Z(asReal(v1) + asInt(v2), n)
-                else if (isReal(v1) && isReal(v2)) Z(asReal(v1) + asReal(v2), 
n)
+                if isStr(v1) && isStr(v2) then Z(asStr(v1) + asStr(v2), n)
+                else if isInt(v1) && isInt(v2) then Z(asInt(v1) + asInt(v2), n)
+                else if isInt(v1) && isReal(v2) then Z(asInt(v1) + asReal(v2), 
n)
+                else if isReal(v1) && isInt(v2) then Z(asReal(v1) + asInt(v2), 
n)
+                else if isReal(v1) && isReal(v2) then Z(asReal(v1) + 
asReal(v2), n)
                 else
                     throw rtBinaryOpError("+", v1, v2)
             })
-        else {
+        else
             assert(minus != null)
 
             stack.push(() => {
                 val (v1, v2, n) = extract2(x1, x2)
 
-                if (isInt(v1) && isInt(v2)) Z(asInt(v1) - asInt(v2), n)
-                else if (isInt(v1) && isReal(v2)) Z(asInt(v1) - asReal(v2), n)
-                else if (isReal(v1) && isInt(v2)) Z(asReal(v1) - asInt(v2), n)
-                else if (isReal(v1) && isReal(v2)) Z(asReal(v1) - asReal(v2), 
n)
+                if isInt(v1) && isInt(v2) then Z(asInt(v1) - asInt(v2), n)
+                else if isInt(v1) && isReal(v2) then Z(asInt(v1) - asReal(v2), 
n)
+                else if isReal(v1) && isInt(v2) then Z(asReal(v1) - asInt(v2), 
n)
+                else if isReal(v1) && isReal(v2) then Z(asReal(v1) - 
asReal(v2), n)
                 else
                     throw rtBinaryOpError("-", v1, v2)
             })
-        }
     }
 
     /**
@@ -448,26 +435,23 @@ trait NCIDLCodeGenerator:
     def parseUnaryExpr(minus: TN, not: TN)(implicit ctx: PRC): SI = (_, stack: 
S, _) => {
         val x = pop1()(stack, ctx)
 
-        if (minus != null)
+        if minus != null then
             stack.push(() => {
                 val Z(v, n) = x()
 
-                if (isReal(v)) Z(-asReal(v), n)
-                else if (isInt(v)) Z(-asInt(v), n)
-                else
-                    throw rtUnaryOpError("-", v)
+                if isReal(v) then Z(-asReal(v), n)
+                else if isInt(v) then Z(-asInt(v), n)
+                else throw rtUnaryOpError("-", v)
             })
-        else {
+        else
             assert(not != null)
 
             stack.push(() => {
                 val Z(v, n) = x()
 
-                if (isBool(v)) Z(!asBool(v), n)
-                else
-                    throw rtUnaryOpError("!", v)
+                if isBool(v) then Z(!asBool(v), n)
+                else throw rtUnaryOpError("!", v)
             })
-        }
     }
 
     /**
@@ -477,25 +461,19 @@ trait NCIDLCodeGenerator:
       */
     def parseAtom(txt: String)(implicit ctx: PRC): SI = {
         val atom =
-            if (txt == "null") null // Try 'null'.
-            else if (txt == "true") Boolean.box(true) // Try 'boolean'.
-            else if (txt == "false") Boolean.box(false) // Try 'boolean'.
+            if txt == "null" then null // Try 'null'.
+            else if txt == "true" then Boolean.box(true) // Try 'boolean'.
+            else if txt == "false" then Boolean.box(false) // Try 'boolean'.
             // Only numeric or string values below...
-            else {
+            else
                 // Strip '_' from numeric values.
                 val num = txt.replaceAll("_", "")
 
-                try
-                    Long.box(JLong.parseLong(num)) // Try 'long'.
-                catch {
-                    case _: NumberFormatException =>
-                        try
-                            Double.box(JDouble.parseDouble(num)) // Try 
'double'.
-                        catch {
-                            case _: NumberFormatException => 
NCUtils.escapesQuotes(txt) // String in the end.
-                        }
-                }
-            }
+                try Long.box(JLong.parseLong(num)) // Try 'long'.
+                catch case _: NumberFormatException =>
+                    try Double.box(JDouble.parseDouble(num)) // Try 'double'.
+                    catch case _: NumberFormatException => 
NCUtils.escapesQuotes(txt) // String in the end.
+
 
         (_, stack, _) => stack.push(() => Z(atom, 0))
     }
@@ -506,597 +484,418 @@ trait NCIDLCodeGenerator:
       * @param ctx
       * @return
       */
-    def parseCallExpr(fun: String)(implicit ctx: PRC): SI = (tok, stack: S, 
idlCtx) => {
+    def parseCallExpr(fun: String)(implicit ctx: PRC): SI = (ent, stack: S, 
idlCtx) =>
         implicit val evidence: S = stack
 
-        def popMarker(argNum: Int): Unit = if (pop1() != stack.PLIST_MARKER) 
throw rtTooManyParamsError(argNum, fun)
-        def arg[X](argNum: Int, f: () => X): X = {
-            if (stack.size < argNum + 1) // +1 for stack frame marker.
-                throw rtMissingParamError(argNum, fun)
+        def popMarker(argNum: Int): Unit = if pop1() != stack.PLIST_MARKER 
then throw rtTooManyParamsError(argNum, fun)
+        def arg[X](argNum: Int, f: () => X): X =
+            // +1 for stack frame marker.
+            if stack.size < argNum + 1 then throw rtMissingParamError(argNum, 
fun)
 
             val x = f()
-
-            x match {
+            x match
                 case p: Product =>
                     for (e <- p.productIterator)
-                        if (e == stack.PLIST_MARKER)
-                            rtMissingParamError(argNum, fun)
-                case _ =>
-                    if (x.asInstanceOf[ST] == stack.PLIST_MARKER)
-                        rtMissingParamError(argNum, fun)
-            }
+                        if e == stack.PLIST_MARKER then 
rtMissingParamError(argNum, fun)
+                case _ => if x.asInstanceOf[ST] == stack.PLIST_MARKER then 
rtMissingParamError(argNum, fun)
 
             // Make sure to pop up the parameter list stack frame marker.
             popMarker(argNum)
 
             x
-        }
+
         def arg1(): ST = arg(1, pop1)
         def arg2(): (ST, ST) = arg(2, pop2)
         def arg3(): (ST, ST, ST) = arg(3, pop3)
         def arg1Tok(): ST =
-            if (stack.nonEmpty && stack.top == stack.PLIST_MARKER) {
+            if stack.nonEmpty && stack.top == stack.PLIST_MARKER then
                 popMarker(1)
-
-                () => Z(tok, 1)
-            }
+                () => Z(ent, 1)
             else
                 arg1()
 
-        def toX[T](typ: String, v: Object, is: Object => Boolean, as: Object 
=> T): T = {
-            if (v == null)
-                throw rtParamNullError(fun)
-            else if (!is(v))
-                throw rtParamTypeError(fun, v, typ)
-
+        def toX[T](typ: String, v: Object, is: Object => Boolean, as: Object 
=> T): T =
+            if v == null then throw rtParamNullError(fun)
+            else if !is(v) then throw rtParamTypeError(fun, v, typ)
             as(v)
-        }
+
         def toStr(v: Object): String = toX("string", v, isStr, asStr)
         def toInt(v: Object): JInt = toX("int", v, isInt, asInt).toInt
         def toList(v: Object): JList[_] = toX("list", v, isList, asList)
         def toMap(v: Object): JMap[_, _] = toX("map", v, isMap, asMap)
-        def toToken(v: Object): NCToken = toX("token", v, isToken, asToken)
+        def toEntity(v: Object): NCIDLEntity = toX("entity", v, isEntity, 
asEntity)
         def toBool(v: Object): Boolean = toX("boolean", v, isBool, asBool)
         def toDouble(v: Object): JDouble = toX("double or int", v, x => 
isInt(x) || isReal(x), asReal)
 
-        def doSplit(): Unit = {
+        def doSplit(): Unit =
             val (x1, x2) = arg2()
-
             stack.push(
                 () => {
                     val (v1, v2, n) = extract2(x1, x2)
-
                     Z(util.Arrays.asList(toStr(v1).split(toStr(v2)):_*), n)
                 }
             )
-        }
 
-        def doSplitTrim(): Unit = {
+        def doSplitTrim(): Unit =
             val (x1, x2) = arg2()
-
             stack.push(
                 () => {
                     val (v1, v2, n) = extract2(x1, x2)
-
                     
Z(util.Arrays.asList(toStr(v1).split(toStr(v2)).toList.map(_.strip):_*), n)
                 }
             )
-        }
 
-        def doStartsWith(): Unit = {
+        def doStartsWith(): Unit =
             val (x1, x2) = arg2()
-
             stack.push(
                 () => {
                     val (v1, v2, n) = extract2(x1, x2)
-
                     Z(toStr(v1).startsWith(toStr(v2)), n)
                 }
             )
-        }
 
-        def doEndsWith(): Unit = {
+        def doEndsWith(): Unit =
             val (x1, x2) = arg2()
-
             stack.push(
                 () => {
                     val (v1, v2, n) = extract2(x1, x2)
-
                     Z(toStr(v1).endsWith(toStr(v2)), n)
                 }
             )
-        }
 
-        def doContains(): Unit = {
+        def doContains(): Unit =
             val (x1, x2) = arg2()
-
             stack.push(
                 () => {
                     val (v1, v2, n) = extract2(x1, x2)
-
                     Z(toStr(v1).contains(toStr(v2)),n)
                 }
             )
-        }
 
-        def doIndexOf(): Unit = {
+        def doIndexOf(): Unit =
             val (x1, x2) = arg2()
-
             stack.push(
                 () => {
                     val (v1, v2, n) = extract2(x1, x2)
-
                     Z(toStr(v1).indexOf(toStr(v2)), n)
                 }
             )
-        }
 
-        def doSubstr(): Unit = {
+        def doSubstr(): Unit =
             val (x1, x2, x3) = arg3()
-
             stack.push(
                 () => {
                     val (v1, v2, v3, n) = extract3(x1, x2, x3)
-
                     Z(toStr(v1).substring(toInt(v2), toInt(v3)), n)
                 }
             )
-        }
 
-        def doRegex(): Unit = {
+        def doRegex(): Unit =
             val (x1, x2) = arg2()
-
             stack.push(
                 () => {
                     val (v1, v2, n) = extract2(x1, x2)
-
                     Z(toStr(v1).matches(toStr(v2)), n)
                 }
             )
-        }
 
-        def doReplace(): Unit = {
-            val (x1, x2, x3) = arg3()
 
+        def doReplace(): Unit =
+            val (x1, x2, x3) = arg3()
             stack.push(
                 () => {
                     val (v1, v2, v3, n) = extract3(x1, x2, x3)
-
                     Z(toStr(v1).replaceAll(toStr(v2), toStr(v3)), n)
                 }
             )
-        }
 
-        def doList(): Unit = {
+        def doList(): Unit =
             val dump = new S() // Empty list is allowed.
-
-            while (stack.nonEmpty && stack.top != stack.PLIST_MARKER)
-                dump += stack.pop()
+            while (stack.nonEmpty && stack.top != stack.PLIST_MARKER) dump += 
stack.pop()
 
             require(stack.nonEmpty)
 
             // Pop frame marker.
             pop1()
-
             stack.push(() => {
                 val jl = new util.ArrayList[Object]()
                 var z = 0
-
                 dump.toSeq.reverse.foreach { x =>
                     val Z(v, n) = x()
-
                     z += n
-
                     jl.add(v)
                 }
-
                 Z(jl, z)
             })
-        }
 
-        def doReverse(): Unit = {
+        def doReverse(): Unit =
             val x = arg1()
-
             stack.push(() => {
                 val Z(v, n) = x()
-
                 val jl = toList(v)
-
                 Collections.reverse(jl)
-
                 Z(jl, n)
             })
-        }
 
-        def doMin(): Unit = {
+        def doMin(): Unit =
             val x = arg1()
-
             stack.push(() => {
                 val Z(v, n) = x()
-
                 val lst = toList(v).asInstanceOf[util.List[Object]]
-
                 try
-                    if (lst.isEmpty)
-                        throw newRuntimeError(s"Unexpected empty list in IDL 
function: $fun()")
-                    else
-                        Z(Collections.min(lst, null), n)
-                catch {
-                    case e: Exception => throw rtListTypeError(fun, e)
-                }
+                    if lst.isEmpty then throw newRuntimeError(s"Unexpected 
empty list in IDL function: $fun()")
+                    else Z(Collections.min(lst, null), n)
+                catch case e: Exception => throw rtListTypeError(fun, e)
             })
-        }
 
-        def doAvg(): Unit = {
+        def doAvg(): Unit =
             val x = arg1()
-
             stack.push(() => {
                 val Z(v, n) = x()
-
                 val lst = toList(v).asInstanceOf[util.List[Object]]
-
                 try
-                    if (lst.isEmpty)
-                        throw newRuntimeError(s"Unexpected empty list in IDL 
function: $fun()")
-                    else {
+                    if lst.isEmpty then throw newRuntimeError(s"Unexpected 
empty list in IDL function: $fun()")
+                    else
                         val seq: Seq[Double] = lst.asScala.map(p => 
JDouble.valueOf(p.toString).doubleValue()).toSeq
-
                         Z(seq.sum / seq.length, n)
-                    }
-                catch {
-                    case e: Exception => throw rtListTypeError(fun, e)
-                }
+                catch case e: Exception => throw rtListTypeError(fun, e)
             })
-        }
 
-        def doStdev(): Unit = {
+        def doStdev(): Unit =
             val x = arg1()
-
             stack.push(() => {
                 val Z(v, n) = x()
-
                 val lst = toList(v).asInstanceOf[util.List[Object]]
-
                 try
-                    if (lst.isEmpty)
-                        throw newRuntimeError(s"Unexpected empty list in IDL 
function: $fun()")
-                    else {
+                    if lst.isEmpty then throw newRuntimeError(s"Unexpected 
empty list in IDL function: $fun()")
+                    else
                         val seq: Seq[Double] = lst.asScala.map(p => 
JDouble.valueOf(p.toString).doubleValue()).toSeq
-
                         val mean = seq.sum / seq.length
                         val stdDev = Math.sqrt(seq.map( _ - mean).map(t => t * 
t).sum / seq.length)
-
                         Z(stdDev, n)
-                    }
-                catch {
-                    case e: Exception => throw rtListTypeError(fun, e)
-                }
+                catch case e: Exception => throw rtListTypeError(fun, e)
             })
-        }
 
-        def doToString(): Unit = {
+        def doToString(): Unit =
             val x = arg1()
-
             stack.push(() => {
                 val Z(v, n) = x()
-
-                if (isList(v)) {
+                if isList(v) then
                     val jl = new util.ArrayList[Object]()
-
-                    for (d <- toList(v).asScala.map(_.toString))
-                        jl.add(d)
-
+                    for (d <- toList(v).asScala.map(_.toString)) jl.add(d)
                     Z(jl, n)
-                }
                 else
                     Z(v.toString, n)
             })
-        }
 
-        def doToDouble(): Unit = {
+        def doToDouble(): Unit =
             val x = arg1()
-
             stack.push(() => {
                 val Z(v, n) = x()
-
-                if (isInt(v))
-                    Z(asInt(v).toDouble, n)
-                else if (isStr(v))
-                    try
-                        Z(toStr(v).toDouble, n)
-                    catch {
-                        case e: Exception => throw newRuntimeError(s"Invalid 
double value '$v' in IDL function: $fun()", e)
-                    }
+                if isInt(v) then Z(asInt(v).toDouble, n)
+                else if isStr(v) then
+                    try Z(toStr(v).toDouble, n)
+                    catch case e: Exception => throw newRuntimeError(s"Invalid 
double value '$v' in IDL function: $fun()", e)
                 else
                     throw rtParamTypeError(fun, v, "int or string")
             })
-        }
 
-        def doToInt(): Unit = {
+        def doToInt(): Unit =
             val x = arg1()
-
             stack.push(() => {
                 val Z(v, n) = x()
-
-                if (isReal(v))
-                    Z(Math.round(asReal(v)), n)
-                else if (isStr(v))
-                    try
-                        Z(toStr(v).toLong, n)
-                    catch {
-                        case e: Exception => throw newRuntimeError(s"Invalid 
int value '$v' in IDL function: $fun()", e)
-                    }
+                if isReal(v) then Z(Math.round(asReal(v)), n)
+                else if isStr(v) then
+                    try Z(toStr(v).toLong, n)
+                    catch case e: Exception => throw newRuntimeError(s"Invalid 
int value '$v' in IDL function: $fun()", e)
                 else
                     throw rtParamTypeError(fun, v, "double or string")
             })
-        }
 
-        def doMax(): Unit = {
+        def doMax(): Unit =
             val x = arg1()
-
             stack.push(() => {
                 val Z(v, n) = x()
-
                 val lst = toList(v).asInstanceOf[util.List[Object]]
-
                 try
-                    if (lst.isEmpty)
-                        throw newRuntimeError(s"Unexpected empty list in IDL 
function: $fun()")
-                    else
-                        Z(Collections.max(lst, null), n)
-                catch {
-                    case e: Exception => throw rtListTypeError(fun, e)
-                }
+                    if lst.isEmpty then throw newRuntimeError(s"Unexpected 
empty list in IDL function: $fun()")
+                    else Z(Collections.max(lst, null), n)
+                catch case e: Exception => throw rtListTypeError(fun, e)
             })
-        }
 
-        def doSort(): Unit = {
+        def doSort(): Unit =
             val x = arg1()
-
             stack.push(() => {
                 val Z(v, n) = x()
-
                 val jl = toList(v)
-
-                try
-                    jl.sort(null) // Use natural order.
-                catch {
-                    case e: Exception => throw rtListTypeError(fun, e)
-                }
+                try jl.sort(null) // Use natural order.
+                catch case e: Exception => throw rtListTypeError(fun, e)
 
                 Z(jl, n)
             })
-        }
 
-        def doDistinct(): Unit = {
+        def doDistinct(): Unit =
             val x = arg1()
-
             stack.push(() => {
                 val Z(v, n) = x()
-
                 val jl = new util.ArrayList[Object]()
-
                 for (d <- toList(v).asScala.toSeq.distinct)
                     jl.add(d.asInstanceOf[Object])
-
                 Z(jl, n)
             })
-        }
 
-        def doConcat(): Unit = {
+        def doConcat(): Unit =
             val (x1, x2) = arg2()
-
             stack.push(() => {
                 val (lst1, lst2, n) = extract2(x1, x2)
-
                 val jl = new util.ArrayList[Object]()
-
                 for (d <- toList(lst1).asScala ++ toList(lst2).asScala)
                     jl.add(d.asInstanceOf[Object])
-
                 Z(jl, n)
             })
-        }
 
-        def doHas(): Unit = {
+        def doHas(): Unit =
             val (x1, x2) = arg2()
-
             stack.push(() => {
                 val (lst, obj, n) = extract2(x1, x2)
-
                 Z(toList(lst).contains(box(obj)), n)
             })
-        }
 
-        def doHasAll(): Unit = {
+        def doHasAll(): Unit =
             val (x1, x2) = arg2()
-
             stack.push(() => {
                 val (lst1, lst2, n) = extract2(x1, x2)
-
                 Z(toList(lst1).containsAll(toList(lst2)), n)
             })
-        }
 
-        def doHasAny(): Unit = {
+        def doHasAny(): Unit =
             val (x1, x2) = arg2()
-
             stack.push(() => {
                 val (lst1, lst2, n) = extract2(x1, x2)
-
                 Z(CollectionUtils.containsAny(toList(lst1), toList(lst2)), n)
             })
-        }
 
-        def doGet(): Unit = {
+        def doGet(): Unit =
             val (x1, x2) = arg2()
-
             stack.push(() => {
                 val (col, key, n) = extract2(x1, x2)
-
-                if (isList(col)) {
-                    if (isInt(key))
-                        
Z(asList(col).get(asInt(key).intValue()).asInstanceOf[Object], n)
-                    else
-                        throw rtParamTypeError(fun, key, "numeric")
-                }
-                else if (isMap(col))
-                    Z(asMap(col).get(box(key)).asInstanceOf[Object], n)
-                else
-                    throw rtParamTypeError(fun, col, "list or map")
+                if isList(col) then
+                    if isInt(key) then 
Z(asList(col).get(asInt(key).intValue()).asInstanceOf[Object], n)
+                    else throw rtParamTypeError(fun, key, "numeric")
+                else if isMap(col) then 
Z(asMap(col).get(box(key)).asInstanceOf[Object], n)
+                else throw rtParamTypeError(fun, col, "list or map")
             })
-        }
 
-        def doAbs(): Unit = arg1() match {
+        def doAbs(): Unit = arg1() match
             case x => stack.push(() => {
                 val Z(v, n) = x()
-
-                v match {
+                v match
                     case a: JLong => Z(Math.abs(a), n)
                     case a: JDouble => Z(Math.abs(a), n)
                     case _ => throw rtParamTypeError(fun, v, "numeric")
-                }
             })
-        }
 
-        def doSquare(): Unit = arg1() match {
+        def doSquare(): Unit = arg1() match
             case x => stack.push(() => {
                 val Z(v, n) = x()
-
-                v match {
+                v match
                     case a: JLong => Z(a * a, n)
                     case a: JDouble => Z(a * a, n)
                     case _ => throw rtParamTypeError(fun, v, "numeric")
-                }
             })
-        }
 
-        def doIf(): Unit = {
+
+        def doIf(): Unit =
             val (x1, x2, x3) = arg3()
 
             stack.push(() => {
                 val Z(v1, n1) = x1()
-
-                if (toBool(v1)) {
+                if toBool(v1) then
                     val Z(v2, n2) = x2()
-
                     Z(v2, n1 + n2)
-                }
-                else {
+                else
                     val Z(v3, n3) = x3()
-
                     Z(v3, n1 + n3)
-                }
             })
-        }
 
-        def doOrElse(): Unit = {
+        def doOrElse(): Unit =
             val (x1, x2) = arg2()
-
             stack.push(() => {
                 val Z(v1, n1) = x1()
-
-                if (v1 != null)
-                    Z(v1, n1)
-                else
-                    x2()
+                if v1 != null then Z(v1, n1)
+                else x2()
             })
-        }
 
-        def doIsBefore(f: (NCToken, String) => Boolean): Unit = {
+        def doIsBefore(f: (NCIDLEntity, String) => Boolean): Unit =
             val x = arg1()
-
             stack.push(() => {
                 val Z(arg, n) = x()
-
-                Z(idlCtx.ents.exists(t => t.getIndex > tok.getIndex && f(t, 
toStr(arg))), n)
+                Z(idlCtx.entities.exists(t => t.getIndex > ent.getIndex && 
f(t, toStr(arg))), n)
             })
-        }
 
-        def doIsAfter(f: (NCToken, String) => Boolean): Unit = {
+        def doIsAfter(f: (NCIDLEntity, String) => Boolean): Unit =
             val x = arg1()
-
             stack.push(() => {
                 val Z(arg, n) = x()
-
-                Z(idlCtx.ents.exists(t => t.getIndex < tok.getIndex && f(t, 
toStr(arg))), n)
+                Z(idlCtx.entities.exists(t => t.getIndex < ent.getIndex && 
f(t, toStr(arg))), n)
             })
-        }
 
-        def doIsBetween(f: (NCToken, String) => Boolean): Unit = {
+        def doIsBetween(f: (NCIDLEntity, String) => Boolean): Unit =
             val (x1, x2) = arg2()
-
             stack.push(() => {
                 val (a1, a2, n) = extract2(x1, x2)
-
                 Z(
-                    idlCtx.ents.exists(t => t.getIndex < tok.getIndex && f(t, 
toStr(a1)))
-                        &&
-                        idlCtx.ents.exists(t => t.getIndex > tok.getIndex && 
f(t, toStr(a2)))
+                    idlCtx.entities.exists(t => t.getIndex < ent.getIndex && 
f(t, toStr(a1)))
+                    &&
+                    idlCtx.entities.exists(t => t.getIndex > ent.getIndex && 
f(t, toStr(a2)))
                     ,
                     n
                 )
             })
-        }
 
-        def doForAll(f: (NCToken, String) => Boolean): Unit = {
+        def doForAll(f: (NCIDLEntity, String) => Boolean): Unit =
             val x = arg1()
-
             stack.push(() => {
                 val Z(arg, n) = x()
-
-                Z(idlCtx.ents.filter(f(_, toStr(arg))).asJava, n)
+                Z(idlCtx.entities.filter(f(_, toStr(arg))).asJava, n)
             })
-        }
 
-        def doLength(): Unit = {
+        def doLength(): Unit =
             val x = arg1()
-
             stack.push(() => {
                 val Z(v, n) = x()
-
-                if (isList(v))
-                    Z(asList(v).size(), n)
-                else if (isMap(v))
-                    Z(asMap(v).size(), n)
-                else if (isStr(v))
-                    Z(asStr(v).length, n)
-                else
-                    throw rtParamTypeError(fun, v, "string or list")
+                if isList(v) then Z(asList(v).size(), n)
+                else if isMap(v) then Z(asMap(v).size(), n)
+                else if isStr(v) then Z(asStr(v).length, n)
+                else throw rtParamTypeError(fun, v, "string or list")
             })
-        }
 
-        def doIsEmpty(empty: Boolean): Unit = {
+        def doIsEmpty(empty: Boolean): Unit =
             val x = arg1()
-
             stack.push(() => {
                 val Z(v, n) = x()
-
-                if (isList(v))
-                    Z(asList(v).isEmpty == empty, n)
-                else if (isMap(v))
-                    Z(asMap(v).isEmpty == empty, n)
-                else if (isStr(v))
-                    Z(asStr(v).isEmpty == empty, n)
-                else
-                    throw rtParamTypeError(fun, v, "string or list")
+                if isList(v) then Z(asList(v).isEmpty == empty, n)
+                else if isMap(v) then Z(asMap(v).isEmpty == empty, n)
+                else if isStr(v) then Z(asStr(v).isEmpty == empty, n)
+                else throw rtParamTypeError(fun, v, "string or list")
             })
-        }
 
-        def z[Y](args: () => Y, body: Y => Z): Unit = { val x = args(); 
stack.push(() => body(x)) }
-        def z0(body: () => Z): Unit = { popMarker(0); stack.push(() => body()) 
}
+        def z[Y](args: () => Y, body: Y => Z): Unit =
+            val x = args()
+            stack.push(() => body(x))
+
+        def z0(body: () => Z): Unit =
+            popMarker(0)
+            stack.push(() => body())
 
-        def checkAvail(): Unit =
-            if (idlCtx.ents.isEmpty)
-                throw rtUnavailFunError(fun)
+        def checkAvail(): Unit = if idlCtx.entities.isEmpty then throw 
rtUnavailFunError(fun)
 
         try
-            fun match {
+            fun match
                 // Metadata access.
-                case "meta_model" => z[ST](arg1, { x => val Z(v, _) = x(); 
Z(box(tok.getModel.meta[Object](toStr(v))), 0) })
+                case "meta_ent" => ???
+                case "meta_cfg" => z[ST](arg1, { x => val Z(v, _) = x(); 
Z(box(idlCtx.mdlCf.get[Object](toStr(v))), 0) })
                 case "meta_req" => z[ST](arg1, { x => val Z(v, _) = x(); 
Z(box(idlCtx.req.getRequestData.get(toStr(v))), 0) })
-                case "meta_user" => z[ST](arg1, { x => val Z(v, _) = x(); 
Z(box(idlCtx.req.getUser.meta(toStr(v))), 0) })
-                case "meta_company" => z[ST](arg1, { x => val Z(v, _) = x(); 
Z(box(idlCtx.req.getCompany.meta(toStr(v))), 0) })
                 case "meta_intent" => z[ST](arg1, { x => val Z(v, _) = x(); 
Z(box(idlCtx.intentMeta.get(toStr(v)).orNull), 0) })
                 case "meta_conv" => z[ST](arg1, { x => val Z(v, _) = x(); 
Z(box(idlCtx.convMeta.get(toStr(v)).orNull), 0) })
                 case "meta_frag" => z[ST](arg1, { x => val Z(v, f) = x(); 
Z(box(idlCtx.fragMeta.get(toStr(v)).orNull), f) })
@@ -1107,11 +906,18 @@ trait NCIDLCodeGenerator:
 
                 // Inline if-statement.
                 case "if" => doIf()
-
                 case "or_else" => doOrElse()
 
-//                // Token functions.
-//                case "tok_id" => arg1Tok() match { case x => stack.push(() 
=> { Z(toToken(x().value).getId, 1) }) }
+                // Entity functions.
+                case "ent_id" => arg1Tok() match { case x => stack.push(() => 
Z(toEntity(x().value).getId, 1)) }
+                case "ent_index" => arg1Tok() match { case x => stack.push(() 
=> Z(toEntity(x().value).getIndex, 1)) }
+                case "ent_text" => arg1Tok() match { case x => stack.push(() 
=> Z(toEntity(x().value).getText, 1)) }
+                case "ent_count" => checkAvail(); z0(() => 
Z(idlCtx.entities.size, 0))
+                case "ent_groups" => arg1Tok() match { case x => stack.push(() 
=> Z(toEntity(x().value).getGroups, 1)) }
+                case "ent_all" => checkAvail(); z0(() => 
Z(idlCtx.entities.asJava, 0))
+                case "ent_all_for_id" => checkAvail(); doForAll((ent, id) => 
ent.getId == id)
+                case "ent_all_for_group" => checkAvail(); doForAll((ent, grp) 
=> ent.getGroups.contains(grp))
+
 //                case "tok_lemma" => arg1Tok() match { case x => 
stack.push(() => { Z(toToken(x().value).getLemma, 1) }) }
 //                case "tok_stem" => arg1Tok() match { case x => stack.push(() 
=> { Z(toToken(x().value).getStem, 1) }) }
 //                case "tok_pos" => arg1Tok() match { case x => stack.push(() 
=> { Z(toToken(x().value).getPos, 1) }) }
@@ -1122,17 +928,17 @@ trait NCIDLCodeGenerator:
 //                case "tok_unid" => arg1Tok() match { case x => stack.push(() 
=> { Z(toToken(x().value).getUnid, 1) }) }
 //
 //                case "tok_index" => checkAvail(); arg1Tok() match { case x 
=> stack.push(() => { Z(toToken(x().value).getIndex, 1) }) }
-//                case "tok_is_last" => checkAvail(); arg1Tok() match { case x 
=> stack.push(() => { Z(toToken(x().value).getIndex == idlCtx.ents.size - 1, 1) 
}) }
+//                case "tok_is_last" => checkAvail(); arg1Tok() match { case x 
=> stack.push(() => { Z(toToken(x().value).getIndex == idlCtx.entities.size - 
1, 1) }) }
 //                case "tok_is_first" => checkAvail(); arg1Tok() match { case 
x => stack.push(() => { Z(toToken(x().value).getIndex == 0, 1) }) }
-//                case "tok_is_before_id" => checkAvail(); doIsBefore((tok, 
id) => tok.getId == id)
-//                case "tok_is_before_group" => checkAvail(); doIsBefore((tok, 
grpId) => tok.getGroups.contains(grpId))
-//                case "tok_is_before_parent" => checkAvail(); 
doIsBefore((tok, id) => tok.getParentId == id)
-//                case "tok_is_after_id" => checkAvail(); doIsAfter((tok, id) 
=> tok.getId == id)
-//                case "tok_is_after_group" => checkAvail(); doIsAfter((tok, 
grpId) => tok.getGroups.contains(grpId))
-//                case "tok_is_after_parent" => checkAvail(); doIsAfter((tok, 
id) => tok.getParentId == id)
-//                case "tok_is_between_ids" => checkAvail(); doIsBetween((tok, 
id) => tok.getId == id)
-//                case "tok_is_between_groups" => checkAvail(); 
doIsBetween((tok, grpId) => tok.getGroups.contains(grpId))
-//                case "tok_is_between_parents" => checkAvail(); 
doIsBetween((tok, id) => tok.getParentId == id)
+//                case "tok_is_before_id" => checkAvail(); doIsBefore((tok, 
id) => ent.getId == id)
+//                case "tok_is_before_group" => checkAvail(); doIsBefore((tok, 
grpId) => ent.getGroups.contains(grpId))
+//                case "tok_is_before_parent" => checkAvail(); 
doIsBefore((tok, id) => ent.getParentId == id)
+//                case "tok_is_after_id" => checkAvail(); doIsAfter((tok, id) 
=> ent.getId == id)
+//                case "tok_is_after_group" => checkAvail(); doIsAfter((tok, 
grpId) => ent.getGroups.contains(grpId))
+//                case "tok_is_after_parent" => checkAvail(); doIsAfter((tok, 
id) => ent.getParentId == id)
+//                case "tok_is_between_ids" => checkAvail(); doIsBetween((tok, 
id) => ent.getId == id)
+//                case "tok_is_between_groups" => checkAvail(); 
doIsBetween((tok, grpId) => ent.getGroups.contains(grpId))
+//                case "tok_is_between_parents" => checkAvail(); 
doIsBetween((tok, id) => ent.getParentId == id)
 //
 //                case "tok_is_abstract" => arg1Tok() match { case x => 
stack.push(() => { Z(toToken(x().value).isAbstract, 1) }) }
 //                case "tok_is_bracketed" => arg1Tok() match { case x => 
stack.push(() => { Z(toToken(x().value).isBracketed, 1) }) }
@@ -1147,7 +953,6 @@ trait NCIDLCodeGenerator:
 //                case "tok_is_wordnet" => arg1Tok() match { case x => 
stack.push(() => { Z(toToken(x().value).isWordnet, 1) }) }
 //                case "tok_ancestors" => arg1Tok() match { case x => 
stack.push(() => { Z(toToken(x().value).getAncestors, 1) }) }
 //                case "tok_parent" => arg1Tok() match { case x => 
stack.push(() => { Z(toToken(x().value).getParentId, 1) }) }
-//                case "tok_groups" => arg1Tok() match { case x => 
stack.push(() => { Z(toToken(x().value).getGroups, 1) }) }
 //                case "tok_value" => arg1Tok() match { case x => 
stack.push(() => { Z(toToken(x().value).getValue, 1) }) }
 //                case "tok_aliases" => arg1Tok() match { case x => 
stack.push(() => { Z(box(toToken(x().value).getAliases), 1) }) }
 //                case "tok_start_idx" => arg1Tok() match { case x => 
stack.push(() => { Z(toToken(x().value).getStartCharIndex, 1) }) }
@@ -1157,36 +962,12 @@ trait NCIDLCodeGenerator:
 //                case "tok_find_part" => doFindPart()
 //                case "tok_find_parts" => doFindParts()
 //
-//                case "tok_count" => checkAvail(); z0(() => 
Z(idlCtx.ents.size, 0))
-//                case "tok_all" => checkAvail(); z0(() => 
Z(idlCtx.ents.asJava, 0))
-//                case "tok_all_for_id" => checkAvail(); doForAll((tok, id) => 
tok.getId == id)
-//                case "tok_all_for_parent" => checkAvail(); doForAll((tok, 
id) => tok.getParentId == id)
-//                case "tok_all_for_group" => checkAvail(); doForAll((tok, 
grp) => tok.getGroups.contains(grp))
 
                 // Request data.
-                case "req_id" => z0(() => Z(idlCtx.req.getServerRequestId, 0))
-                case "req_normtext" => z0(() => 
Z(idlCtx.req.getNormalizedText, 0))
+                case "req_id" => z0(() => Z(idlCtx.req.getRequestId, 0))
+                case "req_text" => z0(() => Z(idlCtx.req.getText, 0))
                 case "req_tstamp" => z0(() => 
Z(idlCtx.req.getReceiveTimestamp, 0))
-                case "req_addr" => z0(() => 
Z(idlCtx.req.getRemoteAddress.orElse(null), 0))
-                case "req_agent" => z0(() => 
Z(idlCtx.req.getClientAgent.orElse(null), 0))
-
-                // User data.
-                case "user_id" => z0(() => Z(idlCtx.req.getUser.getId, 0))
-                case "user_fname" => z0(() => 
Z(idlCtx.req.getUser.getFirstName.orElse(null), 0))
-                case "user_lname" => z0(() => 
Z(idlCtx.req.getUser.getLastName.orElse(null), 0))
-                case "user_email" => z0(() => 
Z(idlCtx.req.getUser.getEmail.orElse(null), 0))
-                case "user_admin" => z0(() => Z(idlCtx.req.getUser.isAdmin, 0))
-                case "user_signup_tstamp" => z0(() => 
Z(idlCtx.req.getUser.getSignupTimestamp, 0))
-
-                // Company data.
-                case "comp_id" => z0(() => Z(idlCtx.req.getCompany.getId, 0))
-                case "comp_name" => z0(() => Z(idlCtx.req.getCompany.getName, 
0))
-                case "comp_website" => z0(() => 
Z(idlCtx.req.getCompany.getWebsite.orElse(null), 0))
-                case "comp_country" => z0(() => 
Z(idlCtx.req.getCompany.getCountry.orElse(null), 0))
-                case "comp_region" => z0(() => 
Z(idlCtx.req.getCompany.getRegion.orElse(null), 0))
-                case "comp_city" => z0(() => 
Z(idlCtx.req.getCompany.getCity.orElse(null), 0))
-                case "comp_addr" => z0(() => 
Z(idlCtx.req.getCompany.getAddress.orElse(null), 0))
-                case "comp_postcode" => z0(() => 
Z(idlCtx.req.getCompany.getPostalCode.orElse(null), 0))
+                case "user_id" => z0(() => Z(idlCtx.req.getUserId, 0))
 
                 // String functions.
                 case "trim" | "strip" => z[ST](arg1, { x => val Z(v, f) = x(); 
Z(toStr(v).trim, f) })
@@ -1288,10 +1069,8 @@ trait NCIDLCodeGenerator:
                 case "now" => z0(() => Z(NCUtils.now(), 0)) // Epoc time.
 
                 case _ => throw rtUnknownFunError(fun) // Assertion.
-            }
-        catch {
+
+        catch
             case e: NCException => throw e // Rethrow.
             case e: Exception => throw rtFunError(fun, e)
-        }
-    }
 
diff --git 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/compiler/antlr4/NCIDL.g4
 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/compiler/antlr4/NCIDL.g4
index 090a338..e697ef4 100644
--- 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/compiler/antlr4/NCIDL.g4
+++ 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/compiler/antlr4/NCIDL.g4
@@ -149,6 +149,9 @@ FUN_NAME
     | 'ent_text'
     | 'ent_groups'
     | 'ent_count'
+    | 'ent_all'
+    | 'ent_all_for_id'
+    | 'ent_all_for_group'
     | 'req_id'
     | 'req_text'
     | 'req_tstamp'
diff --git a/pom.xml b/pom.xml
index ca9e879..34be601 100644
--- a/pom.xml
+++ b/pom.xml
@@ -102,6 +102,7 @@
         <commons.io.ver>2.11.0</commons.io.ver>
         <commons.lang3.ver>3.12.0</commons.lang3.ver>
         <commons.codec.ver>1.15</commons.codec.ver>
+        <commons.collections.ver>4.4</commons.collections.ver>
         <scala3.ref.ver>1.1.1</scala3.ref.ver>
         <junit.ver>5.8.2</junit.ver>
         <scalatest.ver>3.2.9</scalatest.ver>
@@ -180,6 +181,12 @@
             </dependency>
 
             <dependency>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-collections4</artifactId>
+                <version>${commons.collections.ver}</version>
+            </dependency>
+
+            <dependency>
                 <groupId>com.fasterxml.jackson.dataformat</groupId>
                 <artifactId>jackson-dataformat-yaml</artifactId>
                 <version>${jackson.ver}</version>

Reply via email to