Grammalecte  Check-in [fb8de11c89]

Overview
Comment:[core][fr] tests suggestions for JS, suggestions update
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk | fr | core
Files: files | file ages | folders
SHA3-256: fb8de11c89bac99c911f9fa9836a2fa9cf37280f24d01f1e692e91776a03c0fa
User & Date: olr on 2021-01-21 18:04:41
Other Links: manifest | tags
Context
2021-01-21
21:12
[build] nnbsp in py2js() also check-in: b217bc2731 user: olr tags: trunk, build
18:04
[core][fr] tests suggestions for JS, suggestions update check-in: fb8de11c89 user: olr tags: trunk, fr, core
10:30
[fr] ajustements (tests) check-in: 8e7a1e20da user: olr tags: trunk, fr
Changes

Modified gc_core/js/tests.js from [5a6c382af8] to [9717be7ff0].

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36



37
38

39
40
41
42
43
44
45
        this.spfTests = spfTests;
        this._aRuleTested = new Set();
    }

    * testParse (bDebug=false) {
        const t0 = Date.now();
        let sURL;
        if(typeof(process) !== 'undefined') {
            sURL = (this.spfTests !== "") ? this.spfTests : "./"+this.gce.lang+"/tests_data.json";
        } else {
            sURL = (this.spfTests !== "") ? this.spfTests : "resource://grammalecte/"+this.gce.lang+"/tests_data.json";
        }
        const aData = JSON.parse(helpers.loadFile(sURL)).aData;
        let nInvalid = 0;
        let nTotal = 0;
        let sErrorText;
        let sSugg;
        let sExpectedErrors;



        let sTextToCheck;
        let sFoundErrors;

        let sListErr;
        let sLineNum;
        let i = 1;
        let sUntestedRules = "";
        let bShowUntested = false;
        let zOption = /^__([a-zA-Z0-9]+)__ /;
        let sOption;







|








|

>
>
>


>







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
        this.spfTests = spfTests;
        this._aRuleTested = new Set();
    }

    * testParse (bDebug=false) {
        const t0 = Date.now();
        let sURL;
        if (typeof(process) !== 'undefined') {
            sURL = (this.spfTests !== "") ? this.spfTests : "./"+this.gce.lang+"/tests_data.json";
        } else {
            sURL = (this.spfTests !== "") ? this.spfTests : "resource://grammalecte/"+this.gce.lang+"/tests_data.json";
        }
        const aData = JSON.parse(helpers.loadFile(sURL)).aData;
        let nInvalid = 0;
        let nTotal = 0;
        let sErrorText;
        let sExpectedSuggs;
        let sExpectedErrors;
        let nTestWithExpectedError = 0;
        let nTestWithExpectedErrorAndSugg = 0;
        let nUnexpectedErrors = 0;
        let sTextToCheck;
        let sFoundErrors;
        let sFoundSuggs;
        let sListErr;
        let sLineNum;
        let i = 1;
        let sUntestedRules = "";
        let bShowUntested = false;
        let zOption = /^__([a-zA-Z0-9]+)__ /;
        let sOption;
53
54
55
56
57
58
59
60
61
62
63
64

65
66



67
68
69
70
71
72
73
74
75
76
77










78
79
80
81
82
83
84














85









































86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
                    sOption = false;
                    m = zOption.exec(sLine);
                    if (m) {
                        sLine = sLine.slice(sLine.indexOf(" ")+1);
                        sOption = m[1];
                    }
                    if (sLine.includes("->>")) {
                        [sErrorText, sSugg] = sLine.split("->>");
                        sErrorText = sErrorText.trim();
                        sSugg = sSugg.trim();
                    } else {
                        sErrorText = sLine.trim();

                    }
                    sExpectedErrors = this._getExpectedErrors(sErrorText);



                    sTextToCheck = sErrorText.replace(/\{\{/g, "").replace(/\}\}/g, "");
                    [sFoundErrors, sListErr] = this._getFoundErrors(sTextToCheck, bDebug, sOption);
                    if (sExpectedErrors !== sFoundErrors) {
                        yield "\n" + i.toString() +
                              "\n# Line num: " + sLineNum +
                              "\n> to check: " + sTextToCheck +
                              "\n  expected: " + sExpectedErrors +
                              "\n  found:    " + sFoundErrors +
                              "\n  errors:   \n" + sListErr;
                        nInvalid = nInvalid + 1;
                    }










                    nTotal = nTotal + 1;
                }
                i = i + 1;
                if (i % 1000 === 0) {
                    yield i.toString();
                }
            }














            bShowUntested = true;









































        }
        catch (e) {
            console.error(e);
        }

        if (bShowUntested) {
            i = 0;
            for (let [sOpt, sLineId, sRuleId] of this.gce.listRules()) {
                if (sOpt !== "@@@@" && !this._aRuleTested.has(sLineId) && !/^[0-9]+[sp]$|^[pd]_/.test(sRuleId)) {
                    sUntestedRules += sLineId + "/" + sRuleId + ", ";
                    i += 1;
                }
            }
            if (i > 0) {
                yield sUntestedRules + "\n[" + i.toString() + " untested rules]";
            }
        }

        const t1 = Date.now();
        yield "Tests parse finished in " + ((t1-t0)/1000).toString()
            + " s\nTotal errors: " + nInvalid.toString() + " / " + nTotal.toString();
    }

    _getExpectedErrors (sLine) {
        try {
            let sRes = " ".repeat(sLine.length);
            let z = /\{\{.+?\}\}/g;
            let m;







|
<
|


>


>
>
>

|









>
>
>
>
>
>
>
>
>
>







>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







57
58
59
60
61
62
63
64

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
















163
164
165
166
167
168
169
                    sOption = false;
                    m = zOption.exec(sLine);
                    if (m) {
                        sLine = sLine.slice(sLine.indexOf(" ")+1);
                        sOption = m[1];
                    }
                    if (sLine.includes("->>")) {
                        [sErrorText, sExpectedSuggs] = this._splitTestLine(sLine);

                        nTestWithExpectedErrorAndSugg += 1
                    } else {
                        sErrorText = sLine.trim();
                        sExpectedSuggs = "";
                    }
                    sExpectedErrors = this._getExpectedErrors(sErrorText);
                    if (sExpectedErrors.trim() != "") {
                        nTestWithExpectedError += 1;
                    }
                    sTextToCheck = sErrorText.replace(/\{\{/g, "").replace(/\}\}/g, "");
                    [sFoundErrors, sListErr, sFoundSuggs] = this._getFoundErrors(sTextToCheck, bDebug, sOption);
                    if (sExpectedErrors !== sFoundErrors) {
                        yield "\n" + i.toString() +
                              "\n# Line num: " + sLineNum +
                              "\n> to check: " + sTextToCheck +
                              "\n  expected: " + sExpectedErrors +
                              "\n  found:    " + sFoundErrors +
                              "\n  errors:   \n" + sListErr;
                        nInvalid = nInvalid + 1;
                    }
                    else if (sExpectedSuggs) {
                        if (!this._checkSuggestions(sExpectedSuggs, sFoundSuggs)) {
                            yield  "\n# Line num: " + sLineNum +
                                   "\n> to check: " + sTextToCheck +
                                   "\n  expected: " + sExpectedSuggs +
                                   "\n  found:    " + sFoundSuggs +
                                   "\n  errors:   \n" + sListErr;
                            nUnexpectedErrors += 1;
                        }
                    }
                    nTotal = nTotal + 1;
                }
                i = i + 1;
                if (i % 1000 === 0) {
                    yield i.toString();
                }
            }
            yield "Tests with expected errors: " + nTestWithExpectedError + " and suggestions: " + nTestWithExpectedErrorAndSugg + " > " + nTestWithExpectedErrorAndSugg/nTestWithExpectedError*100 + " %";
            if (nUnexpectedErrors) {
                yield "Unexpected errors: " + nUnexpectedErrors;
            }
            yield* this._showUntestedRules()
        }
        catch (e) {
            console.error(e);
        }
        const t1 = Date.now();
        yield "Tests parse finished in " + ((t1-t0)/1000).toString()
            + " s\nTotal errors: " + nInvalid.toString() + " / " + nTotal.toString();
    }

    * _showUntestedRules () {
        let i = 0;
        for (let [sOpt, sLineId, sRuleId] of this.gce.listRules()) {
            if (sOpt !== "@@@@" && !this._aRuleTested.has(sLineId) && !/^[0-9]+[sp]$|^[pd]_/.test(sRuleId)) {
                sUntestedRules += sLineId + "/" + sRuleId + ", ";
                i += 1;
            }
        }
        if (i > 0) {
            yield sUntestedRules + "\n[" + i.toString() + " untested rules]";
        }
    }

    _splitTestLine (sLine) {
        let [sText, sSugg] = sLine.split("->>");
        sSugg = sSugg.trim().replace(/ /g, " ");
        if (sSugg.startsWith('"') && sSugg.endsWith('"')) {
            sSugg = sSugg.slice(1,-1);
        }
        return [sText.trim(), sSugg];
    }

    _getFoundErrors (sLine, bDebug, sOption) {
        try {
            let aErrs = [];
            if (sOption) {
                this.gce.setOption(sOption, true);
                aErrs = this.gce.parse(sLine, "FR", bDebug);
                this.gce.setOption(sOption, false);
            } else {
                aErrs = this.gce.parse(sLine, "FR", bDebug);
            }
            let sRes = " ".repeat(sLine.length);
            let sListErr = "";
            let lAllSugg = [];
            for (let oErr of aErrs.sort( (a,b) => a["nStart"] - b["nStart"] )) {
                sRes = sRes.slice(0, oErr["nStart"]) + "~".repeat(oErr["nEnd"] - oErr["nStart"]) + sRes.slice(oErr["nEnd"]);
                sListErr += "    * {" + oErr['sLineId'] + " / " + oErr['sRuleId'] + "}  at  " + oErr['nStart'] + ":" + oErr['nEnd'] + "\n";
                lAllSugg.push(oErr["aSuggestions"].join("|"));
                this._aRuleTested.add(oErr["sLineId"]);
            }
            return [sRes, sListErr, lAllSugg.join("|||")];
        }
        catch (e) {
            console.error(e);
        }
        return [" ".repeat(sLine.length), "", ""];
















    }

    _getExpectedErrors (sLine) {
        try {
            let sRes = " ".repeat(sLine.length);
            let z = /\{\{.+?\}\}/g;
            let m;
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

152
153
154
155
156
157
158
159
160
161
162
163
164
165
        }
        catch (e) {
            console.error(e);
        }
        return " ".repeat(sLine.length);
    }

    _getFoundErrors (sLine, bDebug, sOption) {
        try {
            let aErrs = [];
            if (sOption) {
                this.gce.setOption(sOption, true);
                aErrs = this.gce.parse(sLine, "FR", bDebug);
                this.gce.setOption(sOption, false);
            } else {
                aErrs = this.gce.parse(sLine, "FR", bDebug);
            }
            let sRes = " ".repeat(sLine.length);
            let sListErr = "";
            for (let dErr of aErrs) {
                sRes = sRes.slice(0, dErr["nStart"]) + "~".repeat(dErr["nEnd"] - dErr["nStart"]) + sRes.slice(dErr["nEnd"]);
                sListErr += "    * {" + dErr['sLineId'] + " / " + dErr['sRuleId'] + "}  at  " + dErr['nStart'] + ":" + dErr['nEnd'] + "\n";
                this._aRuleTested.add(dErr["sLineId"]);
            }

            return [sRes, sListErr];
        }
        catch (e) {
            console.error(e);
        }
        return [" ".repeat(sLine.length), ""];
    }

}


