From e2104898d7d7c2999d64588f1803c7c8e4c5e913 Mon Sep 17 00:00:00 2001 From: Roman Dvornov Date: Wed, 25 Oct 2023 01:15:43 +0200 Subject: [PATCH] Remove support for a legacy syntax for functions --- CHANGELOG.md | 1 + src/compile-modules/lang/grammar.cjs | 13 +-- src/compile-modules/lang/nodes.cjs | 5 +- src/compile-modules/lang/parse-patch.cjs | 8 -- test/helpers/all-syntax.js | 2 +- test/lang/function.js | 138 ----------------------- test/suggestions.js | 11 -- test/syntax/parse.js | 4 +- 8 files changed, 7 insertions(+), 175 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9b3b6c..0536b4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## next +- Removed support for a legacy syntax for functions, i.e. `` - Disallowed whitespace between a method name and open parenthesis - Allowed keywords as a property getter in query chains when a dot is before the keyword. For example, `.has.and.is` is now a valid query, while `has.and` is not valid due to the missing dot before `has`. - Added support for keyword literals (`null`, `undefined`, `true`, `false`, `NaN` and `Infinity`), numbers and strings as property name in an object literal when a value is not specified, i.e. `{ null }` is the same as `{ "null": $["null"] }` diff --git a/src/compile-modules/lang/grammar.cjs b/src/compile-modules/lang/grammar.cjs index 58fe476..b850cd9 100644 --- a/src/compile-modules/lang/grammar.cjs +++ b/src/compile-modules/lang/grammar.cjs @@ -264,10 +264,6 @@ exports.lex = { // functions ['=>', 'return "FUNCTION";'], - ['<(?!=)', function() { - this.fnOpened++; - return 'FUNCTION_START'; - }], // operators ['=', 'return "=";'], @@ -276,13 +272,7 @@ exports.lex = { ['>=', 'return ">=";'], ['<=', 'return "<=";'], ['<', 'return "<";'], - ['>', function() { - if (this.fnOpened) { - this.fnOpened--; - return 'FUNCTION_END'; - } - return '>'; - }], + ['>', 'return ">";'], ['\\.\\.\\(', 'return "..(";'], ['\\.\\(', 'return ".(";'], ['\\.\\[', 'return ".[";'], @@ -377,7 +367,6 @@ exports.bnf = { ['query', asis], // functions - ['FUNCTION_START block FUNCTION_END', $$(Function([], $2, true))], ['FUNCTION e', $$(Function([], $2))], ['compareFunction', $$(CompareFunction($1))], diff --git a/src/compile-modules/lang/nodes.cjs b/src/compile-modules/lang/nodes.cjs index 61760bf..13d401d 100644 --- a/src/compile-modules/lang/nodes.cjs +++ b/src/compile-modules/lang/nodes.cjs @@ -87,12 +87,11 @@ exports.Filter = function(value, query) { query }; }; -exports.Function = function(args, body, legacy) { +exports.Function = function(args, body) { return { type: 'Function', arguments: args, - body, - legacy: Boolean(legacy) + body }; }; exports.GetProperty = function(value, property) { diff --git a/src/compile-modules/lang/parse-patch.cjs b/src/compile-modules/lang/parse-patch.cjs index 316a1dc..23ef6e7 100644 --- a/src/compile-modules/lang/parse-patch.cjs +++ b/src/compile-modules/lang/parse-patch.cjs @@ -12,8 +12,6 @@ module.exports = function buildParsers(strictParser) { ['EOF', ['']], ['IDENT', ['ident']], ['$IDENT', ['$ident']], - ['FUNCTION_START', ["'<'"]], - ['FUNCTION_END', ["'>'"]], ['FUNCTION', ["'=>'"]], ['NOT', ["'not'"]], ['NO', ["'no'"]], @@ -230,8 +228,6 @@ module.exports = function buildParsers(strictParser) { } }; - this.fnOpened = 0; - this.fnOpenedStack = []; this.bracketStack = []; this.prevToken = null; this.prevYylloc = { @@ -386,14 +382,10 @@ module.exports = function buildParsers(strictParser) { if (expected !== token) { this.parseError(`Expected "${expected}" got "${token}"`); } - - this.fnOpened = this.fnOpenedStack.pop() || 0; } if (openBalance.has(token)) { this.bracketStack.push(openBalance.get(token)); - this.fnOpenedStack.push(this.fnOpened); - this.fnOpened = 0; } return token; diff --git a/test/helpers/all-syntax.js b/test/helpers/all-syntax.js index 732733d..9652a49 100644 --- a/test/helpers/all-syntax.js +++ b/test/helpers/all-syntax.js @@ -1,6 +1,6 @@ export default [ '$foo:true;$a:false;$c;$;$d:d.e;$f:$["f"];', - 'bar([#,@,null,undefined,Infinity,NaN,not $,no $,1,"2\'\\"",/3/i,/asd/],{a:3,$b,$,c,$d:1,"asd":3,["asd"+x]:3,...,...$,...foo,...(a+5)},,', + 'bar([#,@,null,undefined,Infinity,NaN,not $,no $,1,"2\'\\"",/3/i,/asd/],{a:3,$b,$,c,$d:1,"asd":3,["asd"+x]:3,...,...$,...foo,...(a+5)},', '`template`,`temp${1}late`,`te${1+1}mp${{a:3}["a"]+`xxx${42}xxx`}late`,`${1}${2} ${3}${4} ${5}${6}`,`${} ${} ${}`,', '[...,...$,...1+1],', 'x?1 in xx():2,sort((($x;$x+b)*7) asc,b desc)).(a.[foo]).x($[a+"asd"],$[foo])', diff --git a/test/lang/function.js b/test/lang/function.js index 1e6b8c1..56aaa80 100644 --- a/test/lang/function.js +++ b/test/lang/function.js @@ -1,144 +1,6 @@ import assert from 'assert'; import query from 'jora'; -describe('lang/function (legacy)', () => { - it('empty function', () => { - assert.strictEqual( - typeof query('<>')(), - 'function' - ); - }); - - it('body is a query', () => { - assert.strictEqual( - typeof query('')(), - 'function' - ); - }); - - it('allow definitions in a function', () => { - assert.strictEqual( - query('map(<$a;$a>)')({ a: 42 }), - 42 - ); - }); - - it('body is an empty object', () => { - assert.deepEqual( - query('<{}>')()(), - {} - ); - }); - - it('body is an object with a single key', () => { - assert.deepEqual( - query('<{foo:1}>')()(), - { foo: 1 } - ); - }); - - it('body is an object with a couple keys', () => { - assert.deepEqual( - query('<{foo:1,bar:2}>')()(), - { foo: 1, bar: 2 } - ); - }); - - it('body is an expression', () => { - assert.strictEqual( - typeof query('')(), - 'function' - ); - }); - - it('body is an expression #2', () => { - assert.strictEqual( - query('map()')({ foo: true }), - 1 - ); - }); - - it('body is an expression with `>` operator', () => { - assert.strictEqual( - typeof query('<(a > b)>')(), - 'function' - ); - - assert.strictEqual( - query('map(<(a > b)>)')({ a: 1, b: 2 }), - false - ); - - assert.strictEqual( - query('map(<(a > b)>)')({ a: 2, b: 1 }), - true - ); - - assert.deepEqual( - query('map(<{ test: a.size() > 2 }>)')([{ a: [2, 3] }, { a: [1, 2, 3] }]), - [{ test: false }, { test: true }] - ); - - assert.deepEqual( - query('map( 2]>)')([{ a: [2, 3] }, { a: [1, 5, 2] }]), - [3, 5] - ); - - assert.deepEqual( - query('map( 2)>)')([{ a: [2, 3] }, { a: [1, 5, 2] }]), - [false, true] - ); - - assert.deepEqual( - query('map( 2)>)')([{ a: [2, 3] }, { a: [1, 5, 2] }]), - [false, true] - ); - - assert.deepEqual( - query('map( 2]>)')([{ a: { true: 1, false: 2 }, b: 1 }, { a: { true: 3, false: 4 }, b: 3 }]), - [2, 3] - ); - }); - - it('body is an expression with `<` operator', () => { - assert.strictEqual( - typeof query('')(), - 'function' - ); - - assert.strictEqual( - query('map()')({ a: 1, b: 2 }), - true - ); - - assert.strictEqual( - query('map()')({ a: 2, b: 1 }), - false - ); - }); - - it('body is an expression with `<` and `>` operators', () => { - assert.strictEqual( - typeof query('<$ < 10 or ($ > 20)>')(), - 'function' - ); - }); - - it('body is an expression with `<` and `>` operators with map()', () => { - assert.deepEqual( - [5, 15, 25].map(value => query('map(<$ < 10 or ($ > 20)>)')(value)), - [true, false, true] - ); - }); - - it('nested functions', () => { - assert.deepEqual( - query('map(<>)')([1, 2]).map(value => typeof value), - ['function', 'function'] - ); - }); -}); - describe('lang/function', () => { it('empty function', () => { assert.strictEqual( diff --git a/test/suggestions.js b/test/suggestions.js index 864d6e6..6768d8f 100644 --- a/test/suggestions.js +++ b/test/suggestions.js @@ -249,17 +249,6 @@ describe('query/suggestions', () => { ); }); - it('function context old syntax <...>', () => { - assert.deepEqual( - suggestQuery('map(|<|>|)', data), - [ - null, - suggestion('', ['foo', 'bar'], 5, 5), - null - ] - ); - }); - it('function context', () => { assert.deepEqual( suggestQuery('map(|=|>|)', data), diff --git a/test/syntax/parse.js b/test/syntax/parse.js index d8cfaa1..4cc3b9d 100644 --- a/test/syntax/parse.js +++ b/test/syntax/parse.js @@ -45,10 +45,10 @@ describe('syntax/parse', () => { () => parse('foo\n .[bar =]'), function(e) { assert.deepEqual(e.details, { - rawMessage: "Parse error on line 2:\nfoo\\n .[bar =]\n-------------^\nExpecting '$', 'IDENT', '$IDENT', '?', 'FUNCTION_START', 'FUNCTION', 'NOT', 'NO', '-', '+', 'IS', '@', '#', '$$', 'STRING', 'NUMBER', 'REGEXP', 'LITERAL', '[', '(', '.', '.(', '.[', '..', '..(', 'METHOD(', '$METHOD(', 'TEMPLATE', 'TPL_START', '{', got ']'", + rawMessage: "Parse error on line 2:\nfoo\\n .[bar =]\n-------------^\nExpecting '$', 'IDENT', '$IDENT', '?', 'FUNCTION', 'NOT', 'NO', '-', '+', 'IS', '@', '#', '$$', 'STRING', 'NUMBER', 'REGEXP', 'LITERAL', '[', '(', '.', '.(', '.[', '..', '..(', 'METHOD(', '$METHOD(', 'TEMPLATE', 'TPL_START', '{', got ']'", text: ']', token: ']', - expected: ["'$'", 'ident', '$ident', "'?'", "'<'", "'=>'", "'not'", "'no'", "'-'", "'+'", "'is'", "'@'", "'#'", "'$$'", 'string', 'number', 'regexp', "'true'", "'false'", "'null'", "'undefined'", "'NaN'", "'Infinity'", "'['", "'('", "'.'", "'.('", "'.['", "'..'", "'..('", "'method('", "'$method('", 'template', "'{'"], + expected: ["'$'", 'ident', '$ident', "'?'", "'=>'", "'not'", "'no'", "'-'", "'+'", "'is'", "'@'", "'#'", "'$$'", 'string', 'number', 'regexp', "'true'", "'false'", "'null'", "'undefined'", "'NaN'", "'Infinity'", "'['", "'('", "'.'", "'.('", "'.['", "'..'", "'..('", "'method('", "'$method('", 'template', "'{'"], loc: { range: [12, 13], start: {