PreJsPy is highly configurable a precedence-based parser written in both Python (3.8+) and JavaScript (ES5+). The default grammar is based on a subset of JavaScript but can be adapted to a lot of different scenarios.
>>> from PreJsPy import PreJsPy
>>> parser = PreJsPy()
>>> parser.parse("6 * 9 == 42")
{'type': 'BinaryExpression', 'operator': '==', 'right': {'type': 'Literal', 'raw': '42', 'value': 42.0}, 'left': {'type': 'BinaryExpression', 'operator': '*', 'right': {'type': 'Literal', 'raw': '9', 'value': 9.0}, 'left': {'type': 'Literal', 'raw': '6', 'value': 6.0}}}
> var PreJsPy = require('pre-js-py').PreJsPy;
> parser = new PreJsPy()
> parser.parse('6 * 9 == 42')
{ type: 'BinaryExpression',
operator: '==',
left:
{ type: 'BinaryExpression',
operator: '*',
left: { type: 'Literal', value: 6, raw: '6' },
right: { type: 'Literal', value: 9, raw: '9' } },
right: { type: 'Literal', value: 42, raw: '42' } }
The JavaScript version of this library has been adapted from the JavaScript library JSEP which is (c) 2013 Stephen Oney, http://jsep.from.so/ and has been published under the terms of the MIT license. The code has been ported to Python and a lot of utility functions have been added.
- Symbolic Values
- Constants
- such as
true
,false
andnull
- configurable: Arbitrary constants can be added
- such as
- Identifiers
- may contain $,_ or alphanumeric characters but may not start with a number
- for example
foo
- Accessors
- can be static or computed
foo.bar
,foo['bar']
- can be static or computed
- Constants
- Various types of literals
- Numeric Literals (
42.001
)- decimal notation (
-42
) - exponential notation (
6.7E-10
)
- decimal notation (
- String Literals (
"Hello world"
)- can be either double or single quotes
- special characters can be escaped
- Array Literals (
[1, 2, 3]
)- must be surrounded by square brackets
- can be nested
- Numeric Literals (
- Multiple types of operators
- Unary operators
- by default
-
,!
,~
and+
- custom operators can be added, existing ones can be removed
- by default
- Binary operators
- precedence based
- by default contains all JavaScript operators
- custom ones can be added with custom precedences
- brackets can be used to override precedences
- JavaScript Conditional operator
- single ternary operator
a ? b : c
- single ternary operator
- Unary operators
- Call Expressions
- must use round brackets
- for example
Math.cos(x)
The API in JavaScript and python are almost identical. The only differences come from the features of the languages themselves.
var PreJsPy = require('pre-js-py').PreJsPy;
var parser = new PreJsPy(); // creates a new parser
var ast = parser.parse(s); // parses a string into a AST.
var config = parser.getConfig(); // returns a configuration object of the parser.
parser.setConfig(config); // sets configuration of the parser. May be partial.
PreJsPy.getDefaultConfig(); // returns the default configuration for new parsers.
from PreJsPy import PreJsPy
parser = PreJsPy() # creates a new parser.
ast = parser.parse(s) # parses a string into a AST,
config = parser.getConfig() # returns a configuration object of the parser.
parser.setConfig(config) # sets configuration of the parser. May be partial.
PreJsPy.getDefaultConfig() # returns the default configuration for new parsers
Configuration passed to and from returned from getConfig
configures the desired features of the parser.
A configuration passed to setConfig
may be partial, in which case the previously configured settings are left intact.
A configuration returned from getConfig
is always complete.
The default configuration (which explanations) is found below:
{
// Operators supported by the parser.
// These can be configured individually.
"Operators": {
// The set of literals (i.e. constants) recognized by the parser.
// Note that these cannot be used as identifiers.
"Literals": { "true": true, "false": false, "null": null },
// The set of unary operators recognized by the parser.
// These all bind more tightly than binary operators.
// For example, "- a || b" parses as "(-a) || b".
"Unary": [ "-", "!", "~", "+" ],
// A set of binary operators mapped to their precedence.
// Higher precedence means higher binding power.
// For example "a || b == c", parses as "(a || b) == c".
"Binary": {
"||": 1,
"&&": 2,
"|": 3,
"^": 4,
"&": 5,
"==": 6,
"!=": 6,
"===": 6,
"!==": 6,
"<": 7,
">": 7,
"<=": 7,
">=": 7,
"<<": 8,
">>": 8,
">>>": 8,
"+": 9,
"-": 9,
"*": 10,
"/": 10,
"%": 10
}
},
// Enable and disable specific features.
"Features": {
// The tertiary operators "a ? b : c".
"Tertiary": true,
// Non-constant, non-quoted identifiers in the code.
"Identifiers": true,
// Function calls.
"Calls": true,
"Members": {
// Static Member Accesses like "car.wheels"
"Static": true,
// Computed Member Accesses like "something[i + 1]"
"Computed": true
},
"Literals": {
// Numeric literals like "1.2"
"Numeric": true,
// String literals, enclosed in double quotes.
"String": true,
// Array literals, like "[1,2,3]"
"Array": true
}
}
}
This package is published on the Python Package Index Installation can be done simply via pip:
pip install pre_js_py
It is also published on Nodejs Package Manager Installation can be done simply via npm:
npm install pre-js-py
This module and associated documentation is Copyright (c) Tom Wiesing 2016 and licensed under the MIT license, see license for details.