Skip to content

Commit cf28128

Browse files
committed
fix english conjugation over-verb; fixes #54; optimize conjugation
1 parent 8dd4429 commit cf28128

File tree

3 files changed

+188
-64
lines changed

3 files changed

+188
-64
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
[![Project](https://img.shields.io/badge/Project-JsLingua-FDEE00.svg)](https://kariminf.github.com/jslingua.web)
88
[![License](https://img.shields.io/badge/License-Apache_2.0-FDEE00.svg)](http://www.apache.org/licenses/LICENSE-2.0)
99
[![Version](https://img.shields.io/npm/v/jslingua.svg)](https://www.npmjs.com/package/jslingua)
10-
[![Gemnasium](https://img.shields.io/gemnasium/kariminf/jslingua.svg)](https://gemnasium.com/github.com/kariminf/jslingua)
1110
[![Travis](https://img.shields.io/travis/kariminf/jslingua.svg)](https://travis-ci.org/kariminf/jslingua)
1211
[![codecov](https://img.shields.io/codecov/c/github/kariminf/jslingua.svg)](https://codecov.io/gh/kariminf/jslingua)
1312
[![downloads](https://img.shields.io/npm/dm/jslingua.svg)](https://www.npmjs.com/package/jslingua)

eng/eng.morpho.js

Lines changed: 177 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
Pp: "had"
4545
}
4646
},
47-
irregular0 = {
47+
irregular2 = {
4848
"bet": 1, "bid": 1, "broadcast": 1, "burst": 1, "cast": 1, "clad": 1,
4949
"clearcut": 1, "cost": 1, "crosscut": 1, "cut": 1, "fit": 1, "handset": 1,
5050
"hit": 1, "hurt": 1, "intercut": 1, "let": 1, "lipread": 1, "podcast": 1,
@@ -53,7 +53,7 @@
5353
"split": 1, "spread": 1, "sublet": 1, "telecast": 1, "thrust": 1,
5454
"typecast": 1, "typeset": 1, "webcast": 1, "wed": 1
5555
},
56-
irregular1 = {
56+
irregular3 = {
5757
"babysit": "babysat", "bend": "bent", "beseech": "besought",
5858
"besprenge": "besprent", "bind": "bound", "bleed": "bled",
5959
"breastfeed": "breastfed", "breed": "bred", "bring": "brought",
@@ -78,7 +78,7 @@
7878
"tell": "told", "think": "thought", "tread": "trod", "understand": "understood",
7979
"waylay": "waylaid", "win": "won", "wind": "wound", "wring": "wrung"
8080
},
81-
irregular2 = {
81+
irregular4 = {
8282
"acknow": ["acknew", "1n"], "ake": ["oke", "1n"], "arise": ["arose", "1n"],
8383
"awake": ["awoke", "2n"], "bear": ["bore", "born"], "beat": ["1", "1en"],
8484
"bedo": ["bedid", "1ne"], "begin": ["began", "begun"], "bego": ["bewent", "1ne"],
@@ -380,6 +380,26 @@
380380

381381
let g;
382382

383+
/**
384+
* An object to be a medium between different functions,
385+
* Its function is to optimize conjugation when the same verb is used
386+
* @type {Object}
387+
*/
388+
let verbInfo = {
389+
/**
390+
* The verb
391+
* @type {String}
392+
*/
393+
verb: "",
394+
/**
395+
* Is it irregular, values are: null (no value yet), 0 (regular) or 1 (irregular)
396+
* @type {Number}
397+
*/
398+
irregular: null,
399+
prefix: "",
400+
rverb: ""
401+
};
402+
383403
//==========================================
384404
// CLASS CONSTRUCTOR
385405
//==========================================
@@ -712,79 +732,119 @@
712732

713733
let begin = "", end = "";
714734

735+
__verbTypes(verb);
736+
737+
//the case of be and have
738+
let conjVerb = {
739+
v: verbInfo.rverb, //verb
740+
p: verbInfo.prefix,
741+
i: verbInfo.irregular, //irregular
742+
c: verbInfo.conj //conjugation table
743+
};
744+
715745
if ((opts.voice) && (opts.voice === Voice.P)) {
716-
if (beHave[verb]) end = " " + __beHaveConj(verb, "Pp", opts);
717-
else if (__isIrregular(verb)) end = " " + __irregularConj(verb, 1);
718-
else end = " " + this.conj(verb, {tense:Tense.Pa});
719-
verb = "be";
746+
switch (conjVerb.i) {
747+
case 1:
748+
end = " " + __beHaveConj(conjVerb, "Pp", opts);
749+
break;
750+
case 2:
751+
case 3:
752+
case 4:
753+
end = " " + __irregularConj(conjVerb, 1);
754+
break;
755+
default:
756+
end = " " + this.conj(verb, {tense:Tense.Pa});
757+
}
758+
conjVerb = {
759+
v: "be",
760+
p: "",
761+
i: 1,
762+
c: beHave["be"]
763+
};
720764
}
721765

722766
if (opts.aspect) {
723767
if ([Aspect.C, Aspect.PC].includes(opts.aspect)) {
724768
// http://www.eclecticenglish.com/grammar/PresentContinuous1G.html
725-
let base = verb;
769+
let base = conjVerb.v;
726770
if(["lie", "die"].includes(verb)) base = verb.slice(0,-2) + "y";
727771
else if (/^[^aeuio]*[aeuio][^aeuioy]$/g.test(verb)) base = verb + verb.slice(-1);
728772
else if (/^.{2,}e$/g.test(verb)) base = verb.slice(0,-1);
729773

730774
end = " " + base + "ing" + end;
731-
verb = "be";
775+
conjVerb = {
776+
v: "be",
777+
p: "",
778+
i: 1,
779+
c: beHave["be"]
780+
};
732781
}
733782

734783
if ([Aspect.P, Aspect.PC].includes(opts.aspect)) {
735-
if (beHave[verb]) end = " " + __beHaveConj(verb, "Pp", opts) + end;
736-
else if (__isIrregular(verb)) end = " " + __irregularConj(verb, 1) + end;
737-
else end = " " + this.conj(verb, {tense:Tense.Pa}) + end;
738-
verb = "have";
739-
}
784+
switch (conjVerb.i) {
785+
case 1:
786+
end = " " + __beHaveConj(conjVerb, "Pp", opts) + end;
787+
break;
788+
case 2:
789+
case 3:
790+
case 4:
791+
end = " " + __irregularConj(conjVerb, 1) + end;
792+
break;
793+
default:
794+
end = " " + this.conj(verb, {tense:Tense.Pa}) + end;
795+
}
796+
conjVerb = {
797+
v: "have",
798+
p: "",
799+
i: 1,
800+
c: beHave["have"]
801+
};
802+
}
740803
}
741804

742805
if ((opts.negated) && (opts.tense !== Tense.Fu)) {
743806
end = " not" + end;
744807
if ((!opts.aspect) || opts.aspect === Aspect.S) {
745808
if ((!opts.voice) || opts.voice === Voice.A) {
746809
end += " " + verb;
747-
verb = "do";
810+
conjVerb = {
811+
v: "do",
812+
p: "",
813+
i: 4,
814+
c: irregular4["do"]
815+
};
748816
//console.log("negation active aspect");
749817
}
750818
}
751819
}
752820

821+
let cverb = conjVerb.v;
822+
753823
switch (opts.tense) {
754824

755825
case Tense.Pr:
756-
if (beHave[verb]) return begin + __beHaveConj(verb, "Pr", opts) + end;
826+
if (conjVerb.i == 1) return begin + __beHaveConj(conjVerb, "Pr", opts) + end;
827+
cverb = conjVerb.p + cverb;
757828
if (opts.person == Person.T && opts.number === GNumber.S) {
758829
//hurry, clarify
759-
verb = verb.replace(/([^aeuio])y$/, "$1ie");
830+
cverb = cverb.replace(/([^aeuio])y$/, "$1ie");
760831
//go, veto, do, wash, mix, fizz (add e )
761-
verb = verb.replace(/(s|z|sh|ch|[^aeui]o)$/, "$1e");
832+
cverb = cverb.replace(/(s|z|sh|ch|[^aeui]o)$/, "$1e");
762833
end = "s" + end;
763834
}
764835
break;
765836

766837
case Tense.Pa:
767838
//To be, To have
768-
if (beHave[verb]) return begin + __beHaveConj(verb, "Pa", opts) + end;
839+
if (conjVerb.i == 1) return begin + __beHaveConj(conjVerb, "Pa", opts) + end;
769840
//Irregular (the block is just for variables)
770-
{
771-
const pref = /(back|be|down|fore|for|in|mis|off|out|over|pre|re|sub|under|un|up|with)(.{3,})/gi;
772-
let match = pref.exec(verb);
773-
if (match) {
774-
//verify if the verb is in Irregular list with the prefix
775-
if (__isIrregular(verb)) return begin + __irregularConj(verb, 0) + end;
776-
//Otherwise, delete the prefix and procede
777-
begin = match[1];
778-
verb = match[2];
779-
}
780-
}
781841

782-
if (__isIrregular(verb)) return begin + __irregularConj(verb, 0) + end;
842+
if (conjVerb.i > 1) return begin + __irregularConj(conjVerb, 0) + end;
783843

784-
verb = verb.replace(/([^aeuio])y$/, "$1i");
785-
verb = verb.replace(/c$/, "ck");
786-
verb = verb.replace(/^([^aeuio]*[aeuio])([^aeuiohwxy])$/, "$1$2$2");
787-
if (verb.endsWith("e")) end = "d" + end;
844+
cverb = cverb.replace(/([^aeuio])y$/, "$1i");
845+
cverb = cverb.replace(/c$/, "ck");
846+
cverb = cverb.replace(/^([^aeuio]*[aeuio])([^aeuiohwxy])$/, "$1$2$2");
847+
if (cverb.endsWith("e")) end = "d" + end;
788848
else end = "ed" + end;
789849
break;
790850

@@ -795,30 +855,22 @@
795855

796856
}//swich(tense)
797857

798-
return begin + verb + end;
858+
return begin + cverb + end;
799859

800860
};
801861

802-
function __beHaveConj(verb, idx, opts) {
803-
if (! (verb in beHave)) return verb;
804-
if (! "Pr|Pa|Pp".includes(idx)) return verb;
805-
if (idx === "Pp") return beHave[verb][idx];
862+
function __beHaveConj(conjVerb, idx, opts) {
863+
if (conjVerb.i != 1) return conjVerb.v;
864+
if (! "Pr|Pa|Pp".includes(idx)) return conjVerb.v;
865+
if (idx === "Pp") return conjVerb.c[idx];
806866

807867
if (opts.number === GNumber.S) {
808-
if (opts.person == Person.F) return beHave[verb][idx][0];
809-
else if (opts.person == Person.T) return beHave[verb][idx][1];
810-
return beHave[verb][idx][2];
868+
if (opts.person == Person.F) return conjVerb.c[idx][0];
869+
else if (opts.person == Person.T) return conjVerb.c[idx][1];
870+
return conjVerb.c[idx][2];
811871
}
812872

813-
return beHave[verb][idx][2];
814-
}
815-
816-
817-
function __isIrregular(verb) {
818-
if (irregular0[verb]) return 1;
819-
if (irregular1[verb]) return 1;
820-
if (irregular2[verb]) return 1;
821-
return 0;//false
873+
return conjVerb.c[idx][2];
822874
}
823875

824876
/**
@@ -828,21 +880,83 @@
828880
* @method __irregularConj
829881
* @private
830882
* @memberof EngMorpho
831-
* @param {String} verb the irregular verb
883+
* @param {Object} verb the irregular verb
832884
* @param {Number} idx 0 for past, 1 for past participle
833885
* @return {String} the conjugation
834886
*/
835-
function __irregularConj(verb, idx) {
836-
if (irregular0[verb]) return verb;
837-
if (irregular1[verb])return irregular1[verb];
838-
//Here, we suppose it is irregular2[verb]
839-
let res = irregular2[verb][idx];
840-
res = res.replace("1", verb);
841-
if(idx === 1) {
842-
res = res.replace("2", irregular2[verb][0]);
843-
res = res.replace(/.-/,"");
887+
function __irregularConj(conjVerb, idx) {
888+
switch (conjVerb.i) {
889+
case 3: return conjVerb.p + conjVerb.c;
890+
case 4:
891+
let res = conjVerb.c[idx];
892+
res = res.replace("1", conjVerb.v);
893+
if(idx === 1) {
894+
res = res.replace("2", conjVerb.c[0]);
895+
res = res.replace(/.-/,"");
896+
}
897+
return conjVerb.p + res;
898+
default: return conjVerb.p + conjVerb.v;
899+
}
900+
}
901+
902+
//==========================================
903+
// CONJUGATION PREPROCESSOR FUNCTIONS
904+
//==========================================
905+
906+
function __verbTypes(verb) {
907+
//delete spaces
908+
verb = verb.trim();
909+
if (verb === verbInfo.verb) return;
910+
911+
verbInfo.rverb = verb;
912+
verbInfo.prefix = "";
913+
914+
// conjugation table for the verb "be" or "have"
915+
let conjInfo = beHave[verb];
916+
917+
if (conjInfo) {
918+
verbInfo.irregular = 1;
919+
verbInfo.conj = conjInfo;
920+
return;
921+
}
922+
923+
{
924+
const pref = /(back|be|down|fore|for|in|mis|off|out|over|pre|re|sub|under|un|up|with)(.{3,})/gi;
925+
let match = pref.exec(verb);
926+
if (match) {
927+
verbInfo.prefix = match[1];
928+
verbInfo.rverb = match[2];
929+
}
930+
}
931+
932+
//These verbs do not need conjugation table
933+
// Past = past participle = verb
934+
if (irregular2[verbInfo.rverb]) {
935+
verbInfo.irregular = 2;
936+
verbInfo.conj = null;
937+
return;
938+
}
939+
940+
//These verbs have irregularities in past participle and past
941+
// past = past participle
942+
conjInfo = irregular3[verbInfo.rverb];
943+
if (conjInfo) {
944+
verbInfo.irregular = 3;
945+
verbInfo.conj = conjInfo;
946+
return;
844947
}
845-
return res;
948+
949+
// These verbs have irregularities in te past: a table of conjugation
950+
conjInfo = irregular4[verbInfo.rverb];
951+
if (conjInfo) {
952+
verbInfo.irregular = 4;
953+
verbInfo.conj = conjInfo;
954+
return;
955+
}
956+
957+
verbInfo.irregular = 0;
958+
verbInfo.conj = null;
959+
846960
}
847961

848962
//==========================================

test/unit/eng.morpho_t.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ describe("English Verb conjugation", function(){
166166
expect(morpho.conjugate("be",$({tense:"present"}, I))).to.eql("am");
167167
expect(morpho.conjugate("be",$({tense:"present"}, heSheIt))).to.eql("is");
168168
expect(morpho.conjugate("be",$({tense:"present"}, they))).to.eql("are");
169+
//Override
170+
expect(morpho.conjugate("override",$({tense:"present"}, I))).to.eql("override");
171+
expect(morpho.conjugate("override",$({tense:"present"}, heSheIt))).to.eql("overrides");
169172

170173
});
171174

@@ -188,6 +191,8 @@ describe("English Verb conjugation", function(){
188191
expect(morpho.conjugate("be",$({tense:"past"}, they))).to.eql("were");
189192
//Go
190193
expect(morpho.conjugate("go",$({tense:"past"}, I))).to.eql("went");
194+
//Override
195+
expect(morpho.conjugate("override",$({tense:"past"}, I))).to.eql("overrode");
191196

192197
});
193198

@@ -205,6 +210,8 @@ describe("English Verb conjugation", function(){
205210
expect(morpho.conjugate("be",$({tense:"past", voice: "passive"}, I))).to.eql("was been");
206211
//Go
207212
expect(morpho.conjugate("go",$({tense:"past", voice: "passive"}, I))).to.eql("was gone");
213+
//Override
214+
expect(morpho.conjugate("override",$({tense:"past", voice: "passive"}, I))).to.eql("was overridden");
208215

209216
});
210217

@@ -222,6 +229,8 @@ describe("English Verb conjugation", function(){
222229
expect(morpho.conjugate("be",$({tense:"past", aspect: "perfect"}, I))).to.eql("had been");
223230
//Go
224231
expect(morpho.conjugate("go",$({tense:"past", aspect: "perfect"}, I))).to.eql("had gone");
232+
//Override
233+
expect(morpho.conjugate("override",$({tense:"past", aspect: "perfect"}, I))).to.eql("had overridden");
225234

226235
});
227236

@@ -246,6 +255,8 @@ describe("English Verb conjugation", function(){
246255
expect(morpho.conjugate("lie",$({tense:"past", aspect: "perfect-continuous"}, I))).to.eql("had been lying");
247256
expect(morpho.conjugate("die",$({tense:"past", aspect: "perfect-continuous"}, I))).to.eql("had been dying");
248257

258+
//override
259+
expect(morpho.conjugate("override",$({tense:"past", aspect: "perfect-continuous"}, I))).to.eql("had been overriding");
249260
});
250261

251262
it("Negation", function() {

0 commit comments

Comments
 (0)