Fix for NLPCRAFT-417 + WIP on NLPCRAFT-384
diff --git a/nlpcraft-examples/cargps/src/main/resources/cargps_model.yaml b/nlpcraft-examples/cargps/src/main/resources/cargps_model.yaml
index d8c6199..357fcf7 100644
--- a/nlpcraft-examples/cargps/src/main/resources/cargps_model.yaml
+++ b/nlpcraft-examples/cargps/src/main/resources/cargps_model.yaml
@@ -65,7 +65,7 @@
   - id: "x:remove-waypoint"
     description: "Remove 'waypoint' action."
     synonyms:
-      - "{skip|remove} {over|*} {last|latest|*} <WAYPOINT>"
+      - "{skip|remove} {over|_} {last|latest|_} <WAYPOINT>"
 
 intents:
   - "import('cargps_intents.idl')"
\ No newline at end of file
diff --git a/nlpcraft-examples/cargps/src/main/resources/samples/cargps_cancel_samples.txt b/nlpcraft-examples/cargps/src/main/resources/samples/cargps_cancel_samples.txt
index 80c6568..c6b132d 100644
--- a/nlpcraft-examples/cargps/src/main/resources/samples/cargps_cancel_samples.txt
+++ b/nlpcraft-examples/cargps/src/main/resources/samples/cargps_cancel_samples.txt
@@ -19,4 +19,10 @@
 # Set of samples (corpus) for automatic unit and regression testing.
 #
 
-Hey truck - stop the navigation!
\ No newline at end of file
+Hey truck - stop the navigation!
+Howdy, car, please cancel the routing now.
+Hi car - stop the route.
+Hi car - stop the navigation...
+Howdy truck - quit navigating.
+Hi car - finish off the driving.
+Hi car - cancel the journey.
\ No newline at end of file
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 95928cd..b643a22 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
@@ -624,8 +624,14 @@
             line: Int, // 1, 2, ...
             charPos: Int, // 1, 2, ...
             msg: String,
-            e: RecognitionException): Unit =
-            throw new NCE(mkSyntaxError(msg, recog.getInputStream.getSourceName, line, charPos - 1, dsl, origin, mdl))
+            e: RecognitionException): Unit = {
+            val aMsg = if ((msg.contains("'\"") && msg.contains("\"'")) || msg.contains("''"))
+                s"${if (msg.last == '.') msg.substring(0, msg.length - 1) else msg} - try removing quotes."
+            else
+                msg
+
+            throw new NCE(mkSyntaxError(aMsg, recog.getInputStream.getSourceName, line, charPos - 1, dsl, origin, mdl))
+        }
     }
 
     /**
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/deploy/NCDeployManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/deploy/NCDeployManager.scala
index 8d89477..122b5dc 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/deploy/NCDeployManager.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/deploy/NCDeployManager.scala
@@ -156,6 +156,16 @@
 
         for (makro <- macros.keys if !set.exists(_.contains(makro)))
             logger.warn(s"Unused macro detected [mdlId=${mdl.getId}, macro=$makro]")
+
+        def isSuspicious(s: String): Boolean = //s.toCharArray.toSeq.intersect(SUSP_SYNS_CHARS).nonEmpty
+            SUSP_SYNS_CHARS.exists(susp => s.contains(susp))
+
+        for (makro <- macros)
+            if (isSuspicious(makro._1) || isSuspicious(makro._2))
+                logger.warn(s"Suspicious macro definition (use of ${SUSP_SYNS_CHARS.map(s => s"'$s'").mkString(", ")} chars) [" +
+                    s"mdlId=${mdl.getId}, " +
+                    s"macro=$makro" +
+                s"]")
     }
 
     /**
@@ -236,7 +246,7 @@
 
             if (susp.nonEmpty)
                 logger.warn(
-                    s"Suspicious synonyms detected [" +
+                    s"Suspicious synonyms detected (use of ${SUSP_SYNS_CHARS.map(s => s"'$s'").mkString(", ")} chars) [" +
                         s"mdlId=$mdlId, " +
                         s"elementId=$elmId, " +
                         s"synonyms=[${susp.mkString(", ")}]" +
@@ -1719,25 +1729,46 @@
                 if (intAnns.isEmpty && refAnns.isEmpty)
                     throw new NCE(s"@NCIntentSample or @NCIntentSampleRef annotations without corresponding @NCIntent or @NCIntentRef annotations: $mtdStr")
                 else {
-                    def read[T](arr: Array[T], annName: String, getValue: T => Seq[String]): Seq[Seq[String]] = {
-                        val seq = arr.toSeq.map(getValue).map(_.map(_.strip).filter(s => s.nonEmpty && s.head != '#'))
+                    /**
+                     *
+                     * @param annArr
+                     * @param annName
+                     * @param getSamples
+                     * @param getSource
+                     * @tparam T
+                     * @return
+                     */
+                    def read[T](
+                        annArr: Array[T],
+                        annName: String,
+                        getSamples: T => Seq[String],
+                        getSource: Option[T => String]): Seq[Seq[String]] = {
+                            for (ann <- annArr.toSeq) yield {
+                                val samples = getSamples(ann).map(_.strip).filter(s => s.nonEmpty && s.head != '#')
 
-                        if (seq.exists(_.isEmpty))
-                            logger.warn(s"$annName annotation has no samples: $mtdStr")
+                                if (samples.isEmpty) {
+                                    getSource match {
+                                        case None => logger.warn(s"$annName annotation has no samples: $mtdStr")
+                                        case Some(f) => logger.warn(s"$annName annotation references '${f(ann)}' file that has no samples: $mtdStr")
+                                    }
 
-                        seq
-                    }
+                                    Seq.empty
+                                }
+                                else
+                                    samples
+                            }
+                    }.filter(_.nonEmpty)
 
                     val seqSeq =
                         read[NCIntentSample](
-                            smpAnns, "@NCIntentSample", _.value().toSeq
+                            smpAnns, "@NCIntentSample", _.value().toSeq, None
                         ) ++
                         read[NCIntentSampleRef](
-                            smpAnnsRef, "@NCIntentSampleRef", a => U.readAnySource(a.value())
+                            smpAnnsRef, "@NCIntentSampleRef", a => U.readAnySource(a.value()), Some(_.value())
                         )
 
                     if (U.containsDups(seqSeq.flatMap(_.toSeq).toList))
-                        logger.warn(s"@NCIntentSample and @NCIntentSampleRef annotations have duplicates (safely ignoring): $mtdStr")
+                        logger.warn(s"@NCIntentSample and @NCIntentSampleRef annotations have duplicates: $mtdStr")
 
                     val distinct = seqSeq.map(_.distinct).distinct