From 97cf99c730084af06d77bf6432baad3a705e935e Mon Sep 17 00:00:00 2001 From: Lars Willighagen Date: Sat, 4 Jan 2025 22:21:33 +0100 Subject: [PATCH] fix(parser): update optional whitespace limitations --- src/parser/base.js | 72 +++++++++++++++++++++++++++ src/parser/kdl.js | 105 +++++++++++---------------------------- test/kdl/node_spaces.kdl | 12 +++++ test/suite.json | 14 ++++++ 4 files changed, 126 insertions(+), 77 deletions(-) create mode 100644 test/kdl/node_spaces.kdl diff --git a/src/parser/base.js b/src/parser/base.js index 6eac00d..b0871f7 100644 --- a/src/parser/base.js +++ b/src/parser/base.js @@ -70,7 +70,9 @@ class BaseParser extends EmbeddedActionsParser { */ this.RULE('tag', () => { this.CONSUME(Tokens.LeftParenthesis) + this.OPTION(() => this.SUBRULE(this.nodeSpace)) const tag = this.SUBRULE(this.string) + this.OPTION1(() => this.SUBRULE1(this.nodeSpace)) this.CONSUME(Tokens.RightParenthesis) return tag }) @@ -206,6 +208,76 @@ class BaseParser extends EmbeddedActionsParser { return String.fromCharCode(codepoint) }) + + /** + * Consume node space + * @method #nodeSpace + * @memberof module:kdljs.parser.kdl.BaseParser + */ + this.RULE('nodeSpace', () => { + this.AT_LEAST_ONE(() => this.OR([ + { ALT: () => this.SUBRULE(this.whiteSpace) }, + { ALT: () => this.SUBRULE(this.lineContinuation) } + ])) + }) + + /** + * Consume a line continuation + * @method #lineContinuation + * @memberof module:kdljs.parser.kdl.BaseParser + */ + this.RULE('lineContinuation', () => { + this.CONSUME(Tokens.EscLine) + this.OPTION(() => this.SUBRULE(this.whiteSpace)) + this.OR([ + { ALT: () => this.SUBRULE(this.lineComment) }, + { ALT: () => this.CONSUME(Tokens.NewLine) }, + { ALT: () => this.CONSUME(Tokens.EOF) } + ]) + }) + + /** + * Consume a line comment + * @method #lineComment + * @memberof module:kdljs.parser.kdl.BaseParser + */ + this.RULE('lineComment', () => { + this.CONSUME(Tokens.LineComment) + this.OR([ + { ALT: () => this.CONSUME(Tokens.NewLine) }, + { ALT: () => this.CONSUME(Tokens.EOF) } + ]) + }) + + /** + * Consume a multiline comment + * @method #multilineComment + * @memberof module:kdljs.parser.kdl.BaseParser + */ + this.RULE('multilineComment', () => { + this.CONSUME(Tokens.OpenMultiLineComment) + this.MANY(() => { + this.OR([ + { ALT: () => this.CONSUME(Tokens.MultiLineCommentContent) }, + { ALT: () => this.SUBRULE(this.multilineComment) } + ]) + }) + this.CONSUME(Tokens.CloseMultiLineComment) + }) + + /** + * Consume whitespace + * @method #whiteSpace + * @memberof module:kdljs.parser.kdl.BaseParser + */ + this.RULE('whiteSpace', () => { + this.AT_LEAST_ONE(() => { + this.OR([ + { ALT: () => this.CONSUME(Tokens.WhiteSpace) }, + { ALT: () => this.SUBRULE(this.multilineComment) } + ]) + }) + }) } /** diff --git a/src/parser/kdl.js b/src/parser/kdl.js index 3f9fdb4..d41fb1e 100644 --- a/src/parser/kdl.js +++ b/src/parser/kdl.js @@ -83,13 +83,11 @@ class KdlParser extends BaseParser { { ALT: () => { this.CONSUME(Tokens.BlockComment) - this.OPTION1(() => this.SUBRULE(this.nodeSpace)) + this.OPTION1(() => this.SUBRULE(this.lineSpace)) this.SUBRULE(this.node) } }, - { ALT: () => this.SUBRULE(this.lineComment) }, - { ALT: () => this.SUBRULE(this.whiteSpace) }, - { ALT: () => this.CONSUME(Tokens.NewLine) }, + { ALT: () => this.SUBRULE1(this.lineSpace) }, { ALT: () => nodes.push(this.SUBRULE1(this.node)) } ])) @@ -104,7 +102,11 @@ class KdlParser extends BaseParser { */ this.RULE('node', () => { const tags = { - name: this.OPTION(() => this.SUBRULE(this.tag)), + name: this.OPTION(() => { + const tag = this.SUBRULE(this.tag) + this.OPTION1(() => this.SUBRULE(this.nodeSpace)) + return tag + }), properties: {}, values: [] } @@ -113,11 +115,11 @@ class KdlParser extends BaseParser { const values = [] this.MANY(() => { - this.SUBRULE(this.nodeSpace) + this.SUBRULE1(this.nodeSpace) - const commented = this.OPTION1(() => { + const commented = this.OPTION2(() => { this.CONSUME(Tokens.BlockComment) - this.OPTION2(() => this.SUBRULE1(this.nodeSpace)) + this.OPTION3(() => this.SUBRULE(this.lineSpace)) return true }) @@ -150,7 +152,7 @@ class KdlParser extends BaseParser { this.SUBRULE(this.nodeChildrenSlashdash) }) - const children = this.OPTION3(() => { + const children = this.OPTION4(() => { this.SUBRULE3(this.nodeSpace) const children = this.SUBRULE(this.nodeChildren) return children @@ -161,7 +163,7 @@ class KdlParser extends BaseParser { this.SUBRULE1(this.nodeChildrenSlashdash) }) - this.OPTION4(() => this.SUBRULE5(this.nodeSpace)) + this.OPTION5(() => this.SUBRULE5(this.nodeSpace)) if (this.LA(1).tokenType !== Tokens.RightBrace) { this.SUBRULE(this.nodeTerminator) @@ -177,7 +179,7 @@ class KdlParser extends BaseParser { */ this.RULE('nodeChildrenSlashdash', () => { this.CONSUME(Tokens.BlockComment) - this.OPTION(() => this.SUBRULE(this.nodeSpace)) + this.OPTION(() => this.SUBRULE(this.lineSpace)) this.SUBRULE(this.nodeChildren) }) @@ -185,11 +187,13 @@ class KdlParser extends BaseParser { * Consume a property * @method #property * @memberof module:kdljs.parser.kdl.KdlParser - * @return {Array} key-value pair + * @return {[string, module:kdljs~Value>, string]} key-value-type tuple */ this.RULE('property', () => { const key = this.SUBRULE(this.string) + this.OPTION(() => this.SUBRULE(this.nodeSpace)) this.CONSUME(Tokens.Equals) + this.OPTION1(() => this.SUBRULE1(this.nodeSpace)) const parts = this.SUBRULE(this.taggedValue) return [key, parts[0], parts[1]] }) @@ -198,10 +202,14 @@ class KdlParser extends BaseParser { * Consume a tagged value * @method #taggedValue * @memberof module:kdljs.parser.kdl.KdlParser - * @return {module:kdljs~Value} + * @return {[module:kdljs~Value, string]} value-type tuple */ this.RULE('taggedValue', () => { - const tag = this.OPTION(() => this.SUBRULE(this.tag)) + const tag = this.OPTION(() => { + const tag = this.SUBRULE(this.tag) + this.OPTION1(() => this.SUBRULE(this.nodeSpace)) + return tag + }) const value = this.SUBRULE(this.value) return [value, tag] }) @@ -220,30 +228,16 @@ class KdlParser extends BaseParser { }) /** - * Consume node space - * @method #nodeSpace + * Consume line space + * @method #lineSpace * @memberof module:kdljs.parser.kdl.KdlParser */ - this.RULE('nodeSpace', () => { + this.RULE('lineSpace', () => { this.AT_LEAST_ONE(() => this.OR([ - { ALT: () => this.SUBRULE(this.whiteSpace) }, - { ALT: () => this.SUBRULE(this.lineContinuation) } - ])) - }) - - /** - * Consume a line continuation - * @method #lineContinuation - * @memberof module:kdljs.parser.kdl.KdlParser - */ - this.RULE('lineContinuation', () => { - this.CONSUME(Tokens.EscLine) - this.OPTION(() => this.SUBRULE1(this.whiteSpace)) - this.OPTION1(() => this.CONSUME(Tokens.LineComment)) - this.OR([ + { ALT: () => this.SUBRULE(this.nodeSpace) }, { ALT: () => this.CONSUME(Tokens.NewLine) }, - { ALT: () => this.CONSUME(Tokens.EOF) } - ]) + { ALT: () => this.SUBRULE(this.lineComment) } + ])) }) /** @@ -260,49 +254,6 @@ class KdlParser extends BaseParser { ]) }) - /** - * Consume a line comment - * @method #lineComment - * @memberof module:kdljs.parser.kdl.KdlParser - */ - this.RULE('lineComment', () => { - this.CONSUME(Tokens.LineComment) - this.OR([ - { ALT: () => this.CONSUME(Tokens.NewLine) }, - { ALT: () => this.CONSUME(Tokens.EOF) } - ]) - }) - - /** - * Consume a multiline comment - * @method #multilineComment - * @memberof module:kdljs.parser.kdl.KdlParser - */ - this.RULE('multilineComment', () => { - this.CONSUME(Tokens.OpenMultiLineComment) - this.MANY(() => { - this.OR([ - { ALT: () => this.CONSUME(Tokens.MultiLineCommentContent) }, - { ALT: () => this.SUBRULE(this.multilineComment) } - ]) - }) - this.CONSUME(Tokens.CloseMultiLineComment) - }) - - /** - * Consume whitespace - * @method #whiteSpace - * @memberof module:kdljs.parser.kdl.KdlParser - */ - this.RULE('whiteSpace', () => { - this.AT_LEAST_ONE(() => { - this.OR([ - { ALT: () => this.CONSUME(Tokens.WhiteSpace) }, - { ALT: () => this.SUBRULE(this.multilineComment) } - ]) - }) - }) - this.performSelfAnalysis() } } diff --git a/test/kdl/node_spaces.kdl b/test/kdl/node_spaces.kdl new file mode 100644 index 0000000..002e247 --- /dev/null +++ b/test/kdl/node_spaces.kdl @@ -0,0 +1,12 @@ +(\ +tag )\ +/* + +*/ node prop /* + +*/\ + = (\ +tag )\ // comment +/* + +*/ value diff --git a/test/suite.json b/test/suite.json index 30cd475..cb7ed10 100644 --- a/test/suite.json +++ b/test/suite.json @@ -54,5 +54,19 @@ "name": "node", "children": [{ "name": "foo" }, { "name": "bar" }] } + ], + "node_spaces": [ + { + "name": "node", + "properties": { + "prop": "value" + }, + "tags": { + "name": "tag", + "properties": { + "prop": "tag" + } + } + } ] }