Repository files navigation

CIRelease Version

Javascript Left-Right Parser

Jsleri is an easy-to-use language parser for JavaScript.



Installation

Using npm:

$ npm i jsleri

In your project:

import*asjslerifrom'jsleri';// Exposes:// - jsleri.version// - jsleri.noop// - jsleri.Keyword// - jsleri.Regex// - jsleri.Token// - jsleri.Tokens// - jsleri.Sequence// - jsleri.Choice// - jsleri.Repeat// - jsleri.List// - jsleri.Optional// - jsleri.Ref// - jsleri.Prio// - jsleri.THIS// - jsleri.Grammar// - jsleri.EOS

Or... download the latest release from here and load the file in inside your project. For example:

<!-- Add this line to the <head> section to expose window.jsleri --><scriptsrc="jsleri-1.1.15.min.js"></script>

Related projects

Quick usage

import{Regex,Keyword,Sequence,Grammar}from'jsleri';// create your grammarclassMyGrammarextendsGrammar{staticSTART=Sequence(Keyword('hi'),Regex('(?:"(?:[^"]*)")+'));}// create a instance of your grammarconstmyGrammar=newMyGrammar();// do something with the grammaralert(myGrammar.parse('hi "Iris"').isValid);// alerts truealert(myGrammar.parse('hello "Iris"').isValid);// alerts false

Grammar

When writing a grammar you should subclass Grammar. A Grammar expects at least a START property so the parser knows where to start parsing. Grammar has a parse method: parse().

parse

syntax:

myGrammar.parse(string)

The parse() method returns a result object which has the following properties that are further explained in Result:

  • expecting
  • isValid
  • pos
  • tree

Result

The result of the parse() method contains 4 properties that will be explained next.

isValid

isValid returns a boolean value, True when the given string is valid according to the given grammar, False when not valid. node_result.isValid) # => False

Let us take the example from Quick usage.

alert(myGrammar.parse('hello "Iris"').isValid);// alerts false

Position

pos returns the position where the parser had to stop. (when isValid is True this value will be equal to the length of the given string with str.rstrip() applied)

Let us take the example from Quick usage.

alert(myGrammar.parse('hello "Iris"').pos);// alerts 0

Tree

tree contains the parse tree. Even when isValid is False the parse tree is returned but will only contain results as far as parsing has succeeded. The tree is the root node which can include several children nodes. The structure will be further clarified in the example found in the "example" folder. It explains a way of visualizing the parse tree.

The nodes in the example contain 5 properties:

  • start property returns the start of the node object.
  • end property returns the end of the node object.
  • element returns the type of Element (e.g. Repeat, Sequence, Keyword, etc.).
  • string returns the string that is parsed.
  • children can return a node object containing deeper layered nodes provided that there are any. In our example the root node has an element type Repeat(), starts at 0 and ends at 24, and it has two children. These children are node objects that have both an element type Sequence, start at 0 and 12 respectively, and so on.

Expecting

expecting returns an array containing elements which jsleri expects at pos. Even if isValid is true there might be elements in this object, for example when an Optional() element could be added to the string. Expecting is useful if you want to implement things like auto-completion, syntax error handling, auto-syntax-correction etc. In the "example" folder you will find an example. Run the html script in a browser. You will see that expecting is used to help you create a valid query string for SiriDB. SiriDB is an open source time series database with its own grammar class. Start writing something, click one of the options that appear and see what happens.

Elements

Jsleri has several Elements which can be used to create a grammar.

Keyword

Keyword(keyword,ignCase)

The parser needs to match the keyword which is just a string. When matching keywords we need to tell the parser what characters are allowed in keywords. By default Jsleri uses ^\w+ which equals to ^[A-Za-z0-9_]+. Keyword() accepts one more argument ignCase to tell the parser if we should match case insensitive.

Example:

constgrammar=newGrammar(Keyword('tic-tac-toe',true),// case insensitive'[A-Za-z-]+'// alternative keyword matching);console.log(grammar.parse('Tic-Tac-Toe').isValid);// true

Regex

Regex(pattern,ignCase)

The parser compiles a regular expression. Argument ignCase is set to false by default but can be set to true if you want the regular expression to be case insensitive. Note that ignore case is the only re flag from pyleri which will be compiled and accepted by jsleri.

See the Quick Usage example for how to use Regex.

Token

Token(token)

A token can be one or more characters and is usually used to match operators like +, -, // and so on. When we parse a string object where jsleri expects an element, it will automatically be converted to a Token() object.

Example:

// We could just write '-' instead of Token('-')// because any string will be converted to Token()constgrammar=newGrammar(List(Keyword('ni'),Token('-')));console.log(grammar.parse('ni-ni-ni-ni-ni').isValid);// true

Tokens

Tokens(tokens)

Can be used to register multiple tokens at once. The tokens argument should be a string with tokens separated by spaces. If given tokens are different in size the parser will try to match the longest tokens first.

Example:

constgrammar=newGrammar(List(Keyword('ni'),Tokens('+ - !=')));grammar.parse('ni + ni != ni - ni').isValid// => True

Sequence

Sequence(element,element, ...)

The parser needs to match each element in a sequence.

Example:

constgrammar=newGrammar(Sequence(Keyword('Tic'),Keyword('Tac'),Keyword('Toe')));console.log(grammar.parse('Tic Tac Toe').isValid);// true

Repeat

Repeat(element,mi,ma)

The parser needs at least mi elements and at most ma elements. When ma is set to undefined we allow unlimited number of elements. mi can be any integer value equal or higher than 0 but not larger then ma. The default value for mi is 0 and undefined for ma

Example:

constgrammar=newGrammar(Repeat(Keyword('ni')));console.log(grammar.parse('ni ni ni ni').isValid);// true

One should avoid to bind a name to the same element twice and Repeat(element, 1, 1) is a common solution to bind the element a second (or more) time(s).

For example consider the following:

constr_name=Regex('(?:"(?:[^"]*)")+');// Do NOT do thisconstr_address=r_name;// WRONG// Instead use Repeatconstr_address=Repeat(r_name,1,1);// Correct

List

List(element,delimiter,mi,ma,opt)

List is like Repeat but with a delimiter. A comma is used as default delimiter but any element is allowed. When a string is used as delimiter it will be converted to a Token element. mi and ma work excatly like with Repeat. opt kan be set to set to true to allow the list to end with a delimiter. By default this is set to false which means the list has to end with an element.

Example:

constgrammar=newGrammar(List(Keyword('ni')));console.log(grammar.parse('ni, ni, ni, ni, ni').isValid);// true

Optional

Optional(element)

The parser looks for an optional element. It is like using Repeat(element, 0, 1) but we encourage to use Optional since it is more readable. (and slightly faster)

Example:

constgrammar=newGrammar(Sequence(Keyword('hi'),Optional(Regex('(?:"(?:[^"]*)")+'))));console.log(grammar.parse('hi "Iris"').isValid);// trueconsole.log(grammar.parse('hi').isValid);// true

Ref

Ref(Constructor)

The grammar can make a forward reference to make recursion possible. In the example below we create a forward reference to START but note that a reference to any element can be made.

Warning: A reference is not protected against testing the same position in in a string. This could potentially lead to an infinite loop. For example:

letr=Ref(Optional);r.set(Optional(r));// DON'T DO THIS

Use Prio if such recursive construction is required.

Example:

// make a forward reference START to a Sequence.letSTART=Ref(Sequence);// we can now use STARTconstni_item=Choice(Keyword('ni'),START);// here we actually set STARTSTART.set(Sequence('[',List(ni_item),']'));// create and test the grammarconstgrammar=Grammar(START);console.log(grammar.parse('[ni, [ni, [], [ni, ni]]]').isValid);// true

Prio

Prio(element,element, ...)

Choose the first match from the prio elements and allow THIS for recursive operations. With THIS we point to the Prio element. Probably the example below explains how Prio and THIS can be used.

Note: Use a Ref when possible. A Prio element is required when the same position in a string is potentially checked more than once.

Example:

constgrammar=newGrammar(Prio(Keyword('ni'),Sequence('(',THIS,')'),Sequence(THIS,Keyword('or'),THIS),Sequence(THIS,Keyword('and'),THIS)));console.log(grammar.parse('(ni or ni) and (ni or ni)').isValid);// true

About

Parser for JavaScript

Resources

Stars

10 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

CIRelease Version

Javascript Left-Right Parser

Jsleri is an easy-to-use language parser for JavaScript.



Installation

Using npm:

$ npm i jsleri

In your project:

import*asjslerifrom'jsleri';// Exposes:// - jsleri.version// - jsleri.noop// - jsleri.Keyword// - jsleri.Regex// - jsleri.Token// - jsleri.Tokens// - jsleri.Sequence// - jsleri.Choice// - jsleri.Repeat// - jsleri.List// - jsleri.Optional// - jsleri.Ref// - jsleri.Prio// - jsleri.THIS// - jsleri.Grammar// - jsleri.EOS

Or... download the latest release from here and load the file in inside your project. For example:

<!-- Add this line to the <head> section to expose window.jsleri --><scriptsrc="jsleri-1.1.15.min.js"></script>

Related projects

Quick usage

import{Regex,Keyword,Sequence,Grammar}from'jsleri';// create your grammarclassMyGrammarextendsGrammar{staticSTART=Sequence(Keyword('hi'),Regex('(?:"(?:[^"]*)")+'));}// create a instance of your grammarconstmyGrammar=newMyGrammar();// do something with the grammaralert(myGrammar.parse('hi "Iris"').isValid);// alerts truealert(myGrammar.parse('hello "Iris"').isValid);// alerts false

Grammar

When writing a grammar you should subclass Grammar. A Grammar expects at least a START property so the parser knows where to start parsing. Grammar has a parse method: parse().

parse

syntax:

myGrammar.parse(string)

The parse() method returns a result object which has the following properties that are further explained in Result:

  • expecting
  • isValid
  • pos
  • tree

Result

The result of the parse() method contains 4 properties that will be explained next.

isValid

isValid returns a boolean value, True when the given string is valid according to the given grammar, False when not valid. node_result.isValid) # => False

