ScriptBasic

Extension Modules => Extension Modules => Topic started by: Support on October 19, 2017, 05:25:25 am

Title: Script BASIC JavaScript Extension Module (Linux)
Post by: Support on October 19, 2017, 05:25:25 am
The Script BASIC JS extension module for Linux is based on the Cesanta's V7 JavaScript Engine (https://github.com/cesanta/v7). It claims to be the world's smallest footprint JavaScript 5.1 compatible embeddable engine. There are no other dependencies required.

JavaScript Programmers Guide (https://developer.mozilla.org/en-US/docs/Web/JavaScript)

V7 JavaScript Documentation (https://docs.cesanta.com/v7/master/)

Features:

Note: The \ character is used by Script BASIC as a string escape character and must be inserted in the JavaScript code to make the \ just text. Loading JavaScript code from a file doesn't have the escape character issue and can be run verbatim.

js.inc
MODULE JS

' CORE
DECLARE SUB      js_create                  ALIAS "js_create"                 LIB "js"
DECLARE SUB      js_destroy                 ALIAS "js_destroy"                LIB "js"
DECLARE SUB      js_get_global              ALIAS "js_get_global"             LIB "js"
DECLARE SUB      js_get_this                ALIAS "js_get_this"               LIB "js"
DECLARE SUB      js_get_arguments           ALIAS "js_get_arguments"          LIB "js"
DECLARE SUB      js_arg                     ALIAS "js_arg"                    LIB "js"
DECLARE SUB      js_argc                    ALIAS "js_argc"                   LIB "js"
DECLARE SUB      js_own                     ALIAS "js_own"                    LIB "js"
DECLARE SUB      js_disown                  ALIAS "js_disown"                 LIB "js"
DECLARE SUB      js_set_gc_enabled          ALIAS "js_set_gc_enabled"         LIB "js"
DECLARE SUB      js_interrupt               ALIAS "js_interrupt"              LIB "js"
DECLARE SUB      js_get_parser_error        ALIAS "js_get_parser_error"       LIB "js"

' PRIMITIVES
DECLARE SUB      js_mk_number               ALIAS "js_mk_number"              LIB "js"
DECLARE SUB      js_get_double              ALIAS "js_get_double"             LIB "js"
DECLARE SUB      js_get_int                 ALIAS "js_get_int"                LIB "js"
DECLARE SUB      js_is_number               ALIAS "js_is_number"              LIB "js"
DECLARE SUB      js_mk_boolean              ALIAS "js_mk_boolean"             LIB "js"
DECLARE SUB      js_get_bool                ALIAS "js_get_bool"               LIB "js"
DECLARE SUB      js_is_boolean              ALIAS "js_is_boolean"             LIB "js"
DECLARE SUB      js_mk_null                 ALIAS "js_mk_null"                LIB "js"
DECLARE SUB      js_is_null                 ALIAS "js_is_null"                LIB "js"
DECLARE SUB      js_mk_undefined            ALIAS "js_mk_undefined"           LIB "js"
DECLARE SUB      js_is_undefined            ALIAS "js_is_undefined"           LIB "js"
DECLARE SUB      js_mk_foreign              ALIAS "js_mk_foreign"             LIB "js"
DECLARE SUB      js_get_ptr                 ALIAS "js_get_ptr"                LIB "js"
DECLARE SUB      js_is_foreign              ALIAS "js_is_foreign"             LIB "js"

' STRINGS
DECLARE SUB      js_mk_string               ALIAS "js_mk_string"              LIB "js"
DECLARE SUB      js_is_string               ALIAS "js_is_string"              LIB "js"
DECLARE SUB      js_get_string              ALIAS "js_get_string"             LIB "js"
DECLARE SUB      js_get_cstring             ALIAS "js_get_cstring"            LIB "js"

' OBJECTS
DECLARE SUB      js_mk_object               ALIAS "js_mk_object"              LIB "js"
DECLARE SUB      js_is_object               ALIAS "js_is_object"              LIB "js"
DECLARE SUB      js_get_proto               ALIAS "js_get_proto"              LIB "js"
DECLARE SUB      js_set_proto               ALIAS "js_set_proto"              LIB "js"
DECLARE SUB      js_get                     ALIAS "js_get"                    LIB "js"
DECLARE SUB      js_def                     ALIAS "js_def"                    LIB "js"
DECLARE SUB      js_set                     ALIAS "js_set"                    LIB "js"
DECLARE SUB      js_del                     ALIAS "js_del"                    LIB "js"
DECLARE SUB      js_init_prop_iter_ctx      ALIAS "js_init_prop_iter_ctx"     LIB "js"
DECLARE SUB      js_next_prop               ALIAS "js_next_prop"              LIB "js"
DECLARE SUB      js_destruct_prop_iter_ctx  ALIAS "js_destruct_prop_iter_ctx" LIB "js"
DECLARE SUB      js_is_instanceof           ALIAS "js_is_instanceof"          LIB "js"
DECLARE SUB      js_is_instanceof_v         ALIAS "js_is_instanceof_v"        LIB "js"

' ARRAYS
DECLARE SUB      js_mk_array                ALIAS "js_mk_array"               LIB "js"
DECLARE SUB      js_is_array                ALIAS "js_is_array"               LIB "js"
DECLARE SUB      js_array_length            ALIAS "js_array_length"           LIB "js"
DECLARE SUB      js_array_push              ALIAS "js_array_push"             LIB "js"
DECLARE SUB      js_array_get               ALIAS "js_array_get"              LIB "js"
DECLARE SUB      js_array_set               ALIAS "js_array_set"              LIB "js"
DECLARE SUB      js_array_del               ALIAS "js_array_del"              LIB "js"

' EXECUTION
DECLARE SUB      js_exec                    ALIAS "js_exec"                   LIB "js"
DECLARE SUB      js_exec_file               ALIAS "js_exec_file"              LIB "js"
DECLARE SUB      js_apply                   ALIAS "js_apply"                  LIB "js"
DECLARE SUB      js_parse_json              ALIAS "js_parse_json"             LIB "js"
DECLARE SUB      js_parse_json_file         ALIAS "js_parse_json_file"        LIB "js"

'REGEX
DECLARE SUB      js_mk_regexp               ALIAS "js_mk_regexp"              LIB "js"
DECLARE SUB      js_is_regexp               ALIAS "js_is_regexp"              LIB "js"

' UTILITY
DECLARE SUB      js_stringify               ALIAS "js_stringify"              LIB "js"
DECLARE SUB      js_println                 ALIAS "js_println"                LIB "js"

DECLARE SUB      SB_shifts                  ALIAS "SB_shifts"                 LIB "js"
DECLARE COMMAND  js_iif                     ALIAS "js_iif"                    LIB "js"


' JS Global Module Variables
OBJ = 0
SYS = 0

' Stringify Modes
DEFAULT = 0
JSON    = 1
DEBUG   = 2

' Property Attribute Support

CONST V7_PROPERTY_NON_WRITABLE              = 1
CONST V7_PROPERTY_NON_ENUMERABLE            = 2
CONST V7_PROPERTY_NON_CONFIGURABLE          = 4
CONST V7_PROPERTY_GETTER                    = 8
CONST V7_PROPERTY_SETTER                    = 16
CONST _V7_PROPERTY_HIDDEN                   = 32
CONST _V7_PROPERTY_OFF_HEAP                 = 64
CONST _V7_PROPERTY_USER_DATA_AND_DESTRUCTOR = 128
CONST _V7_DESC_PRESERVE_VALUE               = 256
CONST _V7_DESC_MASK                         = &HFFFF

CONST PROPERTY_DEFAULT = 0

' TRUE or FALSE. Whether the property's value can be set.
FUNCTION WRITABLE(v)
  IF v THEN
    WRITABLE = PROPERTY_DEFAULT
  ELSE
    WRITABLE = V7_PROPERTY_NON_WRITABLE
  END IF
END FUNCTION

' TRUE or FALSE. Whether the property shows in some loop constructs.
FUNCTION ENUMERABLE(v)
  IF v THEN
    ENUMERABLE = PROPERTY_DEFAULT
  ELSE
    ENUMERABLE = V7_PROPERTY_NON_ENUMERABLE
  END IF
END FUNCTION

' TRUE or FALSE. Whether the property can be deleted and whether its attributes can be changed.
FUNCTION CONFIGURABLE(v)
  IF v THEN
    CONFIGURABLE = PROPERTY_DEFAULT
  ELSE
    CONFIGURABLE = V7_PROPERTY_NON_CONFIGURABLE
  END IF
END FUNCTION

' TRUE or FALSE. When a property is accessed the value is generated by calling a function implicitly.
FUNCTION GETTER(v)
  IF v THEN
    GETTER = V7_PROPERTY_GETTER
  ELSE
    GETTER = FALSE
  END IF
END FUNCTION

' TRUE or FALSE. When a property is set it will implicitly call a function and pass a
' value as argument, and the return value of the function is set to the property.
FUNCTION SETTER(v)
  IF v THEN
    SETTER = V7_PROPERTY_SETTER
  ELSE
    SETTER = FALSE
  END IF
END FUNCTION

FUNCTION PRESERVE_VALUE
    PRESERVE_VALUE = _V7_DESC_PRESERVE_VALUE
END FUNCTION

FUNCTION HIDDEN(v)
  IF v THEN
    HIDDEN = V7_PROPERTY_HIDDEN
  ELSE
    HIDDEN = FALSE
  END IF
END FUNCTION

FUNCTION OFF_HEAP(v)
  IF v THEN
    OFF_HEAP = _V7_PROPERTY_OFF_HEAP
  ELSE
    OFF_HEAP = FALSE
  END IF
END FUNCTION


' JS API Function Wrappers

' Create V7 instance
FUNCTION CREATE
  OBJ = js_create()
  SYS = js_get_global(OBJ)
  CREATE = OBJ
END FUNCTION

' Destroy V7 instance
SUB DESTROY
  js_destroy(OBJ)
  UNDEF OBJ
END SUB

' Return root level (`global`) object of the given V7 instance
FUNCTION GET_GLOBAL
  GET_GLOBAL = js_get_global(OBJ)
END FUNCTION

' Return current `this` object
FUNCTION GET_THIS
  GET_THIS = js_get_this(OBJ)
END FUNCTION

' Return current `arguments` array
FUNCTION GET_ARGUMENTS
  GET_ARGUMENTS = js_get_arguments(OBJ)
END FUNCTION

' Return i-th argument
FUNCTION ARG(i)
  ARG = js_arg(OBJ, i)
END FUNCTION

' Return the length (`count`) of `arguments`
FUNCTION ARGC
  ARGC = js_argc(OBJ)
END FUNCTION

' Tells the GC about a JS value variable/field owned by `C` code.
SUB OWN(v)
  js_own(OBJ, v)
END SUB

' User code should also explicitly disown the variables with v7_disown
' once it goes out of scope or the structure containing the v7_val_t field is freed.
' Returns 1 if value is found, 0 otherwise
FUNCTION DISOWN(v)
  DISOWN = js_disown(OBJ, v)
END FUNCTION

' Enable or disable GC
SUB SET_GC_ENABLED(enabled)
  js_set_gc_enabled(OBJ, enabled)
END SUB

' It sets a flag that will cause the interpreter to throw an Interrupted Error
SUB INTERRUPT
  js_interrupt(OBJ)
END SUB

' Returns last parser error message
FUNCTION GET_ERROR
  GET_ERROR = js_get_parser_error(OBJ)
END FUNCTION

' Make numeric primitive value
FUNCTION MK_NUMBER(num)
  MK_NUMBER = js_mk_number(OBJ, num)
END FUNCTION

' Returns number value stored in `v7_val_t` as `double`
FUNCTION GET_DOUBLE(v)
  GET_DOUBLE = js_get_double(OBJ, v)
END FUNCTION

' Returns number value stored in `v7_val_t` as `int`. If the number
' value is not an integer, the fraction part will be discarded.
FUNCTION GET_INT(v)
  GET_INT = js_get_int(OBJ, v)
END FUNCTION

' Returns true if given value is a primitive number value
FUNCTION IS_NUMBER(v)
  IS_NUMBER = js_is_number(v)
END FUNCTION

' Make boolean primitive value (either `true` or `false`)
FUNCTION MK_BOOLEAN(is_true)
  MK_BOOLEAN = js_mk_boolean(OBJ, is_true)
END FUNCTION

' Returns boolean stored in `v7_val_t`: 0 for `false` or
' non-boolean, non-0 for `true`
FUNCTION GET_BOOL(v)
  GET_BOOL = js_get_bool(OBJ, v)
END FUNCTION

' Returns `true` if given value is a primitive boolean value
FUNCTION IS_BOOLEAN(v)
  IS_BOOLEAN = js_is_boolean(v)
END FUNCTION

' Make `null` primitive value
FUNCTION MK_NULL
  MK_NULL = js_mk_null()
END FUNCTION

' Returns true if given value is a primitive `null` value
FUNCTION IS_NULL(v)
  IS_NULL = js_is_null(v)
END FUNCTION

' Make `undefined` primitive value
FUNCTION MK_UNDEFINED
  MK_UNDEFINED = js_mk_undefined()
END FUNCTION

' Returns true if given value is a primitive `undefined` value
FUNCTION IS_UNDEFINED(v)
  IS_UNDEFINED = js_is_undefined(v)
END FUNCTION

' Make JavaScript value that holds C/C++ `void *` pointer
FUNCTION MK_FOREIGN
  MK_FOREIGN = js_mk_foreign(OBJ)
END FUNCTION

' Returns `void *` pointer stored in `v7_val_t`
' Returns NULL `undef` if the value is not a foreign pointer
FUNCTION GET_PTR(v)
  GET_PTR = js_get_ptr(OBJ, v)
END FUNCTION

' Returns true if given value holds `void *` pointer
FUNCTION IS_FOREIGN(v)
  IS_FOREIGN = js_is_foreign(v)
END FUNCTION

' Creates a string primitive value
FUNCTION MK_STRING(strval)
  MK_STRING = js_mk_string(OBJ, strval, LEN(strval), 1)
END FUNCTION

' Returns true if given value is a primitive string value
FUNCTION IS_STRING(v)
  IS_STRING = js_is_string(v)
END FUNCTION

' Returns a pointer to the string stored in `v7_val_t`
FUNCTION GET_STRING(v)
  GET_STRING = js_get_string(OBJ, v)
END FUNCTION

' Returns a pointer to the string stored in `v7_val_t`
' Returns NULL `undef` if the value is not a string or
' if the string is not compatible with a C string
FUNCTION GET_CSTRING(v)
  GET_CSTRING = js_get_cstring(OBJ, v)
END FUNCTION

' Make an empty object
FUNCTION MK_OBJECT
  MK_OBJECT = js_mk_object(OBJ)
END FUNCTION

' Returns true if the given value is an object or function
FUNCTION IS_OBJECT(v)
  IS_OBJECT = js_is_object(v)
END FUNCTION

' Get object's prototype.
FUNCTION GET_PROTO(object)
  GET_PROTO = js_get_proto(OBJ, object)
END FUNCTION

' Set object's prototype. Return old prototype or undefined on error
FUNCTION SET_PROTO(object, proto)
  SET_PROTO = js_set_proto(OBJ, object, proto)
END FUNCTION

' Lookup property `name` in object `obj`. If `obj` holds no such property,
' an `undefined` value is returned
FUNCTION GETS(object, objname)
  GETS = js_get(OBJ, object, objname, LEN(objname))
END FUNCTION

' Define object property, similar to JavaScript `Object.defineProperty()`
FUNCTION DEF(object, objname, attr, value)
  DEF = js_def(OBJ, object, objname, LEN(objname), attr, value)
END FUNCTION

' Set object property. Behaves just like JavaScript assignment
FUNCTION SETS(object, objname, value)
  SETS = js_set(OBJ, object, objname, LEN(objname), value)
END FUNCTION

' Delete own property `name` of the object `obj`
' Does not follow the prototype chain
FUNCTION DEL(object, objname)
  DEL = js_del(OBJ, object, objname, LEN(objname))
END FUNCTION

' Returns true if the object is an instance of a given constructor / class name
FUNCTION IS_INSTANCEOF(object, classname)
  IS_INSTANCEOF = js_is_instanceof(OBJ, object, classname)
END FUNCTION

' Returns true if the object is an instance of a given constructor object class
FUNCTION IS_INSTANCEOF_V(object, objclass)
  IS_INSTANCEOF_V = js_is_instanceof_v(OBJ, object, objclass)
END FUNCTION

' Custom multi-property `GET` function
FUNCTION GET_PROPERTIES(object, proparray)
  LOCAL objname, value, attr, propcnt
  objname = ""
  value = 0
  attr = 0
  propcnt = 1
 ' UNDEF proparray
 js_init_prop_iter_ctx(OBJ, object)
  WHILE js_next_prop(OBJ, objname, value, attr) <> undef
    proparray[propcnt, 0] = js_get_string(OBJ, objname)
    proparray[propcnt, 1] = js_get_int(OBJ, value)
    proparray[propcnt, 2] = attr
    propcnt += 1
  WEND
  js_destruct_prop_iter_ctx(OBJ)
  GET_PROPERTIES = propcnt - 1
END FUNCTION

' Make an empty array object
FUNCTION MK_ARRAY
  MK_ARRAY = js_mk_array(OBJ)
END FUNCTION

' Returns true if given value is an array object
FUNCTION IS_ARRAY(object)
  IS_ARRAY = js_is_array(OBJ, object)
END FUNCTION

' Returns length on an array. If `object` is not an array, 0 is returned
FUNCTION ARRAY_LENGTH(object)
  ARRAY_LENGTH = js_array_length(OBJ, object)
END FUNCTION

' Insert `value` in `object` at the end of the array
FUNCTION ARRAY_PUSH(object, value)
  ARRAY_PUSH = js_array_push(OBJ, object, value)
END FUNCTION

'  Return array member at index `index`. If `index` is out of bounds, undefined is returned
FUNCTION ARRAY_GET(object, index)
  ARRAY_GET = js_array_get(OBJ, object, index)
END FUNCTION

' Insert value `v` into `arr` at 'index`
FUNCTION ARRAY_SET(object, index, value)
  ARRAY_SET = js_array_set(OBJ, object, index, value)
END FUNCTION

' Delete value in array `arr` at index `index`, if it exists
SUB ARRAY_DEL(object, index)
   js_array_del(OBJ, object, index)
END SUB

' Execute JavaScript `js_code`
' The result of evaluation is stored in the `return` variable
' The 'ok' argument will contain the function's execution success status flag
FUNCTION EXEC(code, ok)
  EXEC = js_exec(OBJ, code, ok)
END FUNCTION

' Same as `v7_exec()`, but loads source code from `path` file
FUNCTION EXEC_FILE(codepath, ok)
  EXEC_FILE = js_exec_file(OBJ, codepath, ok)
END FUNCTION

' Parse `json_code`
' The result of evaluation is stored in the `return` variable
' The 'ok' argument will contain the function's parse success status flag
FUNCTION PARSE_JSON(json_code, ok)
  PARSE_JSON = js_parse_json(OBJ, json_code, ok)
END FUNCTION

' Same as `v7_parse_json()`, but loads `json_code` from `path` file
FUNCTION PARSE_JSON_FILE(json_code_file, ok)
  PARSE_JSON_FILE = js_parse_json_file(OBJ, json_code_file, ok)
END FUNCTION

' Call function `func` with arguments `args`, using `object` as `this`
' `args` should be an array containing arguments or `undefined`
FUNCTION APPLY(func, object, args)
  APPLY = js_apply(OBJ, func, object, args)
END FUNCTION

' Make RegExp object. For example, `regex` is `(.+)`, `flags` is `gi`.
FUNCTION MK_REGEXP(regex, flags, rcode)
  MK_REGEXP = js_mk_regexp(OBJ, regex, LEN(regex), flags, LEN(flags), rcode)
END FUNCTION

' Returns true if given value is a JavaScript RegExp object
FUNCTION IS_REGEXP(object)
  IS_REGEXP = js_is_regexp(OBJ, object)
END FUNCTION

' Generate string representation of the JavaScript value
FUNCTION STRINGIFY(object, convtype)
  STRINGIFY = js_stringify(OBJ, object, convtype)
END FUNCTION

' Output a string representation of the value to stdout followed by a newline
SUB PRINTIFY(object)
  js_println(OBJ, object)
END SUB


END MODULE
 

Hello JavaScript
IMPORT js.inc

JS::CREATE
PRINT JS::GET_INT(JS::EXEC("1 + 1")),"\n"
JS::DESTROY
 

jrs@jrs-laptop:~/sb/examples/js$ time scriba js_hello2.sb
2

real   0m0.026s
user   0m0.016s
sys   0m0.008s
jrs@jrs-laptop:~/sb/examples/js$


Fibonacci
IMPORT js.inc

jscode = """
function fibonacci(n) {
  if (n <= 2) {
    return 1;
  } else {
    return fibonacci(n - 1) + fibonacci(n - 2);
  }
}

print(fibonacci(24));
"
""

JS::CREATE
JS::EXEC(jscode)
JS::DESTROY
 

jrs@jrs-laptop:~/sb/examples/js$ scriba js_fibonacci.sb
46368
jrs@jrs-laptop:~/sb/examples/js$


Create object, property and attributes
IMPORT js.inc

JS::CREATE
myobj = JS::MK_OBJECT()
JS::DEF(myobj, "test", 0, JS::MK_NUMBER(64))
JS::SETS(myobj, "test", JS::MK_NUMBER(32))
JS::DEF(myobj, "test", JS::WRITABLE(FALSE) OR JS::PRESERVE_VALUE(),JS::MK_NULL())
JS::SETS(myobj, "test", JS::MK_NUMBER(16))
PRINT "test = ",JS::GET_INT(JS::GETS(myobj, "test")),"\n"
JS::DESTROY
 

jrs@jrs-laptop:~/sb/examples/js$ scriba js_deftest.sb
test = 32
jrs@jrs-laptop:~/sb/examples/js$


Load .js file and get properties
IMPORT js.inc

JS::CREATE
JS::EXEC_FILE "properties.js"
propcnt = JS::GET_PROPERTIES(JS::GETS(JS::SYS,"test"), proparray)
PRINT "Property\tValue\tAttribute\n"
FOR i = 1 to propcnt
  PRINT proparray[i,0],"\t\t",proparray[i,1],"\t",proparray[i,2],"\n"
NEXT
JS::DESTROY
 
properties.js
var test = {};

Object.defineProperty(test, 'a', {
  value: 1,
  writable: true,
  enumerable: true,
  configurable: true
});

Object.defineProperty(test, 'b', {
  value: 2,
  writable: false,
  enumerable: false,
  configurable: false
});
 

jrs@jrs-laptop:~/sb/examples/js$ scriba js_propfile.sb
Property   Value   Attribute
b      2   7
a      1   0
jrs@jrs-laptop:~/sb/examples/js$


Call JavaScript function
IMPORT js.inc

jscode = """
var sum = function(a, b, c) {
  print (c);
  return a + b; };
"
""

JS::CREATE()
JS::EXEC(jscode)
func = JS::GETS(JS::SYS, "sum")
args = JS::MK_ARRAY()
JS::ARRAY_PUSH(args, JS::MK_NUMBER(123.0))
JS::ARRAY_PUSH(args, JS::MK_NUMBER(0.456))
JS::ARRAY_PUSH(args, JS::MK_STRING("Script BASIC"))
result = JS::APPLY(func, 0, args, rcode)
PRINT FORMAT("Result: %g\n", JS::GET_DOUBLE(result))
JS::DESTROY
 

jrs@jrs-laptop:~/sb/examples/js$ scriba js_callfunc.sb
Script BASIC
Result: 123.456
jrs@jrs-laptop:~/sb/examples/js$


Describe Properties with JavaScript
IMPORT js.inc

' Create JavaScript instance
JS::CREATE

' Create JavaScript object
JS::EXEC("var myobj = {};")
myobj = JS::GETS(JS::SYS, "myobj")

' Create object property
JS::DEF(myobj, "test", JS::WRITABLE(TRUE), JS::MK_NUMBER(64))

' Describe object properties with JavaScript
jscode = """
var descriptors = {};

Object.keys(myobj).forEach(function(key) {
    descriptors[key] = Object.getOwnPropertyDescriptor(myobj, key);
});

var objdesc = JSON.stringify(descriptors);
"
""
JS::EXEC(jscode)

' Return JSON formatted result string
PRINT JS::GET_STRING(JS::GETS(JS::SYS, "objdesc")),"\n"

' Release JavaScript instance
JS::DESTROY
 

jrs@jrs-laptop:~/sb/examples/js$ scriba js_defobj.sb
{"test":{"configurable":true,"enumerable":true,"writable":true,"value":64}}
jrs@jrs-laptop:~/sb/examples/js$


JSON / Stringify
IMPORT js.inc

JS::CREATE
myobj = JS::MK_OBJECT()
JS::DEF(myobj, "myprop_1", 0, JS::MK_NUMBER(64))
JS::DEF(myobj, "myprop_2", 0, JS::MK_NUMBER(1.23))
JS::DEF(myobj, "myprop_3", 0, JS::MK_STRING("JavaScript"))
PRINT JS::STRINGIFY(myobj, JS::JSON),"\n"
JS::DESTROY
 

jrs@jrs-laptop:~/sb/examples/js$ scriba js_stringify.sb
{"myprop_3":"JavaScript","myprop_2":1.23,"myprop_1":64}
jrs@jrs-laptop:~/sb/examples/js$


JavaScript Regular Expression
IMPORT js.inc

jscode = """
var output = ['---------- Original String\\n', names + '\\n'];

// Prepare two regular expression patterns and array storage.
// Split the string into array elements.

// pattern: possible white space then semicolon then possible white space
var pattern = /\\s*;\\s*/;

// Break the string into pieces separated by the pattern above and
// store the pieces in an array called nameList
var nameList = names.split(pattern);

// new pattern: one or more characters then spaces then characters.
// Use parentheses to "
memorize" portions of the pattern.
// The memorized portions are referred to later.
pattern = /(\\w+)\\s+(\\w+)/;

// New array for holding names being processed.
var bySurnameList = [];

// Display the name array and populate the new array
// with comma-separated names, last first.
//
// The replace method removes anything matching the pattern
// and replaces it with the memorized string—second memorized portion
// followed by comma space followed by first memorized portion.
//
// The variables $1 and $2 refer to the portions
// memorized while matching the pattern.

output.push('---------- After Split by Regular Expression');

var i, len;
for (i = 0, len = nameList.length; i < len; i++) {
  output.push(nameList[i]);
  bySurnameList[i] = nameList[i].replace(pattern, '$2, $1');
}

// Display the new array.
output.push('---------- Names Reversed');
for (i = 0, len = bySurnameList.length; i < len; i++) {
  output.push(bySurnameList[i]);
}

// Sort by last name, then display the sorted array.
bySurnameList.sort();
output.push('---------- Sorted');
for (i = 0, len = bySurnameList.length; i < len; i++) {
  output.push(bySurnameList[i]);
}

output.push('---------- End');

var retstr = output.join('\\n');
"
""

' The name string contains multiple spaces and tabs,
' and may have multiple spaces between first and last names.

JS::CREATE
JS::EXEC("var names = 'Harry Trump ;Fred Barney; Helen Rigby ; Bill Abel ; Chris Hand ';")
JS::EXEC(jscode)
PRINT JS::GET_STRING(JS::GETS(JS::SYS, "retstr"))
JS::DESTROY
 

jrs@jrs-laptop:~/sb/examples/js$ time scriba js_regexp.sb
---------- Original String

Harry Trump ;Fred Barney; Helen Rigby ; Bill Abel ; Chris Hand

---------- After Split by Regular Expression
Harry Trump
Fred Barney
Helen Rigby
Bill Abel
Chris Hand
---------- Names Reversed
Trump, Harry
Barney, Fred
Rigby, Helen
Abel, Bill
Hand, Chris
---------- Sorted
Abel, Bill
Barney, Fred
Hand, Chris
Rigby, Helen
Trump, Harry
---------- End
real   0m0.030s
user   0m0.028s
sys   0m0.000s
jrs@jrs-laptop:~/sb/examples/js$