diff --git a/src/utils/latl/README.md b/src/utils/latl/README.md index 2beb442..4740152 100644 --- a/src/utils/latl/README.md +++ b/src/utils/latl/README.md @@ -38,6 +38,13 @@ Sets are defined with the set keyword followed by an equal sign and a set expres ``` set SHORT_VOWELS = [ a, i, u ] ``` + +A single alias can be provided to the set during definition: +``` +; the alias N can be used to refer to this set +set NASAL_PULMONIC_CONSONANTS, N = [ m, ɱ, n̼, n, ɳ, ɲ, ŋ, ɴ ] +``` + Lists of sets can be defined using a comma followed by whitespace syntax ``` set PLOSIVES = [ p, t, k ], diff --git a/src/utils/latl/grammar.js b/src/utils/latl/grammar.js index 92e653a..378577f 100644 --- a/src/utils/latl/grammar.js +++ b/src/utils/latl/grammar.js @@ -58,13 +58,27 @@ var grammar = { d => d.map(u => u && u.length ? u.map(v => v.length ? v.filter(t => t && t.type !== 'comma' && t.type !== 'kwSet')[0] : v) : u), clearNull, ) }, - {"name": "setDefinition", "symbols": [(lexer.has("setIdentifier") ? {type: "setIdentifier"} : setIdentifier), "__", "equal", "__", "setExpression"], "postprocess": + {"name": "setDefinition$ebnf$1$subexpression$1", "symbols": ["setAlias"]}, + {"name": "setDefinition$ebnf$1", "symbols": ["setDefinition$ebnf$1$subexpression$1"], "postprocess": id}, + {"name": "setDefinition$ebnf$1", "symbols": [], "postprocess": function(d) {return null;}}, + {"name": "setDefinition", "symbols": [(lexer.has("setIdentifier") ? {type: "setIdentifier"} : setIdentifier), "setDefinition$ebnf$1", "__", "equal", "__", "setExpression"], "postprocess": pipe( d => d.filter(t => !!t && t.length !== 0), + d => d.map(u => u && u.length ? u.map(t => t && t.length ? t.filter(v => v && v.type !== 'comma') : t) : u), d => d.map(t => t.type === 'setIdentifier' ? { setIdentifier: t.toString() } : t), d => d.map(t => t && t.length && t[0].hasOwnProperty('setExpression') ? t[0] : t), + d => d.map(t => t.length ? + // pretty ugly ([ { type: 'aias', alias: [ string ] }] ) => { setAlias: str } + { setAlias: t.reduce((aliases, token) => token.type === 'alias' ? [...aliases, ...token.alias] : aliases, [])[0] } + : t), ) }, + {"name": "setAlias", "symbols": [(lexer.has("comma") ? {type: "comma"} : comma), "_", (lexer.has("setIdentifier") ? {type: "setIdentifier"} : setIdentifier)], "postprocess": pipe( + d => d && d.length ? d.filter(t => !!t) : d, + d => d.map(t => t.type === 'setIdentifier' ? t.toString() : null), + d => d.filter(t => !!t), + d => ({type: 'alias', alias: d }), + ) }, {"name": "setExpression", "symbols": [(lexer.has("openSquareBracket") ? {type: "openSquareBracket"} : openSquareBracket), "_", "phoneList", "_", (lexer.has("closeSquareBracket") ? {type: "closeSquareBracket"} : closeSquareBracket)], "postprocess": pipe( // filters commas and whitespace diff --git a/src/utils/latl/grammar.ne b/src/utils/latl/grammar.ne index cdbf5e0..40bc172 100644 --- a/src/utils/latl/grammar.ne +++ b/src/utils/latl/grammar.ne @@ -59,14 +59,26 @@ definition -> %kwSet __ (setDefinition %comma __):* setDefinition d => d.map(u => u && u.length ? u.map(v => v.length ? v.filter(t => t && t.type !== 'comma' && t.type !== 'kwSet')[0] : v) : u), clearNull, ) %} -setDefinition -> %setIdentifier __ equal __ setExpression +setDefinition -> %setIdentifier (setAlias):? __ equal __ setExpression {% pipe( d => d.filter(t => !!t && t.length !== 0), + d => d.map(u => u && u.length ? u.map(t => t && t.length ? t.filter(v => v && v.type !== 'comma') : t) : u), d => d.map(t => t.type === 'setIdentifier' ? { setIdentifier: t.toString() } : t), d => d.map(t => t && t.length && t[0].hasOwnProperty('setExpression') ? t[0] : t), + d => d.map(t => t.length ? + // pretty ugly ([ { type: 'aias', alias: [ string ] }] ) => { setAlias: str } + { setAlias: t.reduce((aliases, token) => token.type === 'alias' ? [...aliases, ...token.alias] : aliases, [])[0] } + : t), ) %} +setAlias -> %comma _ %setIdentifier + {% pipe( + d => d && d.length ? d.filter(t => !!t) : d, + d => d.map(t => t.type === 'setIdentifier' ? t.toString() : null), + d => d.filter(t => !!t), + d => ({type: 'alias', alias: d }), + ) %} setExpression -> %openSquareBracket _ phoneList _ %closeSquareBracket {% pipe( diff --git a/src/utils/latl/test/assertionData.js b/src/utils/latl/test/assertionData.js index f80be9a..d3351c3 100644 --- a/src/utils/latl/test/assertionData.js +++ b/src/utils/latl/test/assertionData.js @@ -228,7 +228,17 @@ set NASAL_PULMONIC_CONSONANTS, N = [ m̥, m, ɱ, n̼, n̥, n, ɳ̊, { type: 'phone', value: 'ɴ' }, { type: 'whiteSpace', value: ' ' }, { type: 'closeSquareBracket', value: ']' }, - ] + ], + AST: { + main: [ + { + type: 'set', + setIdentifier: 'NASAL_PULMONIC_CONSONANTS', + setAlias: 'N', + setExpression: [ 'm̥', 'm', 'ɱ', 'n̼', 'n̥', 'n', 'ɳ̊', 'ɳ', 'ɲ̊', 'ɲ', 'ŋ', '̊ŋ', 'ɴ' ] + } + ] + } }, setDefinitionJoin: { latl: ` diff --git a/src/utils/latl/test/parser.test.js b/src/utils/latl/test/parser.test.js index ce36f87..71c7b25 100644 --- a/src/utils/latl/test/parser.test.js +++ b/src/utils/latl/test/parser.test.js @@ -24,12 +24,12 @@ describe('parser', () => { expect(feedResults[0]).toStrictEqual(AST); }); - it.todo('lexes set definition with alias' - // , () => { - // const { latl, tokens } = assertionData.setAliasDefinition; - // const stream = getStream(latl); - // expect(stream).toStrictEqual(tokens); - // } + it('lexes set definition with alias' + , () => { + const { latl, AST } = assertionData.setAliasDefinition; + const feedResults = parser().feed(latl).results; + expect(feedResults[0]).toStrictEqual(AST); + } ); it.todo('lexes set definition with set join'