Skip to content
This repository was archived by the owner on Jul 15, 2021. It is now read-only.

Commit 90aaf5a

Browse files
committed
some more tweaks to the error output of Tracer. Even though the Tracer is now pretty good at pinpointing where a SyntaxError occurred, it is still removing CREATE TABLE node when there is a failure in the statement, even though that information should be part of the error message. refs #2
1 parent ee529be commit 90aaf5a

File tree

12 files changed

+3608
-3614
lines changed

12 files changed

+3608
-3614
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ All notable changes to this project will be documented in this file.
66
- forked `pegjs` repository as `nwronski/pegjs` to get the changes into `pegjs` core into version control so they are not accidentally overwritten
77
- getting closer to displaying correct error location when there are multiple statements in the input SQL
88

9+
### Notes
10+
- Even though the `Tracer` is now pretty good at pinpointing where a SyntaxError occurred, it is still removing `CREATE TABLE` node when there is a failure in the statement, even though that information should be part of the error message.
11+
912
## [v0.8.0] - 2015-07-04
1013
### Added
1114
- added several array methods (e.g.: `findLast()`, `takeRight()`, `pluck()`) so that I could remove `lodash` as a dependency of the "smart error" `Tracer` class

demo/sqlite-parser-demo.js

Lines changed: 1187 additions & 1191 deletions
Large diffs are not rendered by default.

dist/sqlite-parser.js

Lines changed: 1187 additions & 1191 deletions
Large diffs are not rendered by default.

index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
});
2121
}
2222
sqliteParser['NAME'] = 'sqlite-parser';
23-
sqliteParser['VERSION'] = '0.8.2';
23+
sqliteParser['VERSION'] = '0.8.3';
2424

2525
module.exports = root.sqliteParser = sqliteParser;
2626
})(typeof self === 'object' ? self : global);