if (typeof(exports) !== 'undefined') {
    exports.TestGrammarChecking = TestGrammarChecking;
}







|
|
|
|
<
<
<
|
<
|
|
|
|
<
<
<
<
>
|
|
<
<

|

<






184
185
186
187
188
189
190
191
192
193
194



195

196
197
198
199




200
201
202


203
204
205

206
207
208
209
210
211
        }
        catch (e) {
            console.error(e);
        }
        return " ".repeat(sLine.length);
    }

    _checkSuggestions (sAllExceptedSuggs, sAllFoundSuggs) {
        let lAllExpectedSuggs = sAllExceptedSuggs.split("|||");
        let lAllFoundSuggs = sAllFoundSuggs.split("|||");
        if (lAllExpectedSuggs.length != lAllFoundSuggs.length) {



            return false;

        }
        for (let i = 0;  i < lAllExpectedSuggs.length;  i++) {
            let aExpectedSuggs = new Set(lAllExpectedSuggs[i].split("|"));
            let aFoundSuggs = new Set(lAllFoundSuggs[i].split("|"));




            if (aExpectedSuggs.size !== aFoundSuggs.size || ![...aExpectedSuggs].every(value => aFoundSuggs.has(value))) {
                return false;
            }


        }
        return true;
    }

}


if (typeof(exports) !== 'undefined') {
    exports.TestGrammarChecking = TestGrammarChecking;
}

Modified gc_core/py/lang_core/tests_core.py from [f2f8ff9a94] to [335b223b65].

108
109
110
111
112
113
114
115
116
117
118


119
120
121
122
123
124
125
                    if not self._checkSuggestions(sExceptedSuggs, sFoundSuggs):
                        print("\n# Line num: " + sLineNum + \
                              "\n> to check: " + _fuckBackslashUTF8(sTextToCheck) + \
                              "\n  expected: " + sExceptedSuggs + \
                              "\n  found:    " + sFoundSuggs + \
                              "\n  errors:   \n" + sListErr)
                        nUnexpectedErrors += 1
            print("Tests with expected errors:", nTestWithExpectedError, " and suggestions:", nTestWithExpectedErrorAndSugg, ":{:.4}%".format(nTestWithExpectedErrorAndSugg/nTestWithExpectedError*100))
            if nUnexpectedErrors:
                print("Unexpected errors:", nUnexpectedErrors)
        # untested rules


        aUntestedRules = set()
        for _, sOpt, sLineId, sRuleId in gc_engine.listRules():
            sRuleId = sRuleId.rstrip("0123456789")
            if sOpt != "@@@@" and sRuleId not in self._aTestedRules and not re.search("^[0-9]+[sp]$|^[pd]_", sRuleId):
                aUntestedRules.add(f"{sLineId}/{sRuleId}")
        if aUntestedRules:
            print()







|


|
>
>







108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
                    if not self._checkSuggestions(sExceptedSuggs, sFoundSuggs):
                        print("\n# Line num: " + sLineNum + \
                              "\n> to check: " + _fuckBackslashUTF8(sTextToCheck) + \
                              "\n  expected: " + sExceptedSuggs + \
                              "\n  found:    " + sFoundSuggs + \
                              "\n  errors:   \n" + sListErr)
                        nUnexpectedErrors += 1
            print("Tests with expected errors:", nTestWithExpectedError, " and suggestions:", nTestWithExpectedErrorAndSugg, "> {:.4} %".format(nTestWithExpectedErrorAndSugg/nTestWithExpectedError*100))
            if nUnexpectedErrors:
                print("Unexpected errors:", nUnexpectedErrors)
            self._showUntestedRules()

    def _showUntestedRules (self):
        aUntestedRules = set()
        for _, sOpt, sLineId, sRuleId in gc_engine.listRules():
            sRuleId = sRuleId.rstrip("0123456789")
            if sOpt != "@@@@" and sRuleId not in self._aTestedRules and not re.search("^[0-9]+[sp]$|^[pd]_", sRuleId):
                aUntestedRules.add(f"{sLineId}/{sRuleId}")
        if aUntestedRules:
            print()
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
        sRes = " " * len(sLine)
        for i, m in enumerate(self._zError.finditer(sLine)):
            nStart = m.start() - (4 * i)
            nEnd = m.end() - (4 * (i+1))
            sRes = sRes[:nStart] + "~" * (nEnd - nStart) + sRes[nEnd:-4]
        return sRes

    def _checkSuggestions (self, sExceptedSuggs, sFoundSuggs):
        lAllExpectedSuggs = sExceptedSuggs.split("|||")
        lAllFoundSuggs = sFoundSuggs.split("|||")
        if len(lAllExpectedSuggs) != len(lAllFoundSuggs):
            return False
        for sExceptedSuggs, sFoundSuggs in zip(lAllExpectedSuggs, lAllFoundSuggs):
            if set(sExceptedSuggs.split("|")) != set(sFoundSuggs.split("|")):
                return False
        return True








