diff --git a/package.json b/package.json index e073c59..1db8f61 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ }, "scripts": { "test": "npm run generate && mocha test --recursive", - "test:dev": "npm run generate && mocha ./test/parse", + "test:dev": "npm run generate && mocha ./test/syntax", "test:cov": "nyc --reporter=lcov npm run test", "test:bin": "npm run generate && node bin/heta.js run test/parse/input/include.heta", "generate": "pegjs -o src/index.js src/pegjs/heta.pegjs" diff --git a/src/index.js b/src/index.js index 6eca734..00a9975 100644 --- a/src/index.js +++ b/src/index.js @@ -290,13 +290,23 @@ function peg$parse(input, options) { peg$c71 = /^[^;{#@']/, peg$c72 = peg$classExpectation([";", "{", "#", "@", "'"], true, false), peg$c73 = function(s) { - let str = s.join('').replace(/[\s]+/g, ' ').replace(/^ +/g, '').replace(/ +$/g, ''); + let str = s.join('') + .replace(/[\s]+/g, ' ') // remove multiple spaces + .replace(/^ +/g, '') // remove leading spaces + .replace(/ +$/g, ''); // remove trailing spaces let doubleRegExpr = /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/; - let res = doubleRegExpr.test(str) - ? parseFloat(str) - : str; - - return res; + + if (str === 'null') { + return null; + } else if (str === 'true') { + return true; + } else if (str === 'false') { + return false; + } else if (doubleRegExpr.test(str)) { + return parseFloat(str); + } else { + return str; + } }, peg$c74 = peg$otherExpectation("Include"), peg$c75 = "include", @@ -372,7 +382,9 @@ function peg$parse(input, options) { // XXX: alternative but bad solution, remove trailing comments //let str = s.match(/\s*(.*?)\s*(?:\/\/|\/\*|$)/)[1] // ignores text after // or /* - if (str === 'true') { + if (str === 'null') { + res = null; + } else if (str === 'true') { var res = true } else if (str === 'false') { res = false diff --git a/src/pegjs/heta.pegjs b/src/pegjs/heta.pegjs index 8796b1a..0ed22b7 100644 --- a/src/pegjs/heta.pegjs +++ b/src/pegjs/heta.pegjs @@ -131,13 +131,23 @@ QuotedString "Quoted String"= (Break/Space)* "\"" s: [^"]* "\"" // all string until stop list, trim spaces AssignString "Assignment String" = s: [^;{#@']* { - let str = s.join('').replace(/[\s]+/g, ' ').replace(/^ +/g, '').replace(/ +$/g, ''); + let str = s.join('') + .replace(/[\s]+/g, ' ') // remove multiple spaces + .replace(/^ +/g, '') // remove leading spaces + .replace(/ +$/g, ''); // remove trailing spaces let doubleRegExpr = /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/; - let res = doubleRegExpr.test(str) - ? parseFloat(str) - : str; - - return res; + + if (str === 'null') { + return null; + } else if (str === 'true') { + return true; + } else if (str === 'false') { + return false; + } else if (doubleRegExpr.test(str)) { + return parseFloat(str); + } else { + return str; + } } // -- BLOCKS -- @@ -221,7 +231,9 @@ String "String" = (Break/Space)* s: $([^,[\]{};] !"//" !"/*")+ Comment? // XXX: alternative but bad solution, remove trailing comments //let str = s.match(/\s*(.*?)\s*(?:\/\/|\/\*|$)/)[1] // ignores text after // or /* - if (str === 'true') { + if (str === 'null') { + res = null; + } else if (str === 'true') { var res = true } else if (str === 'false') { res = false diff --git a/test/parse/index.js b/test/parse/index.js index 72b9300..d764d4e 100644 --- a/test/parse/index.js +++ b/test/parse/index.js @@ -21,6 +21,7 @@ const cases = [ { source: './input/other-tabs.heta', target: './output/other-tabs.json' }, { source: './input/other-strings.heta', target: './output/other-strings.json' }, { source: './input/empty-statement.heta', target: './output/empty-statement.json' }, + { source: './input/null.heta', target: './output/null.json' }, ]; describe('Check "parse"', () => { diff --git a/test/parse/input/null.heta b/test/parse/input/null.heta new file mode 100644 index 0000000..136d939 --- /dev/null +++ b/test/parse/input/null.heta @@ -0,0 +1,4 @@ +x1 @Record := 5; +x1 := null; + +x2 @Record {assignments: {start_: null}}; diff --git a/test/parse/output/null.json b/test/parse/output/null.json new file mode 100644 index 0000000..07de37d --- /dev/null +++ b/test/parse/output/null.json @@ -0,0 +1,5 @@ +[ + { "action": "upsert", "id": "x1", "class": "Record", "assignments": {"ode_": 5}}, + { "action": "upsert", "id": "x1", "assignments": {"ode_": null}}, + { "action": "upsert", "id": "x2", "class": "Record", "assignments": {"start_": null}} +] \ No newline at end of file diff --git a/test/syntax/index.js b/test/syntax/index.js index f581699..cbd8b81 100644 --- a/test/syntax/index.js +++ b/test/syntax/index.js @@ -437,6 +437,52 @@ let to_test = [ id: 'p1', string: 'xxx/yyy' }] + }, + // null + { + description: 'null as property', + source: 'p1 {key: null};', + expectation: [{ + action: 'upsert', + id: 'p1', + key: null + }] + }, + { + description: 'null as deep property', + source: 'p1 {key: {subkey: null}};', + expectation: [{ + action: 'upsert', + id: 'p1', + key: {subkey: null} + }] + }, + { + description: 'null as array element', + source: 'p1 {key: [null]};', + expectation: [{ + action: 'upsert', + id: 'p1', + key: [null] + }] + }, + { + description: 'null inside assignment', + source: 'p1 .= null;', + expectation: [{ + action: 'upsert', + id: 'p1', + assignments: {start_: null} + }] + }, + { + description: 'null inside assignment expression', + source: 'p1 .= a + null;', + expectation: [{ + action: 'upsert', + id: 'p1', + assignments: {start_: 'a + null'} + }] } ];