Let us take the example from Quick usage.

alert(myGrammar.parse('hello "Iris"').isValid);// alerts false

Position

pos returns the position where the parser had to stop. (when isValid is True this value will be equal to the length of the given string with str.rstrip() applied)

Let us take the example from Quick usage.

alert(myGrammar.parse('hello "Iris"').pos);// alerts 0

Tree

tree contains the parse tree. Even when isValid is False the parse tree is returned but will only contain results as far as parsing has succeeded. The tree is the root node which can include several children nodes. The structure will be further clarified in the example found in the "example" folder. It explains a way of visualizing the parse tree.

The nodes in the example contain 5 properties:

  • start property returns the start of the node object.
  • end property returns the end of the node object.
  • element returns the type of Element (e.g. Repeat, Sequence, Keyword, etc.).
  • string returns the string that is parsed.
  • children can return a node object containing deeper layered nodes provided that there are any. In our example the root node has an element type Repeat(), starts at 0 and ends at 24, and it has two children. These children are node objects that have both an element type Sequence, start at 0 and 12 respectively, and so on.

Expecting

expecting returns an array containing elements which jsleri expects at pos. Even if isValid is true there might be elements in this object, for example when an Optional() element could be added to the string. Expecting is useful if you want to implement things like auto-completion, syntax error handling, auto-syntax-correction etc. In the "example" folder you will find an example. Run the html script in a browser. You will see that expecting is used to help you create a valid query string for SiriDB. SiriDB is an open source time series database with its own grammar class. Start writing something, click one of the options that appear and see what happens.

Elements

Jsleri has several Elements which can be used to create a grammar.

Keyword

Keyword(keyword,ignCase)

The parser needs to match the keyword which is just a string. When matching keywords we need to tell the parser what characters are allowed in keywords. By default Jsleri uses ^\w+ which equals to ^[A-Za-z0-9_]+. Keyword() accepts one more argument ignCase to tell the parser if we should match case insensitive.

Example:

constgrammar=newGrammar(Keyword('tic-tac-toe',true),// case insensitive'[A-Za-z-]+'// alternative keyword matching);console.log(grammar.parse('Tic-Tac-Toe').isValid);// true

Regex

Regex(pattern,ignCase)

The parser compiles a regular expression. Argument ignCase is set to false by default but can be set to true if you want the regular expression to be case insensitive. Note that ignore case is the only re flag from pyleri which will be compiled and accepted by jsleri.

See the Quick Usage example for how to use Regex.

Token

Token(token)

A token can be one or more characters and is usually used to match operators like +, -, // and so on. When we parse a string object where jsleri expects an element, it will automatically be converted to a Token() object.

Example:

// We could just write '-' instead of Token('-')// because any string will be converted to Token()constgrammar=newGrammar(List(Keyword('ni'),Token('-')));console.log(grammar.parse('ni-ni-ni-ni-ni').isValid);// true

Tokens

Tokens(tokens)

Can be used to register multiple tokens at once. The tokens argument should be a string with tokens separated by spaces. If given tokens are different in size the parser will try to match the longest tokens first.

Example:

constgrammar=newGrammar(List(Keyword('ni'),Tokens('+ - !=')));grammar.parse('ni + ni != ni - ni').isValid// => True

Sequence

Sequence(element,element, ...)

The parser needs to match each element in a sequence.

Example:

constgrammar=newGrammar(Sequence(Keyword('Tic'),Keyword('Tac'),Keyword('Toe')));console.log(grammar.parse('Tic Tac Toe').isValid);// true

Repeat

Repeat(element,mi,ma)

The parser needs at least mi elements and at most ma elements. When ma is set to undefined we allow unlimited number of elements. mi can be any integer value equal or higher than 0 but not larger then ma. The default value for mi is 0 and undefined for ma

Example:

constgrammar=newGrammar(Repeat(Keyword('ni')));console.log(grammar.parse('ni ni ni ni').isValid);// true

One should avoid to bind a name to the same element twice and Repeat(element, 1, 1) is a common solution to bind the element a second (or more) time(s).

For example consider the following:

constr_name=Regex('(?:"(?:[^"]*)")+');// Do NOT do thisconstr_address=r_name;// WRONG// Instead use Repeatconstr_address=Repeat(r_name,1,1);// Correct

List

List(element,delimiter,mi,ma,opt)

List is like Repeat but with a delimiter. A comma is used as default delimiter but any element is allowed. When a string is used as delimiter it will be converted to a Token element. mi and ma work excatly like with Repeat. opt kan be set to set to true to allow the list to end with a delimiter. By default this is set to false which means the list has to end with an element.

Example:

constgrammar=newGrammar(List(Keyword('ni')));console.log(grammar.parse('ni, ni, ni, ni, ni').isValid);// true

Optional

Optional(element)

The parser looks for an optional element. It is like using Repeat(element, 0, 1) but we encourage to use Optional since it is more readable. (and slightly faster)

Example:

constgrammar=newGrammar(Sequence(Keyword('hi'),Optional(Regex('(?:"(?:[^"]*)")+'))));console.log(grammar.parse('hi "Iris"').isValid);// trueconsole.log(grammar.parse('hi').isValid);// true

Ref

Ref(Constructor)

The grammar can make a forward reference to make recursion possible. In the example below we create a forward reference to START but note that a reference to any element can be made.

Warning: A reference is not protected against testing the same position in in a string. This could potentially lead to an infinite loop. For example:

letr=Ref(Optional);r.set(Optional(r));// DON'T DO THIS

Use Prio if such recursive construction is required.

Example:

// make a forward reference START to a Sequence.letSTART=Ref(Sequence);// we can now use STARTconstni_item=Choice(Keyword('ni'),START);// here we actually set STARTSTART.set(Sequence('[',List(ni_item),']'));// create and test the grammarconstgrammar=Grammar(START);console.log(grammar.parse('[ni, [ni, [], [ni, ni]]]').isValid);// true

Prio

Prio(element,element, ...)

Choose the first match from the prio elements and allow THIS for recursive operations. With THIS we point to the Prio element. Probably the example below explains how Prio and THIS can be used.

Note: Use a Ref when possible. A Prio element is required when the same position in a string is potentially checked more than once.

Example:

constgrammar=newGrammar(Prio(Keyword('ni'),Sequence('(',THIS,')'),Sequence(THIS,Keyword('or'),THIS),Sequence(THIS,Keyword('and'),THIS)));console.log(grammar.parse('(ni or ni) and (ni or ni)').isValid);// true

About

Parser for JavaScript

Resources

Stars

10 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

CIRelease Version

Javascript Left-Right Parser

Jsleri is an easy-to-use language parser for JavaScript.



Installation

Using npm:

$ npm i jsleri

In your project:

import*asjslerifrom'jsleri';// Exposes:// - jsleri.version// - jsleri.noop// - jsleri.Keyword// - jsleri.Regex// - jsleri.Token// - jsleri.Tokens// - jsleri.Sequence// - jsleri.Choice// - jsleri.Repeat// - jsleri.List// - jsleri.Optional// - jsleri.Ref// - jsleri.Prio// - jsleri.THIS// - jsleri.Grammar// - jsleri.EOS

Or... download the latest release from here and load the file in inside your project. For example:

<!-- Add this line to the <head> section to expose window.jsleri --><scriptsrc="jsleri-1.1.15.min.js"></script>

Related projects

Quick usage

import{Regex,Keyword,Sequence,Grammar}from'jsleri';// create your grammarclassMyGrammarextendsGrammar{staticSTART=Sequence(Keyword('hi'),Regex('(?:"(?:[^"]*)")+'));}// create a instance of your grammarconstmyGrammar=newMyGrammar();// do something with the grammaralert(myGrammar.parse('hi "Iris"').isValid);// alerts truealert(myGrammar.parse('hello "Iris"').isValid);// alerts false

Grammar

When writing a grammar you should subclass Grammar. A Grammar expects at least a START property so the parser knows where to start parsing. Grammar has a parse method: parse().

parse

syntax:

myGrammar.parse(string)

The parse() method returns a result object which has the following properties that are further explained in Result:

  • expecting
  • isValid
  • pos
  • tree

Result

The result of the parse() method contains 4 properties that will be explained next.

isValid

isValid returns a boolean value, True when the given string is valid according to the given grammar, False when not valid. node_result.isValid) # => False