|
|
|







167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
        sRes = " " * len(sLine)
        for i, m in enumerate(self._zError.finditer(sLine)):
            nStart = m.start() - (4 * i)
            nEnd = m.end() - (4 * (i+1))
            sRes = sRes[:nStart] + "~" * (nEnd - nStart) + sRes[nEnd:-4]
        return sRes

    def _checkSuggestions (self, sAllExceptedSuggs, sAllFoundSuggs):
        lAllExpectedSuggs = sAllExceptedSuggs.split("|||")
        lAllFoundSuggs = sAllFoundSuggs.split("|||")
        if len(lAllExpectedSuggs) != len(lAllFoundSuggs):
            return False
        for sExceptedSuggs, sFoundSuggs in zip(lAllExpectedSuggs, lAllFoundSuggs):
            if set(sExceptedSuggs.split("|")) != set(sFoundSuggs.split("|")):
                return False
        return True

Modified gc_lang/fr/modules-js/gce_suggestions.js from [916bb2d5db] to [807177b0cf].

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
        }
        return Array.from(aSugg).join("|");
    }
    return "";
}

function joinVerbAndSuffix (sFlex, sSfx) {
    if (/^-[tT]-/.test(sSfx) && /[tdTD]$/.test(sFlex)) {
        return sFlex + sSfx.slice(2);
    }
    if (/[eacEAC]$/.test(sFlex)) {
        if (/-(?:en|y)$/i.test(sSfx)) {
            return sFlex + "s" + sSfx;
        }
        if (/-(?:ie?l|elle|on)$/i.test(sSfx)) {
            return sFlex + "-t" + sSfx;
        }
    }
    return sFlex + sSfx;
}

function suggVerbPpas (sFlex, sWhat=null) {







|


|
|


|







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
        }
        return Array.from(aSugg).join("|");
    }
    return "";
}

function joinVerbAndSuffix (sFlex, sSfx) {
    if (/^-t-/i.test(sSfx) && /[td]$/i.test(sFlex)) {
        return sFlex + sSfx.slice(2);
    }
    if (/[eac]$/i.test(sFlex)) {
        if (/^-(?:en|y)$/i.test(sSfx)) {
            return sFlex + "s" + sSfx;
        }
        if (/^-(?:ie?l|elle|on)$/i.test(sSfx)) {
            return sFlex + "-t" + sSfx;
        }
    }
    return sFlex + sSfx;
}