lib/parser-util.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,9 @@ function has(thing, item) {
127127
return findWhere(thing, item) !== undefined;
128128
}
129129
} else if (isPlain(thing)) {
130-
// thing is an object
131-
if (isPlain(item)) {
130+
if (isFunc(item)) {
131+
return item(thing);
132+
} else if (isPlain(item)) {
132133
// item is an object, find each prop key and value in item within thing
133134
for (k in item) {
134135
v = item[k];

lib/parser.js

Lines changed: 1145 additions & 1152 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/tracer.js

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ module.exports = (function (util) {
2424
this.indentation += 1;
2525
break;
2626
case 'rule.match':
27-
/*
28-
* TODO: need to remove entire statement from events once fully
29-
* matched as right now the last location from the previous
30-
* statement is reported when there is an error within a
31-
* statement that follows it
32-
*/
3327
this.indentation -= 1;
3428
break;
3529
case 'rule.fail':
30+
/**
31+
* @note
32+
* This is removing CREATE TABLE node when there is a failure in
33+
* the statement, even though that information should be part of
34+
* the error message.
35+
*/
3636
// remove failed leaf
3737
this.events.splice(util.findLastIndex(this.events, {rule: event.rule}), 1);
3838
this.indentation -= 1;
@@ -41,41 +41,43 @@ module.exports = (function (util) {
4141
};
4242

4343
Tracer.prototype.smartError = function smartError(err) {
44-
var message, location, chain, chainDetail,
45-
lastIndent = 10000,
46-
bestDescriptor = false,
47-
multiStatement = false;
44+
var message, location, chain, chainDetail, firstNode,
45+
bestNode = {indentation: -1},
46+
deep = false,
47+
stmts = 0,
48+
namedEvents = this.events
49+
.filter(function (e) {
50+
return e.description !== null &&
51+
!/whitespace|(new\sline)|(char$)|(^[oe]$)/i.test(e.description);
52+
})
53+
.reverse();
4854

49-
chain = this.events
50-
.reverse()
51-
.filter(function (e) {
52-
// Only use nodes with a set description
53-
if (multiStatement) {
55+
chain = util.takeWhile(namedEvents, function (elem) {
56+
if (/^(sym\_semi)$/i.test(elem.rule)) {
57+
stmts += 1;
58+
}
59+
if (stmts > 1) {
60+
return false;
61+
}
62+
if (!deep) {
63+
if (elem.indentation > bestNode.indentation) {
64+
bestNode = elem;
65+
} else {
66+
deep = true;
67+
}
68+
} else if (/^(stmt)$/i.test(elem.rule)) {
5469
return false;
55-
} else if (/Statement$/i.test(e.description)) {
56-
multiStatement = true;
57-
return true;
5870
}
59-
return e.description !== null && !/whitespace|(semi$)|(^[oe]$)/i.test(e.rule);
71+
return true;
6072
});
6173

6274
if (chain.length) {
63-
// Get best location data
64-
location = util.first(chain).location;
65-
// Collect descriptions
66-
chain = util.uniq(util.takeWhile(util.pluck(chain, 'description'), function (d) {
67-
if (!bestDescriptor && /(Statement|Clause)$/i.test(d)) {
68-
bestDescriptor = true;
69-
return true;
70-
}
71-
return !bestDescriptor;
72-
}))
73-
.reverse();
74-
// Don't accidentally repeat the first description in the output
75-
chainDetail = util.takeRight(util.rest(chain), 2);
76-
message = 'Syntax error found near ' + util.first(chain) +
77-
(chainDetail.length > 0 ? ' (' + chainDetail.join(', ') + ')' : '');
78-
//location = this.events.findLast({description: chain.last()}).location;
75+
location = bestNode.location;
76+
firstNode = util.findLast(chain.reverse(), function (elem) {
77+
return /(Statement|Clause)$/i.test(elem.description);
78+
});
79+
chainDetail = firstNode != null ? ' (' + firstNode.description + ')' : '';
80+
message = 'Syntax error found near ' + bestNode.description + chainDetail;
7981
util.extend(err, {
8082
'message': message,
8183
'location': location

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "sqlite-parser",
33
"description": "JavaScript implentation of SQLite 3 query parser",
44
"author": "Code School (http://codeschool.com)",
5-
"version": "0.8.2",
5+
"version": "0.8.3",
66
"contributors": [
77
"Nick Wronski <nick@javascript.com>"
88
],

src/grammar.pegjs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,7 +1102,7 @@ stmt_fallback_types
11021102
{ return k; }
11031103

11041104
/** {@link https://www.sqlite.org/lang_insert.html} */
1105-
stmt_insert
1105+
stmt_insert "INSERT Statement"
11061106
= k:( insert_keyword ) o t:( insert_target ) o p:( insert_parts )
11071107
{
11081108
// TODO: Not final syntax!
@@ -1120,15 +1120,15 @@ insert_keyword
11201120
= insert_keyword_ins
11211121
/ insert_keyword_repl
11221122

1123-
insert_keyword_ins "INSERT Statement"
1123+
insert_keyword_ins
11241124
= a:( INSERT ) e m:( insert_keyword_mod )?
11251125
{
11261126
return util.extend({
11271127
'action': util.key(a)
11281128
}, m);
11291129
}
11301130

1131-
insert_keyword_repl "REPLACE Statement"
1131+
insert_keyword_repl
11321132
= a:( REPLACE ) e
11331133
{
11341134
return {

src/parser-util.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,9 @@ function has(thing, item) {
127127
return findWhere(thing, item) !== undefined;
128128
}
129129
} else if (isPlain(thing)) {
130-
// thing is an object
131-
if (isPlain(item)) {
130+
if (isFunc(item)) {
131+
return item(thing);
132+
} else if (isPlain(item)) {
132133
// item is an object, find each prop key and value in item within thing
133134
for (k in item) {
134135
v = item[k];

0 commit comments

Comments
 (0)