Let us take the example from Quick usage.

alert(myGrammar.parse('hello "Iris"').isValid);// alerts false

Position

pos returns the position where the parser had to stop. (when isValid is True this value will be equal to the length of the given string with str.rstrip() applied)

Let us take the example from Quick usage.

alert(myGrammar.parse('hello "Iris"').pos);// alerts 0

Tree

tree contains the parse tree. Even when isValid is False the parse tree is returned but will only contain results as far as parsing has succeeded. The tree is the root node which can include several children nodes. The structure will be further clarified in the example found in the "example" folder. It explains a way of visualizing the parse tree.

The nodes in the example contain 5 properties:

  • start property returns the start of the node object.
  • end property returns the end of the node object.
  • element returns the type of Element (e.g. Repeat, Sequence, Keyword, etc.).
  • string returns the string that is parsed.
  • children can return a node object containing deeper layered nodes provided that there are any. In our example the root node has an element type Repeat(), starts at 0 and ends at 24, and it has two children. These children are node objects that have both an element type Sequence, start at 0 and 12 respectively, and so on.

Expecting

expecting returns an array containing elements which jsleri expects at pos. Even if isValid is true there might be elements in this object, for example when an Optional() element could be added to the string. Expecting is useful if you want to implement things like auto-completion, syntax error handling, auto-syntax-correction etc. In the "example" folder you will find an example. Run the html script in a browser. You will see that expecting is used to help you create a valid query string for SiriDB. SiriDB is an open source time series database with its own grammar class. Start writing something, click one of the options that appear and see what happens.

Elements

Jsleri has several Elements which can be used to create a grammar.

Keyword

Keyword(keyword,ignCase)

The parser needs to match the keyword which is just a string. When matching keywords we need to tell the parser what characters are allowed in keywords. By default Jsleri uses ^\w+ which equals to ^[A-Za-z0-9_]+. Keyword() accepts one more argument ignCase to tell the parser if we should match case insensitive.

Example:

constgrammar=newGrammar(Keyword('tic-tac-toe',true),// case insensitive'[A-Za-z-]+'// alternative keyword matching);console.log(grammar.parse('Tic-Tac-Toe').isValid);// true

Regex

Regex(pattern,ignCase)

The parser compiles a regular expression. Argument ignCase is set to false by default but can be set to true if you want the regular expression to be case insensitive. Note that ignore case is the only re flag from pyleri which will be compiled and accepted by jsleri.

See the Quick Usage example for how to use Regex.

Token

Token(token)

A token can be one or more characters and is usually used to match operators like +, -, // and so on. When we parse a string object where jsleri expects an element, it will automatically be converted to a Token() object.

Example:

// We could just write '-' instead of Token('-')// because any string will be converted to Token()constgrammar=newGrammar(List(Keyword('ni'),Token('-')));console.log(grammar.parse('ni-ni-ni-ni-ni').isValid);// true

Tokens

Tokens(tokens)

Can be used to register multiple tokens at once. The tokens argument should be a string with tokens separated by spaces. If given tokens are different in size the parser will try to match the longest tokens first.

Example:

constgrammar=newGrammar(List(Keyword('ni'),Tokens('+ - !=')));grammar.parse('ni + ni != ni - ni').isValid// => True

Sequence

Sequence(element,element, ...)

The parser needs to match each element in a sequence.

Example:

constgrammar=newGrammar(Sequence(Keyword('Tic'),Keyword('Tac'),Keyword('Toe')));console.log(grammar.parse('Tic Tac Toe').isValid);// true

Repeat

Repeat(element,mi,ma)

The parser needs at least mi elements and at most ma elements. When ma is set to undefined we allow unlimited number of elements. mi can be any integer value equal or higher than 0 but not larger then ma. The default value for mi is 0 and undefined for ma

Example:

constgrammar=newGrammar(Repeat(Keyword('ni')));console.log(grammar.parse('ni ni ni ni').isValid);// true

One should avoid to bind a name to the same element twice and Repeat(element, 1, 1) is a common solution to bind the element a second (or more) time(s).

For example consider the following:

constr_name=Regex('(?:"(?:[^"]*)")+');// Do NOT do thisconstr_address=r_name;// WRONG// Instead use Repeatconstr_address=Repeat(r_name,1,1);// Correct

List

List(element,delimiter,mi,ma,opt)

List is like Repeat but with a delimiter. A comma is used as default delimiter but any element is allowed. When a string is used as delimiter it will be converted to a Token element. mi and ma work excatly like with Repeat. opt kan be set to set to true to allow the list to end with a delimiter. By default this is set to false which means the list has to end with an element.

Example:

constgrammar=newGrammar(List(Keyword('ni')));console.log(grammar.parse('ni, ni, ni, ni, ni').isValid);// true

Optional

Optional(element)

The parser looks for an optional element. It is like using Repeat(element, 0, 1) but we encourage to use Optional since it is more readable. (and slightly faster)

Example:

constgrammar=newGrammar(Sequence(Keyword('hi'),Optional(Regex('(?:"(?:[^"]*)")+'))));console.log(grammar.parse('hi "Iris"').isValid);// trueconsole.log(grammar.parse('hi').isValid);// true

Ref

Ref(Constructor)

The grammar can make a forward reference to make recursion possible. In the example below we create a forward reference to START but note that a reference to any element can be made.

Warning: A reference is not protected against testing the same position in in a string. This could potentially lead to an infinite loop. For example:

letr=Ref(Optional);r.set(Optional(r));// DON'T DO THIS

Use Prio if such recursive construction is required.

Example:

// make a forward reference START to a Sequence.letSTART=Ref(Sequence);// we can now use STARTconstni_item=Choice(Keyword('ni'),START);// here we actually set STARTSTART.set(Sequence('[',List(ni_item),']'));// create and test the grammarconstgrammar=Grammar(START);console.log(grammar.parse('[ni, [ni, [], [ni, ni]]]').isValid);// true

Prio

Prio(element,element, ...)

Choose the first match from the prio elements and allow THIS for recursive operations. With THIS we point to the Prio element. Probably the example below explains how Prio and THIS can be used.

Note: Use a Ref when possible. A Prio element is required when the same position in a string is potentially checked more than once.

Example:

constgrammar=newGrammar(Prio(Keyword('ni'),Sequence('(',THIS,')'),Sequence(THIS,Keyword('or'),THIS),Sequence(THIS,Keyword('and'),THIS)));console.log(grammar.parse('(ni or ni) and (ni or ni)').isValid);// true

About

Parser for JavaScript

Resources

Stars

10 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

CIRelease Version

Javascript Left-Right Parser

Jsleri is an easy-to-use language parser for JavaScript.



Installation

Using npm:

$ npm i jsleri

In your project:

import*asjslerifrom'jsleri';// Exposes:// - jsleri.version// - jsleri.noop// - jsleri.Keyword// - jsleri.Regex// - jsleri.Token// - jsleri.Tokens// - jsleri.Sequence// - jsleri.Choice// - jsleri.Repeat// - jsleri.List// - jsleri.Optional// - jsleri.Ref// - jsleri.Prio// - jsleri.THIS// - jsleri.Grammar// - jsleri.EOS

Or... download the latest release from here and load the file in inside your project. For example:

<!-- Add this line to the <head> section to expose window.jsleri --><scriptsrc="jsleri-1.1.15.min.js"></script>

Related projects

Quick usage

import{Regex,Keyword,Sequence,Grammar}from'jsleri';// create your grammarclassMyGrammarextendsGrammar{staticSTART=Sequence(Keyword('hi'),Regex('(?:"(?:[^"]*)")+'));}// create a instance of your grammarconstmyGrammar=newMyGrammar();// do something with the grammaralert(myGrammar.parse('hi "Iris"').isValid);// alerts truealert(myGrammar.parse('hello "Iris"').isValid);// alerts false

Grammar

When writing a grammar you should subclass Grammar. A Grammar expects at least a START property so the parser knows where to start parsing. Grammar has a parse method: parse().

parse

syntax:

myGrammar.parse(string)

The parse() method returns a result object which has the following properties that are further explained in Result:

  • expecting
  • isValid
  • pos
  • tree

Result

The result of the parse() method contains 4 properties that will be explained next.

isValid

isValid returns a boolean value, True when the given string is valid according to the given grammar, False when not valid. node_result.isValid) # => False

