WIP.
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlContext.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlContext.scala
index 1d09238..32fa895 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlContext.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlContext.scala
@@ -19,6 +19,9 @@
import org.apache.nlpcraft.common.ScalaMeta
import org.apache.nlpcraft.model.NCRequest
+import org.apache.nlpcraft.model.intent.compiler.NCIdlStackItem
+
+import scala.collection.mutable
/**
*
@@ -26,11 +29,13 @@
* @param convMeta Conversation metadata.
* @param fragMeta Optional fragment (argument) metadata passed during intent fragment reference.
* @param req Server request holder.
+ * @param vars Variable storage.
*/
case class NCIdlContext(
intentMeta: ScalaMeta = Map.empty[String, Object],
convMeta: ScalaMeta = Map.empty[String, Object],
fragMeta: ScalaMeta = Map.empty[String, Object],
- req: NCRequest
+ req: NCRequest,
+ vars: mutable.Map[String, NCIdlStackItem]
)
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlTokenPredicate.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlFunction.scala
similarity index 86%
rename from nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlTokenPredicate.scala
rename to nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlFunction.scala
index d585a8a..a876960 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlTokenPredicate.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlFunction.scala
@@ -22,4 +22,4 @@
/**
*
*/
-trait NCIdlTokenPredicate extends ((NCToken, NCIdlContext) ⇒ (Boolean /* Predicate. */ , Int /* How many times a token was used. */ ))
+trait NCIdlFunction[T] extends ((NCToken, NCIdlContext) ⇒ (T , Int /* How many times a token was used. */ ))
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlSynonym.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlSynonym.scala
index 4abe52a..c092801 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlSynonym.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlSynonym.scala
@@ -17,8 +17,6 @@
package org.apache.nlpcraft.model.intent
-import org.apache.nlpcraft.model.NCToken
-
/**
* DSl synonym.
*
@@ -28,7 +26,7 @@
case class NCIdlSynonym(
origin: String,
alias: Option[String],
- pred: NCIdlTokenPredicate,
+ pred: NCIdlFunction[Boolean],
) {
require(origin != null)
require(pred != null)
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlTerm.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlTerm.scala
index 5e24e8c..8d33c1a 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlTerm.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/NCIdlTerm.scala
@@ -24,7 +24,8 @@
*
* @param idl
* @param id Optional ID of this term.
- * @param pred
+ * @param decls Term optional declarations.
+ * @param pred Term predicate.
* @param min
* @param max
* @param conv
@@ -33,7 +34,8 @@
case class NCIdlTerm(
idl: String,
id: Option[String],
- pred: NCIdlTokenPredicate,
+ decls: List[NCIdlFunction[Object]],
+ pred: NCIdlFunction[Boolean],
min: Int,
max: Int,
conv: Boolean,
@@ -51,6 +53,7 @@
NCIdlTerm(
idl,
id,
+ decls,
pred,
min,
max,
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/compiler/NCIdlCompiler.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/compiler/NCIdlCompiler.scala
index a49a71c..356288f 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/compiler/NCIdlCompiler.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/compiler/NCIdlCompiler.scala
@@ -22,10 +22,10 @@
import org.antlr.v4.runtime._
import org.antlr.v4.runtime.{ParserRuleContext ⇒ PRC}
import org.apache.nlpcraft.common._
-import org.apache.nlpcraft.model.intent.compiler.antlr4.{NCIdlBaseListener, NCIdlLexer, NCIdlParser ⇒ IDP}
+import org.apache.nlpcraft.model.intent.compiler.antlr4.{NCIdlBaseListener, NCIdlLexer, NCIdlParser, NCIdlParser ⇒ IDP}
import org.apache.nlpcraft.model.intent.compiler.{NCIdlCompilerGlobal ⇒ Global}
import org.apache.nlpcraft.model._
-import org.apache.nlpcraft.model.intent.{NCIdlContext, NCIdlIntent, NCIdlSynonym, NCIdlTerm, NCIdlTokenPredicate}
+import org.apache.nlpcraft.model.intent.{NCIdlContext, NCIdlIntent, NCIdlSynonym, NCIdlTerm, NCIdlFunction}
import java.io._
import java.net._
@@ -71,6 +71,7 @@
private val terms = ArrayBuffer.empty[NCIdlTerm]
// Currently term.
+ private var vars = mutable.HashMap.empty[String, NCIdlFunction[Object]]
private var termId: String = _
private var termConv: Boolean = _
private var min = 1
@@ -81,7 +82,7 @@
private var refMtdName: Option[String] = None
// List of instructions for the current expression.
- private var instrs = mutable.Buffer.empty[I]
+ private var expr = mutable.Buffer.empty[I]
/**
@@ -99,14 +100,14 @@
/*
* Shared/common implementation.
*/
- override def exitUnaryExpr(ctx: IDP.UnaryExprContext): Unit = instrs += parseUnaryExpr(ctx.MINUS(), ctx.NOT())(ctx)
- override def exitMultDivModExpr(ctx: IDP.MultDivModExprContext): Unit = instrs += parseMultDivModExpr(ctx.MULT(), ctx.MOD(), ctx.DIV())(ctx)
- override def exitPlusMinusExpr(ctx: IDP.PlusMinusExprContext): Unit = instrs += parsePlusMinusExpr(ctx.PLUS(), ctx.MINUS())(ctx)
- override def exitCompExpr(ctx: IDP.CompExprContext): Unit = instrs += parseCompExpr(ctx.LT(), ctx.GT(), ctx.LTEQ(), ctx.GTEQ())(ctx)
- override def exitAndOrExpr(ctx: IDP.AndOrExprContext): Unit = instrs += parseAndOrExpr(ctx.AND, ctx.OR())(ctx)
- override def exitEqNeqExpr(ctx: IDP.EqNeqExprContext): Unit = instrs += parseEqNeqExpr(ctx.EQ, ctx.NEQ())(ctx)
- override def exitCallExpr(ctx: IDP.CallExprContext): Unit = instrs += parseCallExpr(ctx.FUN_NAME())(ctx)
- override def exitAtom(ctx: IDP.AtomContext): Unit = instrs += parseAtom(ctx.getText)(ctx)
+ override def exitUnaryExpr(ctx: IDP.UnaryExprContext): Unit = expr += parseUnaryExpr(ctx.MINUS(), ctx.NOT())(ctx)
+ override def exitMultDivModExpr(ctx: IDP.MultDivModExprContext): Unit = expr += parseMultDivModExpr(ctx.MULT(), ctx.MOD(), ctx.DIV())(ctx)
+ override def exitPlusMinusExpr(ctx: IDP.PlusMinusExprContext): Unit = expr += parsePlusMinusExpr(ctx.PLUS(), ctx.MINUS())(ctx)
+ override def exitCompExpr(ctx: IDP.CompExprContext): Unit = expr += parseCompExpr(ctx.LT(), ctx.GT(), ctx.LTEQ(), ctx.GTEQ())(ctx)
+ override def exitAndOrExpr(ctx: IDP.AndOrExprContext): Unit = expr += parseAndOrExpr(ctx.AND, ctx.OR())(ctx)
+ override def exitEqNeqExpr(ctx: IDP.EqNeqExprContext): Unit = expr += parseEqNeqExpr(ctx.EQ, ctx.NEQ())(ctx)
+ override def exitCallExpr(ctx: IDP.CallExprContext): Unit = expr += parseCallExpr(ctx.FUN_NAME())(ctx)
+ override def exitAtom(ctx: IDP.AtomContext): Unit = expr += parseAtom(ctx.getText)(ctx)
override def exitTermEq(ctx: IDP.TermEqContext): Unit = termConv = ctx.TILDA() != null
override def exitFragMeta(ctx: IDP.FragMetaContext): Unit = fragMeta = U.jsonToScalaMap(ctx.jsonObj().getText)
override def exitMetaDecl(ctx: IDP.MetaDeclContext): Unit = intentMeta = U.jsonToScalaMap(ctx.jsonObj().getText)
@@ -115,7 +116,7 @@
override def exitAlias(ctx: IDP.AliasContext): Unit = alias = ctx.id().getText
override def enterCallExpr(ctx: IDP.CallExprContext): Unit =
- instrs += ((_, stack: NCIdlStack, _) ⇒ stack.push(stack.PLIST_MARKER))
+ expr += ((_, stack: NCIdlStack, _) ⇒ stack.push(stack.PLIST_MARKER))
/**
*
@@ -127,6 +128,34 @@
this.max = max
}
+ override def exitVarRef(ctx: NCIdlParser.VarRefContext): Unit = {
+
+ }
+
+ override def exitVarDecl(ctx: NCIdlParser.VarDeclContext): Unit = {
+ val varName = ctx.id().getText
+
+ if (vars.contains(varName))
+ throw newSyntaxError(s"Duplicate variable: $varName")(ctx)
+
+ vars += varName
+
+ val fun = exprToFunction[Object]("Variable declaration", _ ⇒ true, x ⇒ x)(ctx)
+
+ val instr = (tok: NCToken, ctx: NCIdlContext) ⇒ {
+ val (res, tokUses) = fun(tok, ctx)
+
+ (null, 0)
+ }
+
+
+
+
+
+
+ expr.clear()
+ }
+
override def exitMinMaxShortcut(ctx: IDP.MinMaxShortcutContext): Unit = {
if (ctx.PLUS() != null)
setMinMax(1, MINMAX_MAX)
@@ -178,9 +207,9 @@
override def exitSynonym(ctx: IDP.SynonymContext): Unit = {
implicit val evidence: PRC = ctx
- val pred = instrToPredicate("Synonym")
+ val pred = exprToFunction("Synonym", isBool, asBool)
val capture = alias
- val wrapper: NCIdlTokenPredicate = (tok: NCToken, ctx: NCIdlContext) ⇒ {
+ val wrapper: NCIdlFunction[Boolean] = (tok: NCToken, ctx: NCIdlContext) ⇒ {
val (res, tokUses) = pred(tok, ctx)
// Store predicate's alias, if any, in token metadata if this token satisfies this predicate.
@@ -202,7 +231,7 @@
synonym = NCIdlSynonym(origin, Option(alias), wrapper)
alias = null
- instrs.clear()
+ expr.clear()
}
override def exitFragId(ctx: IDP.FragIdContext): Unit = {
@@ -254,7 +283,7 @@
if (max < 1)
throw newSyntaxError(s"Invalid intent term max quantifiers: $max (must be max >= 1).")(ctx.minMax())
- val pred: NCIdlTokenPredicate = if (refMtdName.isDefined) { // User-code defined term.
+ val pred: NCIdlFunction[Boolean] = if (refMtdName.isDefined) { // User-code defined term.
// Closure copies.
val clsName = refClsName.orNull
val mtdName = refMtdName.orNull
@@ -289,7 +318,7 @@
}
}
else // IDL term.
- instrToPredicate("Intent term")(ctx.expr())
+ exprToFunction("Intent term", isBool, asBool)(ctx.expr())
// Add term.
terms += NCIdlTerm(
@@ -304,7 +333,8 @@
// Reset term vars.
setMinMax(1, 1)
termId = null
- instrs.clear()
+ expr.clear()
+ vars.clear()
refClsName = None
refMtdName = None
}
@@ -312,12 +342,23 @@
/**
*
* @param subj
+ * @param check
+ * @param cast
+ * @param ctx
+ * @tparam T
* @return
*/
- private def instrToPredicate(subj: String)(implicit ctx: PRC): NCIdlTokenPredicate = {
+ private def exprToFunction[T](
+ subj: String,
+ check: Object ⇒ Boolean,
+ cast: Object ⇒ T
+ )
+ (
+ implicit ctx: PRC
+ ): NCIdlFunction[T] = {
val code = mutable.Buffer.empty[I]
- code ++= instrs
+ code ++= expr
(tok: NCToken, termCtx: NCIdlContext) ⇒ {
val stack = new S()
@@ -329,10 +370,10 @@
val x = stack.pop()()
val v = x.value
- if (!isBool(v))
- throw newRuntimeError(s"$subj did not return boolean value: ${ctx.getText}")
+ if (!check(v))
+ throw newRuntimeError(s"$subj returned value of unexpected type '$v' in: ${ctx.getText}")
- (asBool(v), x.tokUse)
+ (cast(v), x.tokUse)
}
}
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/solver/NCIntentSolverEngine.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/solver/NCIntentSolverEngine.scala
index 99f8576..6cd92b5 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/solver/NCIntentSolverEngine.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/solver/NCIntentSolverEngine.scala
@@ -26,6 +26,7 @@
import org.apache.nlpcraft.model.{NCContext, NCDialogFlowItem, NCIntentMatch, NCResult, NCToken}
import org.apache.nlpcraft.probe.mgrs.dialogflow.NCDialogFlowManager
import org.apache.nlpcraft.model.impl.NCTokenPimp._
+import org.apache.nlpcraft.model.intent.compiler.NCIdlStackItem
import org.apache.nlpcraft.model.intent.{NCIdlContext, NCIdlIntent, NCIdlTerm}
import java.util.function.Function
@@ -494,7 +495,8 @@
val termCtx = NCIdlContext(
intentMeta = intent.meta,
convMeta = if (x.isEmpty) Map.empty[String, Object] else x.asScala.toMap[String, Object],
- req = ctx.getRequest
+ req = ctx.getRequest,
+ vars = mutable.HashMap.empty[String, NCIdlStackItem]
)
// Check terms.
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/NCProbeSynonymChunk.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/NCProbeSynonymChunk.scala
index cefb16a..ebc1d8e 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/NCProbeSynonymChunk.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/NCProbeSynonymChunk.scala
@@ -17,7 +17,7 @@
package org.apache.nlpcraft.probe.mgrs
-import org.apache.nlpcraft.model.intent.NCIdlTokenPredicate
+import org.apache.nlpcraft.model.intent.NCIdlFunction
import org.apache.nlpcraft.probe.mgrs.NCProbeSynonymChunkKind._
import java.util.regex.Pattern
@@ -39,7 +39,7 @@
wordStem: String = null, // Only for kind == TEXT.
posTag: String = null,
regex: Pattern = null,
- idlPred: NCIdlTokenPredicate = null
+ idlPred: NCIdlFunction = null
) {
require(origText != null)
require(kind != null)