Make loose parser work with minor interface changes introduced by modularization
This commit is contained in:
parent
a1fe3a1859
commit
dd89c6e112
@ -41,13 +41,13 @@
|
|||||||
acorn.defaultOptions.tabSize = 4;
|
acorn.defaultOptions.tabSize = 4;
|
||||||
|
|
||||||
exports.parse_dammit = function(input, options) {
|
exports.parse_dammit = function(input, options) {
|
||||||
var p = new LooseParser(options, input);
|
var p = new LooseParser(input, options);
|
||||||
p.next();
|
p.next();
|
||||||
return p.parseTopLevel();
|
return p.parseTopLevel();
|
||||||
};
|
};
|
||||||
|
|
||||||
var LooseParser = exports.LooseParser = function(input, options) {
|
var LooseParser = exports.LooseParser = function(input, options) {
|
||||||
this.toks = new acorn.Parser(input, options);
|
this.toks = acorn.tokenizer(input, options)
|
||||||
this.options = this.toks.options;
|
this.options = this.toks.options;
|
||||||
this.input = this.toks.input;
|
this.input = this.toks.input;
|
||||||
this.tok = this.last = {type: tt.eof, start: 0, end: 0};
|
this.tok = this.last = {type: tt.eof, start: 0, end: 0};
|
||||||
@ -149,9 +149,9 @@
|
|||||||
|
|
||||||
if (this.options.locations) {
|
if (this.options.locations) {
|
||||||
this.toks.curLine = 1;
|
this.toks.curLine = 1;
|
||||||
this.toks.lineStart = acorn.lineBreak.lastIndex = 0;
|
this.toks.lineStart = acorn.lineBreakG.lastIndex = 0;
|
||||||
var match;
|
var match;
|
||||||
while ((match = acorn.lineBreak.exec(this.input)) && match.index < pos) {
|
while ((match = acorn.lineBreakG.exec(this.input)) && match.index < pos) {
|
||||||
++this.toks.curLine;
|
++this.toks.curLine;
|
||||||
this.toks.lineStart = match.index + match[0].length;
|
this.toks.lineStart = match.index + match[0].length;
|
||||||
}
|
}
|
||||||
@ -273,7 +273,7 @@
|
|||||||
|
|
||||||
lp.canInsertSemicolon = function() {
|
lp.canInsertSemicolon = function() {
|
||||||
return this.tok.type === tt.eof || this.tok.type === tt.braceR ||
|
return this.tok.type === tt.eof || this.tok.type === tt.braceR ||
|
||||||
acorn.newline.test(this.input.slice(this.last.end, this.tok.start));
|
acorn.lineBreak.test(this.input.slice(this.last.end, this.tok.start));
|
||||||
};
|
};
|
||||||
|
|
||||||
lp.semicolon = function() {
|
lp.semicolon = function() {
|
||||||
|
|||||||
128
src/index.js
128
src/index.js
@ -19,15 +19,15 @@
|
|||||||
// [dammit]: acorn_loose.js
|
// [dammit]: acorn_loose.js
|
||||||
// [walk]: util/walk.js
|
// [walk]: util/walk.js
|
||||||
|
|
||||||
import {Parser} from "./state"
|
import {Parser, plugins} from "./state"
|
||||||
import {has, isArray} from "./util"
|
import {getOptions} from "./options"
|
||||||
import {SourceLocation} from "./location"
|
|
||||||
import "./parseutil"
|
import "./parseutil"
|
||||||
import "./statement"
|
import "./statement"
|
||||||
import "./lval"
|
import "./lval"
|
||||||
import "./expression"
|
import "./expression"
|
||||||
|
|
||||||
export {Parser} from "./state"
|
export {Parser} from "./state"
|
||||||
|
export {defaultOptions} from "./options"
|
||||||
export {SourceLocation} from "./location"
|
export {SourceLocation} from "./location"
|
||||||
export {getLineInfo} from "./location"
|
export {getLineInfo} from "./location"
|
||||||
export {Node} from "./node"
|
export {Node} from "./node"
|
||||||
@ -35,7 +35,7 @@ export {TokenType, types as tokTypes} from "./tokentype"
|
|||||||
export {TokContext, types as tokContexts} from "./tokencontext"
|
export {TokContext, types as tokContexts} from "./tokencontext"
|
||||||
export {isIdentifierChar, isIdentifierStart} from "./identifier"
|
export {isIdentifierChar, isIdentifierStart} from "./identifier"
|
||||||
export {Token} from "./tokenize"
|
export {Token} from "./tokenize"
|
||||||
export {isNewLine, lineBreak} from "./whitespace"
|
export {isNewLine, lineBreak, lineBreakG} from "./whitespace"
|
||||||
|
|
||||||
export const version = "0.12.1"
|
export const version = "0.12.1"
|
||||||
|
|
||||||
@ -53,126 +53,6 @@ export function parse(input, options) {
|
|||||||
return p.parseTopLevel(p.options.program || p.startNodeAt(startPos))
|
return p.parseTopLevel(p.options.program || p.startNodeAt(startPos))
|
||||||
}
|
}
|
||||||
|
|
||||||
// A second optional argument can be given to further configure
|
|
||||||
// the parser process. These options are recognized:
|
|
||||||
|
|
||||||
export const defaultOptions = {
|
|
||||||
// `ecmaVersion` indicates the ECMAScript version to parse. Must
|
|
||||||
// be either 3, or 5, or 6. This influences support for strict
|
|
||||||
// mode, the set of reserved words, support for getters and
|
|
||||||
// setters and other features.
|
|
||||||
ecmaVersion: 5,
|
|
||||||
// Source type ("script" or "module") for different semantics
|
|
||||||
sourceType: "script",
|
|
||||||
// `onInsertedSemicolon` can be a callback that will be called
|
|
||||||
// when a semicolon is automatically inserted. It will be passed
|
|
||||||
// th position of the comma as an offset, and if `locations` is
|
|
||||||
// enabled, it is given the location as a `{line, column}` object
|
|
||||||
// as second argument.
|
|
||||||
onInsertedSemicolon: null,
|
|
||||||
// `onTrailingComma` is similar to `onInsertedSemicolon`, but for
|
|
||||||
// trailing commas.
|
|
||||||
onTrailingComma: null,
|
|
||||||
// By default, reserved words are not enforced. Disable
|
|
||||||
// `allowReserved` to enforce them. When this option has the
|
|
||||||
// value "never", reserved words and keywords can also not be
|
|
||||||
// used as property names.
|
|
||||||
allowReserved: true,
|
|
||||||
// When enabled, a return at the top level is not considered an
|
|
||||||
// error.
|
|
||||||
allowReturnOutsideFunction: false,
|
|
||||||
// When enabled, import/export statements are not constrained to
|
|
||||||
// appearing at the top of the program.
|
|
||||||
allowImportExportEverywhere: false,
|
|
||||||
// When enabled, hashbang directive in the beginning of file
|
|
||||||
// is allowed and treated as a line comment.
|
|
||||||
allowHashBang: false,
|
|
||||||
// When `locations` is on, `loc` properties holding objects with
|
|
||||||
// `start` and `end` properties in `{line, column}` form (with
|
|
||||||
// line being 1-based and column 0-based) will be attached to the
|
|
||||||
// nodes.
|
|
||||||
locations: false,
|
|
||||||
// A function can be passed as `onToken` option, which will
|
|
||||||
// cause Acorn to call that function with object in the same
|
|
||||||
// format as tokenize() returns. Note that you are not
|
|
||||||
// allowed to call the parser from the callback—that will
|
|
||||||
// corrupt its internal state.
|
|
||||||
onToken: null,
|
|
||||||
// A function can be passed as `onComment` option, which will
|
|
||||||
// cause Acorn to call that function with `(block, text, start,
|
|
||||||
// end)` parameters whenever a comment is skipped. `block` is a
|
|
||||||
// boolean indicating whether this is a block (`/* */`) comment,
|
|
||||||
// `text` is the content of the comment, and `start` and `end` are
|
|
||||||
// character offsets that denote the start and end of the comment.
|
|
||||||
// When the `locations` option is on, two more parameters are
|
|
||||||
// passed, the full `{line, column}` locations of the start and
|
|
||||||
// end of the comments. Note that you are not allowed to call the
|
|
||||||
// parser from the callback—that will corrupt its internal state.
|
|
||||||
onComment: null,
|
|
||||||
// Nodes have their start and end characters offsets recorded in
|
|
||||||
// `start` and `end` properties (directly on the node, rather than
|
|
||||||
// the `loc` object, which holds line/column data. To also add a
|
|
||||||
// [semi-standardized][range] `range` property holding a `[start,
|
|
||||||
// end]` array with the same numbers, set the `ranges` option to
|
|
||||||
// `true`.
|
|
||||||
//
|
|
||||||
// [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678
|
|
||||||
ranges: false,
|
|
||||||
// It is possible to parse multiple files into a single AST by
|
|
||||||
// passing the tree produced by parsing the first file as
|
|
||||||
// `program` option in subsequent parses. This will add the
|
|
||||||
// toplevel forms of the parsed file to the `Program` (top) node
|
|
||||||
// of an existing parse tree.
|
|
||||||
program: null,
|
|
||||||
// When `locations` is on, you can pass this to record the source
|
|
||||||
// file in every node's `loc` object.
|
|
||||||
sourceFile: null,
|
|
||||||
// This value, if given, is stored in every node, whether
|
|
||||||
// `locations` is on or off.
|
|
||||||
directSourceFile: null,
|
|
||||||
// When enabled, parenthesized expressions are represented by
|
|
||||||
// (non-standard) ParenthesizedExpression nodes
|
|
||||||
preserveParens: false,
|
|
||||||
plugins: {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Registered plugins
|
|
||||||
|
|
||||||
export const plugins = {}
|
|
||||||
|
|
||||||
// Interpret and default an options object
|
|
||||||
|
|
||||||
function getOptions(opts) {
|
|
||||||
let options = {}
|
|
||||||
for (let opt in defaultOptions)
|
|
||||||
options[opt] = opts && has(opts, opt) ? opts[opt] : defaultOptions[opt]
|
|
||||||
|
|
||||||
if (isArray(options.onToken)) {
|
|
||||||
var tokens = options.onToken;
|
|
||||||
options.onToken = (token) => tokens.push(token)
|
|
||||||
}
|
|
||||||
if (isArray(options.onComment))
|
|
||||||
options.onComment = pushComment(options, options.onComment);
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
function pushComment(options, array) {
|
|
||||||
return function (block, text, start, end, startLoc, endLoc) {
|
|
||||||
let comment = {
|
|
||||||
type: block ? 'Block' : 'Line',
|
|
||||||
value: text,
|
|
||||||
start: start,
|
|
||||||
end: end
|
|
||||||
}
|
|
||||||
if (options.locations)
|
|
||||||
comment.loc = new SourceLocation(this, startLoc, endLoc)
|
|
||||||
if (options.ranges)
|
|
||||||
comment.range = [start, end]
|
|
||||||
array.push(comment)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function tries to parse a single expression at a given
|
// This function tries to parse a single expression at a given
|
||||||
// offset in a string. Useful for parsing mixed-language formats
|
// offset in a string. Useful for parsing mixed-language formats
|
||||||
// that embed JavaScript expressions.
|
// that embed JavaScript expressions.
|
||||||
|
|||||||
119
src/options.js
Normal file
119
src/options.js
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
import {has, isArray} from "./util"
|
||||||
|
import {SourceLocation} from "./location"
|
||||||
|
|
||||||
|
// A second optional argument can be given to further configure
|
||||||
|
// the parser process. These options are recognized:
|
||||||
|
|
||||||
|
export const defaultOptions = {
|
||||||
|
// `ecmaVersion` indicates the ECMAScript version to parse. Must
|
||||||
|
// be either 3, or 5, or 6. This influences support for strict
|
||||||
|
// mode, the set of reserved words, support for getters and
|
||||||
|
// setters and other features.
|
||||||
|
ecmaVersion: 5,
|
||||||
|
// Source type ("script" or "module") for different semantics
|
||||||
|
sourceType: "script",
|
||||||
|
// `onInsertedSemicolon` can be a callback that will be called
|
||||||
|
// when a semicolon is automatically inserted. It will be passed
|
||||||
|
// th position of the comma as an offset, and if `locations` is
|
||||||
|
// enabled, it is given the location as a `{line, column}` object
|
||||||
|
// as second argument.
|
||||||
|
onInsertedSemicolon: null,
|
||||||
|
// `onTrailingComma` is similar to `onInsertedSemicolon`, but for
|
||||||
|
// trailing commas.
|
||||||
|
onTrailingComma: null,
|
||||||
|
// By default, reserved words are not enforced. Disable
|
||||||
|
// `allowReserved` to enforce them. When this option has the
|
||||||
|
// value "never", reserved words and keywords can also not be
|
||||||
|
// used as property names.
|
||||||
|
allowReserved: true,
|
||||||
|
// When enabled, a return at the top level is not considered an
|
||||||
|
// error.
|
||||||
|
allowReturnOutsideFunction: false,
|
||||||
|
// When enabled, import/export statements are not constrained to
|
||||||
|
// appearing at the top of the program.
|
||||||
|
allowImportExportEverywhere: false,
|
||||||
|
// When enabled, hashbang directive in the beginning of file
|
||||||
|
// is allowed and treated as a line comment.
|
||||||
|
allowHashBang: false,
|
||||||
|
// When `locations` is on, `loc` properties holding objects with
|
||||||
|
// `start` and `end` properties in `{line, column}` form (with
|
||||||
|
// line being 1-based and column 0-based) will be attached to the
|
||||||
|
// nodes.
|
||||||
|
locations: false,
|
||||||
|
// A function can be passed as `onToken` option, which will
|
||||||
|
// cause Acorn to call that function with object in the same
|
||||||
|
// format as tokenize() returns. Note that you are not
|
||||||
|
// allowed to call the parser from the callback—that will
|
||||||
|
// corrupt its internal state.
|
||||||
|
onToken: null,
|
||||||
|
// A function can be passed as `onComment` option, which will
|
||||||
|
// cause Acorn to call that function with `(block, text, start,
|
||||||
|
// end)` parameters whenever a comment is skipped. `block` is a
|
||||||
|
// boolean indicating whether this is a block (`/* */`) comment,
|
||||||
|
// `text` is the content of the comment, and `start` and `end` are
|
||||||
|
// character offsets that denote the start and end of the comment.
|
||||||
|
// When the `locations` option is on, two more parameters are
|
||||||
|
// passed, the full `{line, column}` locations of the start and
|
||||||
|
// end of the comments. Note that you are not allowed to call the
|
||||||
|
// parser from the callback—that will corrupt its internal state.
|
||||||
|
onComment: null,
|
||||||
|
// Nodes have their start and end characters offsets recorded in
|
||||||
|
// `start` and `end` properties (directly on the node, rather than
|
||||||
|
// the `loc` object, which holds line/column data. To also add a
|
||||||
|
// [semi-standardized][range] `range` property holding a `[start,
|
||||||
|
// end]` array with the same numbers, set the `ranges` option to
|
||||||
|
// `true`.
|
||||||
|
//
|
||||||
|
// [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678
|
||||||
|
ranges: false,
|
||||||
|
// It is possible to parse multiple files into a single AST by
|
||||||
|
// passing the tree produced by parsing the first file as
|
||||||
|
// `program` option in subsequent parses. This will add the
|
||||||
|
// toplevel forms of the parsed file to the `Program` (top) node
|
||||||
|
// of an existing parse tree.
|
||||||
|
program: null,
|
||||||
|
// When `locations` is on, you can pass this to record the source
|
||||||
|
// file in every node's `loc` object.
|
||||||
|
sourceFile: null,
|
||||||
|
// This value, if given, is stored in every node, whether
|
||||||
|
// `locations` is on or off.
|
||||||
|
directSourceFile: null,
|
||||||
|
// When enabled, parenthesized expressions are represented by
|
||||||
|
// (non-standard) ParenthesizedExpression nodes
|
||||||
|
preserveParens: false,
|
||||||
|
plugins: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interpret and default an options object
|
||||||
|
|
||||||
|
export function getOptions(opts) {
|
||||||
|
let options = {}
|
||||||
|
for (let opt in defaultOptions)
|
||||||
|
options[opt] = opts && has(opts, opt) ? opts[opt] : defaultOptions[opt]
|
||||||
|
|
||||||
|
if (isArray(options.onToken)) {
|
||||||
|
var tokens = options.onToken;
|
||||||
|
options.onToken = (token) => tokens.push(token)
|
||||||
|
}
|
||||||
|
if (isArray(options.onComment))
|
||||||
|
options.onComment = pushComment(options, options.onComment);
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pushComment(options, array) {
|
||||||
|
return function (block, text, start, end, startLoc, endLoc) {
|
||||||
|
let comment = {
|
||||||
|
type: block ? 'Block' : 'Line',
|
||||||
|
value: text,
|
||||||
|
start: start,
|
||||||
|
end: end
|
||||||
|
}
|
||||||
|
if (options.locations)
|
||||||
|
comment.loc = new SourceLocation(this, startLoc, endLoc)
|
||||||
|
if (options.ranges)
|
||||||
|
comment.range = [start, end]
|
||||||
|
array.push(comment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -59,6 +59,10 @@ Parser.prototype.extend = function(name, f) {
|
|||||||
this[name] = f(this[name])
|
this[name] = f(this[name])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Registered plugins
|
||||||
|
|
||||||
|
export const plugins = {}
|
||||||
|
|
||||||
Parser.prototype.loadPlugins = function(plugins) {
|
Parser.prototype.loadPlugins = function(plugins) {
|
||||||
for (let name in plugins) {
|
for (let name in plugins) {
|
||||||
let plugin = exports.plugins[name]
|
let plugin = exports.plugins[name]
|
||||||
|
|||||||
@ -27,7 +27,7 @@
|
|||||||
try {
|
try {
|
||||||
var ast = parse(test.code, testOpts);
|
var ast = parse(test.code, testOpts);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
if (!(e instanceof SyntaxError)) throw e;
|
if (!(e instanceof SyntaxError)) { console.log(e.stack); throw e; }
|
||||||
if (test.error) {
|
if (test.error) {
|
||||||
if (e.message == test.error) callback("ok", test.code);
|
if (e.message == test.error) callback("ok", test.code);
|
||||||
else callback("fail", test.code,
|
else callback("fail", test.code,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user