diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 9faf9627..9b0f0538 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -977,6 +977,46 @@ jobs: fi echo "[postfix-index] x[i]++ and x[i]-- change that element" + - name: "@PRE conditions on rule elements (#438) (Non-20.04)" + if: matrix.id != 'docker-ubuntu-20.04' + shell: bash + run: | + set -eo pipefail + # A @PRE condition can be written on the rule element itself (#438): + # _xWILD [plus varz="num"] is varz("num"); in @PRE. + # Each case runs in both forms; their matches must agree. + FIX=.github/workflows/tests/element-pre + rm -rf "$FIX/logs" "$FIX/input/text.txt_log" + mkdir -p "$FIX/logs" + ./bin/nlp -ANA "$FIX" -WORK ./ "$FIX/input/text.txt" + OUT="$FIX/input/text.txt_log/output.txt" + if [ ! -f "$OUT" ]; then + echo "FAIL(element-pre): no output.txt -- the analyzer did not build"; exit 1 + fi + got=$(tr -d '\r' < "$OUT") + want=$(printf '%s\n' \ + 'vareq @PRE: two' \ + 'vareq elt : two' \ + 'varz @PRE: two Three ABC 3' \ + 'varz elt : two Three ABC 3' \ + 'two @PRE: one' \ + 'two elt : one' \ + 'flag @PRE: ABC' \ + 'flag elt : ABC' \ + 'cap @PRE: Three' \ + 'cap @PRE: ABC' \ + 'cap elt : Three' \ + 'cap elt : ABC' \ + 'range @PRE: 9' \ + 'range elt : 9' \ + 'regexp @PRE: two' \ + 'regexp elt : two' \ + 'mixed: one two') + if [ "$got" != "$want" ]; then + echo "FAIL(element-pre): output.txt was:"; echo "$got"; echo "wanted:"; echo "$want"; exit 1 + fi + echo "[element-pre] element-key conditions match like @PRE" + - name: factorial() up to 20! (Non-20.04) if: matrix.id != 'docker-ubuntu-20.04' shell: bash diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index e7082454..48d4f7cf 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -876,6 +876,45 @@ jobs: fi echo "[postfix-index] x[i]++ and x[i]-- change that element" + - name: "@PRE conditions on rule elements (#438)" + shell: bash + run: | + set -eo pipefail + # A @PRE condition can be written on the rule element itself (#438): + # _xWILD [plus varz="num"] is varz("num"); in @PRE. + # Each case runs in both forms; their matches must agree. + FIX=.github/workflows/tests/element-pre + rm -rf "$FIX/logs" "$FIX/input/text.txt_log" + mkdir -p "$FIX/logs" + ./bin/Release/nlp.exe -ANA "$FIX" -WORK ./ "$FIX/input/text.txt" + OUT="$FIX/input/text.txt_log/output.txt" + if [ ! -f "$OUT" ]; then + echo "FAIL(element-pre): no output.txt -- the analyzer did not build"; exit 1 + fi + got=$(tr -d '\r' < "$OUT") + want=$(printf '%s\n' \ + 'vareq @PRE: two' \ + 'vareq elt : two' \ + 'varz @PRE: two Three ABC 3' \ + 'varz elt : two Three ABC 3' \ + 'two @PRE: one' \ + 'two elt : one' \ + 'flag @PRE: ABC' \ + 'flag elt : ABC' \ + 'cap @PRE: Three' \ + 'cap @PRE: ABC' \ + 'cap elt : Three' \ + 'cap elt : ABC' \ + 'range @PRE: 9' \ + 'range elt : 9' \ + 'regexp @PRE: two' \ + 'regexp elt : two' \ + 'mixed: one two') + if [ "$got" != "$want" ]; then + echo "FAIL(element-pre): output.txt was:"; echo "$got"; echo "wanted:"; echo "$want"; exit 1 + fi + echo "[element-pre] element-key conditions match like @PRE" + - name: factorial() up to 20! shell: bash run: | diff --git a/.github/workflows/tests/element-pre/input/text.txt b/.github/workflows/tests/element-pre/input/text.txt new file mode 100644 index 00000000..4b5aa417 --- /dev/null +++ b/.github/workflows/tests/element-pre/input/text.txt @@ -0,0 +1 @@ +one two Three ABC 3 9 diff --git a/.github/workflows/tests/element-pre/spec/analyzer.seq b/.github/workflows/tests/element-pre/spec/analyzer.seq new file mode 100644 index 00000000..caf45530 --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/analyzer.seq @@ -0,0 +1,17 @@ +tokenize nil # +nlp mark # +nlp vareq_pre # +nlp vareq_elt # +nlp varz_pre # +nlp varz_elt # +nlp two_pre # +nlp two_elt # +nlp flag_pre # +nlp flag_elt # +nlp cap_pre # +nlp cap_elt # +nlp range_pre # +nlp range_elt # +nlp regexp_pre # +nlp regexp_elt # +nlp mixed # diff --git a/.github/workflows/tests/element-pre/spec/cap_elt.nlp b/.github/workflows/tests/element-pre/spec/cap_elt.nlp new file mode 100644 index 00000000..22e79fc5 --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/cap_elt.nlp @@ -0,0 +1,14 @@ +############################################### +# FILE: cap_elt.nlp +# SUBJ: cap on an alphabetic element. (element-key form) +# NOTE: Part of the element-pre regression (#438); expected output +# is in the CI step. +############################################### + +@NODES _ROOT + +@POST + "output.txt" << "cap elt : " << phrasetext() << "\n"; + noop(); +@RULES +_xNIL <- _xALPHA [cap] @@ diff --git a/.github/workflows/tests/element-pre/spec/cap_pre.nlp b/.github/workflows/tests/element-pre/spec/cap_pre.nlp new file mode 100644 index 00000000..cc32c3fb --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/cap_pre.nlp @@ -0,0 +1,16 @@ +############################################### +# FILE: cap_pre.nlp +# SUBJ: cap on an alphabetic element. (@PRE form) +# NOTE: Part of the element-pre regression (#438); expected output +# is in the CI step. +############################################### + +@NODES _ROOT + +@PRE +<1,1> cap(); +@POST + "output.txt" << "cap @PRE: " << phrasetext() << "\n"; + noop(); +@RULES +_xNIL <- _xALPHA @@ diff --git a/.github/workflows/tests/element-pre/spec/flag_elt.nlp b/.github/workflows/tests/element-pre/spec/flag_elt.nlp new file mode 100644 index 00000000..2e63c9b7 --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/flag_elt.nlp @@ -0,0 +1,14 @@ +############################################### +# FILE: flag_elt.nlp +# SUBJ: A bare action name with no arguments. (element-key form) +# NOTE: Part of the element-pre regression (#438); expected output +# is in the CI step. +############################################### + +@NODES _ROOT + +@POST + "output.txt" << "flag elt : " << phrasetext() << "\n"; + noop(); +@RULES +_xNIL <- _xALPHA [uppercase] @@ diff --git a/.github/workflows/tests/element-pre/spec/flag_pre.nlp b/.github/workflows/tests/element-pre/spec/flag_pre.nlp new file mode 100644 index 00000000..f0e41a93 --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/flag_pre.nlp @@ -0,0 +1,16 @@ +############################################### +# FILE: flag_pre.nlp +# SUBJ: A bare action name with no arguments. (@PRE form) +# NOTE: Part of the element-pre regression (#438); expected output +# is in the CI step. +############################################### + +@NODES _ROOT + +@PRE +<1,1> uppercase(); +@POST + "output.txt" << "flag @PRE: " << phrasetext() << "\n"; + noop(); +@RULES +_xNIL <- _xALPHA @@ diff --git a/.github/workflows/tests/element-pre/spec/mark.nlp b/.github/workflows/tests/element-pre/spec/mark.nlp new file mode 100644 index 00000000..35b62391 --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/mark.nlp @@ -0,0 +1,20 @@ +############################################### +# FILE: mark.nlp +# SUBJ: Gives "two" pos=noun and "one" num=1. +# NOTE: Part of the element-pre regression (#438); expected output +# is in the CI step. +############################################### + +@NODES _ROOT + +@POST + N("pos",1) = "noun"; + noop(); +@RULES +_xNIL <- two @@ + +@POST + N("num",1) = 1; + noop(); +@RULES +_xNIL <- one @@ diff --git a/.github/workflows/tests/element-pre/spec/mixed.nlp b/.github/workflows/tests/element-pre/spec/mixed.nlp new file mode 100644 index 00000000..b4a1b9a7 --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/mixed.nlp @@ -0,0 +1,16 @@ +############################################### +# FILE: mixed.nlp +# SUBJ: Element keys and a @PRE region in one rule. +# NOTE: Part of the element-pre regression (#438); expected output +# is in the CI step. +############################################### + +@NODES _ROOT + +@PRE +<3,3> var("pos"); +@POST + "output.txt" << "mixed: " << phrasetext() << "\n"; + noop(); +@RULES +_xNIL <- _xALPHA [var="num"] _xWHITE [s] _xALPHA @@ diff --git a/.github/workflows/tests/element-pre/spec/range_elt.nlp b/.github/workflows/tests/element-pre/spec/range_elt.nlp new file mode 100644 index 00000000..aa6c428c --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/range_elt.nlp @@ -0,0 +1,14 @@ +############################################### +# FILE: range_elt.nlp +# SUBJ: numrange on a number. (element-key form) +# NOTE: Part of the element-pre regression (#438); expected output +# is in the CI step. +############################################### + +@NODES _ROOT + +@POST + "output.txt" << "range elt : " << phrasetext() << "\n"; + noop(); +@RULES +_xNIL <- _xNUM [numrange=(5 10)] @@ diff --git a/.github/workflows/tests/element-pre/spec/range_pre.nlp b/.github/workflows/tests/element-pre/spec/range_pre.nlp new file mode 100644 index 00000000..3bd19050 --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/range_pre.nlp @@ -0,0 +1,16 @@ +############################################### +# FILE: range_pre.nlp +# SUBJ: numrange on a number. (@PRE form) +# NOTE: Part of the element-pre regression (#438); expected output +# is in the CI step. +############################################### + +@NODES _ROOT + +@PRE +<1,1> numrange(5, 10); +@POST + "output.txt" << "range @PRE: " << phrasetext() << "\n"; + noop(); +@RULES +_xNIL <- _xNUM @@ diff --git a/.github/workflows/tests/element-pre/spec/regexp_elt.nlp b/.github/workflows/tests/element-pre/spec/regexp_elt.nlp new file mode 100644 index 00000000..b800aa1b --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/regexp_elt.nlp @@ -0,0 +1,14 @@ +############################################### +# FILE: regexp_elt.nlp +# SUBJ: regexp (a glob match) on an alphabetic element. (element-key form) +# NOTE: Part of the element-pre regression (#438); expected output +# is in the CI step. +############################################### + +@NODES _ROOT + +@POST + "output.txt" << "regexp elt : " << phrasetext() << "\n"; + noop(); +@RULES +_xNIL <- _xALPHA [regexp="t*"] @@ diff --git a/.github/workflows/tests/element-pre/spec/regexp_pre.nlp b/.github/workflows/tests/element-pre/spec/regexp_pre.nlp new file mode 100644 index 00000000..5cac3001 --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/regexp_pre.nlp @@ -0,0 +1,16 @@ +############################################### +# FILE: regexp_pre.nlp +# SUBJ: regexp (a glob match) on an alphabetic element. (@PRE form) +# NOTE: Part of the element-pre regression (#438); expected output +# is in the CI step. +############################################### + +@NODES _ROOT + +@PRE +<1,1> regexp("t*"); +@POST + "output.txt" << "regexp @PRE: " << phrasetext() << "\n"; + noop(); +@RULES +_xNIL <- _xALPHA @@ diff --git a/.github/workflows/tests/element-pre/spec/two_elt.nlp b/.github/workflows/tests/element-pre/spec/two_elt.nlp new file mode 100644 index 00000000..3499db32 --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/two_elt.nlp @@ -0,0 +1,14 @@ +############################################### +# FILE: two_elt.nlp +# SUBJ: Two conditions on one element. (element-key form) +# NOTE: Part of the element-pre regression (#438); expected output +# is in the CI step. +############################################### + +@NODES _ROOT + +@POST + "output.txt" << "two elt : " << phrasetext() << "\n"; + noop(); +@RULES +_xNIL <- _xALPHA [var="num" varne=("pos" "noun")] @@ diff --git a/.github/workflows/tests/element-pre/spec/two_pre.nlp b/.github/workflows/tests/element-pre/spec/two_pre.nlp new file mode 100644 index 00000000..3022cd92 --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/two_pre.nlp @@ -0,0 +1,17 @@ +############################################### +# FILE: two_pre.nlp +# SUBJ: Two conditions on one element. (@PRE form) +# NOTE: Part of the element-pre regression (#438); expected output +# is in the CI step. +############################################### + +@NODES _ROOT + +@PRE +<1,1> var("num"); +<1,1> varne("pos", "noun"); +@POST + "output.txt" << "two @PRE: " << phrasetext() << "\n"; + noop(); +@RULES +_xNIL <- _xALPHA @@ diff --git a/.github/workflows/tests/element-pre/spec/vareq_elt.nlp b/.github/workflows/tests/element-pre/spec/vareq_elt.nlp new file mode 100644 index 00000000..cade4105 --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/vareq_elt.nlp @@ -0,0 +1,14 @@ +############################################### +# FILE: vareq_elt.nlp +# SUBJ: vareq on an alphabetic element. (element-key form) +# NOTE: Part of the element-pre regression (#438); expected output +# is in the CI step. +############################################### + +@NODES _ROOT + +@POST + "output.txt" << "vareq elt : " << phrasetext() << "\n"; + noop(); +@RULES +_xNIL <- _xALPHA [vareq=("pos" "noun")] @@ diff --git a/.github/workflows/tests/element-pre/spec/vareq_pre.nlp b/.github/workflows/tests/element-pre/spec/vareq_pre.nlp new file mode 100644 index 00000000..492a3c2c --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/vareq_pre.nlp @@ -0,0 +1,16 @@ +############################################### +# FILE: vareq_pre.nlp +# SUBJ: vareq on an alphabetic element. (@PRE form) +# NOTE: Part of the element-pre regression (#438); expected output +# is in the CI step. +############################################### + +@NODES _ROOT + +@PRE +<1,1> vareq("pos", "noun"); +@POST + "output.txt" << "vareq @PRE: " << phrasetext() << "\n"; + noop(); +@RULES +_xNIL <- _xALPHA @@ diff --git a/.github/workflows/tests/element-pre/spec/varz_elt.nlp b/.github/workflows/tests/element-pre/spec/varz_elt.nlp new file mode 100644 index 00000000..6c846806 --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/varz_elt.nlp @@ -0,0 +1,14 @@ +############################################### +# FILE: varz_elt.nlp +# SUBJ: varz on a wildcard between two words (#449 behaviour). (element-key form) +# NOTE: Part of the element-pre regression (#438); expected output +# is in the CI step. +############################################### + +@NODES _ROOT + +@POST + "output.txt" << "varz elt : " << phrasetext() << "\n"; + noop(); +@RULES +_xNIL <- two _xWILD [plus varz="num"] 3 @@ diff --git a/.github/workflows/tests/element-pre/spec/varz_pre.nlp b/.github/workflows/tests/element-pre/spec/varz_pre.nlp new file mode 100644 index 00000000..8441d695 --- /dev/null +++ b/.github/workflows/tests/element-pre/spec/varz_pre.nlp @@ -0,0 +1,16 @@ +############################################### +# FILE: varz_pre.nlp +# SUBJ: varz on a wildcard between two words (#449 behaviour). (@PRE form) +# NOTE: Part of the element-pre regression (#438); expected output +# is in the CI step. +############################################### + +@NODES _ROOT + +@PRE +<2,2> varz("num"); +@POST + "output.txt" << "varz @PRE: " << phrasetext() << "\n"; + noop(); +@RULES +_xNIL <- two _xWILD [plus] 3 @@ diff --git a/lite/ielt.cpp b/lite/ielt.cpp index 6c920dce..e3e03a76 100644 --- a/lite/ielt.cpp +++ b/lite/ielt.cpp @@ -1343,6 +1343,37 @@ for (dpair = list->getFirst(); dpair; dpair = dpair->Right()) } elt->setDeaccent(true); // 01/28/05 AM. } + else if (preActionKey(key)) + { + // A @PRE condition written on the element itself (#438): + // _xWILD [plus match=(_noun) vareq=("pos" "noun") varz="num"] + // is the same as vareq("pos","noun"); varz("num"); + // in a @PRE region, where n is this element's number. + _TCHAR *name = 0; + parse->internStr(key, /*UP*/ name); + Dlist *args = vals ? Iarg::copy_args(vals, parse, true) : 0; + // Element values are strings; the actions that take numbers get + // numbers, as they do from a @PRE region (the compiled form needs it). + if (args && (!strcmp_i(key, _T("numrange")) + || !strcmp_i(key, _T("length")) + || !strcmp_i(key, _T("lengthr")))) + { + for (Delt *darg = args->getFirst(); darg; darg = darg->Right()) + { + Iarg *arg = darg->getData(); + long long num = 0; + if (arg->getType() == IASTR && str_to_long(arg->getStr(), num)) + { + Iarg *narg = new Iarg(num); + darg->setData(narg); + delete arg; + } + } + } + if (!elt->pres_) + elt->pres_ = new Dlist(); + elt->pres_->rpush(new Ipre(name, args, ord, ord)); + } else { std::_t_strstream gerrStr; @@ -1391,6 +1422,27 @@ else if (elt->max_ == -1) } +/******************************************** +* FN: PREACTIONKEY +* SUBJ: Whether an element key names a @PRE action (#438). +* NOTE: The actions Pat::preAction knows. None is also an element key. +********************************************/ + +bool Ielt::preActionKey(_TCHAR *key) +{ +static const _TCHAR *names[] = { + _T("var"), _T("varz"), _T("vareq"), _T("varne"), _T("vargt"), _T("varlt"), + _T("regexp"), _T("regexpi"), _T("uppercase"), _T("lowercase"), _T("cap"), + _T("length"), _T("lengthr"), _T("numrange"), _T("unknown"), _T("debug"), + 0 + }; +for (const _TCHAR **p = names; *p; ++p) + if (key && !strcmp_i(key, (_TCHAR *) *p)) + return true; +return false; +} + + /******************************************** * FN: INTERNPRES * CR: 07/13/99 AM. diff --git a/lite/ielt.h b/lite/ielt.h index a40fc344..6b04ee47 100644 --- a/lite/ielt.h +++ b/lite/ielt.h @@ -130,6 +130,7 @@ class Ielt : public Ielement Parse*, // 08/23/02 AM. /*UP*/ bool &info, bool &f_look, bool fhash = true); + static bool preActionKey(_TCHAR *key); // #438. void internPres( // 07/13/99 AM. Dlist *pres, // For binding pre actions. int ord // Current element number in rule's phrase. diff --git a/nlp/main.cpp b/nlp/main.cpp index 0b015e40..75f47062 100644 --- a/nlp/main.cpp +++ b/nlp/main.cpp @@ -15,7 +15,7 @@ All rights reserved. #include "lite/nlp_engine.h" #include "version.h" -#define NLP_ENGINE_VERSION "4.2.25" +#define NLP_ENGINE_VERSION "4.2.26" bool cmdReadArgs(int, _TCHAR *argv[], _TCHAR *&, _TCHAR *&, _TCHAR *&, _TCHAR *&, bool &, bool &, bool &, bool &, bool &, bool &, int &, bool &); void cmdHelpargs(_TCHAR *);