function suggVerbPpas (sFlex, sWhat=null) {
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181

function suggVerbFrom (sStem, sFlex, sWho="") {
    "conjugate <sStem> according to <sFlex> (and eventually <sWho>)"
    let aSugg = new Set();
    for (let sMorph of gc_engine.oSpellChecker.getMorph(sFlex)) {
        let lTenses = [ ...sMorph.matchAll(/:(?:Y|I[pqsf]|S[pq]|K|P|Q)/g) ];
        if (sWho) {
            for (let sTense of lTenses) {
                if (conj.hasConj(sStem, sTense, sWho)) {
                    aSugg.add(conj.getConj(sStem, sTense, sWho));
                }
            }
        }
        else {
            for (let sTense of lTenses) {
                for (let sWho of [ ...sMorph.matchAll(/:[123][sp]/g) ]) {
                    if (conj.hasConj(sStem, sTense, sWho)) {
                        aSugg.add(conj.getConj(sStem, sTense, sWho));
                    }
                }
            }
        }







|






|







160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181

function suggVerbFrom (sStem, sFlex, sWho="") {
    "conjugate <sStem> according to <sFlex> (and eventually <sWho>)"
    let aSugg = new Set();
    for (let sMorph of gc_engine.oSpellChecker.getMorph(sFlex)) {
        let lTenses = [ ...sMorph.matchAll(/:(?:Y|I[pqsf]|S[pq]|K|P|Q)/g) ];
        if (sWho) {
            for (let [sTense, ] of lTenses) {
                if (conj.hasConj(sStem, sTense, sWho)) {
                    aSugg.add(conj.getConj(sStem, sTense, sWho));
                }
            }
        }
        else {
            for (let [sTense, ] of lTenses) {
                for (let sWho of [ ...sMorph.matchAll(/:[123][sp]/g) ]) {
                    if (conj.hasConj(sStem, sTense, sWho)) {
                        aSugg.add(conj.getConj(sStem, sTense, sWho));
                    }
                }
            }
        }
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
}


const _dQuiEst = new Map ([
    ["je", ":1s"], ["j’", ":1s"], ["tu", ":2s"], ["il", ":3s"], ["on", ":3s"], ["elle", ":3s"], ["iel", ":3s"],
    ["nous", ":1p"], ["vous", ":2p"], ["ils", ":3p"], ["elles", ":3p"], ["iels", ":3p"]
]);
const _lIndicatif = [":Ip", ":Iq", ":Is", ":If"];
const _lSubjonctif = [":Sp", ":Sq"];

function suggVerbMode (sFlex, cMode, sSuj) {
    let lMode;
    if (cMode == ":I") {
        lMode = _lIndicatif;
    } else if (cMode == ":S") {
        lMode = _lSubjonctif;
    } else if (cMode.startsWith(":I") || cMode.startsWith(":S")) {
        lMode = [cMode];
    } else {
        return "";
    }
    let sWho = _dQuiEst.gl_get(sSuj.toLowerCase(), ":3s");
    let aSugg = new Set();







<
<




|

|







221
222
223
224
225
226
227


228
229
230
231
232
233
234
235
236
237
238
239
240
241
}


const _dQuiEst = new Map ([
    ["je", ":1s"], ["j’", ":1s"], ["tu", ":2s"], ["il", ":3s"], ["on", ":3s"], ["elle", ":3s"], ["iel", ":3s"],
    ["nous", ":1p"], ["vous", ":2p"], ["ils", ":3p"], ["elles", ":3p"], ["iels", ":3p"]
]);



function suggVerbMode (sFlex, cMode, sSuj) {
    let lMode;
    if (cMode == ":I") {
        lMode = [":Ip", ":Iq", ":Is", ":If"];
    } else if (cMode == ":S") {
        lMode = [":Sp", ":Sq"];
    } else if (cMode.startsWith(":I") || cMode.startsWith(":S")) {
        lMode = [cMode];
    } else {
        return "";
    }
    let sWho = _dQuiEst.gl_get(sSuj.toLowerCase(), ":3s");
    let aSugg = new Set();
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
        return Array.from(aSugg).join("|");
    }
    return "";
}

//// Nouns and adjectives

function suggPlur (sFlex, sWordToAgree=null, bSelfSugg=false) {
    // returns plural forms assuming sFlex is singular
    if (sWordToAgree) {
        let lMorph = gc_engine.oSpellChecker.getMorph(sWordToAgree);
        if (lMorph.length === 0) {
            return "";
        }
        let sGender = cregex.getGender(lMorph);
        if (sGender == ":m") {
            return suggMasPlur(sFlex);
        } else if (sGender == ":f") {
            return suggFemPlur(sFlex);
        }
    }
    let aSugg = new Set();
    if (sFlex.endsWith("l")) {
        if (sFlex.endsWith("al") && sFlex.length > 2 && gc_engine.oSpellChecker.isValid(sFlex.slice(0,-1)+"ux")) {
            aSugg.add(sFlex.slice(0,-1)+"ux");
        }
        if (sFlex.endsWith("ail") && sFlex.length > 3 && gc_engine.oSpellChecker.isValid(sFlex.slice(0,-2)+"ux")) {
            aSugg.add(sFlex.slice(0,-2)+"ux");







|

<
<
<
<
<
<
<
<
<
<
<
<







253
254
255
256
257
258
259
260
261












262
263
264
265
266
267
268
        return Array.from(aSugg).join("|");
    }
    return "";
}

//// Nouns and adjectives

function suggPlur (sFlex, bSelfSugg=false) {
    // returns plural forms assuming sFlex is singular












    let aSugg = new Set();
    if (sFlex.endsWith("l")) {
        if (sFlex.endsWith("al") && sFlex.length > 2 && gc_engine.oSpellChecker.isValid(sFlex.slice(0,-1)+"ux")) {
            aSugg.add(sFlex.slice(0,-1)+"ux");
        }
        if (sFlex.endsWith("ail") && sFlex.length > 3 && gc_engine.oSpellChecker.isValid(sFlex.slice(0,-2)+"ux")) {
            aSugg.add(sFlex.slice(0,-2)+"ux");
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
            aSugg.add(sFlex+"s");
        }
        if (gc_engine.oSpellChecker.isValid(sFlex+"x")) {
            aSugg.add(sFlex+"x");
        }
    } else {
        if (gc_engine.oSpellChecker.isValid(sFlex+"S")) {
            aSugg.add(sFlex+"s");
        }
        if (gc_engine.oSpellChecker.isValid(sFlex+"X")) {
            aSugg.add(sFlex+"x");
        }
    }
    if (mfsp.hasMiscPlural(sFlex)) {
        mfsp.getMiscPlural(sFlex).forEach(function(x) { aSugg.add(x); });
    }
    if (aSugg.size == 0 && bSelfSugg && (sFlex.endsWith("s") || sFlex.endsWith("x") || sFlex.endsWith("S") || sFlex.endsWith("X"))) {
        aSugg.add(sFlex);
    }
    aSugg.delete("");
    if (aSugg.size > 0) {
        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggSing (sFlex, bSelfSugg=false) {
    // returns singular forms assuming sFlex is plural
    let aSugg = new Set();
    if (sFlex.endsWith("ux")) {
        if (gc_engine.oSpellChecker.isValid(sFlex.slice(0,-2)+"l")) {
            aSugg.add(sFlex.slice(0,-2)+"l");
        }
        if (gc_engine.oSpellChecker.isValid(sFlex.slice(0,-2)+"il")) {







|


|















|







281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
            aSugg.add(sFlex+"s");
        }
        if (gc_engine.oSpellChecker.isValid(sFlex+"x")) {
            aSugg.add(sFlex+"x");
        }
    } else {
        if (gc_engine.oSpellChecker.isValid(sFlex+"S")) {
            aSugg.add(sFlex+"S");
        }
        if (gc_engine.oSpellChecker.isValid(sFlex+"X")) {
            aSugg.add(sFlex+"X");
        }
    }
    if (mfsp.hasMiscPlural(sFlex)) {
        mfsp.getMiscPlural(sFlex).forEach(function(x) { aSugg.add(x); });
    }
    if (aSugg.size == 0 && bSelfSugg && (sFlex.endsWith("s") || sFlex.endsWith("x") || sFlex.endsWith("S") || sFlex.endsWith("X"))) {
        aSugg.add(sFlex);
    }
    aSugg.delete("");
    if (aSugg.size > 0) {
        return Array.from(aSugg).join("|");
    }
    return "";
}

function suggSing (sFlex, bSelfSugg=true) {
    // returns singular forms assuming sFlex is plural
    let aSugg = new Set();
    if (sFlex.endsWith("ux")) {
        if (gc_engine.oSpellChecker.isValid(sFlex.slice(0,-2)+"l")) {
            aSugg.add(sFlex.slice(0,-2)+"l");
        }
        if (gc_engine.oSpellChecker.isValid(sFlex.slice(0,-2)+"il")) {
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
        if (!sMorph.includes(":V")) {
            // not a verb
            if (sMorph.includes(":m") || sMorph.includes(":e")) {
                aSugg.add(suggPlur(sFlex));
            } else {
                let sStem = cregex.getLemmaOfMorph(sMorph);
                if (mfsp.isMasForm(sStem)) {
                    aSugg.add(suggPlur(sStem, null, true));
                }
            }
        } else {
            // a verb
            let sVerb = cregex.getLemmaOfMorph(sMorph);
            if (conj.hasConj(sVerb, ":PQ", ":Q2")) {
                aSugg.add(conj.getConj(sVerb, ":PQ", ":Q2"));







|







379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
        if (!sMorph.includes(":V")) {
            // not a verb
            if (sMorph.includes(":m") || sMorph.includes(":e")) {
                aSugg.add(suggPlur(sFlex));
            } else {
                let sStem = cregex.getLemmaOfMorph(sMorph);
                if (mfsp.isMasForm(sStem)) {
                    aSugg.add(suggPlur(sStem, true));
                }
            }
        } else {
            // a verb
            let sVerb = cregex.getLemmaOfMorph(sMorph);
            if (conj.hasConj(sVerb, ":PQ", ":Q2")) {
                aSugg.add(conj.getConj(sVerb, ":PQ", ":Q2"));

Modified gc_lang/fr/modules/gce_suggestions.py from [af90e8e3f3] to [8bef0dbc3f].

166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
def suggVerbInfi (sFlex):
    "returns infinitive forms of <sFlex>"
    return "|".join([ sStem  for sStem in _oSpellChecker.getLemma(sFlex)  if conj.isVerb(sStem) ])


_dQuiEst = { "je": ":1s", "j’": ":1s", "tu": ":2s", "il": ":3s", "on": ":3s", "elle": ":3s", "iel": ":3s", \
             "nous": ":1p", "vous": ":2p", "ils": ":3p", "elles": ":3p", "iels": ":3p" }
_lIndicatif = [":Ip", ":Iq", ":Is", ":If"]
_lSubjonctif = [":Sp", ":Sq"]

def suggVerbMode (sFlex, cMode, sSuj):
    "returns other conjugations of <sFlex> acconding to <cMode> and <sSuj>"
    if cMode == ":I":
        lMode = _lIndicatif
    elif cMode == ":S":
        lMode = _lSubjonctif
    elif cMode.startswith((":I", ":S")):
        lMode = [cMode]
    else:
        return ""
    sWho = _dQuiEst.get(sSuj.lower(), ":3s")
    aSugg = set()
    for sStem in _oSpellChecker.getLemma(sFlex):
        tTags = conj._getTags(sStem)
        if tTags:
            for sTense in lMode:
                if conj._hasConjWithTags(tTags, sTense, sWho):
                    aSugg.add(conj._getConjWithTags(sStem, tTags, sTense, sWho))
    if aSugg:
        return "|".join(aSugg)
    return ""


## Nouns and adjectives

def suggPlur (sFlex, sWordToAgree=None, bSelfSugg=False):
    "returns plural forms assuming sFlex is singular"
    if sWordToAgree:
        lMorph = _oSpellChecker.getMorph(sFlex)
        if not lMorph:
            return ""
        sGender = cr.getGender(lMorph)
        if sGender == ":m":
            return suggMasPlur(sFlex)
        if sGender == ":f":
            return suggFemPlur(sFlex)
    aSugg = set()
    if sFlex.endswith("l"):
        if sFlex.endswith("al") and len(sFlex) > 2 and _oSpellChecker.isValid(sFlex[:-1]+"ux"):
            aSugg.add(sFlex[:-1]+"ux")
        if sFlex.endswith("ail") and len(sFlex) > 3 and _oSpellChecker.isValid(sFlex[:-2]+"ux"):
            aSugg.add(sFlex[:-2]+"ux")
    if sFlex.endswith("L"):
        if sFlex.endswith("AL") and len(sFlex) > 2 and _oSpellChecker.isValid(sFlex[:-1]+"UX"):
            aSugg.add(sFlex[:-1]+"UX")
        if sFlex.endswith("AIL") and len(sFlex) > 3 and _oSpellChecker.isValid(sFlex[:-2]+"UX"):
            aSugg.add(sFlex[:-2]+"UX")
    if sFlex[-1:].islower():
        if _oSpellChecker.isValid(sFlex+"s"):
            aSugg.add(sFlex+"s")
        if _oSpellChecker.isValid(sFlex+"x"):
            aSugg.add(sFlex+"x")
    else:
        if _oSpellChecker.isValid(sFlex+"S"):
            aSugg.add(sFlex+"s")
        if _oSpellChecker.isValid(sFlex+"X"):
            aSugg.add(sFlex+"x")
    if mfsp.hasMiscPlural(sFlex):
        aSugg.update(mfsp.getMiscPlural(sFlex))
    if not aSugg and bSelfSugg and sFlex.endswith(("s", "x", "S", "X")):
        aSugg.add(sFlex)
    aSugg.discard("")
    if aSugg:
        return "|".join(aSugg)







<
<




|

|



















|

<
<
<
<
<
<
<
<
<


















|

|







166
167
168
169
170
171
172


173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200









201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
def suggVerbInfi (sFlex):
    "returns infinitive forms of <sFlex>"
    return "|".join([ sStem  for sStem in _oSpellChecker.getLemma(sFlex)  if conj.isVerb(sStem) ])


_dQuiEst = { "je": ":1s", "j’": ":1s", "tu": ":2s", "il": ":3s", "on": ":3s", "elle": ":3s", "iel": ":3s", \
             "nous": ":1p", "vous": ":2p", "ils": ":3p", "elles": ":3p", "iels": ":3p" }



def suggVerbMode (sFlex, cMode, sSuj):
    "returns other conjugations of <sFlex> acconding to <cMode> and <sSuj>"
    if cMode == ":I":
        lMode = [":Ip", ":Iq", ":Is", ":If"]
    elif cMode == ":S":
        lMode = [":Sp", ":Sq"]
    elif cMode.startswith((":I", ":S")):
        lMode = [cMode]
    else:
        return ""
    sWho = _dQuiEst.get(sSuj.lower(), ":3s")
    aSugg = set()
    for sStem in _oSpellChecker.getLemma(sFlex):
        tTags = conj._getTags(sStem)
        if tTags:
            for sTense in lMode:
                if conj._hasConjWithTags(tTags, sTense, sWho):
                    aSugg.add(conj._getConjWithTags(sStem, tTags, sTense, sWho))
    if aSugg:
        return "|".join(aSugg)
    return ""


## Nouns and adjectives

def suggPlur (sFlex, bSelfSugg=False):
    "returns plural forms assuming sFlex is singular"









    aSugg = set()
    if sFlex.endswith("l"):
        if sFlex.endswith("al") and len(sFlex) > 2 and _oSpellChecker.isValid(sFlex[:-1]+"ux"):
            aSugg.add(sFlex[:-1]+"ux")
        if sFlex.endswith("ail") and len(sFlex) > 3 and _oSpellChecker.isValid(sFlex[:-2]+"ux"):
            aSugg.add(sFlex[:-2]+"ux")
    if sFlex.endswith("L"):
        if sFlex.endswith("AL") and len(sFlex) > 2 and _oSpellChecker.isValid(sFlex[:-1]+"UX"):
            aSugg.add(sFlex[:-1]+"UX")
        if sFlex.endswith("AIL") and len(sFlex) > 3 and _oSpellChecker.isValid(sFlex[:-2]+"UX"):
            aSugg.add(sFlex[:-2]+"UX")
    if sFlex[-1:].islower():
        if _oSpellChecker.isValid(sFlex+"s"):
            aSugg.add(sFlex+"s")
        if _oSpellChecker.isValid(sFlex+"x"):
            aSugg.add(sFlex+"x")
    else:
        if _oSpellChecker.isValid(sFlex+"S"):
            aSugg.add(sFlex+"S")
        if _oSpellChecker.isValid(sFlex+"X"):
            aSugg.add(sFlex+"X")
    if mfsp.hasMiscPlural(sFlex):
        aSugg.update(mfsp.getMiscPlural(sFlex))
    if not aSugg and bSelfSugg and sFlex.endswith(("s", "x", "S", "X")):
        aSugg.add(sFlex)
    aSugg.discard("")
    if aSugg:
        return "|".join(aSugg)
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
        if not ":V" in sMorph:
            # not a verb
            if ":m" in sMorph or ":e" in sMorph:
                aSugg.add(suggPlur(sFlex))
            else:
                sStem = cr.getLemmaOfMorph(sMorph)
                if mfsp.isMasForm(sStem):
                    aSugg.add(suggPlur(sStem, None, True))
        else:
            # a verb
            sVerb = cr.getLemmaOfMorph(sMorph)
            if conj.hasConj(sVerb, ":PQ", ":Q2"):
                aSugg.add(conj.getConj(sVerb, ":PQ", ":Q2"))
            elif conj.hasConj(sVerb, ":PQ", ":Q1"):
                sSugg = conj.getConj(sVerb, ":PQ", ":Q1")







|







287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
        if not ":V" in sMorph:
            # not a verb
            if ":m" in sMorph or ":e" in sMorph:
                aSugg.add(suggPlur(sFlex))
            else:
                sStem = cr.getLemmaOfMorph(sMorph)
                if mfsp.isMasForm(sStem):
                    aSugg.add(suggPlur(sStem, True))
        else:
            # a verb
            sVerb = cr.getLemmaOfMorph(sMorph)
            if conj.hasConj(sVerb, ":PQ", ":Q2"):
                aSugg.add(conj.getConj(sVerb, ":PQ", ":Q2"))
            elif conj.hasConj(sVerb, ":PQ", ":Q1"):
                sSugg = conj.getConj(sVerb, ":PQ", ":Q1")

Modified gc_lang/fr/rules.grx from [aeba1ed251] to [6130f02351].

2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
TEST: {{Prend-lui}} le pouls.                                                   ->> Prends-lui|Prenons-lui|Prenez-lui
TEST: {{apport-lui}}.                                                           ->>
TEST: {{Expliques-leur}} comment faire.                                         ->> Explique-leur|Expliquons-leur|Expliquez-leur
TEST: {{fou-leur}} la paix                                                      ->> fous-leur
TEST: {{explique-leurs}} de quoi il est question.                               ->> explique-leur
TEST: {{calcul-leurs}} ça.                                                      ->> calcul-leur
TEST: {{aller-y}}                                                               ->> allez-y|vas-y|allons-y
TEST: {{penser-en}}                                                           ->> pensez-en|dépenses-en|dépensons-en
TEST: {{appuis-en}}                                                             ->> appuies-en
TEST: {{appuis-y}}                                                              ->> appuies-y
TEST: {{demande-en}}                                                            ->> demandes-en
TEST: {{demande-y}} comment faire                                               ->> demandes-y
TEST: c’est mon chez-moi
TEST: c’est ton chez-toi
TEST: penses-y







|







2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
TEST: {{Prend-lui}} le pouls.                                                   ->> Prends-lui|Prenons-lui|Prenez-lui
TEST: {{apport-lui}}.                                                           ->>
TEST: {{Expliques-leur}} comment faire.                                         ->> Explique-leur|Expliquons-leur|Expliquez-leur
TEST: {{fou-leur}} la paix                                                      ->> fous-leur
TEST: {{explique-leurs}} de quoi il est question.                               ->> explique-leur
TEST: {{calcul-leurs}} ça.                                                      ->> calcul-leur
TEST: {{aller-y}}                                                               ->> allez-y|vas-y|allons-y
TEST: {{expliquer-en}}                                                          ->> expliquez-en|expliques-en|expliquons-en
TEST: {{appuis-en}}                                                             ->> appuies-en
TEST: {{appuis-y}}                                                              ->> appuies-y
TEST: {{demande-en}}                                                            ->> demandes-en
TEST: {{demande-y}} comment faire                                               ->> demandes-y
TEST: c’est mon chez-moi
TEST: c’est ton chez-toi
TEST: penses-y
6883
6884
6885
6886
6887
6888
6889
6890
6891
6892
6893
6894
6895
6896
6897
    avenir devant [moi|toi|soi|lui|elle|nous|vous|eux|elles]
        <<- /pleo/ morph(<1, ":A.*:[me]:[si]") ->> avenir                                   && Pléonasme.

    >coup de foudre [immédiat+s|instantané+ses|soudain]
        <<- /pleo/ ->> \1 \2 \3                                                             && Pléonasme.

    [paire+s] de >jumeau
        <<- /pleo/ ->> =suggPlur(\-1, "", True)                                             && Pléonasme.

    >panacée >universel
        <<- /pleo/ ->> \1|remède universel                                                  && Pléonasme.

    >secousse [>séismique|>sismique]
        <<- /pleo/ ->> secousse tellurique|secousses telluriques|tremblement de terre       && Pléonasme.








|







6883
6884
6885
6886
6887
6888
6889
6890
6891
6892
6893
6894
6895
6896
6897
    avenir devant [moi|toi|soi|lui|elle|nous|vous|eux|elles]
        <<- /pleo/ morph(<1, ":A.*:[me]:[si]") ->> avenir                                   && Pléonasme.

    >coup de foudre [immédiat+s|instantané+ses|soudain]
        <<- /pleo/ ->> \1 \2 \3                                                             && Pléonasme.

    [paire+s] de >jumeau
        <<- /pleo/ ->> =suggPlur(\-1, True)                                                 && Pléonasme.

    >panacée >universel
        <<- /pleo/ ->> \1|remède universel                                                  && Pléonasme.

    >secousse [>séismique|>sismique]
        <<- /pleo/ ->> secousse tellurique|secousses telluriques|tremblement de terre       && Pléonasme.