diff options
| author | EuAndreh <eu@euandre.org> | 2025-07-15 13:55:36 -0300 |
|---|---|---|
| committer | EuAndreh <eu@euandre.org> | 2025-07-15 13:55:36 -0300 |
| commit | c4f360baf07107468667832be66e5e9c3f92d4b6 (patch) | |
| tree | 321c4f36f43543491c5bd4a5f9ff33ec8086da20 /tests/paca.mjs | |
| parent | tests/paca.mjs (test_rangeStateStep): Finish test cases for rangeStateStep (diff) | |
| download | paca-c4f360baf07107468667832be66e5e9c3f92d4b6.tar.gz paca-c4f360baf07107468667832be66e5e9c3f92d4b6.tar.xz | |
Support tokenizing character class expressions [a-z]
* src/paca.mjs (classStateStep): New function equivalent to
`rangeStateStep()` for character class expressions. For now it knowns
how to handle escaping ([abc\-_]), simple ranges ([a-z]), negation
([^abc]) and the hyphen literal as the first char ([-a-z_]).
* tests.paca.mjs (test_classStateStep): New test entry has a test case
each scenario described above.
Diffstat (limited to '')
| -rw-r--r-- | tests/paca.mjs | 226 |
1 files changed, 224 insertions, 2 deletions
diff --git a/tests/paca.mjs b/tests/paca.mjs index 739fe80..e9c3a6b 100644 --- a/tests/paca.mjs +++ b/tests/paca.mjs @@ -6,6 +6,7 @@ import { ConcatStep, numFromDigits, rangeStateStep, + classStateStep, TRANSITION_FNS, shouldConcat, isOperator, @@ -214,6 +215,227 @@ const test_rangeStateStep = t => { }); }; +const test_classStateStep = t => { + t.start("classStateStep()"); + + t.testing("error when range is unfinished", () => { + const { value: { error }} = classStateStep( + { context: { range: { where: "to" }}}, + "]", + null, + null, + ); + t.assertEq(error.message, "unfinished character class range"); + t.assertEq(error instanceof SyntaxError, true); + }); + + t.testing("error when class is empty", () => { + const { value: { error }} = classStateStep( + { context: { range: {}, set: [] }}, + "]", + null, + null, + ); + t.assertEq(error.message, "empty character class"); + t.assertEq(error instanceof ValueError, true); + }); + + t.testing("OK when class in non-empty", () => { + const given = classStateStep( + { + out: [ 1, 2, 3 ], + context: { + range: {}, + set: [ 4, 5, 6 ], + }, + }, + "]", + null, + null, + ); + const expected = { + out: [ 1, 2, 3, { + operator: "class", + set: [ 4, 5, 6 ], + }], + state: "accepting", + context: null, + }; + t.assertEq(given, expected); + }); + + t.testing("error on descending range", () => { + const { value: { error }} = classStateStep( + { context: { range: { from: "c", where: "to" }}}, + "b", + null, + null, + ); + const message = "bad class range values: [c-b]"; + t.assertEq(error.message, message); + t.assertEq(error instanceof ValueError, true); + }); + + t.testing("OK when adding ending to range", () => { + const given = classStateStep( + { + context: { + range: { + from: "a", + where: "to", + }, + set: [ "a", "b" ], + x: 1, + }, + }, + "z", + null, + null, + ); + const expected = { + out: undefined, + state: undefined, + context: { + range: { + from: null, + where: "from", + }, + set: [ "a", "b", { from: "a", to: "z" }], + x: 1, + }, + }; + t.assertEq(given, expected); + }); + + t.testing("a backslash enters escaping state", () => { + const given = classStateStep( + { context: { what: "ever" }}, + "\\", + null, + null, + ); + const expected = { + out: undefined, + state: undefined, + context: { + what: "ever", + escaping: true, + }, + }; + t.assertEq(given, expected); + }); + + t.testing("when escaping, special chars get added to the set", () => { + const given = classStateStep( + { context: { set: [ "a" ], escaping: true }}, + "]", + null, + null, + ); + const expected = { + out: undefined, + state: undefined, + context: { set: [ "a", "]" ] }, + }; + t.assertEq(given, expected); + }); + + t.testing("a hyphen changes the last char as a range start", () => { + const given = classStateStep( + { + context: { + range: "IGNORED", + set: [ "0" ], + x: 1, + }, + }, + "-", + null, + null, + ); + const expected = { + out: undefined, + state: undefined, + context: { + range: { + from: "0", + where: "to", + }, + set: [], + x: 1, + }, + }; + t.assertEq(given, expected); + }); + + t.testing("hyphen as the first char is taken literally", () => { + const given = classStateStep( + { + context: { + range: {}, + set: [], + x: 1, + }, + }, + "-", + null, + null, + ); + const expected = { + out: undefined, + state: undefined, + context: { + range: {}, + set: [ "-" ], + x: 1, + }, + }; + t.assertEq(given, expected); + }); + + t.testing("caret as the first char toggles the boolean", () => { + const given = classStateStep( + { context: { x: 1, set: [], range: {}}}, + "^", + null, + null, + ); + const expected = { + out: undefined, + state: undefined, + context: { + x: 1, + set: [], + range: {}, + caret: true, + }, + }; + t.assertEq(given, expected); + }); + + t.testing("other chars are just added to the set", () => { + const given = classStateStep( + { context: { x: 1, set: [], range: {}}}, + "_", + null, + null, + ); + const expected = { + out: undefined, + state: undefined, + context: { + x: 1, + set: [ "_" ], + range: {}, + }, + }; + t.assertEq(given, expected); + }); + + t.testing("caret as not the first char is taken literally", () => { + }); +}; + const test_TRANSITION_FNS = t => { t.start("TRANSITION_FNS"); @@ -253,8 +475,7 @@ const test_TRANSITION_FNS = t => { context: { set: [], range: { - from: [], - to: [], + from: null, where: "from", }, }, @@ -2558,6 +2779,7 @@ const test_compile = t => { runTests([ test_numFromDigits, test_rangeStateStep, + test_classStateStep, test_TRANSITION_FNS, test_shouldConcat, test_isOperator, |