Let us take the example from Quick usage.

alert(myGrammar.parse('hello "Iris"').isValid);// alerts false

Position

pos returns the position where the parser had to stop. (when isValid is True this value will be equal to the length of the given string with str.rstrip() applied)

Let us take the example from Quick usage.

alert(myGrammar.parse('hello "Iris"').pos);// alerts 0

Tree

tree contains the parse tree. Even when isValid is False the parse tree is returned but will only contain results as far as parsing has succeeded. The tree is the root node which can include several children nodes. The structure will be further clarified in the example found in the "example" folder. It explains a way of visualizing the parse tree.

The nodes in the example contain 5 properties:

  • start property returns the start of the node object.
  • end property returns the end of the node object.
  • element returns the type of Element (e.g. Repeat, Sequence, Keyword, etc.).
  • string returns the string that is parsed.
  • children can return a node object containing deeper layered nodes provided that there are any. In our example the root node has an element type Repeat(), starts at 0 and ends at 24, and it has two children. These children are node objects that have both an element type Sequence, start at 0 and 12 respectively, and so on.

Expecting

expecting returns an array containing elements which jsleri expects at pos. Even if isValid is true there might be elements in this object, for example when an Optional() element could be added to the string. Expecting is useful if you want to implement things like auto-completion, syntax error handling, auto-syntax-correction etc. In the "example" folder you will find an example. Run the html script in a browser. You will see that expecting is used to help you create a valid query string for SiriDB. SiriDB is an open source time series database with its own grammar class. Start writing something, click one of the options that appear and see what happens.

Elements

Jsleri has several Elements which can be used to create a grammar.

Keyword

Keyword(keyword,ignCase)

The parser needs to match the keyword which is just a string. When matching keywords we need to tell the parser what characters are allowed in keywords. By default Jsleri uses ^\w+ which equals to ^[A-Za-z0-9_]+. Keyword() accepts one more argument ignCase to tell the parser if we should match case insensitive.

Example:

constgrammar=newGrammar(Keyword('tic-tac-toe',true),// case insensitive'[A-Za-z-]+'// alternative keyword matching);console.log(grammar.parse('Tic-Tac-Toe').isValid);// true

Regex

Regex(pattern,ignCase)

The parser compiles a regular expression. Argument ignCase is set to false by default but can be set to true if you want the regular expression to be case insensitive. Note that ignore case is the only re flag from pyleri which will be compiled and accepted by jsleri.

See the Quick Usage example for how to use Regex.

Token

Token(token)

A token can be one or more characters and is usually used to match operators like +, -, // and so on. When we parse a string object where jsleri expects an element, it will automatically be converted to a Token() object.

Example:

// We could just write '-' instead of Token('-')// because any string will be converted to Token()constgrammar=newGrammar(List(Keyword('ni'),Token('-')));console.log(grammar.parse('ni-ni-ni-ni-ni').isValid);// true

Tokens

Tokens(tokens)

Can be used to register multiple tokens at once. The tokens argument should be a string with tokens separated by spaces. If given tokens are different in size the parser will try to match the longest tokens first.

Example:

constgrammar=newGrammar(List(Keyword('ni'),Tokens('+ - !=')));grammar.parse('ni + ni != ni - ni').isValid// => True

Sequence

Sequence(element,element, ...)

The parser needs to match each element in a sequence.

Example:

constgrammar=newGrammar(Sequence(Keyword('Tic'),Keyword('Tac'),Keyword('Toe')));console.log(grammar.parse('Tic Tac Toe').isValid);// true

Repeat

Repeat(element,mi,ma)

The parser needs at least mi elements and at most ma elements. When ma is set to undefined we allow unlimited number of elements. mi can be any integer value equal or higher than 0 but not larger then ma. The default value for mi is 0 and undefined for ma

Example:

constgrammar=newGrammar(Repeat(Keyword('ni')));console.log(grammar.parse('ni ni ni ni').isValid);// true

One should avoid to bind a name to the same element twice and Repeat(element, 1, 1) is a common solution to bind the element a second (or more) time(s).

For example consider the following:

constr_name=Regex('(?:"(?:[^"]*)")+');// Do NOT do thisconstr_address=r_name;// WRONG// Instead use Repeatconstr_address=Repeat(r_name,1,1);// Correct

List

List(element,delimiter,mi,ma,opt)

List is like Repeat but with a delimiter. A comma is used as default delimiter but any element is allowed. When a string is used as delimiter it will be converted to a Token element. mi and ma work excatly like with Repeat. opt kan be set to set to true to allow the list to end with a delimiter. By default this is set to false which means the list has to end with an element.

Example:

constgrammar=newGrammar(List(Keyword('ni')));console.log(grammar.parse('ni, ni, ni, ni, ni').isValid);// true

Optional

Optional(element)

The parser looks for an optional element. It is like using Repeat(element, 0, 1) but we encourage to use Optional since it is more readable. (and slightly faster)

Example:

constgrammar=newGrammar(Sequence(Keyword('hi'),Optional(Regex('(?:"(?:[^"]*)")+'))));console.log(grammar.parse('hi "Iris"').isValid);// trueconsole.log(grammar.parse('hi').isValid);// true

Ref

Ref(Constructor)

The grammar can make a forward reference to make recursion possible. In the example below we create a forward reference to START but note that a reference to any element can be made.

Warning: A reference is not protected against testing the same position in in a string. This could potentially lead to an infinite loop. For example:

letr=Ref(Optional);r.set(Optional(r));// DON'T DO THIS

Use Prio if such recursive construction is required.

Example:

// make a forward reference START to a Sequence.letSTART=Ref(Sequence);// we can now use STARTconstni_item=Choice(Keyword('ni'),START);// here we actually set STARTSTART.set(Sequence('[',List(ni_item),']'));// create and test the grammarconstgrammar=Grammar(START);console.log(grammar.parse('[ni, [ni, [], [ni, ni]]]').isValid);// true

Prio

Prio(element,element, ...)

Choose the first match from the prio elements and allow THIS for recursive operations. With THIS we point to the Prio element. Probably the example below explains how Prio and THIS can be used.

Note: Use a Ref when possible. A Prio element is required when the same position in a string is potentially checked more than once.

Example:

constgrammar=newGrammar(Prio(Keyword('ni'),Sequence('(',THIS,')'),Sequence(THIS,Keyword('or'),THIS),Sequence(THIS,Keyword('and'),THIS)));console.log(grammar.parse('(ni or ni) and (ni or ni)').isValid);// true

About

Parser for JavaScript

Resources

Stars

10 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

CIRelease Version

Javascript Left-Right Parser

Jsleri is an easy-to-use language parser for JavaScript.



Installation

Using npm:

$ npm i jsleri

In your project:

import*asjslerifrom'jsleri';// Exposes:// - jsleri.version// - jsleri.noop// - jsleri.Keyword// - jsleri.Regex// - jsleri.Token// - jsleri.Tokens// - jsleri.Sequence// - jsleri.Choice// - jsleri.Repeat// - jsleri.List// - jsleri.Optional// - jsleri.Ref// - jsleri.Prio// - jsleri.THIS// - jsleri.Grammar// - jsleri.EOS

Or... download the latest release from here and load the file in inside your project. For example:

<!-- Add this line to the <head> section to expose window.jsleri --><scriptsrc="jsleri-1.1.15.min.js"></script>

Related projects

Quick usage

import{Regex,Keyword,Sequence,Grammar}from'jsleri';// create your grammarclassMyGrammarextendsGrammar{staticSTART=Sequence(Keyword('hi'),Regex('(?:"(?:[^"]*)")+'));}// create a instance of your grammarconstmyGrammar=newMyGrammar();// do something with the grammaralert(myGrammar.parse('hi "Iris"').isValid);// alerts truealert(myGrammar.parse('hello "Iris"').isValid);// alerts false

Grammar

When writing a grammar you should subclass Grammar. A Grammar expects at least a START property so the parser knows where to start parsing. Grammar has a parse method: parse().

parse

syntax:

myGrammar.parse(string)

The parse() method returns a result object which has the following properties that are further explained in Result:

  • expecting
  • isValid
  • pos
  • tree

Result

The result of the parse() method contains 4 properties that will be explained next.

isValid

isValid returns a boolean value, True when the given string is valid according to the given grammar, False when not valid. node_result.isValid) # => False

