From d8c1dabcf2fa4df4e6b77fc3d7845706fa030d92 Mon Sep 17 00:00:00 2001 From: Julian Gonggrijp Date: Fri, 6 Aug 2021 13:59:07 +0200 Subject: [PATCH 01/11] Consistently use var This comment also applies to the generated parser itself, but I'm illustrating with the JSON example runner because all the variations are visible within a short section of code: (1) const/let, (2) var and (3) the absence of any such keyword. Mixing (1) and (2) is frowned upon; it makes the scope of variables unpredictable. (1) is newer, hence often considered better. In this case, however, I would suggest that you consistently go with (2), at least in the generated parser module. There are two reasons for my recommendation: 1. var has roughly the same scope semantics as local variables in Python. Since you are transpiling from Python, this makes it easier to generate reliable code. 2. var is older, hence portable to more different JS environments. (3), while allowed, should be avoided at all cost, as it always creates global variables (which is not the same as var at module scope). The fact that this form is allowed at all should be considered a historical artifact. --- examples/run_json_parser.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/run_json_parser.js b/examples/run_json_parser.js index 3cebfb3..1ff046c 100644 --- a/examples/run_json_parser.js +++ b/examples/run_json_parser.js @@ -6,9 +6,9 @@ // // node run_json_parser.js -lark = require('./json_parser.js') +var lark = require('./json_parser.js') -let transformer = { +var transformer = { number: ([n]) => parseFloat(n.value), string: ([s]) => s.value.slice(1, -1), array: Array.from, @@ -24,7 +24,7 @@ var parser = lark.load_parser({transformer}) function test_json() { - text = ` + var text = ` { "empty_object" : {}, "empty_array" : [], From 6d9fb6f953ab7b67c404e5bc949b2de55a763c1e Mon Sep 17 00:00:00 2001 From: Julian Gonggrijp Date: Fri, 6 Aug 2021 14:01:07 +0200 Subject: [PATCH 02/11] Don't forget the semicolons You can often get away without the semicolons, but there are corner cases where it can cause the JS interpreter/compiler to do the wrong thing, especially after inadvertent subsequent edits. It is generally considered better style to finish every statement with a semicolon AND a line end. This also speeds up JS parsing in some cases. This comment only applies to the example runner; it appears that the generated parser consistently includes the semicolons. Nevertheless, including them in your example code makes a better impression and also reduces the probability that users will accidentally break the code through editing. --- examples/run_json_parser.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/run_json_parser.js b/examples/run_json_parser.js index 1ff046c..5da45af 100644 --- a/examples/run_json_parser.js +++ b/examples/run_json_parser.js @@ -6,7 +6,7 @@ // // node run_json_parser.js -var lark = require('./json_parser.js') +var lark = require('./json_parser.js'); var transformer = { number: ([n]) => parseFloat(n.value), @@ -18,9 +18,9 @@ var transformer = { null: () => null, true: () => true, false: () => false, -} +}; -var parser = lark.load_parser({transformer}) +var parser = lark.load_parser({transformer}); function test_json() { @@ -33,14 +33,14 @@ function test_json() { "strings" : [ "This", [ "And" , "That", "And a \\"b" ] ], "nothing" : null } - ` + `; - console.log( parser.parse(text) ) + console.log( parser.parse(text) ); } if (require && require.main === module) { - test_json() + test_json(); } From 6a7d1516750311b6a4cdb21d29f248a1b3b8351a Mon Sep 17 00:00:00 2001 From: Julian Gonggrijp Date: Fri, 6 Aug 2021 14:02:38 +0200 Subject: [PATCH 03/11] Be judicious with blank lines JS users are used to dense code, with only single blank lines between blocks or occasionally inside long blocks. You can stretch this a bit by using double blank lines before classes and standalone functions like in PEP8, but you will have to be very consistent so that it is clear what convention you're maintaining. JS users will get irritated seeing a blank line before a closing semicolon or a blank line separating a single line of code from the rest of a function body. --- examples/run_json_parser.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/run_json_parser.js b/examples/run_json_parser.js index 5da45af..9a80483 100644 --- a/examples/run_json_parser.js +++ b/examples/run_json_parser.js @@ -22,7 +22,6 @@ var transformer = { var parser = lark.load_parser({transformer}); - function test_json() { var text = ` { @@ -34,12 +33,9 @@ function test_json() { "nothing" : null } `; - console.log( parser.parse(text) ); - } - if (require && require.main === module) { test_json(); } From 0b7407b92e915cee7e895a56f7dd641c0411b844 Mon Sep 17 00:00:00 2001 From: Julian Gonggrijp Date: Fri, 6 Aug 2021 14:12:11 +0200 Subject: [PATCH 04/11] Docstrings Using multiline strings as documentation is not a thing in JS; you are expected to always use comments, which should precede the thing they document. The style I've demonstrated in the commit could be broadly referred to as a literate commenting style, which is for example practiced in Underscore and related libraries. It can be read as-is together with the code, or it can be used to present the comments and the code side by side, as illustrated below. Needless to say, this necessitates writing a separate manual by hand (second link). https://underscorejs.org/docs/underscore-esm.html https://underscorejs.org A possible alternative style, which is very popular, is the jsdoc format: /** * Short description * Possibly longer explanation with examples * @param name description * @returns description */ This is more geared to automatically generating reference documentation that is separate from the code. In order for such separate documentation to be useful, the comments need to be quite extensive, which can render the code itself less readable. It should also be noted that the generated reference documentation is generally still not sufficient to completely replace a purpose-written manual. https://github.com/lodash/lodash/blob/c84fe82760fb2d3e03a63379b297a1cc1a2fce12/lodash.js#L459 --- lark-js/lark.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lark-js/lark.js b/lark-js/lark.js index 5230dfb..e605aeb 100644 --- a/lark-js/lark.js +++ b/lark-js/lark.js @@ -4,16 +4,15 @@ "use strict"; +// Main interface, returns a parser object that implements the grammar for +// which this module was generated. The parser object has a .parse method that +// accepts a string as its first argument and returns the parse tree. +// Allowed options: +// - transformer: explanation +// - propagate_positions: explanation +// - tree_class: explanation +// - debug: explanation function load_parser(options = {}) { - ` - Allowed options: - - transformer - - propagate_positions - - tree_class - - debug (untested) - - To test: postlex, lexer_callbacks, g_regex_flags - `; if ( options.transformer && options.transformer.constructor.name === "object" From cc703bc48fd3b2b2d4486962a6e1bf08aefdc5e3 Mon Sep 17 00:00:00 2001 From: Julian Gonggrijp Date: Fri, 6 Aug 2021 14:26:34 +0200 Subject: [PATCH 05/11] Indentation Two-space indents are often considered a convention in JavaScript. Even in the JS community, however, there is sizable subpopulation that appreciates larger indents for better readability. Ultimately, it is important not to do what is most popular but what you believe is best. If you subscribe to PEP8's four-space indent recommendation, there is no reason not to apply it in JS as well. (The reason two-space indents became fashion in JS is also outdated. When JS programmers were still writing module wrappers by hand and there was no async/await syntax yet, indentation tended to go very deep very quickly. This produced an incentive to sacrifice readability in exchange for needing to wrap lines less often. There is no longer a need to make this sacrifice.) --- lark-js/lark.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lark-js/lark.js b/lark-js/lark.js index e605aeb..fab6605 100644 --- a/lark-js/lark.js +++ b/lark-js/lark.js @@ -13,14 +13,14 @@ // - tree_class: explanation // - debug: explanation function load_parser(options = {}) { - if ( - options.transformer && - options.transformer.constructor.name === "object" - ) { - options.transformer = Transformer.fromObj(options.transformer); - } + if ( + options.transformer && + options.transformer.constructor.name === "object" + ) { + options.transformer = Transformer.fromObj(options.transformer); + } - return Lark._load_from_dict({ data: DATA, memo: MEMO, ...options }); + return Lark._load_from_dict({ data: DATA, memo: MEMO, ...options }); } const NO_VALUE = {}; From 1348cb09e66dc3c136ad8a788da5c9e5491c8b34 Mon Sep 17 00:00:00 2001 From: Julian Gonggrijp Date: Fri, 6 Aug 2021 16:20:16 +0200 Subject: [PATCH 06/11] "Polyfill" JS users expect the word "polyfill" to mean something very specific, i.e., code that emulates a builtin feature of *JavaScript* if it is not available by an outdated target environment. Using the word differently might cause confusion. --- lark-js/lark.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lark-js/lark.js b/lark-js/lark.js index fab6605..f938707 100644 --- a/lark-js/lark.js +++ b/lark-js/lark.js @@ -27,8 +27,8 @@ const NO_VALUE = {}; class _Decoratable {} // -// Implementation of Scanner + Regular expression polyfill -// ---------------------------------------------------------- +// Implementation of Scanner + Python stdlib re module emulation +// --------------------------------------------------------------- const re = { escape(string) { From 2b3000f3d5395e00fb15078763abcbe32e068c3a Mon Sep 17 00:00:00 2001 From: Julian Gonggrijp Date: Fri, 6 Aug 2021 16:26:59 +0200 Subject: [PATCH 07/11] Use speaking names When possible, avoid abbreviated names because they cause cognitive strain. Highly idiomatic single-letter variables such as i/j/k in a loop can be acceptable. An additional remark on this snippet: it appears that the re_ parameter is just an alias of the Python re module emulation a few lines up. Avoid this pattern if possible; using re directly will make the code much easier to understand. --- lark-js/lark.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lark-js/lark.js b/lark-js/lark.js index f938707..51c0963 100644 --- a/lark-js/lark.js +++ b/lark-js/lark.js @@ -43,8 +43,8 @@ const re = { }; function _get_match(re_, regexp, s, flags) { - const m = re_.compile(regexp, flags).exec(s); - if (m != null) return m[0]; + const match = re_.compile(regexp, flags).exec(s); + if (match != null) return match[0]; } class Scanner { From 5f7493dd00da3897fdeeb736ca74943bf53a0510 Mon Sep 17 00:00:00 2001 From: Julian Gonggrijp Date: Fri, 6 Aug 2021 16:49:23 +0200 Subject: [PATCH 08/11] Generator functions JavaScript's modern iterator support is of course convenient for transpiling Python generators. Unfortunately, they do have a performance cost. for-of loops also work on plain arrays, so when it is possible to replace a generator function by a normal function that returns a plain array, it is likely that this will make your parser faster. for-of loops on arrays, in turn, should be replaced by old-fashioned for-;; loops for raw performance. The for-of construct involves converting the array to iterator first through the Array[@@iterator] method and then calling iterator#next on each loop iteration, inducing considerable function call overhead. Of course, these considerations only apply to hot loops. An added bonus of reducing iterators and for-of constructs is that compatibility transpilers like Babel will produce less boilerplate code. --- lark-js/lark.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lark-js/lark.js b/lark-js/lark.js index 51c0963..a49fba0 100644 --- a/lark-js/lark.js +++ b/lark-js/lark.js @@ -323,19 +323,21 @@ function isSubset(subset, set) { return true; } -function* segment_by_key(a, key) { +function segment_by_key(a, key) { + const result = []; let buffer = []; let last_k = null; - for (const item of a) { + for (let i = 0, l = a.length, item = a[i]; i < l; item = a[++i]) { const k = key(item); if (last_k && k != last_k) { - yield [last_k, buffer]; + result.push([last_k, buffer]); buffer = []; } buffer.push(item); last_k = k; } - yield [last_k, buffer]; + result.push([last_k, buffer]); + return result; } // -------------------------- From ffe690c8b082bd46070caa376a720fe1236efb4f Mon Sep 17 00:00:00 2001 From: Julian Gonggrijp Date: Fri, 6 Aug 2021 17:24:36 +0200 Subject: [PATCH 09/11] Functional style with Underscore Introducing a library dependency like Underscore allows you to bring back much of the notational elegance that Python brings through itertools and functools, plus some JavaScript-specific extras. Pros: - Shorter, more elegant, more maintainable code. - Removes the need for many of the generic functions that you have written in lines 87-333. - Completely portable; removes need for many constructs that cause compatibility transpilers to generate boilerplate code or introduce polyfills. Cons: - Performance penalty is similar to for-of due to function call overhead. Nothing beats the raw performance of bare for-;; loops. - Having a dependency is perceived as a burden in the JS community. Underscore is however sufficiently small that its added weight can be completely offset by the reduced code size, especially after compatibility transpilation. - No support for iterators (although this can be easily patched). This commit serves to illustrate how Underscore could be used. Some of the code changes might be better left out. In general, I recommend to use Underscore where possible and for-;; where necessary. For completeness, I will mention that I maintain Underscore and that there are alternatives such as Lodash and Ramda. --- lark-js/lark.js | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/lark-js/lark.js b/lark-js/lark.js index a49fba0..c6b223a 100644 --- a/lark-js/lark.js +++ b/lark-js/lark.js @@ -1,3 +1,5 @@ +var { map, find, findKey, extend } = require('underscore'); + // // Lark.js stand-alone parser //=============================== @@ -49,13 +51,8 @@ function _get_match(re_, regexp, s, flags) { class Scanner { constructor(terminals, g_regex_flags, re_, use_bytes, match_whole = false) { - this.terminals = terminals; - this.g_regex_flags = g_regex_flags; - this.re_ = re_; - this.use_bytes = use_bytes; - this.match_whole = match_whole; - this.allowed_types = new Set(this.terminals.map((t) => t.name)); - + extend(this, {terminals, g_regex_flags, re_, use_bytes, match_whole}); + this.allowed_types = new Set(map(this.terminals, 'name')); this._regexps = this._build_mres(terminals); } @@ -66,33 +63,25 @@ class Scanner { t.pattern.flags.join("") ); - let regexps = []; - for (let [flags, patterns] of patterns_by_flags) { - const pattern = patterns - .map((t) => `(?<${t.name}>${t.pattern.to_regexp() + postfix})`) - .join("|"); - regexps.push(new RegExp(pattern, this.g_regex_flags + flags + "y")); - } - - return regexps; + return map(patterns_by_flags, ([flags, patterns]) => { + const pattern = map( + patterns, (t) => `(?<${t.name}>${t.pattern.to_regexp() + postfix})` + ).join("|"); + return new RegExp(pattern, this.g_regex_flags + flags + "y"); + }); } match(text, pos) { - for (const re of this._regexps) { + let result; + find(this._regexps, (re) => { re.lastIndex = pos; let m = re.exec(text); if (m) { - // Find group. Ugly hack, but javascript is forcing my hand. - let group = null; - for (let [k, v] of Object.entries(m.groups)) { - if (v) { - group = k; - break; - } - } - return [m[0], group]; + let group = findKey(m.groups) || null; + return result = [m[0], group]; } - } + }); + return result; } } // // Start of library code From 073fb4e04c5457bb5e2164880bf8fe8e378afee1 Mon Sep 17 00:00:00 2001 From: Julian Gonggrijp Date: Fri, 6 Aug 2021 18:08:33 +0200 Subject: [PATCH 10/11] Remove trailing spaces Please ignore this commit. --- lark-js/lark.js | 84 ++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/lark-js/lark.js b/lark-js/lark.js index c6b223a..2997740 100644 --- a/lark-js/lark.js +++ b/lark-js/lark.js @@ -373,7 +373,7 @@ UnexpectedInput Error. - ``UnexpectedCharacters``: The lexer encountered an unexpected string After catching one of these exceptions, you may call the following helper methods to create a nicer error message. - + */ static get pos_in_stream() { @@ -396,7 +396,7 @@ Returns a pretty string pinpointing the error in the text, Note: The parser doesn't hold a copy of the text it has to parse, so you have to provide it again - + */ let after, before; @@ -444,7 +444,7 @@ Allows you to detect what's wrong in the input text by matching examples: dictionary of ``{'example_string': value}``. use_accepts: Recommended to call this with ``use_accepts=True``. The default is ``False`` for backwards compatibility. - + */ console.assert(this.state !== null, "Not supported for this exception"); @@ -594,7 +594,7 @@ An exception that is raised by the parser, when the token it received which is initialized to the point of failture, and can be used for debugging and error handling. see: ``InteractiveParser``. - + */ constructor({ @@ -639,7 +639,7 @@ VisitError is raised when visitors are interrupted by an exception It provides the following attributes for inspection: - obj: the tree node or token it was processing when the exception was raised - orig_exc: the exception that cause it to fail - + */ constructor(rule, obj, orig_exc) { @@ -706,7 +706,7 @@ Safe-ish serialization interface that doesn't rely on Pickle __serialize_fields__ (List[str]): Fields (aka attributes) to serialize. __serialize_namespace__ (list): List of classes that deserialization is allowed to instantiate. Should include all field types that aren't builtin types. - + */ memo_serialize(types_to_memoize) { @@ -807,7 +807,7 @@ The main tree class. children: List of matched sub-rules and terminals meta: Line & Column numbers (if ``propagate_positions`` is enabled). meta attributes: line, column, start_pos, end_line, end_column, end_pos - + */ constructor(data, children, meta = null) { @@ -860,7 +860,7 @@ The main tree class. Returns an indented string representation of the tree. Great for debugging. - + */ return this._pretty(0, indent_str).join(""); @@ -888,7 +888,7 @@ Returns an indented string representation of the tree. Depth-first iteration. Iterates over all the subtrees, never returning to the same node twice (Lark's parse-tree is actually a DAG). - + */ let queue = [this]; @@ -931,7 +931,7 @@ Return all values in the tree that evaluate pred(value) as true. Example: >>> all_tokens = tree.scan_values(lambda v: isinstance(v, Token)) - + */ for (const c of this.children) { @@ -952,7 +952,7 @@ Return all values in the tree that evaluate pred(value) as true. Breadth-first iteration. Iterates over all the subtrees, return nodes in order like pretty() does. - + */ let node; @@ -988,7 +988,7 @@ class Discard extends Error { /* When raising the Discard exception in a transformer callback, that node is discarded and won't appear in the parent. - + */ // pass } @@ -1019,7 +1019,7 @@ Transformers visit each node of the tree, and run the appropriate method on it a (For processing ignored tokens, use the ``lexer_callbacks`` options) NOTE: A transformer without methods essentially performs a non-memoized partial deepcopy. - + */ static get __visit_tokens__() { @@ -1125,7 +1125,7 @@ Transform the given tree, and return the final result Default function that is called if there is no attribute matching ``data`` Can be overridden. Defaults to creating a new copy of the tree node (i.e. ``return Tree(data, children, meta)``) - + */ return new Tree(data, children, meta); @@ -1136,7 +1136,7 @@ Default function that is called if there is no attribute matching ``data`` Default function that is called if there is no attribute matching ``token.type`` Can be overridden. Defaults to returning the token as-is. - + */ return token; @@ -1148,7 +1148,7 @@ class Transformer_InPlace extends Transformer { Same as Transformer, but non-recursive, and changes the tree in-place instead of returning new instances Useful for huge trees. Conservative in memory. - + */ _transform_tree(tree) { @@ -1172,7 +1172,7 @@ Same as Transformer but non-recursive. Like Transformer, it doesn't change the original tree. Useful for huge trees. - + */ transform(tree) { @@ -1241,7 +1241,7 @@ class VisitorBase { Default function that is called if there is no attribute matching ``tree.data`` Can be overridden. Defaults to doing nothing. - + */ return tree; @@ -1257,7 +1257,7 @@ class Visitor extends VisitorBase { Tree visitor, non-recursive (can handle huge trees). Visiting a node calls its methods (provided by the user via inheritance) according to ``tree.data`` - + */ visit(tree) { @@ -1292,7 +1292,7 @@ Bottom-up visitor, recursive. Visiting a node calls its methods (provided by the user via inheritance) according to ``tree.data`` Slightly faster than the non-recursive version. - + */ visit(tree) { @@ -1337,7 +1337,7 @@ Interpreter walks the tree starting at the root. Unlike ``Transformer`` and ``Visitor``, the Interpreter doesn't automatically visit its sub-branches. The user has to explicitly call ``visit``, ``visit_children``, or use the ``@visit_children_decor``. This allows the user to implement branching and loops. - + */ visit(tree) { @@ -1467,7 +1467,7 @@ class Rule extends Serialize { origin : a symbol expansion : a list of symbols order : index of this expansion amongst all rules of the same name - + */ static get __serialize_fields__() { @@ -1669,7 +1669,7 @@ A string with meta-information, that is produced by the lexer. if the token is a single character with a column value of 4, end_column will be 5. end_pos: the index where the token ends (basically ``start_pos + len(token)``) - + */ constructor( @@ -1756,7 +1756,7 @@ class LineCounter { Consume a token and calculate the new line & column. As an optional optimization, set test_newline=False if token doesn't contain a newline. - + */ let newlines; @@ -1854,7 +1854,7 @@ Expressions that may indicate newlines in a regexp: - anything but ([^...]) - any-char (.) when the flag (?s) exists - spaces (\s) - + */ return ( @@ -1872,7 +1872,7 @@ Lexer interface Method Signatures: lex(self, text) -> Iterator[Token] - + */ static get lex() { @@ -2639,7 +2639,7 @@ class _AmbiguousIntermediateExpander { ... propagating up any nested '_iambig' nodes along the way. - + */ constructor(tree_class, node_builder) { @@ -2660,7 +2660,7 @@ class _AmbiguousIntermediateExpander { node. Returns a list of '_inter' nodes guaranteed not to contain any nested '_iambig' nodes, or None if children does not contain an '_iambig' node. - + */ let collapsed, iambig_node, new_tree, result; @@ -3095,7 +3095,7 @@ class InteractiveParser { InteractiveParser gives you advanced control over parsing and error handling when parsing with LALR. For a simpler interface, see the ``on_error`` argument to ``Lark.parse()``. - + */ constructor(parser, parser_state, lexer_state) { @@ -3109,7 +3109,7 @@ InteractiveParser gives you advanced control over parsing and error handling whe Feed the parser with a token, and advance it to the next state, as if it received it from the lexer. Note that ``token`` has to be an instance of ``Token``. - + */ return this.parser_state.feed_token(token, token.type === "$END"); @@ -3118,7 +3118,7 @@ Feed the parser with a token, and advance it to the next state, as if it receive exhaust_lexer() { /* Try to feed the rest of the lexer state into the interactive parser. - + Note that this modifies the instance in place and does not feed an '$END' Token */ @@ -3188,7 +3188,7 @@ Returns a dictionary of token types, matched to their action in the parser. Only returns token types that are accepted by the current state. Updated by ``feed_token()``. - + */ return this.parser_state.parse_conf.parse_table.states[ @@ -3240,7 +3240,7 @@ class ImmutableInteractiveParser extends InteractiveParser { /* Same as ``InteractiveParser``, but operations create a new instance instead of changing it in-place. - + */ static get result() { @@ -3618,7 +3618,7 @@ class LarkOptions extends Serialize { /* Specifies the options for Lark - + */ static get OPTIONS_DOC() { @@ -3822,7 +3822,7 @@ Main interface for the library. Example: >>> Lark(r'''start: "foo" ''') Lark(...) - + */ constructor({ grammar, ...options } = {}) { @@ -4163,7 +4163,7 @@ Main interface for the library. Saves the instance into the given file object Useful for caching and multiprocessing. - + */ let [data, m] = this.memo_serialize([TerminalDef, Rule]); @@ -4179,7 +4179,7 @@ Saves the instance into the given file object Loads an instance from the given file object Useful for caching and multiprocessing. - + */ let inst = new_object(cls); return inst._load(f); @@ -4268,7 +4268,7 @@ Create an instance of Lark with the grammar given by its filename >>> Lark.open("grammar_file.lark", rel_to=__file__, parser="lalr") Lark(...) - + */ let basepath; if (rel_to) { @@ -4294,7 +4294,7 @@ Create an instance of Lark with the grammar loaded from within the package `pack Example: Lark.open_from_package(__name__, "example.lark", ("grammars",), parser=...) - + */ let package_loader = new FromPackageLoader(package_, search_paths); let [full_path, text] = package_loader(null, grammar_path); @@ -4318,7 +4318,7 @@ Create an instance of Lark with the grammar loaded from within the package `pack Only lex (and postlex) the text, without parsing it. Only relevant when lexer='standard' When dont_ignore=True, the lexer will return all tokens, even those marked for %ignore. - + */ let lexer; @@ -4356,7 +4356,7 @@ Start an interactive parsing session. A new InteractiveParser instance. See Also: ``Lark.parse()`` - + */ return this.parser.parse_interactive(text, start) @@ -4376,7 +4376,7 @@ Parse the given text, according to the options provided. If a transformer is supplied to ``__init__``, returns whatever is the result of the transformation. Otherwise, returns a Tree instance. - + */ return this.parser.parse(text, start, on_error); From 586aa7cd01cf2e13b22117598e8057520c0c1100 Mon Sep 17 00:00:00 2001 From: Julian Gonggrijp Date: Fri, 6 Aug 2021 18:08:55 +0200 Subject: [PATCH 11/11] Whitespace around comment blocks Could use some polishing. --- lark-js/lark.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lark-js/lark.js b/lark-js/lark.js index 2997740..b606382 100644 --- a/lark-js/lark.js +++ b/lark-js/lark.js @@ -83,7 +83,9 @@ class Scanner { }); return result; } -} // +} + +// // Start of library code // -------------------------- @@ -365,7 +367,7 @@ class LexError extends LarkError { class UnexpectedInput extends LarkError { /* -UnexpectedInput Error. + UnexpectedInput Error. Used as a base class for the following exceptions: @@ -374,7 +376,7 @@ UnexpectedInput Error. After catching one of these exceptions, you may call the following helper methods to create a nicer error message. -*/ + */ static get pos_in_stream() { return null;