1.0.5 • Published 2 years ago

scopescript-parser v1.0.5

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

ScopeScript Parser

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

Parser

Given code as raw text, the parser converts it into a syntax tree defined by an operator precedence and a set of grammar rules. Text is parsed left to right in top down manner. The parser is built from larger parse functions built out of smaller parse functions. Specifically, the parser starts by parsing text using simple regular expression parsers. Then, parses expressions using these regex parsers. Then, parses statements using expression parsers. Lastly, parses programs using statement 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. Using Immutable, the variable checker traverses the syntax tree and maintains a set of bound variables at each level of the program. The variable checker is used to find cases of undeclared variables, duplicate parameters, valid statment use and invalid built-in function use. The parser is built using the Parsimmon library.

Installation

Clone repository,

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

Install and run tests,

$ npm install
$ npm run test

Or install package,

$ npm i scopescript-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. 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 *, /, % | 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 scope script programming language. Scope 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 ::= *, /, %, +, -, <<, >>, |, &, |, ^, >=, <=, ==, !=, >, <, &&, ||

Atoms

type atom ::= { kind: 'null' } | { kind: 'boolean', value: boolean } | { kind: 'integer', value: integer } | { kind: 'float', value: float } | { kind: 'string', value: string } | { kind: 'collection', value: { [ key: string ]: [ value: expression ] } } | { kind: 'variable', name: name } | { kind: 'closure', params: name[], body: Stmt[] }

Expressions

type expression ::= atom | { kind: 'unop', op: unop, expr: expression } | { kind: 'binop', op: binop, e1: expression, e2: expression } | { kind: 'call', fun: expression, args: expression[] } | { kind: 'subscriptor', dict: expression, expression: expression } | { kind: 'attribute', dict: expression, attribute: name } | { kind: 'ternary', test: expression, trueExpr: expression, falseExpr: expression }

Statements

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

Program

type program ::= { kind: 'ok', value: statement[] } | { 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;

Uknown attribute reuturns null. Given a = {}, a[1] == null is equivalent to True.

Boolean

Boolean values are represented using true or false.

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

Boolean is a subset of integer. 1 + true is equivalent to 2. 0 + false is equivalent to 0.

Numbers

Numbers are represented as integers, or floats.

Decimal point numbers, scientific notation numbers, and infinity are all interpreted as float values.

Example, 1, integer.

-3.66, decimal point.

2.67e-100, scientific notation.

Infinity, infinity.

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.

pow(..), returns the first argument to the power of the second argument.

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

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 parameters, function code, and a link to lexical environment.

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(a < 10) ++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.

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 call.

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; a is now equivalent to {}.

continue statement

Explicitly jump to next loop iteration.

Syntax, continue;

Example, for(a = 0; a < 10; ++a) { continue; --a; } The loop will run ten times because a is never decremented.

break statement

Explicitly step out of loop iteration.

Syntax, break;

Example, while(true) { break; print(1);} The loop will only run once and nothing will be printed because it breaks immediately.

Additional language information

https://github.com/danpaxton/scopescript-interpreter/blob/main/README.md

1.0.5

2 years ago

1.0.4

2 years ago

1.0.3

2 years ago

1.0.2

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago