1.2.9 • Published 2 years ago

simple-script-parser v1.2.9

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

Simple Script Parser

View on npm: https://www.npmjs.com/package/simple-script-parser View interpreter: https://github.com/danpaxton/simple-script-interpreter View language IDE: https://github.com/danpaxton/simple-script-ide

Parser

Given code as raw text, the parser converts it into an abstract syntax tree defined by an operator precedence and a set of grammar rules. The parser was built using the Parsimmon libray. Text is parsed left to right in top down manner. The parser is built from large parse functions built out of smaller parse functions. Specifically, the parser starts out parsing using simple regular expression parsers. Then, parses expressions using these regex parsers. Then, parses statements using expression parsers. Lastly, parses programs using statements parsers. Operator precedence is handled by building lower precedence operator parsers that use the next highest precedence operator parser as their main parse function. This allows the parser to bind to higher precedence operators before lower precedence operators. The variable checker is used to find cases of undeclared variables, duplicate parameters, valid statment use and invalid built-in function use. It accomplishes this by traversing the abstract syntax tree and maintaining a set of bound variables at each level of the program.

Installation

Clone repository,

$ git clone https://github.com/danpaxton/simple-script-parser.git`
$ cd simple-script-parser

Install and run tests,

$ npm install
$ npm run test

Or install package,

$ npm i simple-script-parser

Operator Precedence

The table below summarizes operator precedence from highest precedence to lowest precedence. Operators in the same box have the same precedence. Operators without syntax are binary. All operators group left to right except exponentiation which groups right to left. Operator| Description ---:| --- (expression),{key: value...} | Binding or parenthesized expression, collection display x(...), x.attribute, x[...] | call, reference, subscriptor !x, ~x, ++x, --x, +x, -x| logical not, bitwise not, pre-increment, pre-decrement, unary plus, unary negative ** | exponentiation *, /, % | multiplication, division, remainder +, -| addition, subtraction <<, >>| shifts & | bit and | | bit or ^ | bit xor <, >, <=, >=, !=, == | comparisons && | logical and || | logical or ... ? ... : ... | ternary

Grammar

Below is a set of instructions that define valid statements and expressions for the simple script programming language. Simple-Script is a procedural and dynamically typed language. Each program consists of a series of statements that change the state of the program.

Lexical

type boolean := true | false

type integer := [+-]?[0-9]+

type float := [+-]?([0-9]+\.?[0-9]*|\.[0-9]+)([eE][+-]?[0-9]+)? | Infinity | -Infinity

type string := (['"])([^'"]*)\1

type name := [a-zA-Z_$][a-zA-Z_$0-9]*

type none := null

Operators

type Unop := !, ~, ++, --, +, -

type Binop := *, /, %, **, +, -, <<, >>, |, &, |, ^, >=, <=, ==, !=, >, <, &&, ||

Expression

type Expr := { kind: 'none' } | { kind: 'boolean', value: boolean } | { kind: 'integer', value: integer } | { kind: 'float', value: float } | { kind: 'string', value: string } | { kind: 'collection', value: { [ key: name | string | number ]: [ value: Expr ] } } | { kind: 'variable', name: name } | { kind: 'closure', params: name[], body: Stmt[], env: State } | { kind: 'unop', op: Unop, expression: Expr } | { kind: 'binop', op: Binop, e1: Expr, e2: Expr } | { kind: 'call', fun: Expr, args: Expr[] } | { kind: 'subscriptor', dict: Expr, expression: Expr } | { kind: 'attribute', dict: Expr, attribute: name } | { kind: 'ternary', test: Expr, trueExpr: Expr, falseExpr: Expr }

Statement

type Stmt := { kind: 'static', expression: Expr } | { kind: 'assignment', assignArr: Expr[], expression: Expr } | { kind: 'if', truePartArr : { test: Expr, part: Stmt[] }[], falsePart: Stmt[]} | { kind: 'for', inits: Stmt[], test: Expr, updates: Stmt[], body: Stmt[] } | { kind: 'while', test: Expr, body: Stmt[]] } | { kind: 'delete', expression: Expr } | { kind: 'return', expression: Expr }

Abstract

type State := { [key: name]: boolean | number | string | collection | closure | none }

type Program := { kind : 'ok', value : Stmt[] } | { kind : 'error', message : string }

Comments

Comments are specified using the // characters.

Example,

// integer value. x = 10;

Null values

The absence of a value is specified using the null keyword.

Example, a = null;

Boolean

Boolean values are represented using true or false.

Example, a = true, true assignment if (false) { ... }, conditional test

Numbers

Numbers are represented as integers, decimal point numbers, scientific notaion numbers, or infinity

Example, 1, integer -3.66, float 2.67e-100, scientific notation -Infinity, infinity

decimal point numbers, scientific notation numbers, and inifinity are all interpreted as floating point values.

Strings

Strings are represented as a sequence of ascii characters between a matching pair of single or double quotes.

Example, '', empty string ' str1 ', single quotes " str2 ", double quotes

Strings can be subscripted at character positions. 'abc'[1] is equivalent to 'b'.

Operators

Define an expression using a binary or unary operator.

Unary Operators

Syntax,

unop expression

Example, !x, ++x

Binary Operators

Syntax,

expression binop expression

Example,

2 ** 8, true && false, a == b

Bitwise Operators

Bitwise Operators only operate on integers.

Example, ~5, 1 >> 2

Error, 1.5 >> 2.5

Comparison chaining

Chaining comparsions will test each comparsion seperated by a logical AND (&&). Example, 1 < 2 < 3, is equivalent to 1 < 2 && 2 < 3 1 == 2 < 3 != 4, is equivalent to 1 == 2 && 2 < 3 && 3 != 4

Built-in functions

Built in functions with default return values unless overwritten.

type(..), Returns the argument type

ord(..), Returns the ASCII value of character argument

abs(..), Returns the absolute value of number argument

len(..), Returns the length of argument collection or string

bool(..), Returns the boolean representation of the argument

int(..), Returns the greatest integer less than or equal to the argument

float(..), Returns the float representation of the argument

str(..), Returns the string represenation of the argument

print(.. , ...), Displays arguments to output.

Assignment statement

Assign a variable, or a collection attribute to an expression.

Syntax, x = expression; x.attribute = expression; x[...] = expression;

Basic assignment

Example, a = 1;

Assign multiple variables, or attributes the same value using an assignment chain. a = b['key'] = c.val = 1;

Compound assignment

'+=' | '-=' | '*=' | '//=' | '/=' | '%=' | '<<=' | '>>=' | '&=' | '^=' | '|='

A variable must be defined before compound assignment.

Example, a = 1; a += 1;

A compound assigment and the equivalent simple assignment will be parsed into the same result. a += 1; is the same as a = a + 1;

Assignment types cannot be mixed. a = b += 1; will result in a parse error.

Closures

Store function code, and lexical environment variables.

No parameters, foo = () => { message = 'Hello'; return message; }; foo();

Single parameter, foo = p => { return p + 1; }; foo(10);

Multiple parameter, foo = (a, b, c) => { return a + b + c; }; foo(1, 2, 3);

Return line, foo = (a, b) => { return a + b; };, using return line foo = (a, b) => a + b;

Both methods will be parsed into the same result. Using no brackets allows only the one return statement.

Currying, foo = a => b => c => a + b + c; foo(1)(2)(3);

Collections

Store a collection of attributes mapped to a value.

Empty, data = {};

New attributes, data = {}; data['key'] = 1; data.number = 10;

data is now equivalent to { 'key': 1, 'number': 10 }

Names, data = { a: 1, 2: true };, is the same as data = { 'a': 1, '2': true };.

Numbers, data = { 1: 1, 2: true }.

Strings, data = { ' ': 1, 'key': true }

Only named attributes can be accesed using the reference ( x.attribute ) operator. Any attribute can be accesed using the subscriptor ( x[...] ) operator. All attributes are stored as strings, x[1] is the same as x['1'].

Example, data = { 1: 1, key: true, ' ': false };, access attribute 1 using data[1], attribute ' ' using data[' '] and attribute key using data.key or data['key'].

Ternary

Conditionally make decisions on the expression level. Defined by a test with a true expression and a false expression.

Syntax, a = test ? true expression : false expression;

Ternary expressions can only contain expressions, use if statements for statement level conditionals.

Nested ternary must be within parentheses.

Example, a = test1 ? ( test2 ? 1 : 3 ) : 2;

Parse error, a = test1 ? test2 ? 1 : 3 : 2;

if statement

Conditionally make decisions on the statement level. Defined by a series of tests with associated parts, and a false part.

Syntax, if( test ) { part } else if( test ) { part } ... else { false part }

if statements require brackets for more than one statement.

if only, if(true) { 1 + 2; }

if else, if(true) { 1 + 2; } else { 1 + 2; }

if else-if, if(true) { 1 + 2; } else if(true) { 1 + 2; }

if else-if else, if(true) { 1 + 2; } else if (true) { 1 + 2; } else { 1 + 2; }

while statement

Loop until termination defined by a test expression.

Syntax, while( test ) { body }

while loops require brackets for more than one statement.

Example, while(true) ++a;

for statement

Loop with initializers. Performs updates at each iteration until termination defined by a test expression.

Syntax, for( inits , test , updates ) { body }

for statements require all parts. Require brackets for more than one statement.

Note, initializers must be assignments and update variables must be defined.

Example, for(i = 0; i < 10; ++i) 2 + i; for(i = 0, j = z = 1; i < 10; ++i, ++z, --j) { z += j; j += i}

Errors,

Need all parts, for(i = 0; true; ) { 2 + i; } for(; true; ++i) { 2 + i; }

z not defined, for(i = 0; i < 10; z = 0) i;

true not an assignment statement, for(i = 0, true; i < 10; ++i) i;

return statement

Returns an expression from a function.

Syntax, return expression;

Example, return 1 + 2;

No return statement or return;, are both equivalent to return null;.

delete statement

Removes an attribute from a collection

Syntax, delete expression;

Example, a = { 1 : true, a : true }; delete a[1]; delete a.a;

Collection a is now equivalent to {}.

1.2.8

2 years ago

1.2.6

2 years ago

1.2.5

2 years ago

1.2.4

2 years ago

1.2.3

2 years ago

1.2.9

2 years ago

1.2.0

2 years ago

1.1.1

2 years ago

1.0.2

2 years ago

1.1.0

2 years ago

1.0.1

2 years ago

1.1.9

2 years ago

1.1.8

2 years ago

1.0.9

2 years ago

1.1.7

2 years ago

1.0.8

2 years ago

1.1.6

2 years ago

1.0.7

2 years ago

1.1.5

2 years ago

1.0.6

2 years ago

1.1.4

2 years ago

1.0.5

2 years ago

1.2.2

2 years ago

1.1.3

2 years ago

1.0.4

2 years ago

1.2.1

2 years ago

1.1.2

2 years ago

1.0.3

2 years ago

1.0.10

2 years ago

1.0.0

2 years ago