diff --git a/generator/gen_wrapper_util.js b/generator/gen_wrapper_util.js index f1d75dfe..1f91f6b1 100644 --- a/generator/gen_wrapper_util.js +++ b/generator/gen_wrapper_util.js @@ -65,7 +65,28 @@ const decomposeWhenClause = function(when) { return result; }; const tokens = when.split(/(\|\||\&\&)/); - const ors_of_ands = splitArray(tokens, '||').map(a => + let nest = 0; + const outMostTokens = []; + for (let i = 0; i < tokens.length; i++) { + let str = tokens[i]; + let open = 0, close = 0; + let m; + while ((m = str.match(/^\s*(\!\s*)*[(]/)) !== null) { + open += 1; + str = str.slice(m[0].length); + } + while ((m = str.match(/[)]\s*$/)) !== null) { + close += 1; + str = str.slice(0, str.length - m[0].length); + } + if (nest === 0) { + outMostTokens.push(tokens[i]); + } else { + outMostTokens[outMostTokens.length - 1] += tokens[i]; + } + nest += open - close; + } + const ors_of_ands = splitArray(outMostTokens, '||').map(a => splitArray(a, '&&').map(x => x.join('').trim()) ); return ors_of_ands; diff --git a/test/suite/gen_wrapper_util.test.js b/test/suite/gen_wrapper_util.test.js index 51a1bafe..cf555f14 100644 --- a/test/suite/gen_wrapper_util.test.js +++ b/test/suite/gen_wrapper_util.test.js @@ -23,15 +23,24 @@ describe('gen_wrapper_util', () => { assert.deepStrictEqual(decomposeWhenClause('!c'), [['!c']]); assert.deepStrictEqual(decomposeWhenClause('c1 || !c2 || !!c3'), [['c1'], ['!c2'], ['!!c3']]); }); - // TODO: https://github.com/tshino/vscode-kb-macro/issues/296 - /* it('should leave parenthesized portion unchanged', () => { assert.deepStrictEqual(decomposeWhenClause('(c1 || c2)'), [['(c1 || c2)']]); assert.deepStrictEqual(decomposeWhenClause('!(c1 || c2)'), [['!(c1 || c2)']]); assert.deepStrictEqual(decomposeWhenClause('c1 && (c2 || c3)'), [['c1', '(c2 || c3)']]); assert.deepStrictEqual(decomposeWhenClause('c1 || (c2 && c3)'), [['c1'], ['(c2 && c3)']]); }); - */ + it('should handle nested parenthesized portion', () => { + assert.deepStrictEqual(decomposeWhenClause('((c1 || c2))'), [['((c1 || c2))']]); + assert.deepStrictEqual(decomposeWhenClause('(!(c1 || c2))'), [['(!(c1 || c2))']]); + assert.deepStrictEqual(decomposeWhenClause('c1 && ((c2 && c3) || c4)'), [['c1', '((c2 && c3) || c4)']]); + assert.deepStrictEqual(decomposeWhenClause('(c1 || !(c2 && c3)) && c4'), [['(c1 || !(c2 && c3))', 'c4']]); + }); + it('should handle spaces around parentheses', () => { + assert.deepStrictEqual(decomposeWhenClause('( (c1 || c2)) || c3'), [['( (c1 || c2))'], ['c3']]); + assert.deepStrictEqual(decomposeWhenClause('((c1 || c2) ) || c3'), [['((c1 || c2) )'], ['c3']]); + assert.deepStrictEqual(decomposeWhenClause('! (c1 || c2)'), [['! (c1 || c2)']]); + assert.deepStrictEqual(decomposeWhenClause('( !(c1 || c2))'), [['( !(c1 || c2))']]); + }); }); describe('addWhenContext', () => { const addWhenContext = genWrapperUtil.addWhenContext;