Let us take the example from Quick usage.

alert(myGrammar.parse('hello "Iris"').isValid);// alerts false

Position

pos returns the position where the parser had to stop. (when isValid is True this value will be equal to the length of the given string with str.rstrip() applied)

Let us take the example from Quick usage.

alert(myGrammar.parse('hello "Iris"').pos);// alerts 0

Tree

tree contains the parse tree. Even when isValid is False the parse tree is returned but will only contain results as far as parsing has succeeded. The tree is the root node which can include several children nodes. The structure will be further clarified in the example found in the "example" folder. It explains a way of visualizing the parse tree.

The nodes in the example contain 5 properties:

  • start property returns the start of the node object.
  • end property returns the end of the node object.
  • element returns the type of Element (e.g. Repeat, Sequence, Keyword, etc.).
  • string returns the string that is parsed.
  • children can return a node object containing deeper layered nodes provided that there are any. In our example the root node has an element type Repeat(), starts at 0 and ends at 24, and it has two children. These children are node objects that have both an element type Sequence, start at 0 and 12 respectively, and so on.

Expecting

expecting returns an array containing elements which jsleri expects at pos. Even if isValid is true there might be elements in this object, for example when an Optional() element could be added to the string. Expecting is useful if you want to implement things like auto-completion, syntax error handling, auto-syntax-correction etc. In the "example" folder you will find an example. Run the html script in a browser. You will see that expecting is used to help you create a valid query string for SiriDB. SiriDB is an open source time series database with its own grammar class. Start writing something, click one of the options that appear and see what happens.

Elements

Jsleri has several Elements which can be used to create a grammar.

Keyword

Keyword(keyword,ignCase)

The parser needs to match the keyword which is just a string. When matching keywords we need to tell the parser what characters are allowed in keywords. By default Jsleri uses ^\w+ which equals to ^[A-Za-z0-9_]+. Keyword() accepts one more argument ignCase to tell the parser if we should match case insensitive.

Example:

constgrammar=newGrammar(Keyword('tic-tac-toe',true),// case insensitive'[A-Za-z-]+'// alternative keyword matching);console.log(grammar.parse('Tic-Tac-Toe').isValid);// true

Regex

Regex(pattern,ignCase)

The parser compiles a regular expression. Argument ignCase is set to false by default but can be set to true if you want the regular expression to be case insensitive. Note that ignore case is the only re flag from pyleri which will be compiled and accepted by jsleri.

See the Quick Usage example for how to use Regex.

Token

Token(token)

A token can be one or more characters and is usually used to match operators like +, -, // and so on. When we parse a string object where jsleri expects an element, it will automatically be converted to a Token() object.

Example:

// We could just write '-' instead of Token('-')// because any string will be converted to Token()constgrammar=newGrammar(List(Keyword('ni'),Token('-')));console.log(grammar.parse('ni-ni-ni-ni-ni').isValid);// true

Tokens

Tokens(tokens)

Can be used to register multiple tokens at once. The tokens argument should be a string with tokens separated by spaces. If given tokens are different in size the parser will try to match the longest tokens first.

Example:

constgrammar=newGrammar(List(Keyword('ni'),Tokens('+ - !=')));grammar.parse('ni + ni != ni - ni').isValid// => True

Sequence

Sequence(element,element, ...)

The parser needs to match each element in a sequence.

Example:

constgrammar=newGrammar(Sequence(Keyword('Tic'),Keyword('Tac'),Keyword('Toe')));console.log(grammar.parse('Tic Tac Toe').isValid);// true

Repeat

Repeat(element,mi,ma)

The parser needs at least mi elements and at most ma elements. When ma is set to undefined we allow unlimited number of elements. mi can be any integer value equal or higher than 0 but not larger then ma. The default value for mi is 0 and undefined for ma

Example:

constgrammar=newGrammar(Repeat(Keyword('ni')));console.log(grammar.parse('ni ni ni ni').isValid);// true

One should avoid to bind a name to the same element twice and Repeat(element, 1, 1) is a common solution to bind the element a second (or more) time(s).

For example consider the following:

constr_name=Regex('(?:"(?:[^"]*)")+');// Do NOT do thisconstr_address=r_name;// WRONG// Instead use Repeatconstr_address=Repeat(r_name,1,1);// Correct

List

List(element,delimiter,mi,ma,opt)

List is like Repeat but with a delimiter. A comma is used as default delimiter but any element is allowed. When a string is used as delimiter it will be converted to a Token element. mi and ma work excatly like with Repeat. opt kan be set to set to true to allow the list to end with a delimiter. By default this is set to false which means the list has to end with an element.

Example:

constgrammar=newGrammar(List(Keyword('ni')));console.log(grammar.parse('ni, ni, ni, ni, ni').isValid);// true

Optional

Optional(element)

The parser looks for an optional element. It is like using Repeat(element, 0, 1) but we encourage to use Optional since it is more readable. (and slightly faster)

Example:

constgrammar=newGrammar(Sequence(Keyword('hi'),Optional(Regex('(?:"(?:[^"]*)")+'))));console.log(grammar.parse('hi "Iris"').isValid);// trueconsole.log(grammar.parse('hi').isValid);// true

Ref

Ref(Constructor)

The grammar can make a forward reference to make recursion possible. In the example below we create a forward reference to START but note that a reference to any element can be made.

Warning: A reference is not protected against testing the same position in in a string. This could potentially lead to an infinite loop. For example:

letr=Ref(Optional);r.set(Optional(r));// DON'T DO THIS

Use Prio if such recursive construction is required.

Example:

// make a forward reference START to a Sequence.letSTART=Ref(Sequence);// we can now use STARTconstni_item=Choice(Keyword('ni'),START);// here we actually set STARTSTART.set(Sequence('[',List(ni_item),']'));// create and test the grammarconstgrammar=Grammar(START);console.log(grammar.parse('[ni, [ni, [], [ni, ni]]]').isValid);// true

Prio

Prio(element,element, ...)

Choose the first match from the prio elements and allow THIS for recursive operations. With THIS we point to the Prio element. Probably the example below explains how Prio and THIS can be used.

Note: Use a Ref when possible. A Prio element is required when the same position in a string is potentially checked more than once.

Example:

constgrammar=newGrammar(Prio(Keyword('ni'),Sequence('(',THIS,')'),Sequence(THIS,Keyword('or'),THIS),Sequence(THIS,Keyword('and'),THIS)));console.log(grammar.parse('(ni or ni) and (ni or ni)').isValid);// true

About

Parser for JavaScript

Resources

Stars

10 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

CIRelease Version

Javascript Left-Right Parser

Jsleri is an easy-to-use language parser for JavaScript.



Installation

Using npm:

$ npm i jsleri

In your project:

import*asjslerifrom'jsleri';// Exposes:// - jsleri.version// - jsleri.noop// - jsleri.Keyword// - jsleri.Regex// - jsleri.Token// - jsleri.Tokens// - jsleri.Sequence// - jsleri.Choice// - jsleri.Repeat// - jsleri.List// - jsleri.Optional// - jsleri.Ref// - jsleri.Prio// - jsleri.THIS// - jsleri.Grammar// - jsleri.EOS

Or... download the latest release from here and load the file in inside your project. For example:

<!-- Add this line to the <head> section to expose window.jsleri --><scriptsrc="jsleri-1.1.15.min.js"></script>

Related projects

Quick usage

import{Regex,Keyword,Sequence,Grammar}from'jsleri';// create your grammarclassMyGrammarextendsGrammar{staticSTART=Sequence(Keyword('hi'),Regex('(?:"(?:[^"]*)")+'));}// create a instance of your grammarconstmyGrammar=newMyGrammar();// do something with the grammaralert(myGrammar.parse('hi "Iris"').isValid);// alerts truealert(myGrammar.parse('hello "Iris"').isValid);// alerts false

Grammar

When writing a grammar you should subclass Grammar. A Grammar expects at least a START property so the parser knows where to start parsing. Grammar has a parse method: parse().

parse

syntax:

myGrammar.parse(string)

The parse() method returns a result object which has the following properties that are further explained in Result:

  • expecting
  • isValid
  • pos
  • tree

Result

The result of the parse() method contains 4 properties that will be explained next.

isValid

isValid returns a boolean value, True when the given string is valid according to the given grammar, False when not valid. node_result.isValid) # => False

