Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add error tokens #25

Merged
merged 5 commits into from
Mar 15, 2017
Merged

Add error tokens #25

merged 5 commits into from
Mar 15, 2017

Conversation

tjvr
Copy link
Collaborator

@tjvr tjvr commented Mar 14, 2017

A proposed scheme for #18.

By default, if no token matches, moo will throw a syntax error.

Unless you define one of your tokens to match the special pattern moo.error, in one of the following ways:

myError: moo.error

myError: { match: moo.error }

myError: { match: [/[`$\t]/, moo.error] }

...in which case, moo will instead return a token object with type: myError, with the value being the remainder of the input buffer.

@tjvr
Copy link
Collaborator Author

tjvr commented Mar 14, 2017

@nathan @Hardmath123 This is kind of mad, but I thought it might be worth a try. :)

Copy link
Collaborator

@nathan nathan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to copy error to the new state map in Lexer#clone().

moo.js Outdated
@@ -13,6 +13,8 @@

function isRegExp(o) { return o && o.constructor === RegExp }

var ERROR = {error: true}
Object.freeze(ERROR)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's seems nicer to write this as var ERROR = Object.freeze({error: true})

moo.js Outdated
@@ -73,7 +78,8 @@
} else if (Array.isArray(obj)) {
// sort to help ensure longest match
var options = sortPatterns(obj)
return '(' + options.map(regexpOrLiteral).join('|') + ')'
options = options.map(regexpOrLiteral).filter(function(o) { return o !== ERROR })
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be cleaner return null or undefined from regexpOrLiteral and filter based on truthiness (filter(function(o) {return o})). I'm not sure

moo.js Outdated
@@ -116,6 +123,14 @@
// convert to RegExp
var pat = pattern(obj.match)

if (pat === ERROR || (Array.isArray(obj) && obj.match.indexOf(ERROR) !== -1)) {
if (error) {
throw new Error("Cannot have multiple error rules")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's nice to provide context for the API user in the error message—the name of the token that generated this error, and perhaps the name of the token already marked as error as well. You should also add a compiler test case to ensure that this error is thrown when appropriate, and that the message contains the correct information.

moo.js Outdated
group = Lexer.error
group = this.error
if (!group) {
throw new Error('Syntax error')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine for now, but perhaps we should think about making it easy for us/users to generate nice syntax errors—with line/column information and a preview of the buffer pointing to the problematic character, for example.

@nathan
Copy link
Collaborator

nathan commented Mar 14, 2017

This API seems rather odd to me. Why not just:

myError: { error: true }, // error should imply lineBreaks
// or optionally:
myError: { match: /[`$\t]/, error: true },

This simplifies the implementation considerably and does less magic with the match pattern; if match is not present, we just don't add anything to the compiled RegExp. Interestingly, it means you can still do myError: moo.error and get the expected result, since moo.error is simply {error: true} :-)

@tjvr tjvr force-pushed the errors branch 2 times, most recently from 7220b2a to 0399ea2 Compare March 15, 2017 14:30
@tjvr
Copy link
Collaborator Author

tjvr commented Mar 15, 2017

{ error: true }

I did consider this. I liked that this more complicated way made a rule that matched a pattern and handled errors more obvious: e.g. [/[`$]/, moo.error]. But for the sake of simplifying the implementation, I agree with you. I'm gonna keep moo.error around, though; I like your point :-)

Sorry about the rebase; #27 moved everything around, and since we're going with the simpler API it wasn't worth re-implementing it on top of #27!

Copy link
Collaborator

@nathan nathan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, other than Lexer#clone needing an update.

@@ -380,9 +404,10 @@
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You still need to copy error in Lexer#clone. Actually, using assign({}, s, {regexp: …}) might be better so we don't have to keep updating it.

moo.js Outdated
continue
}
delete options.error
}
Copy link
Collaborator

@nathan nathan Mar 15, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like you don't have to split it into two rules as long as compileRules knows to skip over rules with no match. Not sure if this would be more or less clear.

Copy link
Collaborator Author

@tjvr tjvr Mar 15, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately sortRules won't emit a rule with an empty match array. :-( Nevermind!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that implies that rules with no error or match set would be silently skipped.

@tjvr tjvr merged commit f55a3e3 into master Mar 15, 2017
@tjvr tjvr deleted the errors branch March 15, 2017 16:21
@nathan nathan mentioned this pull request Mar 17, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants