#jslike JavaScript-like "var" (Number/String/Array/Object/function) for C++
jslike let's you create objects, assign properties, use arrays and strings a JavaScript way right in your C++ code by exposing the single var
class.
###Currently implemented
- Number, String, Array, Object, Boolean.
- Pass by value for Numbers/Boolean, pass by reference for Array/Object.
####Functions and properties:
var = var, int, double, char*, wchar_t*, bool
-- construct var from basic typesvar.toString()
var[#]
-- Array index accessvar[key]
-- Object property accessvar[#]
-- String character accessvar + var
-- Arithmetic/logic operators++
--
+
-
/
*
%
&
|
&&
||
==
!=
<
>
var + var
-- String concatenation, comparison<
>
==
var.round()
var.charAt()
var.charCodeAt()
var.toNumber()
var::fromCharCode()
-- static functionvar.split()
var.objectKeys()
-- JavaScript'sObject.keys()
var.indexOf()
-- Array/Stringvar.push()
var.pop()
var.Push()
-- JavaScriptunshift()
(shift is a reserved word in C++).var.Pop()
-- JavaScriptshift()
var.length()
var.splice()
var.slice()
var.join()
var.typeOf()
var.del()
-- delete key/value pairs from Objectvar.has()
-- check if key is set (exists) in the Object.undefined
-- set and compare vars withundefined
or Undefined().JSON.stringify()
JSON.parse()
Conversion to basic C++ types:
wchar_t* getStringPointer()
char* getStringAllocUtf()
char* getStringAllocAscii()
int toDouble()
int toInt()
Experimental complex literals:
var::arr() = a,b,c,d,....
var::obj() = a,b,c,d,....
ARR(1,2,3,4)
OBJ("a", 2, "b", 4)
log(...)
-- function to conveniently output to console
###Not yet implemented
- mark&sweep GC
- functions, lambdas, closures
- map, sort, filter etc...
##Examples
- Minimal program
- Undefined variables and numbers
- Strings
- Mix numbers and strings
- Arrays
- log()
- Array.slice()
- Array splice()
- Array indexOf() and String indexOf()
- Array literal notation
- concatAll()
- Objects
- Converting between var and basic types
- Getting a pointer to a character buffer of a String.
- Passing var as an argument
The library is included by source, so you simply add these two lines:
#include "jslike.h"
using namespace jslike;
jslike tries not to pollute your namespace as much as possible, so everything is inside the "namespace jslike".
###Minimal program
// hello.cpp
#include "stdio.h"
#include "jslike.h"
using namespace jslike;
int main() {
var hello = "hello world привет мир 你好世界";
log(hello)
}
output:
hello world привет мир 你好世界
###Undefined variables, number variables
var x;
var y = 42;
log(x, x.typeOf());
log(y, y.typeOf());
x = 3, y = 4;
log(x + y);
log(x - 4, x + 5, x / y, x * y);
output:
undefined undefined
42 number
7
-1 8 0.75 12
###Strings
var hello = "hello";
var world;
world = "world";
log(hello + "-" + world + "!"); // string concatenation
log(hello, world); // log can accept unlimited number or arguments
log(hello.indexOf("ll"));
output:
hello-world!
hello world
2
var s = "Nuke the entire site from orbit";
log("Sentence length:", s.length());
log(s.slice(0, 4), s.slice(-10));
for (int i = 0; i < 4; i++) log(s.charAt(i), s.charCodeAt(i));
output:
Sentence length: 31
Nuke from orbit
N 78
u 117
k 107
e 101
###Mix numbers and strings
var a = "A", b = 1; // 'string + number' implies conversion to string
log(a + b);
log((var)"Received #" + 12 + " from " + 2 + " planets");
log((var)"2 + 2 = " + (2 + 2)); // explicit var constructor
output:
A1
Received #12 from 2 planets
2 + 2 = 4
###Arrays
Declare empty array and push something into it.
var A = Array;
A.push("planet");
A.push("LV");
A.push(426);
log(A);
Array toString()
is called before output.
output:
planet, LV, 426
log() is console.log() of JavaScript.
log can print any var or anything that a var constructor accepts.
var a = 1;
var b = "hello";
var c = Array;
c.push(100);
c.push(200);
log(a, b, c, 500, "world");
output:
1 hello 100, 200 500 world
###Array.slice()
var fruits;
fruits = (Arr "Banana", "Orange", "Lemon", "Apple", "Mango");
var citrus = fruits.slice(1, 3);
log(citrus);
The contents of citrus will be:
Orange, Lemon
###Array splice()
Unlike JavaScript you cannot insert more than one item in splice().
var fruits = (Arr "Banana", "Orange", "Apple", "Mango");
fruits.splice(2, 0, "Kiwi");
fruits.splice(2, 0, "Lemon");
log(fruits);
output:
Banana, Orange, Lemon, Kiwi, Apple, Mango
###Array indexOf() and String indexOf()
var q;
q = (Arr 0,1,2,3,4,5,6);
var j = q.indexOf(3);
log(q);
log(j);
var a = "hello world";
log(a.indexOf("wo"));
output:
0, 1, 2, 3, 4, 5, 6
3
6
###Array literal notation
The closest syntax we could achieve in C++ to cozy JavaScript Array literal notation is this: var x = (Arr list-of-items)
.
This syntax is achieved with overloading operator=
and operator,
for a temporary class arrset
. And then hiding it under the macro Arr
.
Arr
is a #define
macro that expands to var::arr() =
.
var planets = (Arr "Earth", "Venus", "Mars", "Jupiter");
var stars = (Arr "Vega", "Aldebaran", "Altair", "Decrux");
for (var i = 0; i < planets.length(); i++)
log((var)"Planet #" + (i+1), planets[i]);
log("Stars:", stars);
log("Space objects:", planets.concat(stars));
output:
Planet #1 Earth
Planet #2 Venus
Planet #3 Mars
Planet #4 Jupiter
Stars: Vega, Aldebaran, Altair, Decrux
Space objects: Earth, Venus, Mars, Jupiter, Vega, Aldebaran, Altair, Decrux
###concatAll()
Unfortunately there is no way use varargs/stdargs with class constructors, so we cannot haveconcat(a,...)
syntax. Instead var.concatAll()
is provided.
var a = Array;
a.push((Arr 1,2,3));
a.push((Arr 4,5,6));
a.push((Arr 7,8,9));
log(JSON.stringify(a));
var b = a.concatAll();
log(JSON.stringify(b));
output:
[[1,2,3],[4,5,6],[7,8,9]]
[1,2,3,4,5,6,7,8,9]
###Objects
var xy = Object; // Declare empty object
xy["x"] = 100;
xy["y"] = 200;
log(JSON.stringify(xy));
log(xy["z"]);
output:
{x:100,y:200}
undefined
Object literal notation:
var o = (Obj "x", 100, "y", 400);
log(JSON.stringify(o));
output:
{x:100,y:400}
Property access. Unfortunately there is no way to enable "o.x" style notation in C++. So we have to use var[key]
syntax.
o["x"]++;
o["y"] = o["x"] * 2;
log(JSON.stringify(o));
output:
{x:101,y:202}
Delete existing propery specified by the key name:
if (o.has("x")) o.del("x");
log(JSON.stringify(o));
output:
{ y: 202 }
###Converting between var and basic types
var a = 123.456;
int i = a.toInt();
double d = a.toDouble();
printf("Basic types, integer=%i, double=%f\n", i, d);
output:
Basic types, integer=123, double=123.456000
###Getting a pointer to a character buffer of a String.
Internally strings are stored as UTF16/32 AKA wchar_t.
You can either get a pointer to a internal wchar_t*
buffer, or get a pointer to a char*
copy of that buffer, allocated and copied for you in either ascii or utf8.
wchar_t* var::getStringPointer()
returns a pointer to an internal data, it
is valid until the var
exists. Do not delete the pointer returned from this function.
When function name has Alloc() in it, it means you are responsible for the deallocation of the returned data. Use C++ delete
operator when you are done.
var var::getStringAllocUtf()
and var var::getStringAllocUtf()
alloc and copy the contents.
var hello = "world,мир,世界";
char *str = hello.getStringAllocUtf();
printf("char* = %s\n", str);
delete str;
str = hello.getStringAllocAscii();
printf("char* = %s\n", str);
delete str;
wchar_t *w = hello.getStringPointer();
for (int i = 0; i < hello.length().toInt(); i++) {
printf("%i: char code: %i\n", i, (int)w[i]);
}
output:
char* = world,мир,世界
char* = world,<8@,�L
0: char code: 119
1: char code: 111
2: char code: 114
3: char code: 108
4: char code: 100
5: char code: 44
6: char code: 1084
7: char code: 1080
8: char code: 1088
9: char code: 44
10: char code: 19990
11: char code: 30028
###Passing var as an argument
Arrays and Objects are passed by reference, just like in JavaScript. Strings, Numbers, Booleans are passed by value. This example illustrates this principle:
#include "stdio.h"
#include "jslike.h"
using namespace jslike;
var sum10(var a, var b) {
a = a * 10;
b = b * 10;
return a + b;
}
void popAndPrint(var a) {
log(a.pop());
}
int main() {
var x = 400, y = 500;
log(sum10(x, y));
log(x, y);
var b;
b = (Arr 100,200,300);
popAndPrint(b);
popAndPrint(b);
log("What remains in b:", b);
}
output:
9000
400 500
300
200
What remains in b: 100
##Implementation details.
###Operator overloading
jslike intensively relies on C++ operator overloading. var
is declared as struct var
, hence all members are public.
The code is C++98 compatible. No modern C++2015 features are used.
###Amalgamated header jslike is header-only library, there is no object file involved. You just include it in your source and it includes other files. The complete size of all files together is about 1700 LOC at the moment of this writing.
jslike.h
includes few more headers, but for your convenience _jslike.h
is also provided, which is an amalgamation or basically concatenation of all headers into one single file. You can just grab it and copy to your project directory if you need.