From 4588113c41137d395771ccce8f7c55573a74800b Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Tue, 8 Dec 2020 16:04:37 +0000 Subject: [PATCH 1/7] Implement initial tagged template parsing support --- src/babel/__snapshots__/plugin.test.js.snap | 66 ++++++++++----------- src/codegen.js | 58 +++++++++--------- src/core.js | 46 +++++++++----- src/core.test.js | 6 +- 4 files changed, 97 insertions(+), 79 deletions(-) diff --git a/src/babel/__snapshots__/plugin.test.js.snap b/src/babel/__snapshots__/plugin.test.js.snap index 9f3d94d..414d292 100644 --- a/src/babel/__snapshots__/plugin.test.js.snap +++ b/src/babel/__snapshots__/plugin.test.js.snap @@ -9,21 +9,21 @@ var _node_expression = (0, _reghex._pattern)(1), _node_expression2 = (0, _reghex._pattern)(2); const node = function (state) { - var idx1 = state.index; + var y1 = state.y; var node = []; var x; if (x = (0, _reghex._exec)(state, _node_expression)) { node.push(x); } else { - state.index = idx1; + state.y = y1; return; } if (x = (0, _reghex._exec)(state, _node_expression2)) { node.push(x); } else { - state.index = idx1; + state.y = y1; return; } @@ -43,14 +43,14 @@ exports[`works with local recursion 1`] = ` var _inner_expression = _pattern(/inner/); const inner = function (state) { - var idx1 = state.index; + var y1 = state.y; var node = []; var x; if (x = _exec(state, _inner_expression)) { node.push(x); } else { - state.index = idx1; + state.y = y1; return; } @@ -59,14 +59,14 @@ const inner = function (state) { }; const node = function (state) { - var idx1 = state.index; + var y1 = state.y; var node = []; var x; if (x = inner(state)) { node.push(x); } else { - state.index = idx1; + state.y = y1; return; } @@ -83,14 +83,14 @@ var _node_expression = _pattern(1), _node_expression3 = _pattern(3); const node = function (state) { - var idx1 = state.index; + var y1 = state.y; var node = []; var x; if (x = _exec(state, _node_expression)) { node.push(x); } else { - state.index = idx1; + state.y = y1; return; } @@ -98,12 +98,12 @@ const node = function (state) { alt_3: { block_3: { - var idx3 = state.index; + var y3 = state.y; if (x = _exec(state, _node_expression2)) { node.push(x); } else { - state.index = idx3; + state.y = y3; node.length = ln2; break block_3; } @@ -112,15 +112,15 @@ const node = function (state) { } loop_3: for (var j3 = 0; 1; j3++) { - var idx3 = state.index; + var y3 = state.y; if (!_exec(state, _node_expression3)) { if (j3) { - state.index = idx3; + state.y = y3; break loop_3; } else {} - state.index = idx1; + state.y = y1; node.length = ln2; return; } @@ -136,14 +136,14 @@ exports[`works with self-referential thunks 1`] = ` "import { match, tag, _exec, _pattern } from 'reghex'; const inner = function (state) { - var idx1 = state.index; + var y1 = state.y; var node = []; var x; if (x = node(state)) { node.push(x); } else { - state.index = idx1; + state.y = y1; return; } @@ -152,14 +152,14 @@ const inner = function (state) { }; const node = function (state) { - var idx1 = state.index; + var y1 = state.y; var node = []; var x; if (x = inner(state)) { node.push(x); } else { - state.index = idx1; + state.y = y1; return; } @@ -178,26 +178,26 @@ var _node_expression = _pattern(1), _node_expression5 = _pattern(5); const node = function (state) { - var idx1 = state.index; + var y1 = state.y; var node = []; var x; alt_2: { block_2: { - var idx2 = state.index; + var y2 = state.y; loop_2: for (var j2 = 0; 1; j2++) { - var idx2 = state.index; + var y2 = state.y; if (x = _exec(state, _node_expression)) { node.push(x); } else { if (j2) { - state.index = idx2; + state.y = y2; break loop_2; } else {} - state.index = idx2; + state.y = y2; break block_2; } } @@ -206,45 +206,45 @@ const node = function (state) { } loop_2: for (var j2 = 0; 1; j2++) { - var idx2 = state.index; + var y2 = state.y; if (x = _exec(state, _node_expression2)) { node.push(x); } else { if (j2) { - state.index = idx2; + state.y = y2; break loop_2; } else {} - state.index = idx1; + state.y = y1; return; } } loop_2: for (;;) { - var idx2 = state.index; + var y2 = state.y; var ln2 = node.length; if (x = _exec(state, _node_expression3)) { node.push(x); } else { - state.index = idx2; + state.y = y2; node.length = ln2; break loop_2; } - var idx4 = state.index; + var y4 = state.y; if (x = _exec(state, _node_expression4)) { node.push(x); } else { - state.index = idx4; + state.y = y4; } if (x = _exec(state, _node_expression5)) { node.push(x); } else { - state.index = idx2; + state.y = y2; node.length = ln2; break loop_2; } @@ -262,7 +262,7 @@ exports[`works with transform functions 1`] = ` var _inner_transform = x => x; const first = function (state) { - var idx1 = state.index; + var y1 = state.y; var node = []; var x; node.tag = 'inner'; @@ -272,7 +272,7 @@ const first = function (state) { const transform = x => x; const second = function (state) { - var idx1 = state.index; + var y1 = state.y; var node = []; var x; node.tag = 'node'; diff --git a/src/codegen.js b/src/codegen.js index ee2e831..9e37fe1 100644 --- a/src/codegen.js +++ b/src/codegen.js @@ -3,6 +3,8 @@ const _state = 'state'; const _node = 'node'; const _match = 'x'; +let _interpolations = 0; + function js(/* arguments */) { let body = arguments[0][0]; for (let i = 1; i < arguments.length; i++) @@ -17,19 +19,12 @@ const copy = (prev) => { }; const assignIndex = (depth) => - depth ? js`var idx${depth} = ${_state}.index;` : ''; + js`var y${depth} = ${_state}.y` + + (_interpolations ? js`, var x${depth} = ${_state}.x;` : ';'); const restoreIndex = (depth) => - depth ? js`${_state}.index = idx${depth};` : ''; - -const abortOnCondition = (condition, hooks) => js` - if (${condition}) { - ${restoreIndex(opts.index)} - ${opts.abort} - } else { - ${opts.onAbort} - } -`; + js`${_state}.y = y${depth}` + + (_interpolations ? js`, ${_state}.x = x${depth};` : ';'); const astExpression = (ast, depth, opts) => { const restoreLength = @@ -200,23 +195,28 @@ const astSequence = (ast, depth, opts) => { `; }; -const astRoot = (ast, name, transform) => js` - (function (${_state}) { - ${assignIndex(1)} - var ${_node} = []; - var ${_match}; - - ${astSequence(ast, 2, { - index: 1, - length: 0, - onAbort: '', - abort: js`return;`, - capture: true, - })} - - ${_node}.tag = ${name}; - return ${transform ? js`(${transform})(${_node})` : _node}; - }) -`; +const astRoot = (ast, name, transform, interpolations) => { + _interpolations = interpolations; + + return js` + (function (${_state}) { + ${assignIndex(1)} + var ${_node} = []; + var ${_match}; + + ${astSequence(ast, 2, { + interpolations, + index: 1, + length: 0, + onAbort: '', + abort: js`return;`, + capture: true, + })} + + ${_node}.tag = ${name}; + return ${transform ? js`(${transform})(${_node})` : _node}; + }) + `; +}; export { astRoot }; diff --git a/src/core.js b/src/core.js index e70cd13..dadd118 100644 --- a/src/core.js +++ b/src/core.js @@ -19,36 +19,54 @@ export const _exec = (state, pattern) => { return pattern(state); } - pattern.lastIndex = state.index; + const input = state.quasis[state.x]; + if (input && (pattern.lastIndex = state.y) < input.length) { + if (isStickySupported) { + if (pattern.test(input)) match = input.slice(state.y, pattern.lastIndex); + } else { + match = pattern.exec(input)[0] || match; + } + } + + state.y = pattern.lastIndex; + return match; +}; - if (isStickySupported) { - if (pattern.test(state.input)) - match = state.input.slice(state.index, pattern.lastIndex); - } else { - match = pattern.exec(state.input)[0] || match; +export const interpolation = (state) => { + let match; + + const input = state.quasis[state.x]; + if (!input || state.y >= input.length) { + state.y = 0; + match = state.expressions[state.x++] || match; } - state.index = pattern.lastIndex; return match; }; -export const parse = (pattern) => (input) => { - const state = { input, index: 0 }; +export const parse = (pattern) => (quasis, ...expressions) => { + if (typeof quasis === 'string') quasis = [quasis]; + const state = { quasis, expressions, x: 0, y: 0 }; return pattern(state); }; export const match = (name, transform) => (quasis, ...expressions) => { + let interpolations = 0; + const ast = parseDSL( quasis, - expressions.map((expression, i) => ({ - fn: typeof expression === 'function' && expression.length, - id: `_${i}`, - })) + expressions.map((expression, i) => { + if (expression === interpolation) interpolations++; + return { + fn: typeof expression === 'function' && expression.length, + id: `_${i}`, + }; + }) ); const makeMatcher = new Function( execId + ',_n,_t,' + expressions.map((_expression, i) => `_${i}`).join(','), - 'return ' + astRoot(ast, '_n', transform ? '_t' : null) + 'return ' + astRoot(ast, '_n', transform ? '_t' : null, interpolations) ); return makeMatcher(_exec, name, transform, ...expressions.map(_pattern)); diff --git a/src/core.test.js b/src/core.test.js index 01fc85e..5013c3f 100644 --- a/src/core.test.js +++ b/src/core.test.js @@ -1,17 +1,17 @@ import { match } from './core'; const expectToParse = (node, input, result, lastIndex = 0) => { - const state = { input, index: 0 }; + const state = { quasis: [input], expressions: [], x: 0, y: 0 }; if (result) result.tag = 'node'; expect(node(state)).toEqual(result); // NOTE: After parsing we expect the current index to exactly match the // sum amount of matched characters if (result === undefined) { - expect(state.index).toBe(0); + expect(state.y).toBe(0); } else { const index = lastIndex || result.reduce((acc, x) => acc + x.length, 0); - expect(state.index).toBe(index); + expect(state.y).toBe(index); } }; -- knotmirror 0.0.1 From 284724d603719cb1ab32b308a44ced5a7945774c Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Tue, 8 Dec 2020 16:05:52 +0000 Subject: [PATCH 2/7] Simplify output of astExpression(...) generator --- src/babel/__snapshots__/plugin.test.js.snap | 2 +- src/codegen.js | 23 +++++---------------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/src/babel/__snapshots__/plugin.test.js.snap b/src/babel/__snapshots__/plugin.test.js.snap index 414d292..c872450 100644 --- a/src/babel/__snapshots__/plugin.test.js.snap +++ b/src/babel/__snapshots__/plugin.test.js.snap @@ -114,7 +114,7 @@ const node = function (state) { loop_3: for (var j3 = 0; 1; j3++) { var y3 = state.y; - if (!_exec(state, _node_expression3)) { + if (x = _exec(state, _node_expression3)) {} else { if (j3) { state.y = y3; break loop_3; diff --git a/src/codegen.js b/src/codegen.js index 9e37fe1..8f032ef 100644 --- a/src/codegen.js +++ b/src/codegen.js @@ -30,31 +30,18 @@ const astExpression = (ast, depth, opts) => { const restoreLength = (opts.length && opts.abort && js`${_node}.length = ln${opts.length};`) || ''; - - const abort = js` - ${opts.onAbort} - ${restoreIndex(opts.index)} - ${restoreLength} - ${opts.abort} - `; - const expression = ast.expression.fn ? `${ast.expression.id}(${_state})` : `${_exec}(${_state}, ${ast.expression.id})`; - if (!opts.capture) { - return js` - if (!${expression}) { - ${abort} - } - `; - } - return js` if (${_match} = ${expression}) { - ${_node}.push(${_match}); + ${opts.capture ? js`${_node}.push(${_match})` : ''} } else { - ${abort} + ${opts.onAbort} + ${restoreIndex(opts.index)} + ${restoreLength} + ${opts.abort} } `; }; -- knotmirror 0.0.1 From 3fe908abbab6ddf61e8dc3aca662c7fcec440b31 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Tue, 8 Dec 2020 16:11:08 +0000 Subject: [PATCH 3/7] Add basic test case for interpolations --- src/codegen.js | 3 +-- src/core.test.js | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/codegen.js b/src/codegen.js index 8f032ef..83c1d23 100644 --- a/src/codegen.js +++ b/src/codegen.js @@ -20,7 +20,7 @@ const copy = (prev) => { const assignIndex = (depth) => js`var y${depth} = ${_state}.y` + - (_interpolations ? js`, var x${depth} = ${_state}.x;` : ';'); + (_interpolations ? js`, x${depth} = ${_state}.x;` : ';'); const restoreIndex = (depth) => js`${_state}.y = y${depth}` + @@ -52,7 +52,6 @@ const astGroup = (ast, depth, opts) => { opts = copy(opts); opts.capture = capture; - let group = ''; if (!opts.length && capture) { opts.length = depth; return js` diff --git a/src/core.test.js b/src/core.test.js index 5013c3f..1472bb8 100644 --- a/src/core.test.js +++ b/src/core.test.js @@ -1,4 +1,4 @@ -import { match } from './core'; +import { parse, match, interpolation } from './core'; const expectToParse = (node, input, result, lastIndex = 0) => { const state = { quasis: [input], expressions: [], x: 0, y: 0 }; @@ -552,3 +552,19 @@ describe('negative lookahead group with plus group and required matcher', () => } ); }); + +describe('interpolation parsing', () => { + const node = match('node')` + ${/1/} + ${interpolation} + ${/3/} + `; + + const expected = ['1', 2, '3']; + expected.tag = 'node'; + + expect(parse(node)`1${2}3`).toEqual(expected); + expect(parse(node)`13`).toBe(undefined); + expect(parse(node)`13${2}`).toBe(undefined); + expect(parse(node)`${2}13`).toBe(undefined); +}); -- knotmirror 0.0.1 From 2f2cc66ad8505638f7382ddebcde5694a3cbc692 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Tue, 8 Dec 2020 16:35:33 +0000 Subject: [PATCH 4/7] Remove interpolations exception from codegen --- src/codegen.js | 21 +++++++++------------ src/core.js | 18 +++++++----------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/codegen.js b/src/codegen.js index 83c1d23..bed79bb 100644 --- a/src/codegen.js +++ b/src/codegen.js @@ -3,8 +3,6 @@ const _state = 'state'; const _node = 'node'; const _match = 'x'; -let _interpolations = 0; - function js(/* arguments */) { let body = arguments[0][0]; for (let i = 1; i < arguments.length; i++) @@ -18,13 +16,15 @@ const copy = (prev) => { return next; }; -const assignIndex = (depth) => - js`var y${depth} = ${_state}.y` + - (_interpolations ? js`, x${depth} = ${_state}.x;` : ';'); +const assignIndex = (depth) => js` + var y${depth} = ${_state}.y, + x${depth} = ${_state}.x; +`; -const restoreIndex = (depth) => - js`${_state}.y = y${depth}` + - (_interpolations ? js`, ${_state}.x = x${depth};` : ';'); +const restoreIndex = (depth) => js` + ${_state}.y = y${depth}; + ${_state}.x = x${depth}; +`; const astExpression = (ast, depth, opts) => { const restoreLength = @@ -181,9 +181,7 @@ const astSequence = (ast, depth, opts) => { `; }; -const astRoot = (ast, name, transform, interpolations) => { - _interpolations = interpolations; - +const astRoot = (ast, name, transform) => { return js` (function (${_state}) { ${assignIndex(1)} @@ -191,7 +189,6 @@ const astRoot = (ast, name, transform, interpolations) => { var ${_match}; ${astSequence(ast, 2, { - interpolations, index: 1, length: 0, onAbort: '', diff --git a/src/core.js b/src/core.js index dadd118..f26ca2e 100644 --- a/src/core.js +++ b/src/core.js @@ -26,9 +26,10 @@ export const _exec = (state, pattern) => { } else { match = pattern.exec(input)[0] || match; } + + state.y = pattern.lastIndex; } - state.y = pattern.lastIndex; return match; }; @@ -51,22 +52,17 @@ export const parse = (pattern) => (quasis, ...expressions) => { }; export const match = (name, transform) => (quasis, ...expressions) => { - let interpolations = 0; - const ast = parseDSL( quasis, - expressions.map((expression, i) => { - if (expression === interpolation) interpolations++; - return { - fn: typeof expression === 'function' && expression.length, - id: `_${i}`, - }; - }) + expressions.map((expression, i) => ({ + fn: typeof expression === 'function' && expression.length, + id: `_${i}`, + })) ); const makeMatcher = new Function( execId + ',_n,_t,' + expressions.map((_expression, i) => `_${i}`).join(','), - 'return ' + astRoot(ast, '_n', transform ? '_t' : null, interpolations) + 'return ' + astRoot(ast, '_n', transform ? '_t' : null) ); return makeMatcher(_exec, name, transform, ...expressions.map(_pattern)); -- knotmirror 0.0.1 From 8b12428d2677114a29d0fdc28a15faa258cee2e5 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Tue, 8 Dec 2020 16:42:09 +0000 Subject: [PATCH 5/7] Add predicate support to interpolations --- src/core.js | 11 +++++++---- src/core.test.js | 19 ++++++++++++------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/core.js b/src/core.js index f26ca2e..650791c 100644 --- a/src/core.js +++ b/src/core.js @@ -33,13 +33,16 @@ export const _exec = (state, pattern) => { return match; }; -export const interpolation = (state) => { +export const interpolation = (predicate) => (state) => { let match; - const input = state.quasis[state.x]; - if (!input || state.y >= input.length) { + if ( + state.y >= state.quasis[state.x].length && + state.x < state.expressions.length + ) { state.y = 0; - match = state.expressions[state.x++] || match; + match = state.expressions[state.x++]; + if (predicate && match) match = predicate(match); } return match; diff --git a/src/core.test.js b/src/core.test.js index 1472bb8..c6b7df0 100644 --- a/src/core.test.js +++ b/src/core.test.js @@ -556,15 +556,20 @@ describe('negative lookahead group with plus group and required matcher', () => describe('interpolation parsing', () => { const node = match('node')` ${/1/} - ${interpolation} + ${interpolation((x) => x > 1 && x)} ${/3/} `; - const expected = ['1', 2, '3']; - expected.tag = 'node'; + it('matches interpolations', () => { + const expected = ['1', 2, '3']; + expected.tag = 'node'; + expect(parse(node)`1${2}3`).toEqual(expected); + }); - expect(parse(node)`1${2}3`).toEqual(expected); - expect(parse(node)`13`).toBe(undefined); - expect(parse(node)`13${2}`).toBe(undefined); - expect(parse(node)`${2}13`).toBe(undefined); + it('does not match invalid inputs', () => { + expect(parse(node)`13`).toBe(undefined); + expect(parse(node)`13${2}`).toBe(undefined); + expect(parse(node)`${2}13`).toBe(undefined); + expect(parse(node)`1${1}3`).toBe(undefined); + }); }); -- knotmirror 0.0.1 From ca927f19cfd9250c165ab150181dc675614e963f Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Tue, 8 Dec 2020 17:02:25 +0000 Subject: [PATCH 6/7] Update codegen to use a combined __private object of methods --- src/babel/__snapshots__/plugin.test.js.snap | 119 +++++++++++++------- src/babel/sharedIds.js | 20 ---- src/babel/transform.js | 30 ++--- src/codegen.js | 5 +- src/core.js | 66 ++++++----- 5 files changed, 129 insertions(+), 111 deletions(-) delete mode 100644 src/babel/sharedIds.js diff --git a/src/babel/__snapshots__/plugin.test.js.snap b/src/babel/__snapshots__/plugin.test.js.snap index c872450..8fe2d29 100644 --- a/src/babel/__snapshots__/plugin.test.js.snap +++ b/src/babel/__snapshots__/plugin.test.js.snap @@ -5,25 +5,28 @@ exports[`works together with @babel/plugin-transform-modules-commonjs 1`] = ` var _reghex = require(\\"reghex\\"); -var _node_expression = (0, _reghex._pattern)(1), - _node_expression2 = (0, _reghex._pattern)(2); +var _node_expression = _reghex.__private.pattern(1), + _node_expression2 = _reghex.__private.pattern(2); const node = function (state) { - var y1 = state.y; + var y1 = state.y, + x1 = state.x; var node = []; var x; - if (x = (0, _reghex._exec)(state, _node_expression)) { + if (x = _reghex.__private.exec(state, _node_expression)) { node.push(x); } else { state.y = y1; + state.x = x1; return; } - if (x = (0, _reghex._exec)(state, _node_expression2)) { + if (x = _reghex.__private.exec(state, _node_expression2)) { node.push(x); } else { state.y = y1; + state.x = x1; return; } @@ -38,19 +41,21 @@ const node = match('node')([\\"\\", \\"+|\\", \\"+(\\", \\"(\\", \\"?\\", \\"))* `; exports[`works with local recursion 1`] = ` -"import { match as m, tag, _exec, _pattern } from 'reghex'; +"import { match as m, tag, __private } from 'reghex'; -var _inner_expression = _pattern(/inner/); +var _inner_expression = __private.pattern(/inner/); const inner = function (state) { - var y1 = state.y; + var y1 = state.y, + x1 = state.x; var node = []; var x; - if (x = _exec(state, _inner_expression)) { + if (x = __private.exec(state, _inner_expression)) { node.push(x); } else { state.y = y1; + state.x = x1; return; } @@ -59,7 +64,8 @@ const inner = function (state) { }; const node = function (state) { - var y1 = state.y; + var y1 = state.y, + x1 = state.x; var node = []; var x; @@ -67,6 +73,7 @@ const node = function (state) { node.push(x); } else { state.y = y1; + state.x = x1; return; } @@ -76,21 +83,23 @@ const node = function (state) { `; exports[`works with non-capturing groups 1`] = ` -"import { match, _exec, _pattern, tag as _tag } from 'reghex'; +"import { match, __private } from 'reghex'; -var _node_expression = _pattern(1), - _node_expression2 = _pattern(2), - _node_expression3 = _pattern(3); +var _node_expression = __private.pattern(1), + _node_expression2 = __private.pattern(2), + _node_expression3 = __private.pattern(3); const node = function (state) { - var y1 = state.y; + var y1 = state.y, + x1 = state.x; var node = []; var x; - if (x = _exec(state, _node_expression)) { + if (x = __private.exec(state, _node_expression)) { node.push(x); } else { state.y = y1; + state.x = x1; return; } @@ -98,12 +107,14 @@ const node = function (state) { alt_3: { block_3: { - var y3 = state.y; + var y3 = state.y, + x3 = state.x; - if (x = _exec(state, _node_expression2)) { + if (x = __private.exec(state, _node_expression2)) { node.push(x); } else { state.y = y3; + state.x = x3; node.length = ln2; break block_3; } @@ -112,15 +123,18 @@ const node = function (state) { } loop_3: for (var j3 = 0; 1; j3++) { - var y3 = state.y; + var y3 = state.y, + x3 = state.x; - if (x = _exec(state, _node_expression3)) {} else { + if (x = __private.exec(state, _node_expression3)) {} else { if (j3) { state.y = y3; + state.x = x3; break loop_3; } else {} state.y = y1; + state.x = x1; node.length = ln2; return; } @@ -133,10 +147,11 @@ const node = function (state) { `; exports[`works with self-referential thunks 1`] = ` -"import { match, tag, _exec, _pattern } from 'reghex'; +"import { match, tag, __private } from 'reghex'; const inner = function (state) { - var y1 = state.y; + var y1 = state.y, + x1 = state.x; var node = []; var x; @@ -144,6 +159,7 @@ const inner = function (state) { node.push(x); } else { state.y = y1; + state.x = x1; return; } @@ -152,7 +168,8 @@ const inner = function (state) { }; const node = function (state) { - var y1 = state.y; + var y1 = state.y, + x1 = state.x; var node = []; var x; @@ -160,6 +177,7 @@ const node = function (state) { node.push(x); } else { state.y = y1; + state.x = x1; return; } @@ -169,35 +187,40 @@ const node = function (state) { `; exports[`works with standard features 1`] = ` -"import { match, _exec, _pattern, tag as _tag } from \\"reghex\\"; +"import { match, __private } from \\"reghex\\"; -var _node_expression = _pattern(1), - _node_expression2 = _pattern(2), - _node_expression3 = _pattern(3), - _node_expression4 = _pattern(4), - _node_expression5 = _pattern(5); +var _node_expression = __private.pattern(1), + _node_expression2 = __private.pattern(2), + _node_expression3 = __private.pattern(3), + _node_expression4 = __private.pattern(4), + _node_expression5 = __private.pattern(5); const node = function (state) { - var y1 = state.y; + var y1 = state.y, + x1 = state.x; var node = []; var x; alt_2: { block_2: { - var y2 = state.y; + var y2 = state.y, + x2 = state.x; loop_2: for (var j2 = 0; 1; j2++) { - var y2 = state.y; + var y2 = state.y, + x2 = state.x; - if (x = _exec(state, _node_expression)) { + if (x = __private.exec(state, _node_expression)) { node.push(x); } else { if (j2) { state.y = y2; + state.x = x2; break loop_2; } else {} state.y = y2; + state.x = x2; break block_2; } } @@ -206,45 +229,53 @@ const node = function (state) { } loop_2: for (var j2 = 0; 1; j2++) { - var y2 = state.y; + var y2 = state.y, + x2 = state.x; - if (x = _exec(state, _node_expression2)) { + if (x = __private.exec(state, _node_expression2)) { node.push(x); } else { if (j2) { state.y = y2; + state.x = x2; break loop_2; } else {} state.y = y1; + state.x = x1; return; } } loop_2: for (;;) { - var y2 = state.y; + var y2 = state.y, + x2 = state.x; var ln2 = node.length; - if (x = _exec(state, _node_expression3)) { + if (x = __private.exec(state, _node_expression3)) { node.push(x); } else { state.y = y2; + state.x = x2; node.length = ln2; break loop_2; } - var y4 = state.y; + var y4 = state.y, + x4 = state.x; - if (x = _exec(state, _node_expression4)) { + if (x = __private.exec(state, _node_expression4)) { node.push(x); } else { state.y = y4; + state.x = x4; } - if (x = _exec(state, _node_expression5)) { + if (x = __private.exec(state, _node_expression5)) { node.push(x); } else { state.y = y2; + state.x = x2; node.length = ln2; break loop_2; } @@ -257,12 +288,13 @@ const node = function (state) { `; exports[`works with transform functions 1`] = ` -"import { match, _exec, _pattern, tag as _tag } from 'reghex'; +"import { match, __private } from 'reghex'; var _inner_transform = x => x; const first = function (state) { - var y1 = state.y; + var y1 = state.y, + x1 = state.x; var node = []; var x; node.tag = 'inner'; @@ -272,7 +304,8 @@ const first = function (state) { const transform = x => x; const second = function (state) { - var y1 = state.y; + var y1 = state.y, + x1 = state.x; var node = []; var x; node.tag = 'node'; diff --git a/src/babel/sharedIds.js b/src/babel/sharedIds.js deleted file mode 100644 index 80df3ec..0000000 --- a/src/babel/sharedIds.js +++ /dev/null @@ -1,20 +0,0 @@ -export class SharedIds { - constructor(t) { - this.t = t; - this.execId = t.identifier('_exec'); - this.patternId = t.identifier('_pattern'); - this.tagId = t.identifier('tag'); - } - - get exec() { - return this.t.identifier(this.execId.name); - } - - get pattern() { - return this.t.identifier(this.patternId.name); - } - - get tag() { - return this.t.identifier(this.tagId.name); - } -} diff --git a/src/babel/transform.js b/src/babel/transform.js index d4dba0b..ff54880 100644 --- a/src/babel/transform.js +++ b/src/babel/transform.js @@ -1,14 +1,17 @@ +import { astRoot, _private } from '../codegen'; import { parse } from '../parser'; -import { astRoot } from '../codegen'; -import { SharedIds } from './sharedIds'; export function makeHelpers({ types: t, template }) { const regexPatternsRe = /^[()\[\]|.+?*]|[^\\][()\[\]|.+?*$^]|\\[wdsWDS]/; const importSourceRe = /reghex$|^reghex\/macro/; const importName = 'reghex'; - const ids = new SharedIds(t); let _hasUpdatedImport = false; + let _matchId = t.identifier('match'); + let _privateId = t.identifier(_private); + + const privateMethod = (name) => + t.memberExpression(t.identifier(_privateId.name), t.identifier(name)); return { /** Adds the reghex import declaration to the Program scope */ @@ -21,30 +24,21 @@ export function makeHelpers({ types: t, template }) { path.node.source = t.stringLiteral(importName); } - path.node.specifiers.push( - t.importSpecifier( - (ids.execId = path.scope.generateUidIdentifier('exec')), - t.identifier('_exec') - ), - t.importSpecifier( - (ids.patternId = path.scope.generateUidIdentifier('pattern')), - t.identifier('_pattern') - ) - ); + path.node.specifiers.push(t.importSpecifier(_privateId, _privateId)); const tagImport = path.node.specifiers.find((node) => { - return t.isImportSpecifier(node) && node.imported.name === 'tag'; + return t.isImportSpecifier(node) && node.imported.name === 'match'; }); if (!tagImport) { path.node.specifiers.push( t.importSpecifier( - (ids.tagId = path.scope.generateUidIdentifier('tag')), - t.identifier('tag') + (_matchId = path.scope.generateUidIdentifier('match')), + t.identifier('match') ) ); } else { - ids.tagId = tagImport.imported; + _matchId = tagImport.imported; } }, @@ -140,7 +134,7 @@ export function makeHelpers({ types: t, template }) { variableDeclarators.push( t.variableDeclarator( id, - t.callExpression(ids.pattern, [expression]) + t.callExpression(privateMethod('pattern'), [expression]) ) ); diff --git a/src/codegen.js b/src/codegen.js index bed79bb..c1ac499 100644 --- a/src/codegen.js +++ b/src/codegen.js @@ -1,4 +1,5 @@ -export const _exec = '_exec'; +export const _private = '__private'; + const _state = 'state'; const _node = 'node'; const _match = 'x'; @@ -32,7 +33,7 @@ const astExpression = (ast, depth, opts) => { ''; const expression = ast.expression.fn ? `${ast.expression.id}(${_state})` - : `${_exec}(${_state}, ${ast.expression.id})`; + : `${_private}.exec(${_state}, ${ast.expression.id})`; return js` if (${_match} = ${expression}) { diff --git a/src/core.js b/src/core.js index 650791c..93eca68 100644 --- a/src/core.js +++ b/src/core.js @@ -1,36 +1,39 @@ -import { astRoot, _exec as execId } from './codegen'; +import { astRoot, _private as privateId } from './codegen'; import { parse as parseDSL } from './parser'; const isStickySupported = typeof /./g.sticky === 'boolean'; -export const _pattern = (input) => { - if (typeof input === 'function') return input; - const source = typeof input !== 'string' ? input.source : input; - return isStickySupported - ? new RegExp(source, 'y') - : new RegExp(source + '|()', 'g'); -}; +export const __private = { + pattern(input) { + if (typeof input === 'function') return input; + const source = typeof input !== 'string' ? input.source : input; + return isStickySupported + ? new RegExp(source, 'y') + : new RegExp(source + '|()', 'g'); + }, -export const _exec = (state, pattern) => { - let match; + exec(state, pattern) { + let match; - if (typeof pattern === 'function') { - if (!pattern.length) pattern = pattern(); - return pattern(state); - } - - const input = state.quasis[state.x]; - if (input && (pattern.lastIndex = state.y) < input.length) { - if (isStickySupported) { - if (pattern.test(input)) match = input.slice(state.y, pattern.lastIndex); - } else { - match = pattern.exec(input)[0] || match; + if (typeof pattern === 'function') { + if (!pattern.length) pattern = pattern(); + return pattern(state); } - state.y = pattern.lastIndex; - } + const input = state.quasis[state.x]; + if (input && (pattern.lastIndex = state.y) < input.length) { + if (isStickySupported) { + if (pattern.test(input)) + match = input.slice(state.y, pattern.lastIndex); + } else { + match = pattern.exec(input)[0] || match; + } - return match; + state.y = pattern.lastIndex; + } + + return match; + }, }; export const interpolation = (predicate) => (state) => { @@ -48,10 +51,10 @@ export const interpolation = (predicate) => (state) => { return match; }; -export const parse = (pattern) => (quasis, ...expressions) => { +export const parse = (matcher) => (quasis, ...expressions) => { if (typeof quasis === 'string') quasis = [quasis]; const state = { quasis, expressions, x: 0, y: 0 }; - return pattern(state); + return matcher(state); }; export const match = (name, transform) => (quasis, ...expressions) => { @@ -64,9 +67,16 @@ export const match = (name, transform) => (quasis, ...expressions) => { ); const makeMatcher = new Function( - execId + ',_n,_t,' + expressions.map((_expression, i) => `_${i}`).join(','), + privateId + + ',_n,_t,' + + expressions.map((_expression, i) => `_${i}`).join(','), 'return ' + astRoot(ast, '_n', transform ? '_t' : null) ); - return makeMatcher(_exec, name, transform, ...expressions.map(_pattern)); + return makeMatcher( + __private, + name, + transform, + ...expressions.map(__private.pattern) + ); }; -- knotmirror 0.0.1 From a4328f60ea2d13c01e2796deed61d355f71f8d4b Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Fri, 8 Jan 2021 21:48:02 +0000 Subject: [PATCH 7/7] Fix default exports for Babel plugin --- babel.js | 2 +- package.json | 2 -- rollup.config.js | 4 ++++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/babel.js b/babel.js index a1cdc91..f3081be 100644 --- a/babel.js +++ b/babel.js @@ -1 +1 @@ -module.exports = require('./dist/reghex-babel.js').default; +module.exports = require('./dist/reghex-babel.js'); diff --git a/package.json b/package.json index 2d6bf93..47fc857 100644 --- a/package.json +++ b/package.json @@ -22,11 +22,9 @@ "require": "./dist/reghex-core.js" }, "./babel": { - "import": "./dist/reghex-babel.mjs", "require": "./dist/reghex-babel.js" }, "./macro": { - "import": "./dist/reghex-macro.mjs", "require": "./dist/reghex-macro.js" }, "./package.json": "./package.json" diff --git a/rollup.config.js b/rollup.config.js index c6e2e7d..6a5ec51 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -66,6 +66,10 @@ export default [ }, { ...base, + output: { + ...output('cjs', '.js'), + exports: 'default', + }, input: { babel: './src/babel/plugin.js', macro: './src/babel/macro.js', -- knotmirror 0.0.1