Let us take the example from Quick usage.

alert(myGrammar.parse('hello "Iris"').isValid);// alerts false

Position

pos returns the position where the parser had to stop. (when isValid is True this value will be equal to the length of the given string with str.rstrip() applied)

Let us take the example from Quick usage.

alert(myGrammar.parse('hello "Iris"').pos);// alerts 0

Tree

tree contains the parse tree. Even when isValid is False the parse tree is returned but will only contain results as far as parsing has succeeded. The tree is the root node which can include several children nodes. The structure will be further clarified in the example found in the "example" folder. It explains a way of visualizing the parse tree.

The nodes in the example contain 5 properties:

  • start property returns the start of the node object.
  • end property returns the end of the node object.
  • element returns the type of Element (e.g. Repeat, Sequence, Keyword, etc.).
  • string returns the string that is parsed.
  • children can return a node object containing deeper layered nodes provided that there are any. In our example the root node has an element type Repeat(), starts at 0 and ends at 24, and it has two children. These children are node objects that have both an element type Sequence, start at 0 and 12 respectively, and so on.

Expecting

expecting returns an array containing elements which jsleri expects at pos. Even if isValid is true there might be elements in this object, for example when an Optional() element could be added to the string. Expecting is useful if you want to implement things like auto-completion, syntax error handling, auto-syntax-correction etc. In the "example" folder you will find an example. Run the html script in a browser. You will see that expecting is used to help you create a valid query string for SiriDB. SiriDB is an open source time series database with its own grammar class. Start writing something, click one of the options that appear and see what happens.

Elements

Jsleri has several Elements which can be used to create a grammar.

Keyword

Keyword(keyword,ignCase)

The parser needs to match the keyword which is just a string. When matching keywords we need to tell the parser what characters are allowed in keywords. By default Jsleri uses ^\w+ which equals to ^[A-Za-z0-9_]+. Keyword() accepts one more argument ignCase to tell the parser if we should match case insensitive.

Example:

constgrammar=newGrammar(Keyword('tic-tac-toe',true),// case insensitive'[A-Za-z-]+'// alternative keyword matching);console.log(grammar.parse('Tic-Tac-Toe').isValid);// true

Regex

Regex(pattern,ignCase)

The parser compiles a regular expression. Argument ignCase is set to false by default but can be set to true if you want the regular expression to be case insensitive. Note that ignore case is the only re flag from pyleri which will be compiled and accepted by jsleri.

See the Quick Usage example for how to use Regex.

Token

Token(token)

A token can be one or more characters and is usually used to match operators like +, -, // and so on. When we parse a string object where jsleri expects an element, it will automatically be converted to a Token() object.

Example:

// We could just write '-' instead of Token('-')// because any string will be converted to Token()constgrammar=newGrammar(List(Keyword('ni'),Token('-')));console.log(grammar.parse('ni-ni-ni-ni-ni').isValid);// true

Tokens

Tokens(tokens)

Can be used to register multiple tokens at once. The tokens argument should be a string with tokens separated by spaces. If given tokens are different in size the parser will try to match the longest tokens first.

Example:

constgrammar=newGrammar(List(Keyword('ni'),Tokens('+ - !=')));grammar.parse('ni + ni != ni - ni').isValid// => True

Sequence

Sequence(element,element, ...)

The parser needs to match each element in a sequence.

Example:

constgrammar=newGrammar(Sequence(Keyword('Tic'),Keyword('Tac'),Keyword('Toe')));console.log(grammar.parse('Tic Tac Toe').isValid);// true

Repeat

Repeat(element,mi,ma)

The parser needs at least mi elements and at most ma elements. When ma is set to undefined we allow unlimited number of elements. mi can be any integer value equal or higher than 0 but not larger then ma. The default value for mi is 0 and undefined for ma

Example:

constgrammar=newGrammar(Repeat(Keyword('ni')));console.log(grammar.parse('ni ni ni ni').isValid);// true

One should avoid to bind a name to the same element twice and Repeat(element, 1, 1) is a common solution to bind the element a second (or more) time(s).

For example consider the following:

constr_name=Regex('(?:"(?:[^"]*)")+');// Do NOT do thisconstr_address=r_name;// WRONG// Instead use Repeatconstr_address=Repeat(r_name,1,1);// Correct

List

List(element,delimiter,mi,ma,opt)

List is like Repeat but with a delimiter. A comma is used as default delimiter but any element is allowed. When a string is used as delimiter it will be converted to a Token element. mi and ma work excatly like with Repeat. opt kan be set to set to true to allow the list to end with a delimiter. By default this is set to false which means the list has to end with an element.

Example:

constgrammar=newGrammar(List(Keyword('ni')));console.log(grammar.parse('ni, ni, ni, ni, ni').isValid);// true

Optional

Optional(element)

The parser looks for an optional element. It is like using Repeat(element, 0, 1) but we encourage to use Optional since it is more readable. (and slightly faster)

Example:

constgrammar=newGrammar(Sequence(Keyword('hi'),Optional(Regex('(?:"(?:[^"]*)")+'))));console.log(grammar.parse('hi "Iris"').isValid);// trueconsole.log(grammar.parse('hi').isValid);// true

Ref

Ref(Constructor)

The grammar can make a forward reference to make recursion possible. In the example below we create a forward reference to START but note that a reference to any element can be made.

Warning: A reference is not protected against testing the same position in in a string. This could potentially lead to an infinite loop. For example:

letr=Ref(Optional);r.set(Optional(r));// DON'T DO THIS

Use Prio if such recursive construction is required.

Example:

// make a forward reference START to a Sequence.letSTART=Ref(Sequence);// we can now use STARTconstni_item=Choice(Keyword('ni'),START);// here we actually set STARTSTART.set(Sequence('[',List(ni_item),']'));// create and test the grammarconstgrammar=Grammar(START);console.log(grammar.parse('[ni, [ni, [], [ni, ni]]]').isValid);// true

Prio

Prio(element,element, ...)

Choose the first match from the prio elements and allow THIS for recursive operations. With THIS we point to the Prio element. Probably the example below explains how Prio and THIS can be used.

Note: Use a Ref when possible. A Prio element is required when the same position in a string is potentially checked more than once.

Example:

constgrammar=newGrammar(Prio(Keyword('ni'),Sequence('(',THIS,')'),Sequence(THIS,Keyword('or'),THIS),Sequence(THIS,Keyword('and'),THIS)));console.log(grammar.parse('(ni or ni) and (ni or ni)').isValid);// true

About

Parser for JavaScript

Resources

Stars

10 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

CIRelease Version

Javascript Left-Right Parser

Jsleri is an easy-to-use language parser for JavaScript.



Installation

Using npm:

$ npm i jsleri

In your project:

import*asjslerifrom'jsleri';// Exposes:// - jsleri.version// - jsleri.noop// - jsleri.Keyword// - jsleri.Regex// - jsleri.Token// - jsleri.Tokens// - jsleri.Sequence// - jsleri.Choice// - jsleri.Repeat// - jsleri.List// - jsleri.Optional// - jsleri.Ref// - jsleri.Prio// - jsleri.THIS// - jsleri.Grammar// - jsleri.EOS

Or... download the latest release from here and load the file in inside your project. For example:

<!-- Add this line to the <head> section to expose window.jsleri --><scriptsrc="jsleri-1.1.15.min.js"></script>

Related projects

Quick usage

import{Regex,Keyword,Sequence,Grammar}from'jsleri';// create your grammarclassMyGrammarextendsGrammar{staticSTART=Sequence(Keyword('hi'),Regex('(?:"(?:[^"]*)")+'));}// create a instance of your grammarconstmyGrammar=newMyGrammar();// do something with the grammaralert(myGrammar.parse('hi "Iris"').isValid);// alerts truealert(myGrammar.parse('hello "Iris"').isValid);// alerts false

Grammar

When writing a grammar you should subclass Grammar. A Grammar expects at least a START property so the parser knows where to start parsing. Grammar has a parse method: parse().

parse

syntax:

myGrammar.parse(string)

The parse() method returns a result object which has the following properties that are further explained in Result:

  • expecting
  • isValid
  • pos
  • tree

Result

The result of the parse() method contains 4 properties that will be explained next.

isValid

isValid returns a boolean value, True when the given string is valid according to the given grammar, False when not valid. node_result.isValid) # => False

Let us take the example from Quick usage.

alert(myGrammar.parse('hello "Iris"').isValid);// alerts false

Position

pos returns the position where the parser had to stop. (when isValid is True this value will be equal to the length of the given string with str.rstrip() applied)

Let us take the example from Quick usage.

alert(myGrammar.parse('hello "Iris"').pos);// alerts 0

Tree

tree contains the parse tree. Even when isValid is False the parse tree is returned but will only contain results as far as parsing has succeeded. The tree is the root node which can include several children nodes. The structure will be further clarified in the example found in the "example" folder. It explains a way of visualizing the parse tree.

The nodes in the example contain 5 properties:

  • start property returns the start of the node object.
  • end property returns the end of the node object.
  • element returns the type of Element (e.g. Repeat, Sequence, Keyword, etc.).
  • string returns the string that is parsed.
  • children can return a node object containing deeper layered nodes provided that there are any. In our example the root node has an element type Repeat(), starts at 0 and ends at 24, and it has two children. These children are node objects that have both an element type Sequence, start at 0 and 12 respectively, and so on.

Expecting

expecting returns an array containing elements which jsleri expects at pos. Even if isValid is true there might be elements in this object, for example when an Optional() element could be added to the string. Expecting is useful if you want to implement things like auto-completion, syntax error handling, auto-syntax-correction etc. In the "example" folder you will find an example. Run the html script in a browser. You will see that expecting is used to help you create a valid query string for SiriDB. SiriDB is an open source time series database with its own grammar class. Start writing something, click one of the options that appear and see what happens.

Elements

Jsleri has several Elements which can be used to create a grammar.

Keyword

Keyword(keyword,ignCase)

The parser needs to match the keyword which is just a string. When matching keywords we need to tell the parser what characters are allowed in keywords. By default Jsleri uses ^\w+ which equals to ^[A-Za-z0-9_]+. Keyword() accepts one more argument ignCase to tell the parser if we should match case insensitive.

Example:

constgrammar=newGrammar(Keyword('tic-tac-toe',true),// case insensitive'[A-Za-z-]+'// alternative keyword matching);console.log(grammar.parse('Tic-Tac-Toe').isValid);// true

Regex

Regex(pattern,ignCase)

The parser compiles a regular expression. Argument ignCase is set to false by default but can be set to true if you want the regular expression to be case insensitive. Note that ignore case is the only re flag from pyleri which will be compiled and accepted by jsleri.

See the Quick Usage example for how to use Regex.

Token

Token(token)

A token can be one or more characters and is usually used to match operators like +, -, // and so on. When we parse a string object where jsleri expects an element, it will automatically be converted to a Token() object.

Example:

// We could just write '-' instead of Token('-')// because any string will be converted to Token()constgrammar=newGrammar(List(Keyword('ni'),Token('-')));console.log(grammar.parse('ni-ni-ni-ni-ni').isValid);// true

Tokens

Tokens(tokens)

Can be used to register multiple tokens at once. The tokens argument should be a string with tokens separated by spaces. If given tokens are different in size the parser will try to match the longest tokens first.

Example:

constgrammar=newGrammar(List(Keyword('ni'),Tokens('+ - !=')));grammar.parse('ni + ni != ni - ni').isValid// => True

Sequence

Sequence(element,element, ...)

The parser needs to match each element in a sequence.

Example:

constgrammar=newGrammar(Sequence(Keyword('Tic'),Keyword('Tac'),Keyword('Toe')));console.log(grammar.parse('Tic Tac Toe').isValid);// true

Repeat

Repeat(element,mi,ma)

The parser needs at least mi elements and at most ma elements. When ma is set to undefined we allow unlimited number of elements. mi can be any integer value equal or higher than 0 but not larger then ma. The default value for mi is 0 and undefined for ma

Example:

constgrammar=newGrammar(Repeat(Keyword('ni')));console.log(grammar.parse('ni ni ni ni').isValid);// true

One should avoid to bind a name to the same element twice and Repeat(element, 1, 1) is a common solution to bind the element a second (or more) time(s).

For example consider the following:

constr_name=Regex('(?:"(?:[^"]*)")+');// Do NOT do thisconstr_address=r_name;// WRONG// Instead use Repeatconstr_address=Repeat(r_name,1,1);// Correct

List

List(element,delimiter,mi,ma,opt)

List is like Repeat but with a delimiter. A comma is used as default delimiter but any element is allowed. When a string is used as delimiter it will be converted to a Token element. mi and ma work excatly like with Repeat. opt kan be set to set to true to allow the list to end with a delimiter. By default this is set to false which means the list has to end with an element.

Example:

constgrammar=newGrammar(List(Keyword('ni')));console.log(grammar.parse('ni, ni, ni, ni, ni').isValid);// true

Optional

Optional(element)

The parser looks for an optional element. It is like using Repeat(element, 0, 1) but we encourage to use Optional since it is more readable. (and slightly faster)

Example:

constgrammar=newGrammar(Sequence(Keyword('hi'),Optional(Regex('(?:"(?:[^"]*)")+'))));console.log(grammar.parse('hi "Iris"').isValid);// trueconsole.log(grammar.parse('hi').isValid);// true

Ref

Ref(Constructor)

The grammar can make a forward reference to make recursion possible. In the example below we create a forward reference to START but note that a reference to any element can be made.

Warning: A reference is not protected against testing the same position in in a string. This could potentially lead to an infinite loop. For example:

letr=Ref(Optional);r.set(Optional(r));// DON'T DO THIS

Use Prio if such recursive construction is required.

Example:

// make a forward reference START to a Sequence.letSTART=Ref(Sequence);// we can now use STARTconstni_item=Choice(Keyword('ni'),START);// here we actually set STARTSTART.set(Sequence('[',List(ni_item),']'));// create and test the grammarconstgrammar=Grammar(START);console.log(grammar.parse('[ni, [ni, [], [ni, ni]]]').isValid);// true

Prio

Prio(element,element, ...)

Choose the first match from the prio elements and allow THIS for recursive operations. With THIS we point to the Prio element. Probably the example below explains how Prio and THIS can be used.

Note: Use a Ref when possible. A Prio element is required when the same position in a string is potentially checked more than once.

Example:

constgrammar=newGrammar(Prio(Keyword('ni'),Sequence('(',THIS,')'),Sequence(THIS,Keyword('or'),THIS),Sequence(THIS,Keyword('and'),THIS)));console.log(grammar.parse('(ni or ni) and (ni or ni)').isValid);// true

About

Parser for JavaScript

Resources

Stars

10 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

CIRelease Version

Javascript Left-Right Parser

Jsleri is an easy-to-use language parser for JavaScript.



Installation

Using npm:

$ npm i jsleri

In your project:

import*asjslerifrom'jsleri';// Exposes:// - jsleri.version// - jsleri.noop// - jsleri.Keyword// - jsleri.Regex// - jsleri.Token// - jsleri.Tokens// - jsleri.Sequence// - jsleri.Choice// - jsleri.Repeat// - jsleri.List// - jsleri.Optional// - jsleri.Ref// - jsleri.Prio// - jsleri.THIS// - jsleri.Grammar// - jsleri.EOS

Or... download the latest release from here and load the file in inside your project. For example:

<!-- Add this line to the <head> section to expose window.jsleri --><scriptsrc="jsleri-1.1.15.min.js"></script>

Related projects

Quick usage

import{Regex,Keyword,Sequence,Grammar}from'jsleri';// create your grammarclassMyGrammarextendsGrammar{staticSTART=Sequence(Keyword('hi'),Regex('(?:"(?:[^"]*)")+'));}// create a instance of your grammarconstmyGrammar=newMyGrammar();// do something with the grammaralert(myGrammar.parse('hi "Iris"').isValid);// alerts truealert(myGrammar.parse('hello "Iris"').isValid);// alerts false

Grammar

When writing a grammar you should subclass Grammar. A Grammar expects at least a START property so the parser knows where to start parsing. Grammar has a parse method: parse().

parse

syntax:

myGrammar.parse(string)

The parse() method returns a result object which has the following properties that are further explained in Result:

  • expecting
  • isValid
  • pos
  • tree

Result

The result of the parse() method contains 4 properties that will be explained next.

isValid

isValid returns a boolean value, True when the given string is valid according to the given grammar, False when not valid. node_result.isValid) # => False

Let us take the example from Quick usage.

alert(myGrammar.parse('hello "Iris"').isValid);// alerts false

Position

pos returns the position where the parser had to stop. (when isValid is True this value will be equal to the length of the given string with str.rstrip() applied)

Let us take the example from Quick usage.

alert(myGrammar.parse('hello "Iris"').pos);// alerts 0

Tree

tree contains the parse tree. Even when isValid is False the parse tree is returned but will only contain results as far as parsing has succeeded. The tree is the root node which can include several children nodes. The structure will be further clarified in the example found in the "example" folder. It explains a way of visualizing the parse tree.

The nodes in the example contain 5 properties:

  • start property returns the start of the node object.
  • end property returns the end of the node object.
  • element returns the type of Element (e.g. Repeat, Sequence, Keyword, etc.).
  • string returns the string that is parsed.
  • children can return a node object containing deeper layered nodes provided that there are any. In our example the root node has an element type Repeat(), starts at 0 and ends at 24, and it has two children. These children are node objects that have both an element type Sequence, start at 0 and 12 respectively, and so on.

Expecting

expecting returns an array containing elements which jsleri expects at pos. Even if isValid is true there might be elements in this object, for example when an Optional() element could be added to the string. Expecting is useful if you want to implement things like auto-completion, syntax error handling, auto-syntax-correction etc. In the "example" folder you will find an example. Run the html script in a browser. You will see that expecting is used to help you create a valid query string for SiriDB. SiriDB is an open source time series database with its own grammar class. Start writing something, click one of the options that appear and see what happens.

Elements

Jsleri has several Elements which can be used to create a grammar.

Keyword

Keyword(keyword,ignCase)

The parser needs to match the keyword which is just a string. When matching keywords we need to tell the parser what characters are allowed in keywords. By default Jsleri uses ^\w+ which equals to ^[A-Za-z0-9_]+. Keyword() accepts one more argument ignCase to tell the parser if we should match case insensitive.

Example:

constgrammar=newGrammar(Keyword('tic-tac-toe',true),// case insensitive'[A-Za-z-]+'// alternative keyword matching);console.log(grammar.parse('Tic-Tac-Toe').isValid);// true

Regex

Regex(pattern,ignCase)

The parser compiles a regular expression. Argument ignCase is set to false by default but can be set to true if you want the regular expression to be case insensitive. Note that ignore case is the only re flag from pyleri which will be compiled and accepted by jsleri.

See the Quick Usage example for how to use Regex.

Token

Token(token)

A token can be one or more characters and is usually used to match operators like +, -, // and so on. When we parse a string object where jsleri expects an element, it will automatically be converted to a Token() object.

Example:

// We could just write '-' instead of Token('-')// because any string will be converted to Token()constgrammar=newGrammar(List(Keyword('ni'),Token('-')));console.log(grammar.parse('ni-ni-ni-ni-ni').isValid);// true

Tokens

Tokens(tokens)

Can be used to register multiple tokens at once. The tokens argument should be a string with tokens separated by spaces. If given tokens are different in size the parser will try to match the longest tokens first.

Example:

constgrammar=newGrammar(List(Keyword('ni'),Tokens('+ - !=')));grammar.parse('ni + ni != ni - ni').isValid// => True

Sequence

Sequence(element,element, ...)

The parser needs to match each element in a sequence.

Example:

constgrammar=newGrammar(Sequence(Keyword('Tic'),Keyword('Tac'),Keyword('Toe')));console.log(grammar.parse('Tic Tac Toe').isValid);// true

Repeat

Repeat(element,mi,ma)

The parser needs at least mi elements and at most ma elements. When ma is set to undefined we allow unlimited number of elements. mi can be any integer value equal or higher than 0 but not larger then ma. The default value for mi is 0 and undefined for ma

Example:

constgrammar=newGrammar(Repeat(Keyword('ni')));console.log(grammar.parse('ni ni ni ni').isValid);// true

One should avoid to bind a name to the same element twice and Repeat(element, 1, 1) is a common solution to bind the element a second (or more) time(s).

For example consider the following:

constr_name=Regex('(?:"(?:[^"]*)")+');// Do NOT do thisconstr_address=r_name;// WRONG// Instead use Repeatconstr_address=Repeat(r_name,1,1);// Correct

List

List(element,delimiter,mi,ma,opt)

List is like Repeat but with a delimiter. A comma is used as default delimiter but any element is allowed. When a string is used as delimiter it will be converted to a Token element. mi and ma work excatly like with Repeat. opt kan be set to set to true to allow the list to end with a delimiter. By default this is set to false which means the list has to end with an element.

Example:

constgrammar=newGrammar(List(Keyword('ni')));console.log(grammar.parse('ni, ni, ni, ni, ni').isValid);// true

Optional

Optional(element)

The parser looks for an optional element. It is like using Repeat(element, 0, 1) but we encourage to use Optional since it is more readable. (and slightly faster)

Example:

constgrammar=newGrammar(Sequence(Keyword('hi'),Optional(Regex('(?:"(?:[^"]*)")+'))));console.log(grammar.parse('hi "Iris"').isValid);// trueconsole.log(grammar.parse('hi').isValid);// true

Ref

Ref(Constructor)

The grammar can make a forward reference to make recursion possible. In the example below we create a forward reference to START but note that a reference to any element can be made.

Warning: A reference is not protected against testing the same position in in a string. This could potentially lead to an infinite loop. For example:

letr=Ref(Optional);r.set(Optional(r));// DON'T DO THIS

Use Prio if such recursive construction is required.

Example:

// make a forward reference START to a Sequence.letSTART=Ref(Sequence);// we can now use STARTconstni_item=Choice(Keyword('ni'),START);// here we actually set STARTSTART.set(Sequence('[',List(ni_item),']'));// create and test the grammarconstgrammar=Grammar(START);console.log(grammar.parse('[ni, [ni, [], [ni, ni]]]').isValid);// true

Prio

Prio(element,element, ...)

Choose the first match from the prio elements and allow THIS for recursive operations. With THIS we point to the Prio element. Probably the example below explains how Prio and THIS can be used.

Note: Use a Ref when possible. A Prio element is required when the same position in a string is potentially checked more than once.

Example:

constgrammar=newGrammar(Prio(Keyword('ni'),Sequence('(',THIS,')'),Sequence(THIS,Keyword('or'),THIS),Sequence(THIS,Keyword('and'),THIS)));console.log(grammar.parse('(ni or ni) and (ni or ni)').isValid);// true

About

Parser for JavaScript

Resources

Stars

10 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages