DEV Community

shajunxing
shajunxing

Posted on • Edited on

Banana Script, An inperpreter for a strict subset of JavaScript

This article is openly licensed via CC BY-NC-ND 4.0.

Project Address: https://github.com/shajunxing/banana-script

Introduction

My goal is to remove and modify useless and ambiguous parts of JavaScript language that I've summarized in practice, and to create a minimal syntax interpreter by keeping only what I like and need. Only JSON-compatible data types and function are supported, function is first-class value, and function supports closure. I don't like object-oriented programming, so everything class related are not supported. There are no built-in immunable global variables, global functions, or object members, even contents added during interpreter initialization can be easily deleted at any time and reverted to clean empty state.

Two-Minute Brief Syntax Guide for Proficient JavaScript Users

Data types are null boolean number string array object function, results of typeof correspond strictly to these names. No undefined because null is enough. Array and object are clean, no predefined members such as __proto__.

Variable declaraction use let, all variables are local, const is not supported because all must be deletable. Access undeclared variables will cause error, access array/object's unexisting members will get null, and put null will delete corresponding member.

Function definition supports default parameter param = value and rest parameter ...params. Array literal and function call support spread syntax ..., which will not skip null members. No predefined members such as this arguments in function. If return is outside function, means exit vm.

Operators follow strict rule, no implicit conversion. Only boolean can do logical operations. == != are strict meaning, and can be done by all types. Strings can do all relational operations and +. Numbers can do all relational and numerical operations. Operator precedence from low to high is:

  • Ternary operator ? :
  • Logical or operator ||
  • Logical and operator &&
  • Relational operator == != < <= > >=
  • Additive operator + -
  • Multiplicative operator * / %
  • Exponential operator **
  • Prefix operator + - ! typeof
  • Array/object member access and function call operator [] . ?. ()

Assignment expression = += -= *= /= %= ++ -- does not return value, Comma expression , is not supported.

Conditional statement is if, loops are while do while for, conditions must be boolean. for loop only support following syntax, [] means optional. for in and for of only handle non-null members:

  • for ([[let] variable = expression ] ; [condition] ; [assignment expression])
  • for ([let] variable in array/object)
  • for ([let] variable of array/object)

No modules. In inperpreter's view, source code is only one large flat text.

Garbage collection is manual, you can do it at any time you need.

delete means delete local variable within current scope (object members can be deleted by setting null). For example, variables added to the function closure are all local variables before return, so unused variables can be deleted before return to reduce closure size, run following two statements in REPL environment to see differences.

  • let f = function(a, b){let c = a + b; return function(d){return c + d;};}(1, 2); dump(); print(f(3)); delete f;
  • let f = function(a, b){let c = a + b; delete a; delete b; return function(d){return c + d;};}(1, 2); dump(); print(f(3)); delete f;

throw can throw any value, which are received by catch. finally is not supported, because I think it's totally unecessary, and will make code execution order weird.

Technical internals

This project is C99 compatable, no other dependences, even make systems are not necessary, only need C compiler, compilation environment is msgc/gcc/mingw. First, from https://github.com/shajunxing/banana-nomake download single file make.h, then open make.c, modify #include to correct path, then with msvc type cl make.c && make.exe release, or with mingw type gcc -o make.exe make.c && ./make.exe release. Executables are in bin folder.

Project follows "minimal dependency" rule, only including necessary headers. Also, there's only one-way referencing between modules, with no circular referencing. Here’s how modules work and their dependencies:

    js-common   js-data     js-vm       js-syntax
        <-----------
                    <-----------
                                <-----------
        <-----------------------
        <-----------------------------------
Enter fullscreen mode Exit fullscreen mode
  • js-common: Constants, macro definitions, and functions common to project, such as log, memory io
  • js-data: Data types and garbage collection, you can even use this module separately in C projects to manipulate high-level data structures with GC functionality, see https://github.com/shajunxing/banana-cvar
  • js-vm: Bytecode Virtual Machine, compiled separately to get an interpreter with minimal footprint without source code parsing
  • js-syntax: Lexical parsing and syntax parsing, which converts source code into bytecode

All values are struct js_value type, you can create by js_xxx() functions, xxx is value type, and you can read c values direct from this struct, see definition in js_data.h. Created values follow garbage collecting rules. DON'T directly modify their content, if you want to get different values, create new one. Compound types array object can be operated by js_array_xxx() js_object_xxx() functions.

C functions must be struct js_result (*)(struct js_vm *) format, use js_c_function() to create c function value, yes of course they are all values and can be put anywhere, for example, if put on stack root using js_variable_declare(), they will be global. struct js_result has two members, if .success is true, .value is return value, if false, .value is received by catch if there are try catch. c function can also call script function using js_call(). Inside C function, use js_parameter_base() js_parameter_length() js_parameter_get() to get passed in parameters.

Top comments (0)