Add source-position information to bare words
This commit is contained in:
parent
6ca93d6615
commit
d57f409a13
4 changed files with 113 additions and 34 deletions
|
@ -7,6 +7,7 @@ exports[`Parsing Notcl Misc Big mess of markup 1`] = `
|
|||
[
|
||||
{
|
||||
"bare": "h1",
|
||||
"pos": 5,
|
||||
},
|
||||
{
|
||||
"text": "Hello, World!",
|
||||
|
@ -15,6 +16,7 @@ exports[`Parsing Notcl Misc Big mess of markup 1`] = `
|
|||
[
|
||||
{
|
||||
"bare": "para",
|
||||
"pos": 28,
|
||||
},
|
||||
{
|
||||
"pieces": [
|
||||
|
@ -23,12 +25,15 @@ exports[`Parsing Notcl Misc Big mess of markup 1`] = `
|
|||
[
|
||||
{
|
||||
"bare": "2",
|
||||
"pos": 34,
|
||||
},
|
||||
{
|
||||
"bare": "+",
|
||||
"pos": 36,
|
||||
},
|
||||
{
|
||||
"bare": "2",
|
||||
"pos": 38,
|
||||
},
|
||||
],
|
||||
],
|
||||
|
@ -39,6 +44,7 @@ exports[`Parsing Notcl Misc Big mess of markup 1`] = `
|
|||
[
|
||||
{
|
||||
"bare": "block",
|
||||
"pos": 45,
|
||||
},
|
||||
{
|
||||
"text": "
|
||||
|
@ -49,9 +55,11 @@ exports[`Parsing Notcl Misc Big mess of markup 1`] = `
|
|||
[
|
||||
{
|
||||
"bare": "block",
|
||||
"pos": 213,
|
||||
},
|
||||
{
|
||||
"bare": "-red",
|
||||
"pos": 219,
|
||||
},
|
||||
{
|
||||
"text": "Beware!",
|
||||
|
@ -60,6 +68,7 @@ exports[`Parsing Notcl Misc Big mess of markup 1`] = `
|
|||
[
|
||||
{
|
||||
"bare": "para",
|
||||
"pos": 238,
|
||||
},
|
||||
{
|
||||
"text": "All text should be quoted, it's clearer that way. & blockquotes already should contain paragraphs. (maybe normalize nested paragraphs)",
|
||||
|
@ -68,6 +77,7 @@ exports[`Parsing Notcl Misc Big mess of markup 1`] = `
|
|||
[
|
||||
{
|
||||
"bare": "block",
|
||||
"pos": 384,
|
||||
},
|
||||
{
|
||||
"text": "
|
||||
|
@ -92,6 +102,7 @@ exports[`Parsing Notcl Misc Big mess of markup 1`] = `
|
|||
[
|
||||
{
|
||||
"bare": "para",
|
||||
"pos": 651,
|
||||
},
|
||||
{
|
||||
"text": "
|
||||
|
|
|
@ -8,56 +8,97 @@ describe("Parsing Notcl", () => {
|
|||
it("can parse a multi-word command", () =>
|
||||
expect(parse("a b c")).toEqual([
|
||||
true,
|
||||
[[{ bare: "a" }, { bare: "b" }, { bare: "c" }]],
|
||||
[
|
||||
[
|
||||
{ bare: "a", pos: 0 },
|
||||
{ bare: "b", pos: 2 },
|
||||
{ bare: "c", pos: 5 },
|
||||
],
|
||||
],
|
||||
]));
|
||||
|
||||
it("accepts newlines as command separators", () =>
|
||||
expect(parse("a\nb")).toEqual([
|
||||
true,
|
||||
[[{ bare: "a" }], [{ bare: "b" }]],
|
||||
[[{ bare: "a", pos: 0 }], [{ bare: "b", pos: 2 }]],
|
||||
]));
|
||||
it("does not split commands on folded newlines", () =>
|
||||
expect(
|
||||
parse(String.raw`a\
|
||||
b`)
|
||||
).toEqual([true, [[{ bare: "a" }, { bare: "b" }]]]));
|
||||
).toEqual([
|
||||
true,
|
||||
[
|
||||
[
|
||||
{ bare: "a", pos: 0 },
|
||||
{ bare: "b", pos: 2 },
|
||||
],
|
||||
],
|
||||
]));
|
||||
it("does split words on folded newlines", () =>
|
||||
expect(
|
||||
parse(String.raw`a\
|
||||
b`)
|
||||
).toEqual([true, [[{ bare: "a" }, { bare: "b" }]]]));
|
||||
).toEqual([
|
||||
true,
|
||||
[
|
||||
[
|
||||
{ bare: "a", pos: 0 },
|
||||
{ bare: "b", pos: 2 },
|
||||
],
|
||||
],
|
||||
]));
|
||||
it("does split commands on newlines with escaped backslashes", () =>
|
||||
expect(
|
||||
parse(String.raw`a\\
|
||||
b`)
|
||||
).toEqual([true, [[{ text: "a\\" }], [{ bare: "b" }]]]));
|
||||
b`)
|
||||
).toEqual([true, [[{ text: "a\\" }], [{ bare: "b", pos: 4 }]]]));
|
||||
it("does not split commands on folded newlines with escaped backslashes", () =>
|
||||
expect(
|
||||
parse(String.raw`a\\\
|
||||
b`)
|
||||
).toEqual([true, [[{ text: "a\\" }, { bare: "b" }]]]));
|
||||
).toEqual([true, [[{ text: "a\\" }, { bare: "b", pos: 4 }]]]));
|
||||
|
||||
it("accepts semicolons as command separators", () =>
|
||||
expect(parse("a;b")).toEqual([true, [[{ bare: "a" }], [{ bare: "b" }]]]));
|
||||
expect(parse("a;b")).toEqual([
|
||||
true,
|
||||
[[{ bare: "a", pos: 0 }], [{ bare: "b", pos: 2 }]],
|
||||
]));
|
||||
|
||||
it("tolerates, and ignores, empty commands", () =>
|
||||
expect(parse("a;;b\n\nc")).toEqual([
|
||||
true,
|
||||
[[{ bare: "a" }], [{ bare: "b" }], [{ bare: "c" }]],
|
||||
[
|
||||
[{ bare: "a", pos: 0 }],
|
||||
[{ bare: "b", pos: 3 }],
|
||||
[{ bare: "c", pos: 6 }],
|
||||
],
|
||||
]));
|
||||
|
||||
test.each([[" a"], ["a "], ["a ;"], ["; a"]])(
|
||||
"tolerates whitespace before and after commands {%s}",
|
||||
(text) => expect(parse(text)).toEqual([true, [[{ bare: "a" }]]])
|
||||
test.each([
|
||||
[" a", 1],
|
||||
["a ", 0],
|
||||
["a ;", 0],
|
||||
["; a", 2],
|
||||
])("tolerates whitespace before and after commands {%s}", (text, pos) =>
|
||||
expect(parse(text)).toEqual([true, [[{ bare: "a", pos }]]])
|
||||
);
|
||||
});
|
||||
|
||||
describe("Comments", () => {
|
||||
it("ignores comments", () => expect(parse("#comment")).toEqual([true, []]));
|
||||
it("does not treat # in argument position as a comment", () =>
|
||||
expect(parse("a #1")).toEqual([true, [[{ bare: "a" }, { bare: "#1" }]]]));
|
||||
expect(parse("a #1")).toEqual([
|
||||
true,
|
||||
[
|
||||
[
|
||||
{ bare: "a", pos: 0 },
|
||||
{ bare: "#1", pos: 2 },
|
||||
],
|
||||
],
|
||||
]));
|
||||
it("can have commands before a comment", () =>
|
||||
expect(parse("a ;#comment")).toEqual([true, [[{ bare: "a" }]]]));
|
||||
expect(parse("a ;#comment")).toEqual([true, [[{ bare: "a", pos: 0 }]]]));
|
||||
|
||||
it("ignores the whole line after a comment", () =>
|
||||
expect(parse("# comment ; not a command")).toEqual([true, []]));
|
||||
|
@ -70,8 +111,8 @@ b`)
|
|||
it("does not continue the comment through a newline with escaped backslashes", () =>
|
||||
expect(
|
||||
parse(String.raw`#a\\
|
||||
b`)
|
||||
).toEqual([true, [[{ bare: "b" }]]]));
|
||||
b`)
|
||||
).toEqual([true, [[{ bare: "b", pos: 5 }]]]));
|
||||
it("continues the comment through a folded newline with escaped backslashes", () =>
|
||||
expect(
|
||||
parse(String.raw`#a\\\
|
||||
|
@ -81,9 +122,12 @@ b`)
|
|||
|
||||
describe("interpolated words", () => {
|
||||
it("can parse a simple word", () =>
|
||||
expect(parse("a")).toEqual([true, [[{ bare: "a" }]]]));
|
||||
expect(parse("a")).toEqual([true, [[{ bare: "a", pos: 0 }]]]));
|
||||
it("can parse a word with non-special punctuation", () =>
|
||||
expect(parse("-switch")).toEqual([true, [[{ bare: "-switch" }]]]));
|
||||
expect(parse("-switch")).toEqual([
|
||||
true,
|
||||
[[{ bare: "-switch", pos: 0 }]],
|
||||
]));
|
||||
|
||||
it("accepts empty quotes", () =>
|
||||
expect(parse('""')).toEqual([true, [[{ text: "" }]]]));
|
||||
|
@ -104,9 +148,9 @@ b`)
|
|||
expect(parse("a\\ b")).toEqual([true, [[{ text: "a b" }]]]));
|
||||
|
||||
it("treats a non-leading quote as a plain character", () =>
|
||||
expect(parse('a"')).toEqual([true, [[{ bare: 'a"' }]]]));
|
||||
expect(parse('a"')).toEqual([true, [[{ bare: 'a"', pos: 0 }]]]));
|
||||
it("treats a non-leading brace as a plain character", () =>
|
||||
expect(parse("a{")).toEqual([true, [[{ bare: "a{" }]]]));
|
||||
expect(parse("a{")).toEqual([true, [[{ bare: "a{", pos: 0 }]]]));
|
||||
it("treats an escaped quote as a plain character", () =>
|
||||
expect(parse('\\"')).toEqual([true, [[{ text: '"' }]]]));
|
||||
it("treats an escaped brace as a plain character", () =>
|
||||
|
@ -127,7 +171,7 @@ b`)
|
|||
it("can parse one-word command interpolations", () =>
|
||||
expect(parse("[a]")).toEqual([
|
||||
true,
|
||||
[[{ pieces: [{ script: [[{ bare: "a" }]] }] }]],
|
||||
[[{ pieces: [{ script: [[{ bare: "a", pos: 1 }]] }] }]],
|
||||
]));
|
||||
it("can parse multi-word command interpolations", () =>
|
||||
expect(parse("[a b c]")).toEqual([
|
||||
|
@ -137,7 +181,13 @@ b`)
|
|||
{
|
||||
pieces: [
|
||||
{
|
||||
script: [[{ bare: "a" }, { bare: "b" }, { bare: "c" }]],
|
||||
script: [
|
||||
[
|
||||
{ bare: "a", pos: 1 },
|
||||
{ bare: "b", pos: 3 },
|
||||
{ bare: "c", pos: 5 },
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -152,7 +202,13 @@ b`)
|
|||
{
|
||||
pieces: [
|
||||
{
|
||||
script: [[{ bare: "a" }], [{ bare: "b" }, { bare: "c" }]],
|
||||
script: [
|
||||
[{ bare: "a", pos: 1 }],
|
||||
[
|
||||
{ bare: "b", pos: 4 },
|
||||
{ bare: "c", pos: 6 },
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -167,7 +223,9 @@ b`)
|
|||
{
|
||||
pieces: [
|
||||
{
|
||||
script: [[{ pieces: [{ script: [[{ bare: "a" }]] }] }]],
|
||||
script: [
|
||||
[{ pieces: [{ script: [[{ bare: "a", pos: 2 }]] }] }],
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -181,7 +239,10 @@ b`)
|
|||
[
|
||||
[
|
||||
{
|
||||
pieces: [{ script: [[{ bare: "a" }]] }, { bare: "b" }],
|
||||
pieces: [
|
||||
{ script: [[{ bare: "a", pos: 1 }]] },
|
||||
{ bare: "b", pos: 3 },
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
|
@ -193,9 +254,9 @@ b`)
|
|||
[
|
||||
{
|
||||
pieces: [
|
||||
{ bare: "a" },
|
||||
{ script: [[{ bare: "b" }]] },
|
||||
{ bare: "c" },
|
||||
{ bare: "a", pos: 0 },
|
||||
{ script: [[{ bare: "b", pos: 2 }]] },
|
||||
{ bare: "c", pos: 4 },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -207,7 +268,10 @@ b`)
|
|||
[
|
||||
[
|
||||
{
|
||||
pieces: [{ bare: "a" }, { script: [[{ bare: "b" }]] }],
|
||||
pieces: [
|
||||
{ bare: "a", pos: 0 },
|
||||
{ script: [[{ bare: "b", pos: 2 }]] },
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
|
@ -219,8 +283,8 @@ b`)
|
|||
[
|
||||
{
|
||||
pieces: [
|
||||
{ script: [[{ bare: "a" }]] },
|
||||
{ script: [[{ bare: "b" }]] },
|
||||
{ script: [[{ bare: "a", pos: 1 }]] },
|
||||
{ script: [[{ bare: "b", pos: 4 }]] },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
|
@ -36,7 +36,7 @@ function bareWordTmpl(charRegex: RegExp) {
|
|||
Bracket,
|
||||
Regex(charRegex)
|
||||
.expects("CHAR")
|
||||
.map(([text]) => ({ bare: text }))
|
||||
.map(([text], index) => ({ bare: text, pos: index }))
|
||||
)
|
||||
)
|
||||
).map(([, pieces]) => SimplifyWord(pieces));
|
||||
|
|
|
@ -13,10 +13,14 @@ export class Pattern<out T> {
|
|||
*
|
||||
* @param map - Mapping function
|
||||
*/
|
||||
public map<U>(map: (value: T) => U): Pattern<U> {
|
||||
public map<U>(map: (value: T, index: number) => U): Pattern<U> {
|
||||
return new Pattern((source, index) => {
|
||||
const [value, furthest, expected] = this.match(source, index);
|
||||
return [value ? [map(value[0]), value[1]] : null, furthest, expected];
|
||||
return [
|
||||
value ? [map(value[0], index), value[1]] : null,
|
||||
furthest,
|
||||
expected,
|
||||
];
|
||||
}, this.expectLabel);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue