├── zipdir └── README ├── tests ├── filetest.txt ├── simple.js ├── invoketime.js ├── prob │ ├── break.js │ ├── withscope.js │ └── callee.js ├── b64.js ├── argumentshared.js ├── format.js ├── recurse.js ├── lambda.js ├── syntax.js ├── util.js ├── arg2.js ├── evalthrow.js ├── except2.js ├── do.js ├── instance.js ├── func.js ├── switch.js ├── excpt3.js ├── construct.js ├── proto3.js ├── this.js ├── this2.js ├── inherit.js ├── ref.js ├── delete.js ├── arg.js ├── arguments.js ├── time.js ├── eval.js ├── file.js ├── eval3.js ├── this3.js ├── float.js ├── badfunc.js ├── local.js ├── apply.js ├── grep.js ├── interp.js ├── inherit2.js ├── number.js ├── while.js ├── in.js ├── redefine.js ├── value.js ├── bind.js ├── excpt.js ├── scope.js ├── io.js ├── update.js ├── foreach.js ├── array2.js ├── 49.js ├── forin.js ├── assert.js ├── trim.js ├── map.js ├── forinstack.js ├── property.js ├── obj.js ├── interp2.js ├── ffi.js ├── excpt4.js ├── signal.js ├── class.js ├── fib.js ├── string.js ├── call.js ├── file2.js ├── json.js ├── switch2.js ├── person1.js ├── person2.js ├── with.js ├── labeled.js ├── excpt5.js ├── eval2.js ├── yhsj.js ├── callee2.js ├── json2.js ├── alias.js ├── prime.js ├── info.js ├── array.js ├── regex.js ├── math.js ├── proto2.js ├── prototypes.js ├── block.js ├── expr.js ├── block2.js └── sqlite.js ├── www ├── email.png ├── techover.ttf ├── Makefile ├── js-threads.wiki ├── js-assert.wiki ├── c-tree.wiki ├── js-format.wiki ├── js-include.wiki ├── c-jsilite.wiki ├── zeroinstall.wiki ├── c-hash.wiki ├── c-commands.wiki ├── js-signal.wiki ├── input_output.wiki ├── editors.wiki ├── index.wiki ├── js-websocket.wiki ├── js-autoload.wiki ├── jsindex.wiki ├── js-json.wiki ├── js-events.wiki ├── getstarted.wiki ├── js-errors.wiki ├── js-zvfs.wiki ├── c-json.wiki ├── usingjsi.wiki ├── js-files.wiki ├── c-extensions.wiki ├── license.wiki ├── js-exec.wiki └── buildjsi.wiki ├── js-demos └── html │ ├── head1.html │ ├── sub2.html │ ├── sub3.html │ ├── subN.html │ ├── sub1.html │ ├── main.jsi │ └── main.ihtml ├── c-demos ├── stubs │ ├── teststubs.js │ ├── demo.h │ ├── Makefile │ ├── demo.c │ ├── user.c │ ├── README │ ├── demoStubs.h │ └── demoStubs.c ├── dyn.c ├── Makefile ├── prime.c └── simple.c ├── makever.js ├── lib ├── string.jsi ├── jsiIndex.jsi ├── zip.jsi ├── websrv.jsi ├── wpp.jsi └── parseOpts.jsi ├── README ├── TODO ├── tools ├── geany │ ├── README │ └── filetypes.javascript ├── mkindex.js ├── mkproto.js ├── testjs.sh ├── mkstubs.js └── mkref.js ├── jsiUtf8.h ├── Changelog ├── CMakeLists.txt ├── jsiLexer.h ├── COPYING ├── jsiBool.c ├── jsiPstate.h ├── jsiStubs.c ├── win ├── compat.h └── regex.h ├── .depend ├── jsmn.h ├── jsiCodeInt.h ├── main.c └── jsiPstate.c /zipdir/README: -------------------------------------------------------------------------------- 1 | Place files here. 2 | -------------------------------------------------------------------------------- /tests/filetest.txt: -------------------------------------------------------------------------------- 1 | Here is some random 2 | Text. 3 | -------------------------------------------------------------------------------- /tests/simple.js: -------------------------------------------------------------------------------- 1 | function foo() { 2 | return; 3 | } 4 | -------------------------------------------------------------------------------- /www/email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/technosaurus/jsish/HEAD/www/email.png -------------------------------------------------------------------------------- /www/techover.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/technosaurus/jsish/HEAD/www/techover.ttf -------------------------------------------------------------------------------- /tests/invoketime.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/technosaurus/jsish/HEAD/tests/invoketime.js -------------------------------------------------------------------------------- /js-demos/html/head1.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /js-demos/html/sub2.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | This is sub-page 2. 4 |
5 | -------------------------------------------------------------------------------- /js-demos/html/sub3.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | This is sub-page 3. 4 |
5 | -------------------------------------------------------------------------------- /c-demos/stubs/teststubs.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env jsish 2 | load('demo.so'); 3 | demo(1,2); 4 | load('user.so'); 5 | user(1,2); 6 | 7 | -------------------------------------------------------------------------------- /www/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | ../jsish ../tools/mkref.js > reference.wiki 3 | ../jsish ../tools/mkindex.js > jsindex.wiki 4 | 5 | -------------------------------------------------------------------------------- /tests/prob/break.js: -------------------------------------------------------------------------------- 1 | var i = 1; 2 | ABC: 3 | { 4 | i++; 5 | break ABC; 6 | puts("FOO"); 7 | } 8 | puts("DONE"); 9 | -------------------------------------------------------------------------------- /js-demos/html/subN.html: -------------------------------------------------------------------------------- 1 | ');?> 2 | 3 | This is sub-page . 4 | 5 | -------------------------------------------------------------------------------- /js-demos/html/sub1.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | This is sub-page 1. 4 |
5 | 6 | 7 | -------------------------------------------------------------------------------- /makever.js: -------------------------------------------------------------------------------- 1 | //#!./jsi 2 | var f = new File('jsiRevision.h'); 3 | var n = f.gets(); 4 | var rev = n.match(/[0-9]+/); 5 | puts('enum { JSI_VERSION = '+rev[0]+' };'); 6 | -------------------------------------------------------------------------------- /tests/b64.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 1234 ---> MTIzNA== 4 | =!EXPECTEND!= 5 | */ 6 | var j = sys.b64encode('1234'); 7 | puts(sys.b64decode(j) + ' ---> ' + j); 8 | -------------------------------------------------------------------------------- /tests/argumentshared.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 100 4 | =!EXPECTEND!= 5 | */ 6 | 7 | function a(x) { 8 | arguments[0] = 100; 9 | puts(x); 10 | }; 11 | 12 | a(1); 13 | -------------------------------------------------------------------------------- /lib/string.jsi: -------------------------------------------------------------------------------- 1 | //String utilities. 2 | 3 | String.prototype.replaceAt=function(index, character) { 4 | return this.substr(0, index) + character + this.substr(index+character.length); 5 | } 6 | -------------------------------------------------------------------------------- /tests/format.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 009 4 | Help Me = 9 5 | =!EXPECTEND!= 6 | */ 7 | 8 | puts(sprintf("%.03d", 9)); 9 | var me = 'Me', cnt = 9; 10 | puts(sprintf('Help %s = %d', me, cnt)); 11 | -------------------------------------------------------------------------------- /tests/recurse.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 3628800 4 | =!EXPECTEND!= 5 | */ 6 | 7 | function jc(n) 8 | { 9 | if (n <= 1) return 1; 10 | return jc(n - 1) * n; 11 | }; 12 | 13 | puts(jc(10)); 14 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Jsi is a tiny javascript interpreter whose primary purpose is to act 2 | as a gateway to C. To this end, it internally emulates Tcl. 3 | 4 | The parser/eval engine originated from quad_wheel, hence the MIT license. 5 | -------------------------------------------------------------------------------- /tests/lambda.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | true 4 | =!EXPECTEND!= 5 | */ 6 | var adder = function (x) { 7 | return function (y) { 8 | return x + y; 9 | }; 10 | }; 11 | add5 = adder(5); 12 | add5(1) == 6 13 | -------------------------------------------------------------------------------- /tests/syntax.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | extra args, expected "cmds(?string|pattern ?,all??)" 4 | =!EXPECTEND!= 5 | */ 6 | function foo() { 7 | info.cmds(1,2,3,4); 8 | } 9 | try { foo(); } catch(e) { puts(e); } 10 | -------------------------------------------------------------------------------- /tests/util.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 100000 4 | =!EXPECTEND!= 5 | */ 6 | var x = 0; 7 | function foo(n) { return n+1; } 8 | function bar() { x += foo(0); } 9 | var tim = sys.times(bar,100000); 10 | puts(x); 11 | 12 | -------------------------------------------------------------------------------- /tests/arg2.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | in b 4 | =!EXPECTEND!= 5 | */ 6 | function a() { 7 | puts('in a'); 8 | }; 9 | 10 | function b() { 11 | puts('in b'); 12 | }; 13 | 14 | var c = a; 15 | 16 | c((c = b), 2); 17 | -------------------------------------------------------------------------------- /tests/evalthrow.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | abc 4 | finally 5 | =!EXPECTEND!= 6 | */ 7 | 8 | try { 9 | eval("throw('abc');"); 10 | } catch(e) { 11 | puts(e); 12 | } finally { 13 | puts("finally"); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /js-demos/html/main.jsi: -------------------------------------------------------------------------------- 1 | //Give browser 5 seconds to get page. 2 | jsi_invokeCmd('websrv', ['-timeout', 5000].concat(console.args)); 3 | /* Or this to disallow override. */ 4 | //jsi_invokeCmd('websrv', console.args.concat(['-timeout', 5000])); 5 | -------------------------------------------------------------------------------- /tests/except2.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | =!EXPECTEND!= 4 | */ 5 | 6 | try { 7 | try { 8 | throw({a:1}); 9 | } catch (b) { 10 | throw({b:2}); 11 | } finally { 12 | } 13 | } catch (b) { 14 | } finally { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /tests/do.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 20 4 | 22 5 | 24 6 | 26 7 | =!EXPECTEND!= 8 | */ 9 | 10 | i = 0; 11 | do { 12 | if (i < 20) continue; 13 | puts(i); 14 | if (i > 25) break; 15 | i++; 16 | } while (++i < 30); 17 | -------------------------------------------------------------------------------- /tests/instance.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | true 4 | false 5 | true 6 | =!EXPECTEND!= 7 | */ 8 | 9 | function f() {}; 10 | function j() {}; 11 | var x = new f(); 12 | puts(x instanceof f); 13 | puts(x instanceof j); 14 | puts(x instanceof Object); 15 | -------------------------------------------------------------------------------- /tests/func.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 4950 4 | =!EXPECTEND!= 5 | */ 6 | 7 | function a(n) { 8 | sum = 0; 9 | for ( i = 0; i < n; i++) { 10 | sum = sum + i; 11 | } 12 | puts(sum); 13 | return sum; 14 | }; 15 | 16 | a(100); 17 | 18 | -------------------------------------------------------------------------------- /tests/switch.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | default 4 | 1 5 | =!EXPECTEND!= 6 | */ 7 | 8 | switch(3) { 9 | default: puts("default"); 10 | case 1: 11 | puts("1"); 12 | break; 13 | case 2: 14 | puts("2"); 15 | continue; 16 | } 17 | -------------------------------------------------------------------------------- /tests/excpt3.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 51 4 | =!EXPECTEND!= 5 | */ 6 | 7 | for (var i = 0; i < 100; ++i) { 8 | try { 9 | if (i == 50) throw(1); 10 | } catch(e) { 11 | break; 12 | } finally { 13 | i++; 14 | } 15 | } 16 | puts(i); 17 | 18 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - Collapse eval of a single function call to call + JSON. 2 | - Implement Regexp.exec for g option. 3 | - Fixup info.cmds 4 | - Add full tests for new features. 5 | - Valgrind for memory leaks 6 | 7 | Less likely. 8 | 9 | - Implement socket/udp 10 | - Implement channels/vfs/zip-pkg?? 11 | -------------------------------------------------------------------------------- /tests/construct.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | true 4 | true 5 | =!EXPECTEND!= 6 | */ 7 | var b = new Boolean(false); 8 | puts(b.constructor == Boolean ); 9 | puts(Boolean == b.constructor ); 10 | 11 | function f() {}; 12 | function g() {}; 13 | g.prototype = new f(); 14 | var h = new g(); 15 | -------------------------------------------------------------------------------- /tests/proto3.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | BAR 4 | =!EXPECTEND!= 5 | */ 6 | var b = { a:1, b:2}; 7 | b.foo = function () {}; 8 | function c() {} 9 | c.prototype.bar = function () {puts('BAR');}; 10 | var C = new c(); 11 | C.bar(); 12 | return; 13 | c.xx(); 14 | var a = [1,2,3]; 15 | a.xx(); 16 | 17 | -------------------------------------------------------------------------------- /www/js-threads.wiki: -------------------------------------------------------------------------------- 1 | Threads 2 | Threads are supported in Jsi, each interp can have only a one thread. This means that thread support is only available by creating threads with the option {subthread:true}. 3 | 4 | This is used in conjunction with Events to multitask a single Jsi program. 5 | 6 | -------------------------------------------------------------------------------- /tests/this.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | a: 1 4 | this.a: a in x 5 | =!EXPECTEND!= 6 | */ 7 | 8 | function fock(a,b){ 9 | puts("a: " + a); 10 | puts("this.a: " + this.a); 11 | }; 12 | 13 | x = { test: fock, a: 'a in x', b: 'b in x' }; 14 | 15 | { test: fock, a: 'a in x', b: 'b in x' }.test(1, 2); 16 | -------------------------------------------------------------------------------- /tests/this2.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | TOP 4 | n 5 | =!EXPECTEND!= 6 | */ 7 | 8 | this.name = 'TOP'; 9 | 10 | function a() { 11 | puts(this.name); 12 | }; 13 | 14 | function b(x, y) { 15 | a(); 16 | puts(this.name); 17 | }; 18 | 19 | var n = { name: 'n', test: b }; 20 | 21 | n.test(1, 2); 22 | -------------------------------------------------------------------------------- /tests/inherit.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | y=2 4 | x=2 5 | z=function () {...} 6 | CALLED Z 7 | =!EXPECTEND!= 8 | */ 9 | var a = { x:1, y:0}; 10 | a.z = function() { puts('CALLED Z'); }; 11 | var b = { y:2 }; 12 | b.__proto__ = a; 13 | a.x++; 14 | for (var i in b) { puts(i+'='+b[i]); } 15 | b.z(); 16 | 17 | 18 | -------------------------------------------------------------------------------- /tests/ref.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | { x:[ 4, 5, 6 ], y:{ a:1, b:2 } } 4 | { a:1, b:2 } 5 | 1 6 | =!EXPECTEND!= 7 | */ 8 | 9 | var a = { "x":[4,5,6], "y":{a:1, b:2}}; 10 | var b = { n:a, m:a.y }; 11 | puts (b.n); 12 | puts (b.m); 13 | 14 | function a() { return {x:1, y:{a:1,b:[]}}; }; 15 | puts(a().y.a); 16 | 17 | -------------------------------------------------------------------------------- /tools/geany/README: -------------------------------------------------------------------------------- 1 | To enable syntax hightlighting in Geany, copy filetypes.javascript to 2 | ~/.config/geany/filedefs/. Then edit /usr/share/geany/filetype_extensions.conf 3 | adding "*.jsi;" to Javascript. 4 | To enable completion, keep the file protos.jsi open in the editor so Geany knows 5 | how to complete Jsi functions. 6 | -------------------------------------------------------------------------------- /tests/delete.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | shot 4 | { x:1, y:2, z:"fock" } 5 | { x:1, y:2, z:"fock" } 6 | 1 7 | 2 8 | =!EXPECTEND!= 9 | */ 10 | 11 | a = { a:"shot", b:{x:1,y:2,z:"fock"}}; 12 | for (x in a) puts(a[x]); 13 | delete a.a; 14 | for (x in a) puts(a[x]); 15 | delete a.b.z; 16 | 17 | for (x in a.b) puts(a.b[x]); 18 | -------------------------------------------------------------------------------- /tests/arg.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 3 4 | [ "g", "2", "3" ] 5 | argv[0] = g 6 | argv[1] = 2 7 | argv[2] = 3 8 | =!EXPECTEND!= 9 | */ 10 | puts(console.args.length); 11 | puts(console.args); 12 | 13 | for (i = 0; i < console.args.length; ++i) { 14 | puts ("argv[" + i + "] = " + console.args[i]); 15 | } 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/arguments.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 1 4 | 2 5 | 3 6 | 4 7 | xfsldafkjasldf 8 | asdfsadfsadf 9 | 6 10 | =!EXPECTEND!= 11 | */ 12 | 13 | function a() { 14 | for (i = 0; i < arguments.length; ++i) { 15 | puts(arguments[i]); 16 | } 17 | }; 18 | 19 | a(1,2,3,4,"xfsldafkjasldf","asdfsadfsadf"); 20 | puts(i); 21 | 22 | -------------------------------------------------------------------------------- /tests/time.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 0 4 | 0 5 | 1970-01-01 6 | =!EXPECTEND!= 7 | */ 8 | var s = sys.strftime(0); 9 | puts(sys.strptime(s)); 10 | var s = sys.strftime(0,{utc:true}); 11 | puts(sys.strptime(s,{utc:true})); 12 | var t = sys.strptime(s,{utc:true,fmt:"%c"}); 13 | puts(sys.strftime(t,{utc:true,fmt:"%Y-%m-%d"})); 14 | 15 | -------------------------------------------------------------------------------- /tests/eval.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | { test:1 } 4 | { a:1, b:2, c:3, d:4 } 5 | undefined 6 | { a:1, b:2, c:3, d:4 } 7 | undefined 8 | =!EXPECTEND!= 9 | */ 10 | 11 | a = eval("{ test:1}"); 12 | puts(a); 13 | 14 | b = eval("puts({a:1,b:2,c:3,d:4});"); 15 | puts(b); 16 | b = eval("puts({a:1,b:2,c:3,d:4})", x, n, g, k); 17 | puts(b); 18 | -------------------------------------------------------------------------------- /tests/prob/withscope.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | { b:{ c:2 } } 4 | undefined 5 | =!EXPECTEND!= 6 | 7 | diff from ecma, var should make var in with 8 | */ 9 | 10 | var a = { 11 | b: { 12 | c: 1 13 | } 14 | }; 15 | 16 | with (a.b) { 17 | c = 2; 18 | eval("var d = 4;"); 19 | } 20 | puts(a); 21 | puts(a.b.d); 22 | 23 | -------------------------------------------------------------------------------- /tests/file.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | Here is some random 4 | Text. 5 | =!EXPECTEND!= 6 | */ 7 | 8 | try { 9 | var f = new File('tests/filetest.txt'); 10 | if (f) { 11 | while((n = f.gets())!=undefined) { 12 | puts(n); 13 | } 14 | } 15 | } catch(e) { 16 | puts('Can not open tests/filetest.txt'); 17 | } 18 | -------------------------------------------------------------------------------- /tests/eval3.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | { a:1 } 4 | { a:1, b:2, c:"abc", d:[ 1, 2, 3 ], e:{ } } 5 | abc 6 | =!EXPECTEND!= 7 | */ 8 | 9 | var a = {}; 10 | eval("a.a = 1;"); 11 | puts(a); 12 | 13 | 14 | var y = eval("{ a:1, b:2, c:'abc', d:[1,2,3], e: {}}"); 15 | puts(y); 16 | 17 | 18 | var n = 'abc'; 19 | eval("(y = n)"); 20 | 21 | puts(y); 22 | 23 | -------------------------------------------------------------------------------- /tests/this3.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | b 4 | c 5 | d 6 | a 7 | =!EXPECTEND!= 8 | */ 9 | 10 | 11 | var showthis = function() { 12 | puts(this.name); 13 | }; 14 | 15 | var a = { name: 'a', f: showthis }; 16 | var b = { name: 'b', f: showthis }; 17 | var c = { name: 'c', f: showthis }; 18 | var d = { name: 'd', f: showthis }; 19 | 20 | a.f(b.f(), c.f(), d.f()); 21 | -------------------------------------------------------------------------------- /c-demos/stubs/demo.h: -------------------------------------------------------------------------------- 1 | #ifndef __DEMO_H__ 2 | #define __DEMO_H__ 3 | #include "jsi.h" 4 | #define DEMO_VERSION 1.0 5 | EXTERN int Demo_Incr(int n); /*STUB = 1*/ 6 | EXTERN int Demo_Decr(int n); /*STUB = 2*/ 7 | 8 | #ifdef DEMO_USE_STUBS 9 | #include "demoStubs.h" 10 | #else 11 | #define DEMO_EXTENSION_INI 12 | #define Demo_StubsInit(i,f) JSI_OK 13 | #endif 14 | 15 | #endif 16 | 17 | -------------------------------------------------------------------------------- /tests/float.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 2400 4 | 2400 5 | 1.212.3 6 | NaN 7 | 99 8 | -9223372036854775808 9 | 99 10 | 99 11 | =!EXPECTEND!= 12 | */ 13 | puts(parseFloat(2400)); 14 | puts(parseFloat('2400')); 15 | puts(1.2 + "12.3"); 16 | puts(parseFloat('xx')); 17 | puts(parseFloat('99')); 18 | puts(parseInt('xx')); 19 | puts(parseInt('99')); 20 | puts(parseInt('99.9')); 21 | 22 | -------------------------------------------------------------------------------- /tests/badfunc.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 'xx', functions are: bad big ugly. 4 | [ "bad", "big", "ugly" ] 5 | [ "a", "b" ] 6 | [ "x" ] 7 | =!EXPECTEND!= 8 | */ 9 | var x = {a:1, b:2}; 10 | x.big = function() {}; 11 | x.bad = function() {}; 12 | x.ugly = function() {}; 13 | try { 14 | x.xx(); 15 | } catch(e) { 16 | puts(e); 17 | } 18 | puts(info.funcs(x)); 19 | puts(info.data(x)); 20 | puts(info.data()); 21 | 22 | -------------------------------------------------------------------------------- /tests/local.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 11 4 | 30 5 | 130 6 | 1 7 | 2 8 | 7 9 | 12 10 | 112 11 | 130 12 | =!EXPECTEND!= 13 | */ 14 | 15 | var a = 1; 16 | var b = 2; 17 | 18 | function abc(a,b) { 19 | var c = a+b; 20 | var d = a * b; 21 | puts(c); 22 | puts(d); 23 | return d; 24 | }; 25 | 26 | puts(x = abc(5,6) + 100); 27 | 28 | puts(a); 29 | puts(b); 30 | puts(abc(3,4)+100); 31 | 32 | puts(x); 33 | -------------------------------------------------------------------------------- /tests/apply.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | { a:"a" } 4 | undefined 5 | undefined 6 | undefined 7 | { b:"b" } 8 | 1 9 | 2 10 | undefined 11 | { c:"c" } 12 | 1 13 | 2 14 | 3 15 | =!EXPECTEND!= 16 | */ 17 | 18 | this.top = 'top'; 19 | 20 | function a(a,b,c) { 21 | puts(this); 22 | puts(a); 23 | puts(b); 24 | puts(c); 25 | }; 26 | 27 | a.apply({a:'a'}); 28 | a.apply({b:'b'}, [1,2]); 29 | a.apply({c:'c'}, [1,2,3,4]); 30 | -------------------------------------------------------------------------------- /tests/grep.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | abc@gmail.com 4 | =!EXPECTEND!= 5 | */ 6 | 7 | 8 | if (console.args.length < 1) { 9 | puts("Usage: jsi grep.ss "); 10 | exit(-1); 11 | } 12 | 13 | var reg = new RegExp(console.args[0]); 14 | line = ""; 15 | while (1) { 16 | line = console.input(); 17 | if (line == undefined) break; 18 | if (line.match(reg)) { 19 | puts(line); 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /tests/interp.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | foo 4 | foo 5 | foo 6 | 0 1 7 | 2 3 8 | 2 4 9 | =!EXPECTEND!= 10 | */ 11 | 12 | function foo(n) { 13 | puts('foo'); 14 | }; 15 | 16 | foo(1); 17 | eval('foo(1);'); 18 | var x1 = info.interp(); 19 | eval('foo(1);'); 20 | var x2 = info.interp(); 21 | puts(x1.codeCacheHits+' '+x2.codeCacheHits); 22 | puts(x1.funcCallCnt+' '+x2.funcCallCnt); 23 | puts(x1.cmdCallCnt+' '+x2.cmdCallCnt); 24 | -------------------------------------------------------------------------------- /tests/inherit2.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | LN:=Smith 4 | LN2:=Doe 5 | LN3:=Smith 6 | LN4:=Smith 7 | =!EXPECTEND!= 8 | */ 9 | 10 | var john = {firstName: 'John', lastName: 'Smith'}; 11 | var jane = {firstName: 'Jane'}; 12 | jane.__proto__ = john; 13 | puts("LN:="+jane.lastName); 14 | jane.lastName = 'Doe'; 15 | puts("LN2:="+jane.lastName); 16 | puts("LN3:="+john.lastName); 17 | delete jane.lastName; 18 | puts("LN4:="+jane.lastName); 19 | -------------------------------------------------------------------------------- /tests/number.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 9.1 4 | 9.12e+0 5 | 9.1 6 | 9.1 7 | 9.12e+0 8 | 9.1 9 | 12 10 | =!EXPECTEND!= 11 | */ 12 | puts(Number.toPrecision(9.1234,2)); 13 | puts(Number.toExponential(9.1234,2)); 14 | puts(Number.toFixed(9.1234,1)); 15 | var j = new Number(9.1234); 16 | puts(j.toPrecision(2)); 17 | puts(j.toExponential(2)); 18 | puts(j.toFixed(1)); 19 | 20 | var num = 15; 21 | puts(String.replace(num, /5/, '2')); 22 | 23 | -------------------------------------------------------------------------------- /tests/while.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 1 4 | 2 5 | 3 6 | 3000000 7 | 1000 8 | 1000 9 | =!EXPECTEND!= 10 | */ 11 | 12 | i = 0; 13 | result = 0; 14 | while (i<3) { 15 | j = 0; 16 | while (j<1000) { 17 | k = 0; 18 | while (k<1000) { 19 | ++k; 20 | ++result; 21 | } 22 | ++j; 23 | } 24 | ++i; 25 | puts(i); 26 | } 27 | puts(result); 28 | puts(j); 29 | puts(k); 30 | 31 | -------------------------------------------------------------------------------- /c-demos/stubs/Makefile: -------------------------------------------------------------------------------- 1 | TOP=../.. 2 | CFLAGS= -g -Wall -I$(TOP) 3 | LDFLAGS=-shared -fpic 4 | CCF=$(CC) $(CFLAGS) $(LDFLAGS) 5 | demo: 6 | $(TOP)/jsish $(TOP)/tools/mkstubs.js prefix demo 7 | $(CCF) -c -DJSI_USE_STUBS demo.c -o demo.o 8 | $(CCF) -c -DJSI_USE_STUBS demoStubs.c -o demoStubs.o 9 | $(CCF) -shared -fpic demo.o demoStubs.o -o demo.so 10 | $(CCF) -DJSI_USE_STUBS -DDEMO_USE_STUBS user.c -o user.so 11 | 12 | clean: 13 | rm *.so *.o 14 | 15 | -------------------------------------------------------------------------------- /tests/in.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | K = true 4 | true 5 | false 6 | true 7 | false 8 | a:1 9 | c:3 10 | d:4 11 | =!EXPECTEND!= 12 | */ 13 | 14 | var w = {a:1,b:2,c:3}; 15 | var x = [1,2,3]; 16 | var z = 2; 17 | var k = (z in x); 18 | puts('K = '+k); 19 | puts(2 in x); 20 | puts(4 in x); 21 | puts('a' in w); 22 | puts('d' in w); 23 | 24 | 25 | 26 | a = {a: 1,b:2,c:3,d:4}; 27 | for(var s in a) { 28 | puts(s + ":" + a[s]); 29 | delete a.b; 30 | } 31 | -------------------------------------------------------------------------------- /www/js-assert.wiki: -------------------------------------------------------------------------------- 1 | Assert 2 | The assert statement takes 1 or 2 arguments: an expression and a string. 3 | When the expression evaluates to false, an error is thrown, eg. 4 | 5 |
 6 | assert(m>0);
 7 | assert(n>=0 && n<100, "passed bad n");
 8 | 
9 | 10 | To disable assert and make it a No-Op use: 11 | 12 |
13 | Interp.conf({nDebug:true});
14 | 
15 | -------------------------------------------------------------------------------- /tests/redefine.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | ORIG FOO: [ 99 ] 4 | LOAD 5 | DONE 6 | FOO: [ 99 ] 7 | =!EXPECTEND!= 8 | */ 9 | 10 | function Load() { 11 | puts("LOAD"); 12 | //delete Foo; 13 | Foo = function (a) { puts("FOO: "+arguments.toString()); }; 14 | puts("DONE"); 15 | } 16 | 17 | function Foo() { 18 | puts("ORIG FOO: "+arguments.toString()); 19 | Load(); 20 | return Foo.apply(this,arguments); 21 | } 22 | 23 | var j = new Foo(99); 24 | 25 | -------------------------------------------------------------------------------- /tests/value.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | true 4 | aa 5 | { a:1, b:3 } 6 | function Boolean() { [native code] } 7 | function Boolean() { [native code] } 8 | true 9 | =!EXPECTEND!= 10 | */ 11 | 12 | var b = new Boolean(true); 13 | puts(b.valueOf()); 14 | 15 | var s = new String('aa'); 16 | puts(s.valueOf()); 17 | 18 | var x = { a:1, b:3 }; 19 | puts(x.valueOf()); 20 | 21 | puts(b.constructor); 22 | puts(Boolean); 23 | puts(Boolean == b.constructor); 24 | 25 | -------------------------------------------------------------------------------- /tests/bind.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 81 4 | 9 5 | 81 6 | =!EXPECTEND!= 7 | */ 8 | var x = 9; 9 | var module = { 10 | x: 81, 11 | getX: function() { return this.x; } 12 | }; 13 | 14 | puts(module.getX()); // 81 15 | 16 | var getX = module.getX; 17 | puts(getX()); // 9, because in this case, "this" refers to the global object 18 | 19 | // create a new function with 'this' bound to module 20 | var boundGetX = getX.bind(module); 21 | puts(boundGetX()); // 81 22 | -------------------------------------------------------------------------------- /tests/excpt.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | catch: b:[object Object] 4 | finally: b:1 5 | { b:2 } 6 | 1 7 | =!EXPECTEND!= 8 | */ 9 | 10 | var i = 0, b = 0; 11 | i++; 12 | try { 13 | try { 14 | b++; 15 | throw({a:1}); 16 | } catch (b) { 17 | puts("catch: b:" + b); 18 | } finally { 19 | puts("finally: b:" + b); 20 | throw({b:2}); 21 | } 22 | } catch (b) { 23 | puts(b); 24 | } finally { 25 | puts(b); 26 | } 27 | -------------------------------------------------------------------------------- /tests/scope.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 140 4 | 623 5 | =!EXPECTEND!= 6 | */ 7 | 8 | function abc(a, b, c) { 9 | var x = 123; 10 | function fx(a, b) { 11 | return (function (f) { 12 | return x + a + b + c + f; 13 | }); 14 | }; 15 | return fx(a, b); 16 | }; 17 | 18 | var fn = abc(3, 5, 6); 19 | 20 | var fsh = abc(100, 100, 100); 21 | 22 | var x = fn(3); 23 | 24 | var y = fsh(200); 25 | 26 | puts(x); 27 | 28 | puts(y); 29 | -------------------------------------------------------------------------------- /tests/io.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | Can not open file: g 4 | =!EXPECTEND!= 5 | */ 6 | 7 | if (console.args.length < 1) { 8 | puts("Usage: jsi io.ss "); 9 | exit(0); 10 | } 11 | 12 | var fp; 13 | try { 14 | fp = new File(console.args[0], "r"); 15 | } 16 | catch (e) { 17 | puts("Can not open file: " + console.args[0]); 18 | exit(0); 19 | } 20 | 21 | while ((line = fp.gets()) != undefined) { 22 | puts(line); 23 | } 24 | 25 | fp.close(); 26 | -------------------------------------------------------------------------------- /tests/update.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | [ 0 ] 4 | UPDATE 5 | UPDATE 6 | UPDATE 7 | UPDATE 8 | FOO CALLED: 6 9 | =!EXPECTEND!= 10 | */ 11 | 12 | var i=0, j = 0, k = 0; 13 | function foo() { 14 | i++,j++; 15 | } 16 | var id = setInterval(foo,100); 17 | puts(info.event()); 18 | while (true) { 19 | if (k++<=3) 20 | puts("UPDATE"); 21 | sys.update(50); 22 | if (i>5) { clearInterval(id); break; } 23 | } 24 | puts("FOO CALLED: "+j); 25 | sys.update(); 26 | 27 | 28 | -------------------------------------------------------------------------------- /tests/foreach.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | a 4 | b 5 | c 6 | c 7 | b 8 | a 9 | [ "c", "a" ] 10 | [ "c", "a" ] 11 | =!EXPECTEND!= 12 | */ 13 | var a = ["a", "b", "c"]; 14 | a.forEach(function(entry) { 15 | puts(entry); 16 | }); 17 | a = a.reverse(); 18 | for (var i in a) { 19 | puts(a[i]); 20 | } 21 | var b = a.filter(function(x) { return (x != 'b'); }); 22 | puts(b); 23 | var c = []; 24 | for (var i in a) { 25 | x = a[i]; 26 | if (x != 'b') c.push(x); 27 | } 28 | puts(c); 29 | -------------------------------------------------------------------------------- /lib/jsiIndex.jsi: -------------------------------------------------------------------------------- 1 | // Index file: sourced the first time an unknown function call occurs. 2 | // This sets up the auto-index which loads code on demand... 3 | if (!jsiIndex) jsiIndex = {}; 4 | jsiIndex.jsi_wpp = 'source("'+info.scriptDir()+'/wpp.jsi")'; 5 | jsiIndex.jsi_websrv = 'source("'+info.scriptDir()+'/websrv.jsi")'; 6 | jsiIndex.jsi_invokeCmd = 7 | jsiIndex.jsi_parseOpts = 'source("'+info.scriptDir()+'/parseOpts.jsi")'; 8 | source(info.scriptDir()+'/string.jsi'); 9 | 10 | -------------------------------------------------------------------------------- /tests/array2.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | [ undefined ] 4 | [ undefined, 2 ] 5 | 5 6 | 3 7 | 2 8 | 1 9 | 2 10 | 2 11 | undefined 12 | undefined 13 | undefined 14 | 0 15 | =!EXPECTEND!= 16 | */ 17 | 18 | var a = new Array(1); 19 | 20 | puts(a); 21 | a[1] = 2; 22 | puts(a); 23 | 24 | puts(a.push(1,2,3)); 25 | puts(a.pop()); 26 | puts(a.pop()); 27 | puts(a.pop()); 28 | puts(a.length); 29 | puts(a.pop()); 30 | puts(a.pop()); 31 | puts(a.pop()); 32 | puts(a.pop()); 33 | puts(a.length); 34 | 35 | -------------------------------------------------------------------------------- /c-demos/dyn.c: -------------------------------------------------------------------------------- 1 | #include "jsi.h" 2 | 3 | Jsi_CmdProcDecl(DynCmd) { 4 | int i, n = Jsi_ValueGetLength(interp, args); 5 | printf("Called dyn() with:\n"); 6 | for (i=0; i 7) break; 26 | puts(i + " * " + j + " = " + (i * j)); 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /tests/forin.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 0:1 4 | 1:2 5 | 2:3 6 | 4:5 7 | 5:6 8 | a: 9 | 1 10 | b: 11 | 2 12 | c: 13 | 3 14 | d: 15 | [ 4, 3, 2, 1 ] 16 | e: 17 | { x:"x", y:"y", z:"z" } 18 | =!EXPECTEND!= 19 | */ 20 | 21 | var x = [1,2,3,4,5, 6,7,8]; 22 | for (var i in x) { 23 | if (i == 3) continue; 24 | puts(i + ":" +x[i]); 25 | if (i > 4) break; 26 | } 27 | 28 | var obj = { a: 1, b:2, c:3, d:[4,3,2,1], e:{x:"x", y:"y", z:"z"}}; 29 | for (i in obj) { 30 | puts(i + ":"); 31 | puts( obj[i]); 32 | } 33 | -------------------------------------------------------------------------------- /tests/assert.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | caught error 4 | K 5 | caught error2 6 | =!EXPECTEND!= 7 | */ 8 | assert(true,'true'); 9 | assert(2*3 == 6,'math'); 10 | try { 11 | assert(false,'false'); 12 | } catch(e) { 13 | puts('caught error'); 14 | } 15 | Interp.conf({nDebug:true}); 16 | assert(false,'false'); 17 | Interp.conf({nDebug:false}); 18 | 19 | var i=1, j=2; 20 | assert(function () { return (i", "", "", "" ] 8 | =!EXPECTEND!= 9 | */ 10 | 11 | function fuzzyPlural(single) { 12 | puts("EE: "+single); 13 | //var result = single.replace(/o/g, 'e'); 14 | var result = single; 15 | if( single === 'kangaroo'){ 16 | result += 'se'; 17 | } 18 | return '<'+result+'>'; 19 | } 20 | 21 | var words = ["foot", "goose", "moose", "kangaroo"]; 22 | puts(words.map(fuzzyPlural)); 23 | 24 | // ["feet", "geese", "meese", "kangareese"] 25 | 26 | -------------------------------------------------------------------------------- /www/c-tree.wiki: -------------------------------------------------------------------------------- 1 | C-API: Trees 2 | 3 | The underlying data structure of objects in JSI is a tree Red-Black trees with invariant node 4 | pointers: nodes are allocated using a single malloc, including space for the key. 5 | This introduces a problem in that varying string keys can not be copied between nodes, 6 | which is required when rebalancing the tree. Although tree supports swapping node positions 7 | instead of keys, objects instead use a key of type STRINGPTR, a combination Hash table and and Tree, 8 | which is fairly efficient because objects often share keys. 9 | 10 | -------------------------------------------------------------------------------- /Changelog: -------------------------------------------------------------------------------- 1 | 14-05-XX: Release 1.0.2 2 | - Migrate documentation into fossil 3 | - Move libwebsocket/sqlite3/miniz dirs out of source tree. 4 | 5 | 14-05-19: Release 1.0.1 6 | - Sqlite enhancements: nocache and mapundef 7 | - Sqlite: add modes array/array1. 8 | - Sqlite: Add execOpts to Sqlite constructor option. 9 | - To option parse, add null resets to defaults. 10 | - Fix bugs in suboptions parsing. 11 | - Rework DString to support static init with {} 12 | - Add --nozvfs option to main.c 13 | - Fix daylight savings off by 1 hour. 14 | 15 | 14-04-20: Release 1.0.0 16 | - Initial release 17 | -------------------------------------------------------------------------------- /tests/forinstack.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | A 4 | fin 5 | fock 6 | =!EXPECTEND!= 7 | */ 8 | 9 | var a = {a:1, b:2}; 10 | 11 | try { 12 | for (var n in a) { 13 | try { 14 | switch(n) { 15 | case "a": 16 | puts("A"); 17 | continue; 18 | case "b": 19 | puts("B"); 20 | throw("ex"); 21 | } 22 | } catch(e) { 23 | puts(e); 24 | throw(e); 25 | } finally { 26 | puts("fin"); 27 | throw("fock"); 28 | } 29 | } 30 | 31 | } catch (e) { 32 | puts(e); 33 | } 34 | -------------------------------------------------------------------------------- /tests/property.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | true 4 | true 5 | false 6 | 9 7 | undefined 8 | undefined 9 | false 10 | true 11 | =!EXPECTEND!= 12 | */ 13 | 14 | var x = {x:1}; 15 | puts(x.propertyIsEnumerable('x')); 16 | var x = {a:1, b:2}; 17 | puts(x.hasOwnProperty('a')); 18 | puts(x.hasOwnProperty('c')); 19 | 20 | function f() {} 21 | f.a = 9; 22 | function g() {} 23 | g.prototype.x = new f(); 24 | var h = new g(); 25 | puts(f.a); 26 | puts(g.a); 27 | puts(h.a); 28 | 29 | var s = new String("Sample"); 30 | puts(s.hasOwnProperty("split")); 31 | puts(String.prototype.hasOwnProperty("split")); 32 | 33 | -------------------------------------------------------------------------------- /c-demos/Makefile: -------------------------------------------------------------------------------- 1 | JSIDIR=.. 2 | CFLAGS= -g -Wall -I$(JSIDIR) 3 | LDFLAGS=-shared -fpic 4 | 5 | all: simple dyn.so prime.so dbdemo 6 | 7 | simple: simple.c 8 | make -C$(JSIDIR) jsi.c 9 | $(CC) $(CFLAGS) -DHAVE_SQLITE=1 simple.c -o simple -lz -lm -ldl -lpthread -lsqlite3 10 | 11 | dbdemo: dbdemo.c 12 | make -C$(JSIDIR) jsi.c 13 | $(CC) $(CFLAGS) -DHAVE_SQLITE=1 dbdemo.c -o dbdemo -lz -lm -ldl -lpthread -lsqlite3 14 | 15 | dyn.so: dyn.c 16 | $(CC) $(CFLAGS) $(LDFLAGS) dyn.c -o dyn.so 17 | 18 | prime.so: prime.c 19 | $(CC) $(CFLAGS) $(LDFLAGS) prime.c -o prime.so 20 | 21 | clean: 22 | rm -rf *.so *.o simple 23 | 24 | -------------------------------------------------------------------------------- /tests/obj.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | { a:[ { b:1, c:[ 2, 3, 5, 6 ], d:{ x:1, y:2 } }, 2, 3, 4 ], x:"yz" } 4 | { abc:1, cde:"123123", x:{ a:1, b:2 }, y:{ a:3, b:4 } } 5 | 1 6 | 2 7 | [ "f", "x", "y" ] 8 | [ "f", "x", "y" ] 9 | =!EXPECTEND!= 10 | */ 11 | 12 | var x = {a:[{b:1,c:[2,3,5,6],d:{x:1,y:2}},2,3,4],x:"yz"}; 13 | puts (x); 14 | 15 | var a = { abc:1,cde:"123123",x:{a:1,b:2},y:{a:3,b:4}}; 16 | puts(a); 17 | 18 | var O = { 19 | x: 1, y: 2, 20 | f : function(n) { return n+1; } 21 | }; 22 | 23 | var o = Object.create(O); 24 | 25 | puts(o.x); 26 | puts(o.f(1)); 27 | puts(o.keys()); 28 | puts(o.keys()); 29 | 30 | -------------------------------------------------------------------------------- /tests/interp2.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 7 4 | write access denied 5 | subinterps disallowed 6 | =!EXPECTEND!= 7 | */ 8 | var ii = new Interp(); 9 | puts (ii.eval('3+4')); 10 | ii.eval('exit(0)'); 11 | delete ii; 12 | 13 | 14 | var ii = new Interp({isSafe:true, safeWriteDirs:['/tmp'], safeReadDirs:['/tmp']}); 15 | ii.eval("file.write('/tmp/xx.txt','hi');"); 16 | try { 17 | ii.eval("file.write('~/xx.txt','bye');"); 18 | } catch (e) { 19 | puts(e); 20 | } 21 | delete ii; 22 | 23 | 24 | var ii = new Interp({noSubInterps:true}); 25 | try { 26 | ii.eval("new Interp()"); 27 | } catch (e) { 28 | puts(e); 29 | } 30 | delete ii; 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /www/js-format.wiki: -------------------------------------------------------------------------------- 1 | Format 2 | The format command adds printf like functionality to javascript, eg. 3 | 4 |
 5 | var me = 'Me', cnt = 9;
 6 | format('Help %s = %d!', me, cnt);
 7 | 
8 | 9 | This can in some case be more convenient than the traditional: 10 | 11 |
12 | format('Help '+me+' = '+cnt+'!');
13 | 
14 | 15 | which ends up dealing with a lot of quotes and plus signs. 16 | 17 | Format also simplifies aligned output: 18 | 19 |
20 | format('Help %-20s = %d!', me, cnt);
21 | 
22 | 23 | -------------------------------------------------------------------------------- /tests/ffi.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | undefined 4 | ================ 5 | a:1 6 | b:2 7 | c:3 8 | d:4 9 | ================ 10 | a:1 11 | b:2 12 | c:3 13 | d:4 14 | shite:fock 15 | ================ 16 | a:1 17 | b:2 18 | c:3 19 | d:4 20 | fock:shite 21 | =!EXPECTEND!= 22 | */ 23 | 24 | a = {a: 1,b:2,c:3,d:4}; 25 | puts(a.e); 26 | 27 | puts("================"); 28 | for(var s in a) { puts(s + ":" + a[s]); } 29 | 30 | a.shite = "fock"; 31 | 32 | puts("================"); 33 | for(var s in a) { a.fock = "shite"; puts(s + ":" + a[s]); } 34 | 35 | puts("================"); 36 | for(var s in a) { 37 | puts(s + ":" + a[s]); 38 | delete a.shite; 39 | } 40 | -------------------------------------------------------------------------------- /tests/excpt4.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | catch 4 | final 5 | shot 6 | 2 7 | 2th final 8 | ff 9 | fock 10 | =!EXPECTEND!= 11 | */ 12 | 13 | var a; 14 | try { 15 | for (a = 0; a < 100; ++a) { 16 | try { 17 | try { 18 | throw(1); 19 | } catch(e) { 20 | puts("catch"); 21 | continue; 22 | } finally { 23 | puts("final"); 24 | throw(2); 25 | } 26 | } catch(f) { 27 | puts("shot"); 28 | puts(f); 29 | throw('ff'); 30 | } finally { 31 | puts("2th final"); 32 | } 33 | } 34 | } catch(x) { 35 | puts(x); 36 | } 37 | puts("fock"); 38 | 39 | -------------------------------------------------------------------------------- /tests/signal.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | [ "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE", "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGPIPE", "SIGALRM", "SIGTERM", "SIGCLD", "SIGCONT", "SIGSTOP", "SIGTSTP", "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGIO", "SIGPWR", "SIGSYS" ] 4 | MYSIG 5 | =!EXPECTEND!= 6 | */ 7 | 8 | puts(signal.names()); 9 | function mysig() { 10 | puts("MYSIG"); 11 | exit(0); 12 | } 13 | 14 | i = sys.getpid(); 15 | //signal.handle('USR1'); 16 | signal.callback(mysig,'USR1'); 17 | 18 | signal.kill(sys.getpid(),'USR1'); 19 | while (true) { 20 | sys.update(1000); 21 | } 22 | -------------------------------------------------------------------------------- /www/js-include.wiki: -------------------------------------------------------------------------------- 1 | include 2 | Jsi allows including files of javascript inline, eg. 3 | 4 |
 5 | var x = 1;
 6 | include('dir/foo.js');
 7 | foo(x);
 8 | 
9 | 10 | During the evaluation of the include, the current include directory is temporarily changed to that 11 | of the include files path. The include file may also include other files, up to a 12 | maximum of 100 (configurable). 13 | 14 | Include may also be given an array of files, as in: 15 | 16 |
17 | include(['foo.js','bar.js']);
18 | 
19 | 20 | NOTE: An optional second argument is ignored as reserved for possible future options. 21 | -------------------------------------------------------------------------------- /www/c-jsilite.wiki: -------------------------------------------------------------------------------- 1 | C-API: JSI_LITE 2 | 3 | Jsi provides a set of light-weight subset of C functions 4 | that can be used without the script engine. These include: 5 | 6 | * [./c-dstring.wiki|Jsi_DString]: Dynamic string. 7 | * [./c-hash.wiki|Jsi_Hash]: Hash tables. 8 | * [./c-tree.wiki|Jsi_Tree]: Tree structures. 9 | * [./c-sqlite.wiki|Jsi_DbQuery]: Sqlite database access. 10 | * a subset a [./c-options.wiki|C Options] (for database): 11 | 12 |
13 | #define JSI_LITE_ONLY
14 | #include "jsi.c"
15 | int main() {
16 |     Jsi_DString dStr = {"Hello World"};
17 |     Jsi_Hash* hPtr = Jsi_HashNew(NULL,0);
18 | }
19 | 
20 | -------------------------------------------------------------------------------- /tests/class.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | Howdy, my name isBob 4 | Bob 5 | object 6 | false 7 | true 8 | object 9 | number 10 | =!EXPECTEND!= 11 | */ 12 | 13 | function Person(name, gender){ 14 | 15 | this.name = name; 16 | this.gender = gender; 17 | } 18 | 19 | Person.prototype = { spake: function() { return puts(this.name); } }; 20 | Person.prototype.speak = function(){ puts("Howdy, my name is" + this.name); }; 21 | 22 | 23 | var person = new Person("Bob", "M"); 24 | 25 | person.speak(); 26 | person.spake(); 27 | puts(typeof person); 28 | puts(person.hasOwnProperty('toString')); 29 | puts(person.hasOwnProperty('name')); 30 | 31 | var y = [1,2,3]; 32 | var x = typeof(y); 33 | puts(x); 34 | puts(typeof((9))); 35 | 36 | -------------------------------------------------------------------------------- /tests/fib.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 1 4 | 1 5 | 2 6 | 3 7 | 5 8 | 8 9 | 13 10 | 21 11 | 34 12 | 55 13 | 89 14 | 144 15 | 233 16 | 377 17 | 610 18 | 987 19 | 1597 20 | 2584 21 | 4181 22 | 6765 23 | 10946 24 | 17711 25 | 28657 26 | 46368 27 | 75025 28 | 121393 29 | 196418 30 | 317811 31 | 514229 32 | 832040 33 | 1346269 34 | 2178309 35 | 3524578 36 | 5702887 37 | 9227465 38 | 14930352 39 | 24157817 40 | 39088169 41 | 63245986 42 | 102334155 43 | 165580141 44 | 267914296 45 | =!EXPECTEND!= 46 | */ 47 | 48 | 49 | 50 | a = 1; 51 | b = 1; 52 | puts(a); 53 | puts(b); 54 | for (i = 0; i < 20; i = i + 1) { 55 | a = a+b; 56 | puts(a); 57 | b = a+b; 58 | puts(b); 59 | } 60 | 61 | -------------------------------------------------------------------------------- /www/zeroinstall.wiki: -------------------------------------------------------------------------------- 1 | Zero Install 2 | Zero Install refers to using Jsi to deploy a standalone application in a self contained executable. 3 | Simply this uses [./js-zvfs.wiki|Zvfs] to wrap scripts, web pages, images, etc all into 4 | a zip archive appended to the end of the jsish binary. 5 | 6 | And because Jsi provides the web server, browser interface, database, and scripting environment, 7 | a full featured, standalone applications can be implemented without low level coding. 8 | 9 | On the other hand, if you need the speed of C, Jsi facilitates writing extensions which can easily 10 | be incorporated into jsish, or Jsi linked into your own application. 11 | 12 |

iSqlite

13 | 14 |

Ledger

15 | 16 | 17 | -------------------------------------------------------------------------------- /tests/string.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | the original string 4 | the original string 5 | he original string 6 | g 7 | 8 | tri 9 | 10 | a 11 | 4 12 | -1 13 | 6 14 | 16 15 | A 16 | d 17 | 2 18 | 6 19 | =!EXPECTEND!= 20 | */ 21 | 22 | var a = "the original string"; 23 | 24 | puts(a.substr()); 25 | puts(a.substr(false)); 26 | puts(a.substr(1)); 27 | puts(a.substr(-1, 1)); 28 | 29 | puts(a.substr(2, -1)); 30 | puts(a.substr(-5, 3)); 31 | puts(a.substr(100, 0)); 32 | puts(a.substr(10, 1)); 33 | 34 | puts(a.indexOf("ori")); 35 | puts(a.indexOf("swer")); 36 | puts(a.indexOf("i")); 37 | puts(a.indexOf("i", 9)); 38 | puts(String.fromCharCode(65)); 39 | var s = 'abcdabcd'; 40 | puts(s.charAt(3)); 41 | puts(s.indexOf('cd')); 42 | puts(s.lastIndexOf('cd')); 43 | 44 | -------------------------------------------------------------------------------- /www/c-hash.wiki: -------------------------------------------------------------------------------- 1 | C-API: Hashes 2 | This pages describes how to use Jsi_Hash. 3 | Search for Jsi_Hash in [../jsi.h#Jsi_Hash|jsi.h] for details. 4 | 5 | Hash provides simple hash table functionality. 6 | 7 |
 8 | int isNew;
 9 | Jsi_Hash *tbl = Jsi_HashNew(interp, JSI_KEYS_STRING, NULL);
10 | hPtr = Jsi_HashEntryCreate(tbl, "foo", &isNew);
11 | Jsi_HashEntrySet(hPtr, 99);
12 | Jsi_HashSet(tbl, "bar", 100);
13 | Jsi_HashSearch search;
14 | for (hPtr = Jsi_HashEntryFirst(tbl, &search);
15 |     hPtr != NULL; hPtr = Jsi_HashEntryNext(&search)) {
16 |     key = Jsi_HashKeyGet(hPtr);
17 |     int n = Jsi_HashValueGet(hPtr);
18 | }
19 | 
20 | 21 | There are plenty of examples Hash usage in the Jsi source code. 22 | -------------------------------------------------------------------------------- /tests/call.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | { a:1 } 4 | { a:1 } 5 | 1 6 | 2 7 | 3 8 | 3 9 | { fock:32 } 10 | 4 11 | 5 12 | 6 13 | 9 14 | 1 15 | 3 16 | { a:1 } 17 | 4 18 | 6 19 | { a:1 } 20 | 1 21 | 3 22 | { fn:4 } 23 | 4 24 | 6 25 | { fm:8 } 26 | =!EXPECTEND!= 27 | */ 28 | 29 | this.a = 1; 30 | puts(this); 31 | 32 | function f(x, y, z) { 33 | var a = arguments[0] + arguments[1]; 34 | puts(this); 35 | puts(x); 36 | puts(y); 37 | puts(z); 38 | puts(a); 39 | var ff = function (a) { 40 | puts(x); 41 | puts(z); 42 | puts(this); 43 | }; 44 | return ff; 45 | }; 46 | 47 | var fn = f(1, 2,3); 48 | 49 | fm = f.call({fock:32}, 4,5,6); 50 | 51 | fn(456); 52 | fm(789); 53 | 54 | fn.call({fn:4}, 456); 55 | fm.call({fm:8}, 55667); 56 | 57 | -------------------------------------------------------------------------------- /tests/file2.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | [ "AA", "CC.txt" ] 4 | XX1 5 | XX1/CC 6 | CC.txt 7 | directory 8 | .txt 9 | true 10 | true 11 | true 12 | true 13 | false 14 | =!EXPECTEND!= 15 | */ 16 | file.mkdir('XX1'); 17 | file.mkdir('XX1/AA'); 18 | file.mkdir('XX1/BB'); 19 | file.rename('XX1/BB','XX1/CC.txt'); 20 | puts(file.glob(null,'XX1').sort()); 21 | puts(file.dirname('XX1/AA')); 22 | puts(file.rootname('XX1/CC.txt')); 23 | puts(file.tail('XX1/CC.txt')); 24 | puts(file.type('XX1/CC.txt')); 25 | puts(file.extension('XX1/CC.txt')); 26 | //puts(file.realpath('XX1/CC.txt')); 27 | puts(file.writable('XX1/CC.txt')); 28 | puts(file.readable('XX1/CC.txt')); 29 | puts(file.exists('XX1/CC.txt')); 30 | puts(file.isdir('XX1/CC.txt')); 31 | puts(file.isfile('XX1/CC.txt')); 32 | file.remove('XX1',true); 33 | -------------------------------------------------------------------------------- /www/c-commands.wiki: -------------------------------------------------------------------------------- 1 | Commands 2 | This pages describes how to use Jsi_CmdSpec. 3 | Search for Jsi_CmdSpec in [../jsi.h#Jsi_CmdSpec|jsi.h] for details. 4 | 5 | Commands are typically defined en-mass, eg. 6 | 7 |
 8 | static Jsi_CmdSpec dateCmds[] = {
 9 |     { "now",    DateNowCmd,     NULL,   0,  1, "?flags?",  .help="Return current time in ms since unix epoch (1970)" },
10 |     { "format", DateFormatCmd,  NULL,  1,  3, "num,?format,flags?",  .help="Format time" },
11 |     { "parse",  DateParseCmd,   NULL,   1,  2, "string,?flags?",  .help="Parse time string and return time in ms since 1970" },
12 |     { NULL,     NULL,  }
13 | };
14 | 
15 | Jsi_SetupCmdSpecs(interp, "Date",   dateCmds,  NULL, JSI_CMDSPEC_NOTOBJ);
16 | 
17 | 18 | -------------------------------------------------------------------------------- /tests/json.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | UMASK: 0422 4 | WDIR: /tmp/ready 5 | TOSTR: { count:422, done:null, gonogo:true, umask:"0422", "watch-dir":"/tmp/ready" } 6 | JSON: { "count":422, "done":null, "gonogo":true, "umask":"0422", "watch-dir":"/tmp/ready" } 7 | { "count":422, "done":null, "gonogo":true, "umask":"0422", "watch-dir":"/tmp/ready" } 8 | =!EXPECTEND!= 9 | */ 10 | 11 | var d = ' 12 | { 13 | "count": 422, 14 | "umask": "0422", 15 | "watch-dir": "/tmp/ready", 16 | "gonogo" : true, 17 | "done" : null 18 | } 19 | '; 20 | var j = JSON.parse(d); 21 | j.toString(); 22 | puts('UMASK: ' + j.umask); 23 | puts('WDIR: ' + j["watch-dir"]); 24 | puts('TOSTR: ' + j.toString()); 25 | puts('JSON: ' + JSON.stringify(j)); 26 | 27 | var x = JSON.stringify(j); 28 | puts(x); 29 | 30 | -------------------------------------------------------------------------------- /tests/switch2.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 10 4 | 20 5 | 30 6 | 20 7 | 30 8 | 30 9 | 7 10 | =!EXPECTEND!= 11 | */ 12 | 13 | for(var i = 0; i < 100; ++i) { 14 | switch(i) { 15 | case 10: 16 | puts("10"); 17 | case 20: 18 | puts("20"); 19 | case 30: 20 | puts("30"); 21 | break; 22 | case 40: { 23 | continue; 24 | puts("40"); 25 | } 26 | break; 27 | case 41: break; 28 | case 50: 29 | for (var j = 0; j < 10; ++j) { 30 | if (j < 5) continue; 31 | if (j > 6) break; 32 | } 33 | puts(j); 34 | break; 35 | default: 36 | break; 37 | } 38 | if (i == 40) puts("hehe"); 39 | } 40 | -------------------------------------------------------------------------------- /c-demos/stubs/demo.c: -------------------------------------------------------------------------------- 1 | #include "jsi.h" 2 | #include "demo.h" 3 | 4 | JSI_EXTENSION_INI 5 | 6 | int Demo_Incr(int n) { 7 | puts("INCR"); 8 | return n+1; 9 | } 10 | 11 | int Demo_Decr(int n) { 12 | puts("DECR"); 13 | return n-1; 14 | } 15 | 16 | Jsi_CmdProcDecl(DemoCmd) { 17 | int i, n = Jsi_ValueGetLength(interp, args); 18 | printf("demo called with %d args\n", n); 19 | for (i=0; iSignal 2 | Signal is used to send signals to processes, or setup handlers 3 | for receiving signals. It is currently only supported on unix. 4 | 5 | The following signal commands are available: 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
MethodDescription
alarm(secs)Setup alarm in seconds
callback(func,sig)Setup callback handler for signal
default(?sig,sig,...?)Set named signals to default action
handle(?sig,sig,...?)Set named signals to handle action
ignore(?sig,sig,...?)Set named signals to ignore action
kill(pid?,sig?)Send signal to process id (default SIGTERM)
names()Return names of all signals
16 | -------------------------------------------------------------------------------- /c-demos/prime.c: -------------------------------------------------------------------------------- 1 | #include "jsi.h" 2 | 3 | JSI_EXTENSION_INI 4 | 5 | static int PrimeCheckCmd(Jsi_Interp *interp, Jsi_Value *args, 6 | Jsi_Value *_this, Jsi_Value **ret, Jsi_Func *funcPtr) 7 | { 8 | int val, lim; 9 | Jsi_GetIntFromValue(interp, Jsi_ValueArrayIndex(interp, args, 0), &val); 10 | Jsi_GetIntFromValue(interp, Jsi_ValueArrayIndex(interp, args, 1), &lim); 11 | int i, rc = 1; 12 | 13 | for (i = 2; i <= lim; i++) { 14 | if ((val % i) == 0) { 15 | rc = 0; 16 | break; 17 | } 18 | } 19 | Jsi_ValueMakeBool(interp, *ret, rc); 20 | return JSI_OK; 21 | } 22 | 23 | int Jsi_InitPrime(Jsi_Interp *interp) { 24 | //puts("LOADED PRIME"); 25 | #ifdef JSI_USE_STUBS 26 | if (Jsi_StubsInit(interp, JSI_STUBS_STRICT) != JSI_OK) 27 | return JSI_ERROR; 28 | #endif 29 | 30 | Jsi_CommandCreate(interp, "primeCheckNative", PrimeCheckCmd, NULL); 31 | return JSI_OK; 32 | } 33 | -------------------------------------------------------------------------------- /jsiLexer.h: -------------------------------------------------------------------------------- 1 | #ifndef __JSILEXER_H__ 2 | #define __JSILEXER_H__ 3 | 4 | #define YYSTYPE void * 5 | 6 | #ifndef JSI_AMALGAMATION 7 | #include "parser.h" 8 | #include "jsiPstate.h" 9 | #endif 10 | 11 | /* Lexer, where input seq provided */ 12 | typedef struct Lexer { 13 | enum { 14 | LT_NONE, 15 | LT_FILE, /* read from file */ 16 | LT_STRING /* read from a string */ 17 | } ltype; 18 | union { 19 | Jsi_Channel fp; /* LT_FILE, where to read */ 20 | char *str; /* LT_STRING */ 21 | } d; 22 | int last_token; /* last token returned */ 23 | int ungot, unch[100]; 24 | int cur; /* LT_STRING, current char */ 25 | int cur_line; /* current line no. */ 26 | int cur_char; /* current column no. */ 27 | jsi_Pstate *pstate; 28 | } Lexer; 29 | 30 | int yylex (YYSTYPE *yylvalp, YYLTYPE *yyllocp, jsi_Pstate *pstate); 31 | void yyerror(YYLTYPE *yylloc, jsi_Pstate *ps, const char *msg); 32 | 33 | #endif /* __JSILEXER_H__ */ 34 | 35 | -------------------------------------------------------------------------------- /tests/eval2.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | at global 4 | predefine must be in global 5 | predefine in global after eval 6 | predefine in global after eval 7 | global predefine: predefine in global after eval 8 | predefine in global after eval 9 | 100 10 | predefine in global after eval 11 | =!EXPECTEND!= 12 | */ 13 | 14 | var PREDEFINE = 'at global'; 15 | 16 | function haha() { 17 | return { 18 | getpredefine: function() { puts(PREDEFINE); }, 19 | setpredefine: function(a) { PREDEFINE = a; }, 20 | eval: function(n) { eval(n); } 21 | }; 22 | }; 23 | 24 | var a = haha(); 25 | 26 | a.getpredefine(); 27 | a.setpredefine('predefine must be in global'); 28 | a.getpredefine(); 29 | a.eval("PREDEFINE = 'predefine in global after eval';"); 30 | a.getpredefine(); 31 | a.eval("var PREDEFINE = 'predefine now in local';"); 32 | a.getpredefine(); 33 | puts("global predefine: " + PREDEFINE); 34 | 35 | function hehe(n) 36 | { 37 | if (n) eval(n); 38 | puts(PREDEFINE); 39 | }; 40 | 41 | hehe(); 42 | hehe("var PREDEFINE = 100;"); 43 | hehe(); 44 | -------------------------------------------------------------------------------- /tests/yhsj.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 100 4 | 99 5 | 98 6 | 97 7 | 96 8 | 95 9 | 94 10 | 93 11 | 92 12 | 91 13 | 90 14 | 89 15 | 88 16 | 87 17 | 86 18 | 85 19 | 84 20 | 83 21 | 82 22 | 81 23 | 80 24 | 79 25 | 78 26 | 77 27 | 76 28 | 75 29 | 74 30 | 73 31 | 72 32 | 71 33 | 70 34 | 69 35 | 68 36 | 67 37 | 66 38 | 65 39 | 64 40 | 63 41 | 62 42 | 61 43 | 60 44 | 59 45 | 58 46 | 57 47 | 56 48 | 55 49 | 54 50 | 53 51 | 52 52 | 51 53 | 50 54 | 49 55 | 48 56 | 47 57 | 46 58 | 45 59 | 44 60 | 43 61 | 42 62 | 41 63 | 40 64 | 39 65 | 38 66 | 37 67 | 36 68 | 35 69 | 34 70 | 33 71 | 32 72 | 31 73 | 30 74 | 29 75 | 28 76 | 27 77 | 26 78 | 25 79 | 24 80 | 23 81 | 22 82 | 21 83 | 20 84 | 19 85 | 18 86 | 17 87 | 16 88 | 15 89 | 14 90 | 13 91 | 12 92 | 11 93 | 10 94 | 9 95 | 8 96 | 7 97 | 6 98 | 5 99 | 4 100 | 3 101 | 2 102 | 1 103 | =!EXPECTEND!= 104 | */ 105 | 106 | function jc(n) { 107 | if (n > 0) { 108 | puts(n); 109 | jc(n - 1); 110 | } 111 | }; 112 | 113 | jc(100); 114 | -------------------------------------------------------------------------------- /js-demos/html/main.ihtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | \n

'+s+'

\n');}; 6 | hdrs('Main'); 7 | ?> 8 | Welcome to the Jsi sample web application. 9 |

10 | What are some reasons for using Jsi: 11 |

    12 | '+xx[i]+''); 16 | ?> 17 |
18 | 19 | 27 | 28 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /tests/callee2.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 100 4 | 99 5 | 98 6 | 97 7 | 96 8 | 95 9 | 94 10 | 93 11 | 92 12 | 91 13 | 90 14 | 89 15 | 88 16 | 87 17 | 86 18 | 85 19 | 84 20 | 83 21 | 82 22 | 81 23 | 80 24 | 79 25 | 78 26 | 77 27 | 76 28 | 75 29 | 74 30 | 73 31 | 72 32 | 71 33 | 70 34 | 69 35 | 68 36 | 67 37 | 66 38 | 65 39 | 64 40 | 63 41 | 62 42 | 61 43 | 60 44 | 59 45 | 58 46 | 57 47 | 56 48 | 55 49 | 54 50 | 53 51 | 52 52 | 51 53 | 50 54 | 49 55 | 48 56 | 47 57 | 46 58 | 45 59 | 44 60 | 43 61 | 42 62 | 41 63 | 40 64 | 39 65 | 38 66 | 37 67 | 36 68 | 35 69 | 34 70 | 33 71 | 32 72 | 31 73 | 30 74 | 29 75 | 28 76 | 27 77 | 26 78 | 25 79 | 24 80 | 23 81 | 22 82 | 21 83 | 20 84 | 19 85 | 18 86 | 17 87 | 16 88 | 15 89 | 14 90 | 13 91 | 12 92 | 11 93 | 10 94 | 9 95 | 8 96 | 7 97 | 6 98 | 5 99 | 4 100 | 3 101 | 2 102 | 1 103 | =!EXPECTEND!= 104 | */ 105 | 106 | (function (a) { 107 | if (a <= 0) { 108 | return; 109 | } 110 | puts(a); 111 | arguments.callee(a - 1); 112 | })(100); 113 | -------------------------------------------------------------------------------- /tests/json2.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | true 4 | true 5 | true 6 | false 7 | { data:[ 6, 2961 ], label:"editTran", type:"" } 8 | { data:[ 6, 2961 ], label:"editTran", type:"" } 9 | { data:[ 6, 2961 ], label:"editTran", type:"" } 10 | parse error (unexpected char in strict mode) at offset 32 "data : [6,2961]}" 11 | { "able":1 } 12 | [ "A B", 1 ] 13 | { A:1, Columns:[ 1, 2, { Au0020B:1, B:[ 2, 3 ] }, 2 ] } 14 | =!EXPECTEND!= 15 | */ 16 | 17 | var x = '{"type":"", "label":"editTran", "data" : [6,2961]}'; 18 | var x2 = '{"type":"", "label":"editTran", data : [6,2961]}'; 19 | puts(JSON.check(x)); 20 | puts(JSON.check(x,true)); 21 | puts(JSON.check(x2)); 22 | puts(JSON.check(x2,true)); 23 | puts(JSON.parseNS(x)); 24 | puts(JSON.parse(x)); 25 | 26 | puts(JSON.parseNS(x2)); 27 | try { puts(JSON.parse(x2)); } catch(e) { puts(e); } 28 | var dat = { able:1, baker:undefined }; 29 | puts(JSON.stringify(dat)); 30 | 31 | var x = JSON.parse('["A\\u0020B",1]'); 32 | puts(x.toString()); 33 | 34 | JSON.parse('{ "Columns": [ 1, 2], "A" : 1 }'); 35 | var x = JSON.parse('{ "Columns": [ 1, 2, {"A\u0020B":1, "B":[2,3]}, 2], "A" : 1 }'); 36 | puts(x.toString()); 37 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Peter MacDonald 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/alias.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | [ "foo", "bar" ] 4 | function myAlias(interp,name,arg1,arg2) {...} 5 | [ #Interp_1, "foo" ] 6 | myAlias2: 1 2 7 | A 8 | B 9 | myAlias: #Interp_1 bb.fig 1 undefined 10 | [ "bb.fig", "foo", "bar" ] 11 | [ "foo", "bar" ] 12 | OK 13 | =!EXPECTEND!= 14 | */ 15 | var i = new Interp({subthread:false}); 16 | //var i = new Interp(); 17 | function myAlias(interp,name,arg1,arg2) { 18 | puts('myAlias: '+interp+' '+name+' '+arg1+' '+arg2); 19 | } 20 | 21 | function myAlias2(arg1,arg2) { 22 | puts('myAlias2: '+arg1+' '+arg2); 23 | } 24 | 25 | i.alias('foo', myAlias, [i, 'foo']); 26 | i.alias('bar', myAlias2,null); 27 | 28 | puts(i.alias()); 29 | puts(i.alias('foo')); 30 | puts(i.alias('foo', myAlias)); 31 | 32 | i.eval('bar(1,2);'); 33 | 34 | puts('A'); 35 | i.eval('var bb = {x:1};'); 36 | puts('B'); 37 | i.alias('bb.fig', myAlias, [i, 'bb.fig']); 38 | i.eval('bb.fig(1)'); 39 | 40 | /*i.alias('bb.fig', myAlias, [i, 'bb.FIG']); 41 | i.eval('bb.fig(1)');*/ 42 | 43 | puts(i.alias()); 44 | i.alias('bb.fig', null, null); 45 | puts(i.alias()); 46 | 47 | //try { i.eval('bb.fig(1)'); } catch(e) { puts("CAUGHT ERROR: "+e); }; 48 | puts("OK"); 49 | -------------------------------------------------------------------------------- /www/input_output.wiki: -------------------------------------------------------------------------------- 1 | Input/Output 2 | 3 | Jsi offers numerous input/output facilities. This page documents basic IO facilities. 4 |
5 |

console.log(str)

6 | 7 | The console.log method simply outputs a string to stderr. 8 | 9 |
10 |

puts(str)

11 | 12 | The puts method outputs a string to stdout. 13 | With 1 or 0 arguments a newline is appended. 14 | 15 |
16 | puts("Hello World");
17 | puts("Hello"," World\n");
18 | 
19 | 20 | Scripts also used in web browsers can add the following for compatibility: 21 | 22 |
23 | if (puts === undefined)
24 |     var puts = console.log.bind(console);
25 | 
26 | 27 |
28 |

console.input()

29 | 30 | User input can be obtained using console.input(): 31 | 32 |
33 | puts("Enter your name: ", "");
34 | var str = console.input();
35 | 
36 | 37 |
38 |

console.args

39 | 40 | Program arguments are available using console.args: 41 | 42 |
43 | for (var i in console.args) {
44 |    puts(console.args[i]);
45 | }
46 | 
47 | -------------------------------------------------------------------------------- /tests/prime.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | Have native helper: false 4 | 1999 2999 4999 8999 5 | =!EXPECTEND!= 6 | */ 7 | 8 | // prime.js 9 | 10 | try { load("prime.so"); } catch(e) { }; 11 | 12 | // Pure Ecmascript version of low level helper 13 | function primeCheckEcmascript(val, limit) { 14 | for (var i = 2; i <= limit; i++) { 15 | if ((val % i) == 0) { return false; } 16 | } 17 | return true; 18 | } 19 | 20 | // Select available helper at load time 21 | var primeCheckHelper = (this.primeCheckNative || primeCheckEcmascript); 22 | 23 | // Check 'val' for primality 24 | function primeCheck(val) { 25 | if (val == 1 || val == 2) { return true; } 26 | var limit = Math.ceil(Math.sqrt(val)); 27 | while (limit * limit < val) { limit += 1; } 28 | return primeCheckHelper(val, limit); 29 | } 30 | 31 | // Find primes below one million ending in '9999'. 32 | function primeTest() { 33 | var res = []; 34 | 35 | puts('Have native helper: ' + (primeCheckHelper !== primeCheckEcmascript)); 36 | for (var i = 1; i < 10000; i++) { 37 | if (primeCheck(i) && (i % 1000) == 999) { res.push(i); } 38 | } 39 | puts(res.join(' ')); 40 | } 41 | 42 | primeTest(); 43 | 44 | -------------------------------------------------------------------------------- /tests/info.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | { type:"number" } 4 | [ "xx", "x" ] 5 | [ "xx", "x", "y" ] 6 | [ "a" ] 7 | [ "XX", "X" ] 8 | [ "XX", "X", "Y" ] 9 | F 10 | [ "z" ] 11 | [ "f", "g" ] 12 | info.js 13 | info.js 14 | info.js 15 | [ "load" ] 16 | { argStr:"str?,str,...?", help:"Append one or more strings", maxArgs:-1, minArgs:1, name:"String.concat", type:"command" } 17 | [ "P", "Q" ] 18 | =!EXPECTEND!= 19 | */ 20 | var x = 1; 21 | var xx = 2; 22 | var y = 2; 23 | 24 | puts(info.vars('x')); 25 | puts(info.vars(/x/)); 26 | puts(info.vars()); 27 | 28 | function X(a) {var jj=1, kk; return jj++;} 29 | function XX(a) {} 30 | function Y(a) {} 31 | 32 | puts(info.funcs('X').args); 33 | puts(info.funcs(/X/)); 34 | puts(info.funcs()); 35 | 36 | var K = {}; 37 | K.f = function(z) { puts("F"); }; 38 | K.g = function(z) { puts("G"); }; 39 | K.f(); 40 | puts(info.funcs(K.f).args); 41 | puts(info.funcs(K)); 42 | 43 | puts(file.tail(info.script())); 44 | puts(file.tail(info.script(XX))); 45 | puts(file.tail(info.script(/.*/)[0])); 46 | 47 | puts(info.cmds(/^loa./)); 48 | puts(info.cmds('String.concat')); 49 | 50 | X.prototype.P = function(M) { return M; }; 51 | X.prototype.Q = function(M) { return M; }; 52 | puts(info.funcs(X.prototype)); 53 | 54 | -------------------------------------------------------------------------------- /tests/array.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | A 4 | 5 5 | SHIFTED: 5 6 | 4 7 | 0 = pig 8 | 1 = cat 9 | 2 = 99 10 | 3 = 4 11 | 4 = 3 12 | 5 = 2 13 | 6 = 1 14 | 10 = -1 15 | 11 = dog 16 | A = pig,cat,99,4,3,2,1,-1,dog 17 | IDX = 11 18 | S = cat,99,4,3 19 | SLICE0 = cat 20 | SLICE* = cat,99,4,3 21 | T: pig,cat,99,4,3,2,1,-1,dog,SICK!!!,cat,99,4,3 22 | Z: 5,4,A,B,1 ==> 3,2 23 | Q: Aaa,aAb,AAc,Bba,bBb 24 | =!EXPECTEND!= 25 | */ 26 | var y = [ '2', '1' ]; 27 | var x = { '0': 'A', '1':'B' }; 28 | puts(x[0]); 29 | var a = new Array(5,4,3,2,1); 30 | a.dog = 9; 31 | puts(a[0]); 32 | var b = a.shift(); 33 | puts("SHIFTED: "+b); 34 | puts(a[0]); 35 | a[7] = -1; 36 | a[8] = 'dog'; 37 | a.unshift('pig', 'cat', 99); 38 | for (var i in a) { puts(i+" = "+a[i]); } 39 | puts('A = '+a.join(',')); 40 | puts("IDX = "+a.indexOf('dog')); 41 | var s = a.slice(1,4); 42 | puts('S = '+ s.join(',')); 43 | puts("SLICE0 = "+s[0]); 44 | puts("SLICE* = "+s.join(',')); 45 | 46 | var t = a.concat('SICK!!!',s); 47 | puts('T: '+t.join(',')); 48 | 49 | 50 | var z = new Array(5,4,3,2,1); 51 | var za = z.splice(2,2,'A','B'); 52 | puts('Z: '+z.join(',') + " ==> "+za.join(',')); 53 | 54 | 55 | //var q = new Array(5,4,2,3,1); 56 | var q = new Array('Aaa','aAb','AAc','Bba','bBb'); 57 | var qq = q.sort(); 58 | 59 | puts('Q: '+qq.join(',')); 60 | 61 | 62 | -------------------------------------------------------------------------------- /www/editors.wiki: -------------------------------------------------------------------------------- 1 | Editors 2 | 3 |

Geany

4 | 5 | [http://www.geany.org|Geany] is a convenient editor to use with Jsish. 6 | To enable file completion in Geany, copy tools/geany/filetypes.javascript to 7 | ~/.config/geany/filedefs/. Then edit /usr/share/geany/filetype_extensions.conf and 8 | add "*.jsi" to Javascript. 9 | Finally, keep the file tools/protos.jsi open in the editor so Geany knows 10 | how to complete Jsi functions. 11 | 12 | Geany can be setup to navigate 13 | through Jsi's gcc style scripting errors: 14 | 15 | * Start by editing any file ending in the suffix .jsi. 16 | * From the Geany Build menu, select Set Build Commands. 17 | * Click on the first blank label in Javascript and enter Jsish. 18 | * In the command section enter the pathspec to jsish, eg. $HOME/bin/jsish %f 19 | * Click Ok 20 | 21 | Now hit F8 to run the script. Upon errors, you should be able to navigate to the 22 | highlighted lines, and see warnings in the bottom pane. 23 | 24 | 25 |

Vim

26 | Here is how to setup vim: 27 | 28 |
29 | :set makeprg=jsish\ %
30 | :copen
31 | 
32 | 33 | Then to run scripts just use: 34 | 35 |
36 | :make
37 | 
38 | -------------------------------------------------------------------------------- /tests/regex.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | input the email 4 | invalid email format 5 | input the email 6 | invalid email format 7 | input the email 8 | match at: abc@gmail.com 9 | name: abc 10 | domain: gmail 11 | input the email 12 | invalid email format 13 | input the email 14 | a c b c d b 15 | a c c c d c 16 | a c b c d b 17 | [ "ain", "AIN", "ain", "ain" ] 18 | 5 19 | 14 20 | 5 21 | [ "pm@gm.com", "pm", "gm.com" ] 22 | null 23 | [ "gm" ] 24 | =!EXPECTEND!= 25 | */ 26 | 27 | 28 | while (1) { 29 | puts("input the email"); 30 | email = console.input(); 31 | if (email == undefined) break; 32 | if ((res = email.match(/([a-zA-Z0-9]+)@([a-zA-Z0-9]+)\.com/))) { 33 | puts("match at: " + res[0]); 34 | puts("name: " + res[1]); 35 | puts("domain: " + res[2]); 36 | } else { 37 | puts("invalid email format"); 38 | } 39 | } 40 | 41 | var s = 'a b b c d b'; 42 | puts(s.replace('b','c')); 43 | puts(s.replace(/b/g,'c')); 44 | puts(s.replace(/b/,'c')); 45 | var str="The rain in SPAIN stays mainly in the plain"; 46 | puts(str.match(/ain/gi)); 47 | puts(str.search(/ain/gi)); 48 | puts(str.search(/AIN/)); 49 | puts(str.search('ain')); 50 | 51 | var s = 'pm@gm.com'; 52 | puts(s.match(/^([a-z]*)@([a-z.]*)$/)); 53 | puts(s.match(/^([t-z]*)@([a-z.]*)$/)); 54 | 55 | var r = new RegExp('gm'); 56 | puts(s.match(r)); 57 | 58 | 59 | -------------------------------------------------------------------------------- /www/index.wiki: -------------------------------------------------------------------------------- 1 | Home 2 | 3 |

4 | 5 | Jsi: Embeddable Javascript 6 | 7 |

8 | [http://pdqi.com/jsi|Jsi] is a small javascript interpreter implemented in C that 9 | provides built-in support for [./js-sqlite.wiki|Sqlite], [./js-websocket.wiki|WebSockets], 10 | [./js-json.wiki|JSON] and a [./js-zvfs.wiki|Zip filesystem]. 11 | It is used for creating [./zeroinstall.wiki|standalone] desktop web-database applications 12 | or for embedding in other applications. 13 | 14 | * [./getstarted.wiki|Jsi In 5 Minutes or Less] 15 | * [./reference.wiki|Language Reference] 16 | * [./jsindex.wiki|Topic Index] 17 | 18 |

Example Applications

19 | 20 | The Jsi distribution comes with several demo applications designed to 21 | showcase it's power and functionality: 22 | 23 | * [app/sqliteui.wiki|SqliteUI]: a user interface to Sqlite. 24 | * [app/ledgerjs.wiki|LedgerJS]: an accounting program. 25 | 26 |

Rationale

27 | 28 | For desktop web-application development, there many alternatives 29 | but none of these 30 | deliver the range of functionality in Jsi, with anything approching it's small form-factor. 31 | 32 | For a description of the rationale 33 | behind Jsi, including comparisons against alternatives such as 34 | NodeJs, Lua, Tcl and LAMP (Linux/Apache/MySql/PHP), 35 | [./rationale.wiki|click here]. 36 | 37 | -------------------------------------------------------------------------------- /jsiBool.c: -------------------------------------------------------------------------------- 1 | #ifndef JSI_LITE_ONLY 2 | #ifndef JSI_AMALGAMATION 3 | #include "jsiInt.h" 4 | #endif 5 | 6 | static int BooleanConstructor(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this, 7 | Jsi_Value **ret, Jsi_Func *funcPtr) 8 | { 9 | if (Jsi_FunctionIsConstructor(funcPtr)) { 10 | int nv = 0; 11 | if (Jsi_ValueGetLength(interp, args) > 0) { 12 | Jsi_Value *v = Jsi_ValueArrayIndex(interp, args, 0); 13 | if (v) { 14 | nv = Jsi_ValueIsTrue(interp, v); 15 | } 16 | } 17 | _this->d.obj->ot = JSI_OT_BOOL; 18 | _this->d.obj->d.val = nv; 19 | return JSI_OK; 20 | } 21 | if (Jsi_ValueGetLength(interp, args) > 0) { 22 | Jsi_Value *v = Jsi_ValueArrayIndex(interp, args, 0); 23 | if (v) { 24 | Jsi_ValueMakeBool(interp, *ret, Jsi_ValueIsTrue(interp, v)); 25 | return JSI_OK; 26 | } 27 | } 28 | Jsi_ValueMakeBool(interp, *ret, 0); 29 | return JSI_OK; 30 | } 31 | 32 | static Jsi_CmdSpec booleanCmds[] = { 33 | { "Boolean", BooleanConstructor, 0, 1, "?bool?", .help="Boolean constructor", .flags=JSI_CMD_IS_CONSTRUCTOR }, 34 | { NULL, .help="A Boolean object" } 35 | }; 36 | 37 | int jsi_BooleanInit(Jsi_Interp *interp) 38 | { 39 | interp->Boolean_prototype = Jsi_CommandCreateSpecs(interp, "Boolean", booleanCmds, NULL, 0); 40 | return JSI_OK; 41 | } 42 | #endif 43 | 44 | -------------------------------------------------------------------------------- /www/js-websocket.wiki: -------------------------------------------------------------------------------- 1 | Websocket 2 | [./reference.wiki#Websocket|<Websocket Reference>] 3 |

Description

4 | 5 | The WebSocket extension uses libwebsockets to implement 6 | bidirectional socket communication with a web browser. 7 | Used in conjunction with [./js-sqlite.wiki|Sqlite] and [./js-json.wiki|JSON], 8 | web browser based applications are easy to implement. 9 | 10 |

Example

11 | 12 | The following creates a client and server using Websockets. 13 | First the server file ws.js: 14 | 15 |
16 | function ws_input(data, id) {
17 |     puts("ws_input: "+ id +": "+data);
18 | };
19 | 
20 | var ws = new Websocket({callback:ws_input});
21 | var msg = { str:"whos there?", cnt:0 };
22 | while (true) {
23 |     sys.update(1);
24 |     if ((msg.cnt++ % 10) == 0)
25 |        ws.send(JSON.stringify(msg));
26 | }
27 | 
28 | 29 | Next the client file: wsc.js: 30 | 31 |
32 | function wsc_input(data) {
33 |     puts("wsc_input: "+data);
34 | };
35 | 
36 | var ws = new Websocket({client:true, callback:wsc_input});
37 | var msg = { str:"knock knock", cnt:0 };
38 | 
39 | while (true) {
40 |     msg.cnt++;
41 |     ws.send(JSON.stringify(msg));
42 |     sys.update(1);
43 | }
44 | 
45 | 46 | Which we run with: 47 | 48 |
49 |   jsish ws.js &
50 |   jsish wsc.js
51 | 
52 | 53 | -------------------------------------------------------------------------------- /tests/math.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 9.1 4 | 9.12e+0 5 | 9.12 6 | 9.1 7 | 9.12e+0 8 | 9.12 9 | -0.452316 10 | -0.4 11 | -0.4 12 | -4.52e-01 13 | -0.45 14 | 1 15 | 0 16 | 1.5708 17 | 0.785398 18 | 0.07983 19 | 0.540302 20 | 0.841471 21 | 7.38906 22 | 6 23 | 5 24 | 1.67335 25 | 3 26 | 1 27 | 8 28 | 5 29 | 2.30868 30 | +Infinity 31 | -Infinity 32 | NaN 33 | 40 34 | 64 35 | 100 36 | 64 37 | =!EXPECTEND!= 38 | */ 39 | puts(Number.toPrecision(9.1234,2)); 40 | puts(Number.toExponential(9.1234,2)); puts(Number.toFixed(9.1234,2)); var j = new Number(9.1234); 41 | puts(j.toPrecision(2)); 42 | puts(j.toExponential(2)); 43 | puts(j.toFixed(2)); 44 | puts(Math.tan(9)); 45 | var k = Math.tan(9); 46 | puts(Number.toPrecision(k,2)); 47 | puts(Number.toPrecision(Math.tan(9),2)); 48 | puts(Number.toExponential(k,2)); 49 | puts(Number.toFixed(k,2)); 50 | puts(Math.abs(-1)); 51 | puts(Math.acos(1)); 52 | puts(Math.asin(1)); 53 | puts(Math.atan(1)); 54 | puts(Math.atan2(0.4,5)); 55 | puts(Math.cos(1)); 56 | puts(Math.sin(1)); 57 | puts(Math.exp(2)); 58 | puts(Math.ceil(5.33)); 59 | puts(Math.floor(5.33)); 60 | puts(Math.log(5.33)); 61 | puts(Math.max(1,2,3)); 62 | puts(Math.min(1,2,3)); 63 | puts(Math.pow(2,3)); 64 | puts(Math.round(5.33)); 65 | Math.random(); 66 | puts(Math.sqrt(5.33)); 67 | puts(1/0); 68 | puts(-1/0); 69 | puts(-1/0*'x'); 70 | var x = Math.pow(2,6); 71 | puts(x.toString(16)); 72 | puts(x.toString(10)); 73 | puts(x.toString(8)); 74 | puts(x.toString(2)); 75 | 76 | -------------------------------------------------------------------------------- /c-demos/simple.c: -------------------------------------------------------------------------------- 1 | /* 2 | Basic example using JSI single file amalgamation. 3 | 4 | BUILDING: 5 | cc simple.c -lz -lm -ldl -lpthread -DHAVE_SQLITE -lsqlite3 6 | */ 7 | #include "../jsi.c" //FYI: use "make -C.. jsi.c" if jsi.c is not already there... 8 | 9 | static Jsi_CmdProcDecl(MyCmd); 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | Jsi_Interp *interp = Jsi_InterpCreate(NULL, argc, argv, 0); 14 | 15 | /* Basic script. */ 16 | Jsi_EvalString(interp, "for (var i=1; i<=3; i++) puts('TEST: '+i);", 0); 17 | 18 | /* C-Extension */ 19 | Jsi_CommandCreate(interp, "MyCmd", MyCmd, NULL); 20 | Jsi_EvalString(interp, "MyCmd(3,2,1);", 0); 21 | 22 | #ifdef HAVE_SQLITE 23 | /* Database */ 24 | Jsi_EvalString(interp, 25 | "var db = new Sqlite('~/testjs.db');" 26 | "db.evaluate('create table if not exists foo(a,b); insert into foo VALUES(1,2);');" 27 | "puts(db.exec('select * from foo;'));" 28 | "puts(db.exec('select * from foo;',{headers:true,mode:'column'}));", 0); 29 | #endif 30 | exit(0); 31 | } 32 | 33 | /* Callback for C extension. */ 34 | static Jsi_CmdProcDecl(MyCmd) { 35 | /* Just echo arguments */ 36 | int i, n = Jsi_ValueGetLength(interp, args); 37 | printf("Called MyCmd() with:\n"); 38 | for (i=0; iMaster Index
"); 12 | puts("\n

General"); 13 | var dat,title; 14 | for (var i in flst.sort()) { 15 | if (flst[i] == "jsindex.wiki") continue; 16 | if (flst[i] == "index.wiki") continue; 17 | dat = file.read(flst[i]); 18 | title = dat.match('([^>]+)'); 19 | if (!title) 20 | console.log("failed on "+flst[i]); 21 | puts(' * '+title[1]+''); 22 | } 23 | puts("

"); 24 | puts("\n

Script"); 25 | var dat,title, ttl; 26 | for (var i in jlst.sort()) { 27 | dat = file.read(jlst[i]); 28 | title = dat.match('([^>]+)'); 29 | if (!title) 30 | console.log("failed on "+flst[i]); 31 | puts(' * '+title[1]+''); 32 | } 33 | puts("

"); 34 | puts("\n

C-API"); 35 | for (var i in clst.sort()) { 36 | dat = file.read(clst[i]); 37 | title = dat.match('([^>]+)'); 38 | if (!title) 39 | console.log("failed on "+flst[i]); 40 | ttl = title[1]; 41 | if (ttl.substr(0,6) == 'C-API:') 42 | ttl = ttl.substr(6); 43 | puts(' * '+ttl+''); 44 | } 45 | puts("

"); 46 | -------------------------------------------------------------------------------- /jsiPstate.h: -------------------------------------------------------------------------------- 1 | #ifndef __JSIPSTATE_H__ 2 | #define __JSIPSTATE_H__ 3 | 4 | #ifndef JSI_AMALGAMATION 5 | #include "jsiInt.h" 6 | #endif 7 | 8 | 9 | Jsi_ScopeStrs *jsi_ScopeStrsNew(struct jsi_Pstate *ps); 10 | void jsi_ScopeStrsPush(struct jsi_Pstate *ps, Jsi_ScopeStrs *ss, const char *string); 11 | void jsi_ScopeStrsFree(Jsi_ScopeStrs *ss); 12 | const char *jsi_ScopeStrsGet(Jsi_ScopeStrs *ss, int i); 13 | 14 | /* what lexical scope means: 15 | * -------------- 16 | * var a; // this is first level of scope 17 | * function foo() { // parsing function make lexical scope to push 18 | * var b; // this is the second level 19 | * var c = function() { // push again 20 | * var d; // third level 21 | * } // end of an function, pop scope 22 | * } // return to first scope 23 | * -------------- 24 | */ 25 | 26 | void jsi_ScopePush(struct jsi_Pstate *ps); 27 | void jsi_ScopePop(struct jsi_Pstate *ps); 28 | void jsi_ScopeAddVar(struct jsi_Pstate *ps, const char *str); 29 | Jsi_ScopeStrs *jsi_ScopeGetVarlist(struct jsi_Pstate *ps); 30 | 31 | void jsi_PstateFree(jsi_Pstate *ps); 32 | jsi_Pstate *jsi_PstateNew(Jsi_Interp *interp); 33 | void jsi_PstateClear(jsi_Pstate *ps); 34 | const char * jsi_PstateGetFilename(jsi_Pstate *ps); 35 | int jsi_PstateSetFile(jsi_Pstate *ps, Jsi_Channel fp, int skipbang); 36 | int jsi_PstateSetString(jsi_Pstate *ps, const char *str); 37 | 38 | extern int yyparse(jsi_Pstate *ps); 39 | 40 | 41 | 42 | 43 | #endif /* __JSIPSTATE_H__ */ 44 | -------------------------------------------------------------------------------- /c-demos/stubs/demoStubs.h: -------------------------------------------------------------------------------- 1 | #ifndef __DEMO_STUBS_H__ 2 | #define __DEMO_STUBS_H__ 3 | #include "demo.h" 4 | 5 | #define DEMO_STUBS_MD5 "adde094d85e7dc1d80911b0caa8fd384" 6 | 7 | #undef DEMO_EXTENSION_INI 8 | #define DEMO_EXTENSION_INI Demo_Stubs *demoStubsPtr = NULL; 9 | 10 | #ifdef HAVE_MUSL 11 | #define DEMO_STUBS_BLDFLAGS 1 12 | #else 13 | #define DEMO_STUBS_BLDFLAGS 0 14 | #endif 15 | #ifndef Demo_StubsInit 16 | #define Demo_StubsInit(interp,flags) (jsiStubsPtr && jsiStubsPtr->sig == \ 17 | JSI_STUBS_SIG?jsiStubsPtr->_Jsi_Stubs__initialize(interp, flags, "demo", \ 18 | DEMO_VERSION, DEMO_STUBS_MD5, DEMO_STUBS_BLDFLAGS, sizeof(Demo_Stubs), (void**)&demoStubsPtr):JSI_ERROR) 19 | #endif 20 | 21 | typedef struct Demo_Stubs { 22 | int sig; 23 | char* name; 24 | int size; 25 | int bldFlags; 26 | char* md5; 27 | void *hook; 28 | int(*_Demo_Stubs__initialize)(Jsi_Interp *interp, double version, const char* name, int flags, const char *md5, int bldFlags, int stubSize, void **ptr); 29 | int(*_Demo_Incr)(int n); 30 | int(*_Demo_Decr)(int n); 31 | void *endPtr; 32 | } Demo_Stubs; 33 | 34 | extern Demo_Stubs* demoStubsPtr; 35 | 36 | #define __DEMO_STUBS_INIT__\ 37 | JSI_STUBS_SIG, "demo", sizeof(Demo_Stubs), DEMO_STUBS_BLDFLAGS, DEMO_STUBS_MD5, NULL,\ 38 | Demo_Stubs__initialize,\ 39 | Demo_Incr,\ 40 | Demo_Decr,\ 41 | NULL 42 | 43 | #ifdef JSI_USE_STUBS 44 | 45 | #define Demo_Incr(n0) JSISTUBCALL(demoStubsPtr, _Demo_Incr(n0)) 46 | #define Demo_Decr(n0) JSISTUBCALL(demoStubsPtr, _Demo_Decr(n0)) 47 | 48 | #endif 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /www/js-autoload.wiki: -------------------------------------------------------------------------------- 1 | Autoload 2 |

Description

3 | The purpose of autoload is to enable dynamic loading of commands upon their first invocation. 4 | We implement this by setting the object jsiIndex with a string script value to evaluate. 5 | For example, given this file myfunc.js: 6 | 7 |
 8 | puts("LOADING");
 9 | function double(n) { return n*2; };
10 | function half(n)   { return n/2; };
11 | 
12 | 13 | then the following evaluates correctly: 14 | 15 |
16 | var jsiIndex = {
17 |   double : 'include("myfunc.js");',
18 |   half   : 'include("myfunc.js");'
19 | };
20 | //...
21 | double(4);
22 | half(4);
23 | 
24 | 25 |

Multiple jsiIndex's

26 | 27 | If jsiIndex is set in more than one place, we would want to be a bit more careful 28 | not to overwrite a previous definition. Here is one way to achieve this: 29 | 30 |
31 | if (!jsiIndex) { var jsiIndex = {}; };
32 | jsiIndex.myfunc = 'include("myfunc.js");';
33 | 
34 | // and in another file ...
35 | 
36 | if (!jsiIndex) { var jsiIndex = {}; };
37 | jsiIndex.yourfunc = 'include("myfunc.js");';
38 | 
39 | 40 | 41 |

Object Methods

42 | 43 | The jsiIndex works only for simple commands. Loading of object methods can be setup as follows: 44 | 45 |
46 | var jsipp = {
47 |     dir : info.scriptdir(),
48 |     parse : function(arg) { include(file.join(jsipp.dir,"jsipp.js")); return jsipp.parse(arg); }
49 | };
50 | 
51 | -------------------------------------------------------------------------------- /www/jsindex.wiki: -------------------------------------------------------------------------------- 1 | Master Index
2 | 3 |

General 4 | * Building 5 | * Editors 6 | * JSI In 5 Minutes or Less 7 | * Input/Output 8 | * License 9 | * Reference 10 | * Using Jsi 11 | * Zero Install 12 |

13 | 14 |

Script 15 | * Assert 16 | * Autoload 17 | * Errors 18 | * Events 19 | * Exec 20 | * Files 21 | * Format 22 | * include 23 | * Interp 24 | * JSON 25 | * Signal 26 | * Sqlite 27 | * Threads 28 | * Websocket 29 | * Zvfs 30 |

31 | 32 |

C-API 33 | * Commands 34 | * DStrings 35 | * Extensions 36 | * Hashes 37 | * JSI_LITE 38 | * JSON 39 | * Options 40 | * Sqlite 41 | * Trees 42 |

43 | -------------------------------------------------------------------------------- /tests/proto2.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | Meow, I am Garfield 4 | Meow, I am Felix 5 | What's new? 6 | Meow, I am Felix 7 | Making a new animal! 8 | true 9 | false 10 | function f(i,j) {...} 11 | function f(i,j) {...} 12 | true 13 | OK 14 | =!EXPECTEND!= 15 | */ 16 | function Cat(name){ 17 | this.name = name; 18 | }; 19 | Cat.prototype; 20 | var garfield = new Cat('Garfield'); 21 | garfield.__proto__ === Cat.prototype; 22 | Cat.prototype.greet = function(){ 23 | puts('Meow, I am ' + this.name); 24 | }; 25 | garfield.greet(); 26 | var felix = new Cat('Felix'); 27 | felix.greet(); 28 | garfield.greet = function(){ 29 | puts("What's new?"); 30 | }; 31 | garfield.greet(); 32 | felix.greet(); 33 | function Animal(){ 34 | }; 35 | Cat.prototype = new Animal; 36 | Cat.prototype.constructor = Cat; 37 | Animal.prototype.breed = function(){ 38 | puts('Making a new animal!'); 39 | return new this.constructor(); 40 | }; 41 | var kitty = garfield.breed(); 42 | function f(i,j) {} 43 | function g() {} 44 | g.prototype = new f(); 45 | var i = new f(); 46 | var h = new g(); 47 | puts(g.prototype.isPrototypeOf(h)); 48 | puts(g.prototype.isPrototypeOf(f)); 49 | puts(i.constructor); 50 | puts(h.constructor); 51 | puts(h.constructor == f); 52 | function Fee() { 53 | // . . . 54 | } 55 | 56 | function Fi() { 57 | // . . . 58 | } 59 | Fi.prototype = new Fee(); 60 | 61 | function Fo() { 62 | // . . . 63 | } 64 | Fo.prototype = new Fi(); 65 | 66 | function Fum() { 67 | // . . . 68 | } 69 | Fum.prototype = new Fo(); 70 | 71 | var fum = new Fum(); 72 | 73 | if (Fi.prototype.isPrototypeOf(fum)) { 74 | // do something safe 75 | puts("OK"); 76 | } 77 | -------------------------------------------------------------------------------- /www/js-json.wiki: -------------------------------------------------------------------------------- 1 | JSON 2 | This pages describes the JSON driver. 3 | For API details see [./reference.wiki#JSON|reference]. 4 | 5 |

Description

6 | JSON (JavaScript Object Notation) is an open standard format that 7 | uses human-readable text to transmit data objects consisting of attribute–value pairs. 8 | It is the primary means of exchanging data with web-browsers. 9 | 10 | The JSON object provides the following methods: 11 | 12 |

stringify(obj)

13 | 14 | The stringify() method converts a javascript data object to a string: 15 | 16 |
17 | var obj = { a:1, b:2, c:"able", d:[ 1, 2, 3 ] };
18 | var str = JSON.stringify(obj);
19 | //RETURNS: '{"a":1, "b":2, "c":"able", "d":[1,2,3]}';
20 | 
21 | 22 |

parse(str)

23 | 24 | The parse() method converts a string into javascript data: 25 | 26 |
27 | var str = '{"a":1, "b":2, "c":"able", "d":[1,2,3]}';
28 | var obj = JSON.parse(str);
29 | //RETURNS: { a:1, b:2, c:"able", d:[ 1, 2, 3 ] }
30 | 
31 | 32 | 33 |

parseNS(str)

34 | 35 | parseNS is a permissive or non-strict implementation of parse(). 36 | Permissive mode does not require quoting of names. 37 | 38 |
39 | var str = '{a:1, b:2, c:"able", d:[1,2,3]}';
40 | var obj = JSON.parseNS(str);
41 | 
42 | 43 | The primary use for parseNS is with [./c-json.wiki|c-json]. 44 | 45 |

Caveats

46 | * the current JSI implementation of JSON lacks support for UTF8. 47 | * the underlying parser is not a validating parser. 48 | -------------------------------------------------------------------------------- /www/js-events.wiki: -------------------------------------------------------------------------------- 1 | Events 2 | 3 |

Description

4 | Ecmascript lets you schedule events using setTimeout/setInterval/clearInterval. 5 | In Jsi, this is extended with info.event() to allow querying pending events, 6 | and sys.update() to service events: 7 | 8 |
 9 | function foo() {
10 |     puts("FOO: "+ i++);
11 |     if (i>=3) exit(0);
12 | }
13 | var i=0, id = setInterval(foo,1000);
14 | var evs = info.event();
15 | for (var i in evs) {
16 |   puts('EV('+i+'): ' + info.event(evs[i]).toString());
17 | }
18 | sys.update();
19 | 
20 | 21 | which outputs: 22 | 23 |
24 | EV(0): { builtin:false, count:0, initial:1000, once:false, type:"timer", when:1000 }
25 | FOO: 0
26 | FOO: 1
27 | FOO: 2
28 | 
29 | 30 |

sys.update(?mintime|options?)

31 | 32 | Process events until minTime milliseconds exceeded, or forever if -1. 33 | Default minTime is 0. With a positive mintime, a sleep occurs between each event check pass. 34 | The returned value is the number of events processed. 35 | 36 |

37 | 38 | 39 | 40 | 41 | 42 |
OptionDescription
maxEventsMaximum number of events to process
maxPassesMaximum passes through event queue
minTimeMinimum milliseconds before returning, or -1 to loop forever
sleepSleep time between event checks in milliseconds
43 | 44 |

info.event(?id?)

45 | 46 | List events or info for 1 event (created with setTimeout/setInterval). 47 | With no args, returns list of all outstanding events. With one arg, returns info for the given event id. 48 | -------------------------------------------------------------------------------- /tests/prototypes.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | { } 4 | should be {} 5 | { a:123 } 6 | should be { a:123 } 7 | 123 8 | should be 123 9 | shot 10 | should be shot 11 | { a:123 } 12 | should be { a:123 } 13 | 6 14 | should be 6 15 | ZhangSan 16 | 18 17 | defaultName 18 | true 19 | false 20 | =!EXPECTEND!= 21 | */ 22 | 23 | puts(Object.prototype); 24 | puts(" should be {}"); 25 | 26 | Object.prototype.a = 123; 27 | //Object.prototype = 123; 28 | 29 | puts(Object.prototype); 30 | puts(" should be { a:123 }"); 31 | 32 | var a = { b:1, c:2 }; 33 | puts(a.a); 34 | puts(" should be 123"); 35 | a.a = 'shot'; 36 | puts(a.a); 37 | puts(" should be shot"); 38 | 39 | puts(Object.prototype); 40 | puts(" should be { a:123 }"); 41 | 42 | Number.prototype.fock = function() { 43 | puts(this / 2); 44 | }; 45 | 46 | var x = 12; 47 | 48 | x.fock(); 49 | puts(" should be 6"); 50 | 51 | function Person(name, sex) { 52 | this.name = name; 53 | this.sex = sex; 54 | }; 55 | 56 | Person.prototype = { 57 | getName: function() { 58 | return this.name; 59 | }, 60 | getSex: function() { 61 | return this.sex; 62 | }, 63 | age: 18 64 | }; 65 | 66 | function Employee(name, sex, employeeID) { 67 | this.name = name; 68 | this.sex = sex; 69 | this.employeeID = employeeID; 70 | }; 71 | 72 | Employee.prototype = new Person("defaultName", "defaultSex"); 73 | Employee.prototype.getEmployeeID = function() { 74 | return this.employeeID; 75 | }; 76 | 77 | var zhang = new Employee("ZhangSan", "man", "1234"); 78 | puts(zhang.getName()); // "ZhangSan 79 | puts(zhang.age); //18 80 | delete zhang.name; 81 | puts(zhang.name); //defaultName 82 | 83 | function f() {} 84 | function g() {} 85 | g.prototype = new f(); 86 | var h = new g(); 87 | puts(g.prototype.isPrototypeOf(h)); 88 | puts(g.prototype.isPrototypeOf(f)); 89 | -------------------------------------------------------------------------------- /www/getstarted.wiki: -------------------------------------------------------------------------------- 1 | JSI In 5 Minutes or Less 2 | 3 |

Embedding JSI in C

4 | 5 | The file "jsi.c" contains the entire source for Jsi amalgamated into a single, standalone file. 6 | This provides a convenient way to embed Jsi into any C application. 7 | 8 | Simply extract "jsi.c" from 9 | [http://pdqi.com/downloads/jsish-1.1.0/jsi_single_src.zip|jsi_single_src.zip], 10 | and include this file directly into your 11 | source file, eg. 12 |
13 |     #include "jsi.c"
14 |     
15 |     int main(int argc, char *argv[])
16 |     {
17 |         Jsi_Interp *interp = Jsi_InterpCreate(NULL, argc, argv, 0);
18 |         Jsi_EvalString(interp, "for (var i=1; i<=3; i++)  puts('TEST: '+i);", 0);
19 |         //...
20 |     }
21 | 
22 | 23 |

The Shell: jsish

24 | 25 | If you just want to give "jsish" a test drive, 26 | linux and windows binaries can be downloaded from [http://pdqi.com/downloads/jsish-1.1.0/]. 27 | Here is a [./usingjsi.wiki|brief tutorial on their use]. 28 | 29 |

Get Source Using Fossil

30 | 31 | Jsi development is maintained within a [http://www.fossil-scm.org|fossil] repository. Once 32 | the "fossil" command is installed, Jsi can be pulled down thus: 33 | 34 |
35 |   fossil clone http://pdqi.com/cgi-bin/cgiwrap/pdqi/jsi.cgi jsi.fossil
36 |   mkdir jsi
37 |   cd jsi
38 |   fossil open ../jsi.fossil
39 |   cd jsi
40 | 
41 | 42 | Then follow the directions in [./buildjsi.wiki|building jsi]. 43 | 44 |

Getting Source Without Fossil

45 | 46 | If you can't (or don't want to use fossil) you can visit [http://pdqi.com/jsi] 47 | and login as anonymous. Then navigate to Files and it will let you download a zip (or tar ball). 48 | Note however, that this approach makes it harder to get updates. 49 | 50 |

Email Contact

51 | 52 | . 53 | -------------------------------------------------------------------------------- /www/js-errors.wiki: -------------------------------------------------------------------------------- 1 | Errors 2 | 3 |

Try/Catch

4 | 5 | in Jsi (unlike EcmaScript) try will pass a string to catch upon error, not an object eg. 6 | 7 |
 8 | try { badcall(); } catch(e) { puts("Note e is a string: "+e); }
 9 | 
10 | 11 |

Error Diagnostics

12 | 13 | Upon error, Jsi does not generate tracebacks. Instead a gcc style warning 14 | containing the file and line number is output. 15 | For example: 16 | 17 |
18 | var x = 1;
19 | foo(x)
20 | 
21 | This results in the following diagnostic: 22 | 23 |
24 | /home/user/myjsi/foo.js:2: error: 'foo', sub-commands are: Array Boolean Date File 
25 |    Function Interp JSON Math Number Object RegExp Sqlite String Websocket alert 
26 |    assert clearInterval console decodeURI encodeURI exit file format include info
27 |    isFinite isNaN load parseFloat parseInt puts quote setInterval setTimeout signal
28 |    sys util zvfs.
29 | 
30 | 31 | The file and line number is reported, as well as an enumeration of known commands 32 | in the given scope. 33 | The first allows errors to be [./editors.wiki|parsable by IDE's]. 34 | The latter helps determine available options without resorting 35 | program documentation. 36 | 37 |

Enumerated Methods

38 | 39 | Similarly an objects sub-methods will be enumerated: 40 | 41 |
42 | # info.xx()
43 | error: 'info', sub-commands are: cmds data error events executable funcs named platform revisions script vars version.    (at or near string "xx")
44 | 
45 | 46 |

Displayed Arguments

47 | 48 | And arguments to builtin methods part of the diagnostic: 49 | 50 |
51 | # format()
52 | error: missing args, expected "format(format?,arg,arg?)" 
53 | 
54 | 55 | 56 | -------------------------------------------------------------------------------- /www/js-zvfs.wiki: -------------------------------------------------------------------------------- 1 | Zvfs 2 | [./reference.wiki#zvfs|<Zvfs Reference>] 3 | 4 | Zvfs stands for Zip Virtual File System. Jsi uses Zvfs to read and write zip archives. 5 |
6 |

Writing

7 | 8 | To create a zip archive simpy use: 9 |
10 |   zvfs.create('arch.zip', file.glob('*.js'))
11 | 
12 | This creates a zip file containing all the .js files in the current directory. 13 |
14 |

Reading

15 | Jsi can mount .zip files as local filesystem: 16 | 17 |
18 | var dir = zvfs.mount('arch.zip');
19 | file.glob('*', dir);
20 | 
21 | 22 | Note: If a mount point is not given, it is generated in the pattern /zvfsN, where N=1,2,3,... 23 |
24 |

Executing

25 | 26 | If a zip archive contains the file "main.jsi" at the toplevel, 27 | Jsi can run it, eg: 28 | 29 |
30 | # jsish arch.zip
31 | 
32 | 33 | Jsi automatically mounts the .zip file at startup, and then executes main.jsi and 34 | jsish exits upon completion. 35 | 36 | If you need to avoid exiting you can make use of [./js-events.wiki|Events]. 37 |
38 |

Zero-Install

39 | 40 | It is also possible to zip "main.jsi and other files directly onto the end of the jsish binary itself. 41 | This converts jsish into a Zero-Install application. 42 | 43 | As above, main.jsi will be sourced automatically and jsish exits upon completion. 44 | 45 | One way to create a Zero-Install application is to use: 46 | 47 |
48 | make jsize
49 | 
50 | 51 | However, this just uses the script "tools/mkjsize.js" and is equivalent to: 52 | 53 |
54 | cp jsish jsize
55 | tools/mkjsize.js create jsize zipdir
56 | 
57 | 58 | Click [./zeroinstall.wiki|here] to learn more about Zero-Install. 59 | -------------------------------------------------------------------------------- /jsiStubs.c: -------------------------------------------------------------------------------- 1 | #ifndef JSI_LITE_ONLY 2 | #ifndef JSI_OMIT_STUBS 3 | #include "jsiInt.h" 4 | #include "jsiStubs.h" 5 | 6 | static int Jsi_Stubs__initialize(Jsi_Interp *interp, double version, const char* name, int flags, 7 | const char *md5, int bldFlags, int stubSize, void **ptr); 8 | 9 | Jsi_Stubs jsiStubsTbl = { __JSI_STUBS_INIT__ }; 10 | Jsi_Stubs *jsiStubsTblPtr = &jsiStubsTbl; 11 | 12 | int Jsi_Stubs__initialize(Jsi_Interp *interp, double version, const char* name, int flags, 13 | const char *md5, int bldFlags, int stubSize, void **ptr) 14 | { 15 | if (strcmp(name,"jsi")) { /* Sub-stub support */ 16 | int rc = Jsi_StubLookup(interp, name, ptr); 17 | if (rc != JSI_OK) 18 | return JSI_ERROR; 19 | Jsi_Stubs *sp = *ptr; 20 | if (sp->_Jsi_Stubs__initialize && sp->sig == JSI_STUBS_SIG && 21 | sp->_Jsi_Stubs__initialize != jsiStubsTbl._Jsi_Stubs__initialize) 22 | return (*sp->_Jsi_Stubs__initialize)(interp, version, name, flags, md5, bldFlags, stubSize, ptr); 23 | Jsi_LogError("failed to find stub for %s", name); 24 | return JSI_ERROR; 25 | } 26 | int strict = (flags & JSI_STUBS_STRICT); 27 | int sizediff = (sizeof(Jsi_Stubs) - stubSize); 28 | assert(jsiStubsTbl.sig == JSI_STUBS_SIG); 29 | if (sizediff<0 || (strict && (strcmp(md5, JSI_STUBS_MD5) || sizediff))) { 30 | fprintf(stderr, "%s: extension from incompatible build: %s\n", name, (sizediff ? "size changed": md5)); 31 | return JSI_ERROR; 32 | } 33 | if (bldFlags != jsiStubsTbl.bldFlags) { 34 | fprintf(stderr, "%s: extension build flags mismatch (different libc?)\n", name); 35 | if (strict) 36 | return JSI_ERROR; 37 | } 38 | if (version > JSI_VERSION) { 39 | fprintf(stderr, "%s: extension version newer than jsish (%g > %g)\n", name, version, JSI_VERSION); 40 | if (strict) 41 | return JSI_ERROR; 42 | } 43 | return JSI_OK; 44 | } 45 | #endif 46 | #endif 47 | -------------------------------------------------------------------------------- /c-demos/stubs/demoStubs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "jsi.h" 4 | #include "demo.h" 5 | #include "jsiStubs.h" 6 | #include "demoStubs.h" 7 | 8 | 9 | static int Demo_Stubs__initialize(Jsi_Interp *interp, double version, const char* name, int flags, 10 | const char *md5, int bldFlags, int stubSize, void **ptr); 11 | 12 | Demo_Stubs demoStubsTbl = { __DEMO_STUBS_INIT__ }; 13 | Demo_Stubs *demoStubsTblPtr = &demoStubsTbl; 14 | 15 | static int Demo_Stubs__initialize(Jsi_Interp *interp, double version, const char* name, int flags, 16 | const char *md5, int bldFlags, int stubSize, void **ptr) 17 | { 18 | if (strcmp(name,"demo")) { /* Sub-stub support */ 19 | int rc = Jsi_StubLookup(interp, name, ptr); 20 | if (rc != JSI_OK) 21 | return JSI_ERROR; 22 | Jsi_Stubs *sp = *ptr; 23 | if (sp->_Jsi_Stubs__initialize && sp->sig == JSI_STUBS_SIG && 24 | sp->_Jsi_Stubs__initialize != demoStubsTbl._Demo_Stubs__initialize) 25 | return (*sp->_Jsi_Stubs__initialize)(interp, version, name, flags, md5, bldFlags, stubSize, ptr); 26 | Jsi_LogError("failed to find stub for %s", name); 27 | return JSI_ERROR; 28 | } 29 | int strict = (flags & JSI_STUBS_STRICT); 30 | int sizediff = (sizeof(Demo_Stubs) - stubSize); 31 | assert(demoStubsTbl.sig == JSI_STUBS_SIG); 32 | if (sizediff<0 || (strict && (strcmp(md5, DEMO_STUBS_MD5) || sizediff))) { 33 | fprintf(stderr, "%s: extension from incompatible build: %s\n", name, (sizediff ? "size changed": md5)); 34 | return JSI_ERROR; 35 | } 36 | if (bldFlags != demoStubsTbl.bldFlags) { 37 | fprintf(stderr, "%s: extension build flags mismatch (different libc?)\n", name); 38 | if (strict) 39 | return JSI_ERROR; 40 | } 41 | if (version != DEMO_VERSION && strict) { 42 | fprintf(stderr, "%s: extension version newer than user (%g > %g)\n", name, version, DEMO_VERSION); 43 | return JSI_ERROR; 44 | } 45 | return JSI_OK; 46 | } 47 | -------------------------------------------------------------------------------- /tools/mkproto.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env jsish 2 | // Generate function prototypes for Jsi builtin cmds. 3 | 4 | function jsi_mkproto() { 5 | 6 | function DumpArgs(ci) { 7 | var argStr = ci.argStr; 8 | if (argStr === undefined) 9 | argStr = ''; 10 | else { 11 | argStr = argStr.replace(/\?/g,''); 12 | argStr = argStr.replace(/ \| /g,'_'); 13 | argStr = argStr.replace(/\|/g,'_'); 14 | } 15 | return argStr; 16 | } 17 | 18 | function DumpCmd(cinf) { 19 | return "var "+cinf.name+" = function("+DumpArgs(tinf)+") {};\n"; 20 | } 21 | 22 | function DumpObj(tinf) { 23 | var hasconf, ro = '', rv = '', ci, cnam = tinf.name, cmds = info.cmds(cnam+'.*'); 24 | rv += "var "+tinf.name+" = function(cmd,args) {};\n"; 25 | if (cmds !== undefined) { 26 | for (var cmd in cmds) { 27 | var nam = cmds[cmd].split('.')[1]; 28 | if (nam == cnam) 29 | continue; 30 | ci = info.cmds(cnam+'.'+nam); 31 | rv += tinf.name+".prototype."+nam+" = function("+DumpArgs(ci)+") {};\n"; 32 | } 33 | } 34 | return rv; 35 | } 36 | 37 | //*************** BEGIN MAIN ************** 38 | var rv = '', tinf, lst = info.cmds(); 39 | var vv = info.version(true); 40 | var ver = vv.major+'.'+vv.minor+'.'+vv.release; 41 | 42 | for (var i in lst) { 43 | tinf = info.cmds(lst[i]); 44 | switch (tinf.type) { 45 | case 'object': 46 | rv += DumpObj(tinf); 47 | break; 48 | case 'command': 49 | rv += DumpCmd(tinf); 50 | break; 51 | default: 52 | throw("bad id"); 53 | continue; 54 | } 55 | } 56 | return '//JSI Command Prototypes: version '+ver+'\nthrow("DO NOT EXECUTE: LEAVING THIS FILE OPEN IN GEANY IS USEFUL FOR CMD LINE COMPLETION + GOTO TAG");\n\n' + rv; 57 | } 58 | 59 | if (info.isInvoked()) { 60 | puts(jsi_mkproto()); 61 | } 62 | -------------------------------------------------------------------------------- /win/compat.h: -------------------------------------------------------------------------------- 1 | #if defined(_WIN32) || defined(WIN32) 2 | #ifndef JSI_WIN32COMPAT_H 3 | #define JSI_WIN32COMPAT_H 4 | 5 | typedef unsigned int uint; 6 | /* TODO: bring in external regex .. 7 | typedef struct { int n; } regex_t; 8 | typedef struct { int n; } regmatch_t; */ 9 | 10 | enum { 11 | DT_UNKNOWN = 0, DT_FIFO = 1, DT_CHR = 2, DT_DIR = 4, 12 | DT_BLK = 6, DT_REG = 8, DT_LNK = 10, DT_SOCK = 12, DT_WHT = 14 13 | }; 14 | 15 | 16 | /* Compatibility for Windows (mingw and msvc, not cygwin */ 17 | 18 | #include 19 | #include 20 | char * strptime(const char *buf, const char *fmt, struct tm *tm); 21 | 22 | #define MAXNAMLEN FILENAME_MAX 23 | int scandir( const char *dirname, struct dirent ***namelist, int (*select)(const struct dirent *), 24 | int (*compar)( const struct dirent **, const struct dirent ** ) 25 | ); 26 | int alphasort( const struct dirent **d1, const struct dirent **d2 ); 27 | int istrcmp( const char *s1, const char *s2 ); 28 | 29 | #define HAVE_DLOPEN 30 | void *dlopen(const char *path, int mode); 31 | int dlclose(void *handle); 32 | void *dlsym(void *handle, const char *symbol); 33 | char *dlerror(void); 34 | 35 | /* MS CRT always uses three digits after 'e' */ 36 | #define JSI_SPRINTF_DOUBLE_NEEDS_FIX 37 | 38 | #ifdef _MSC_VER 39 | /* These are msvc vs gcc */ 40 | 41 | #if _MSC_VER >= 1000 42 | #pragma warning(disable:4146) 43 | #endif 44 | 45 | #include 46 | #define jsi_wide _int64 47 | #ifndef LLONG_MAX 48 | #define LLONG_MAX 9223372036854775807I64 49 | #endif 50 | #ifndef LLONG_MIN 51 | #define LLONG_MIN (-LLONG_MAX - 1I64) 52 | #endif 53 | #define JSI_WIDE_MIN LLONG_MIN 54 | #define JSI_WIDE_MAX LLONG_MAX 55 | #define JSI_WIDE_MODIFIER "I64d" 56 | #define strcasecmp _stricmp 57 | #define strtoull _strtoui64 58 | #define snprintf _snprintf 59 | 60 | #include 61 | 62 | struct timeval { 63 | long tv_sec; 64 | long tv_usec; 65 | }; 66 | 67 | int gettimeofday(struct timeval *tv, void *unused); 68 | 69 | #define HAVE_OPENDIR 70 | struct dirent { 71 | char *d_name; 72 | }; 73 | 74 | typedef struct DIR { 75 | long handle; /* -1 for failed rewind */ 76 | struct _finddata_t info; 77 | struct dirent result; /* d_name null iff first time */ 78 | char *name; /* null-terminated char string */ 79 | } DIR; 80 | 81 | DIR *opendir(const char *name); 82 | int closedir(DIR *dir); 83 | struct dirent *readdir(DIR *dir); 84 | #endif /* _MSC_VER */ 85 | 86 | #endif 87 | 88 | #endif /* WIN32 */ 89 | -------------------------------------------------------------------------------- /tools/geany/filetypes.javascript: -------------------------------------------------------------------------------- 1 | # For complete documentation of this file, please see Geany's main documentation 2 | [styling] 3 | # foreground;background;bold;italic 4 | default=default 5 | comment=comment 6 | commentline=comment 7 | commentdoc=commentdoc 8 | number=number 9 | word=keyword 10 | word2=keyword2 11 | string=string 12 | character=string 13 | uuid=extra 14 | preprocessor=preprocessor 15 | operator=operator 16 | identifier=default 17 | stringeol=stringeol 18 | # @"verbatim" 19 | verbatim=extra 20 | # (/regex/) 21 | regex=extra 22 | commentlinedoc=commentdoc,bold 23 | commentdockeyword=commentdoc,bold,italic 24 | commentdockeyworderror=commentdoc 25 | globalclass=type 26 | 27 | [keywords] 28 | # all items must be in one line 29 | primary=break case catch const continue default delete do each else false finally for function get if in Infinity instanceof let NaN new null return set switch this throw true try typeof undefined var void while with yield sys zvfs console info file puts source signal setTimeout setInterval clearInterval exit load assert quote sprintf 30 | 31 | secondary=Array Boolean Date Function Math Number Object String RegExp EvalError Error RangeError ReferenceError SyntaxError TypeError URIError prototype decodeURI decodeURIComponent encodeURI encodeURIComponent eval isFinite isNaN parseFloat parseInt Sqlite Websocket JSON Interp File 32 | 33 | [settings] 34 | # default extension used when saving files 35 | extension=js 36 | 37 | # the following characters are these which a "word" can contains, see documentation 38 | #wordchars=_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 39 | 40 | # single comments, like # in this file 41 | comment_single=// 42 | # multiline comments 43 | comment_open=/* 44 | comment_close=*/ 45 | 46 | # set to false if a comment character/string should start at column 0 of a line, true uses any 47 | # indentation of the line, e.g. setting to true causes the following on pressing CTRL+d 48 | #command_example(); 49 | # setting to false would generate this 50 | # command_example(); 51 | # This setting works only for single line comments 52 | comment_use_indent=true 53 | 54 | # context action command (please see Geany's main documentation for details) 55 | context_action_cmd= 56 | 57 | [indentation] 58 | #width=4 59 | # 0 is spaces, 1 is tabs, 2 is tab & spaces 60 | #type=1 61 | 62 | [build_settings] 63 | # %f will be replaced by the complete filename 64 | # %e will be replaced by the filename without extension 65 | # (use only one of it at one time) 66 | compiler= 67 | run= 68 | 69 | 70 | -------------------------------------------------------------------------------- /tests/block.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 2 7 6 4 | 9 5 1 5 | 4 3 8 6 | -------- 7 | 2 9 4 8 | 7 5 3 9 | 6 1 8 10 | -------- 11 | 4 3 8 12 | 9 5 1 13 | 2 7 6 14 | -------- 15 | 4 9 2 16 | 3 5 7 17 | 8 1 6 18 | -------- 19 | 6 1 8 20 | 7 5 3 21 | 2 9 4 22 | -------- 23 | 6 7 2 24 | 1 5 9 25 | 8 3 4 26 | -------- 27 | 8 1 6 28 | 3 5 7 29 | 4 9 2 30 | -------- 31 | 8 3 4 32 | 1 5 9 33 | 6 7 2 34 | -------- 35 | =!EXPECTEND!= 36 | */ 37 | 38 | for (a = 1; a < 10; ++a) { 39 | for (b = 1; b < 10; ++b) { 40 | if (b == a) continue; 41 | for (c = 1; c < 10; ++c) { 42 | if (c == a || c == b) continue; 43 | for (d = 1; d < 10; ++d) { 44 | if (d == a || d == b || d == c) continue; 45 | for (e = 1; e < 10; ++e) { 46 | if (e == a || e == b || e == c || e == d) continue; 47 | for (f = 1; f < 10; ++f) { 48 | if (f == a || f == b || f == c || f == d || f == e) continue; 49 | for (g = 1; g < 10; ++g) { 50 | if (g == a || g == b || g == c || g == d || g == e || g == f) continue; 51 | for (h = 1; h < 10; ++h) { 52 | if (h == a || h == b || h == c || h == d || h == e || h == f || h == g) continue; 53 | for (i = 1; i < 10; ++i) { 54 | if (i == a || i == b || i == c || i == d || i == e || i == f || i == g || i == h) continue; 55 | 56 | if (a + b + c == 15 && 57 | d + e + f == 15 && 58 | g + h + i == 15 && 59 | a + d + g == 15 && 60 | b + e + h == 15 && 61 | c + f + i == 15 && 62 | a + e + i == 15 && 63 | c + e + g == 15) { 64 | puts(a + " " + b + " " + c); 65 | puts(d + " " + e + " " + f); 66 | puts(g + " " + h + " " + i); 67 | puts("--------"); 68 | } 69 | } 70 | } 71 | } 72 | } 73 | } 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /www/c-json.wiki: -------------------------------------------------------------------------------- 1 | C-API: JSON 2 | 3 |

Description

4 | 5 | The JSON C API is provided by just two extern functions, whose use should be fairly intuitive. 6 | 7 |
 8 | enum { JSI_JSON_STRICT=1, JSI_JSON_STRKEYS=2 }; /* flags */
 9 | 
10 | extern int Jsi_JSONParse(Jsi_Interp *interp, const char *js, Jsi_Value *ret, int flags);
11 | extern int Jsi_JSONParseFmt(Jsi_Interp *interp, Jsi_Value *ret, const char *fmt, ...);
12 | 
13 | 14 | The parser itself is highly efficient. It uses a single 15 | array of tokens for output so that for small JSON strings 16 | no memory is allocated during the parse. 17 | When memory does get allocated, it is only to increase the size of the token array. 18 | 19 | 20 |

Simplifying C with JSON

21 | 22 | JSON can be enlisted to reduce C-code complexity, particularly when writing commands 23 | that return objects and/or arrays. 24 | While the wisdom of using JSON this way may seem counter-intuitive, 25 | the JSON parser handles this quite efficiently. 26 | 27 | For example, suppose we want to create an object with a couple of values: 28 | 29 |
30 | Jsi_Obj *nobj = Jsi_ObjectNew(interp);
31 | Jsi_ValueMakeObject(interp, ret, nobj);
32 | Jsi_ObjInsertFromValue( interp, nobj, Jsi_ValueNewStringKey(interp, "file"), 
33 |     Jsi_ValueNewStringKey(interp, file));
34 | Jsi_ObjInsertFromValue( interp, nobj, Jsi_ValueNewStringKey(interp, "line"),
35 |    Jsi_ValueNewNumber(interp, line));
36 | 
37 | 38 | Using a JSON string parse, this can be simplified to: 39 | 40 |
41 | sprintf(buf, "{file:\"%s\", line:%d}", file, line);
42 | return Jsi_JSONParse(interp, buf, ret, 0);
43 | 
44 | 45 | The more deeply nested the structure, the greater the code simplification, eg: 46 | 47 |
48 | Jsi_JSONParseFmt(interp, ret, buf, "{ a: [ {x:%d, y:%d}, {x:%d, y:[%d,%d,%d]}] }",a,b,c,d,e,f);
49 | 
50 | 51 | Note: [./js-json.wiki#scan|permissive] mode is the default. So there is 52 | no need to quote property names which in C rapidly becomes tedious: 53 | 54 |
55 | "{\"os\":\"%s\", \"platform\":\"%s\", \"hasThreads\":%s, \"pointerSize\":%d, "
56 | 
57 | 58 | Note: the above trick works only for cases where data does not contain 59 | special JSON characters. 60 | 61 |

Sub-Interps

62 | 63 | Any data sent between sub-[./js-interp.wiki|interps] will first be converted to/from JSON. 64 | This because all data objects are private to an interp. 65 | 66 | -------------------------------------------------------------------------------- /www/usingjsi.wiki: -------------------------------------------------------------------------------- 1 | Using Jsi 2 | 3 | The easiest way to get play around with Jsi is interactively. eg. On Ubuntu: 4 | 5 |
 6 |   ./jsish
 7 | # var a = [1,2,3];
 8 | # for (var i in a) { puts(a[i]); }
 9 | 1
10 | 2
11 | 3
12 | ...
13 | 
14 | 15 | Or, you can run a script with arguments: 16 | jsish prog.js arg1 arg2 ... 17 | Or evaluate javascript from the command line with -e: 18 | 19 |
20 |   jsish -e 'var i = 0; while (i++<10) puts(i);'
21 | 
22 | 23 |

Command Options

24 | 25 | Various commands in Jsi can take an options object containing properties to parametrize behaviour. For example: 26 | 27 |
28 |   var db = new Sqlite('/tmp/testsql.db',{maxStmts:1000, readonly:true});
29 |   db.conf( {debug:1} );
30 |   puts( db.conf() );
31 | 
32 | 33 | In the case of object commands, a conf() method provides access to options after creation. 34 | Introspection 35 | 36 | There are several levels of introspection built-in to Jsi. The conf() method above is one example. Another is apparent upon and invalid method invocation, eg: 37 | 38 |
39 |   # info.xxx()
40 |   error: 'info', sub-commands are: cmds data error event executable funcs interp
41 |   keywords named platform revisions script vars version.    (at or near "xxx")
42 | 
43 | 44 | However, the collection of info methods provide the most important introspection: 45 | 46 |
47 |    # info.cmds()
48 |  [ "Array", "Boolean", "File", "Function", "Interp", "JSON", "Math", "Number",
49 |    "Object", "RegExp", "Sqlite", "String", "Websocket", "assert", "clearInterval",
50 |    "console", "decodeURI", "encodeURI", "exit", "file", "include", "info",
51 |    "isFinite", "isNaN", "load", "parseFloat", "parseInt", "puts", "quote",
52 |    "setInterval", "setTimeout", "signal", "sprintf", "sys", "zvfs" ]
53 | 
54 | 55 |

Doing More

56 | 57 | All built-in Jsi commands (as well as their options) are documented in the Reference. 58 | 59 |

Executable Scripts

60 | 61 | To make a script executable (under unix) the first line of a Jsi script should start with #!, eg: 62 | 63 |
64 | cat > myargs <
73 | 
74 | 

rlwrap

75 | 76 | If you are running the statically compiled Linux version, 77 | you can use rlwrap to provide command-line editing: 78 | 79 |
80 |   rlwrap ./jsish
81 | 
82 | 83 |

Limitations

84 | 85 | A return is not supported within a try/catch. 86 | 87 | -------------------------------------------------------------------------------- /www/js-files.wiki: -------------------------------------------------------------------------------- 1 | Files 2 | There are 2 ways to access files in JSI: 3 | File object for IO to a single file, and 4 | file.* commands for general file access. 5 | 6 |

new File

7 | A File object can be created for reading and/or writing individual files. 8 | Generally an object is instantiated to open the file and then read/write operations are performed. 9 | 10 |
11 | var f = new File('tests/filetest.txt');
12 | if (f) {
13 |     while((n = f.gets())!=undefined) {
14 |         puts(n);
15 |     }
16 | } else console.log('Can not open tests/filetest.txt');
17 | 
18 | 19 |

File

20 | 21 | Synopsis: new File(file,?mode?) 22 | Commands for accessing File objects. 23 | Methods 24 | 25 | The following methods are available in "File": 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
MethodDescription
close()close the file
eof()Return true if read to end-of-file
filename()Get file name
gets()Get one line of input
mode()Get file mode used with open
open(file,?mode?)Open the file (after close)
puts(str)Write one line of output
read()Read entire file into object
38 | 39 |

file.*

40 | 41 | The file sub-methods are used for accessing various attributes and information on files where just basic IO is not necessarily the goal. 42 | 43 |
44 | file.mkdir('XX1');
45 | file.mkdir('XX1/AA');
46 | file.mkdir('XX1/BB');
47 | file.rename('XX1/BB','XX1/CC.txt');
48 | puts(file.glob(null,'XX1').sort());
49 | puts(file.dirname('XX1/AA'));
50 | puts(file.rootname('XX1/CC.txt'));
51 | puts(file.tail('XX1/CC.txt'));
52 | puts(file.type('XX1/CC.txt'));
53 | puts(file.extension('XX1/CC.txt'));
54 | //puts(file.realpath('XX1/CC.txt'));
55 | puts(file.writable('XX1/CC.txt'));
56 | puts(file.readable('XX1/CC.txt'));
57 | puts(file.exists('XX1/CC.txt'));
58 | puts(file.isdir('XX1/CC.txt'));
59 | puts(file.isfile('XX1/CC.txt'));
60 | file.remove('XX1',true);
61 | 
62 | 63 | Output is: 64 | 65 |
66 | [ "AA", "CC.txt" ]
67 | XX1
68 | XX1/CC
69 | CC.txt
70 | directory
71 | .txt
72 | true
73 | true
74 | true
75 | true
76 | false
77 | file
78 | 
79 | 80 | 81 |

File.glob

82 | 83 | The file glob method returns an array of matching files. 84 | With no arguments (or null) returns all files/directories in current directory. 85 | If first argument is a pattern (either a glob or regexp) just files are returned. 86 | If second argument is a string, it denotes the directory to search in. 87 | If second argument is a function, this function is called with each path. 88 | Otherwise second argument is a set of options. 89 | 90 |
91 | file.glob();
92 | file.glob("*.c");
93 | file.glob(/^jsi.*\.c$/);
94 | file.glob('*','tests');
95 | file.glob('*.js',{dir:'tests', recurse:true});
96 | 
97 | 98 | -------------------------------------------------------------------------------- /tests/expr.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | undefined 4 | -1 5 | 0 6 | NaN 7 | -Infinity 8 | -1 9 | -123 10 | 0 11 | 3 12 | 3.6 13 | 1.212.3 14 | 5 15 | 2342true 16 | [object Object]12 17 | NaN 18 | NaNNaN 19 | NaN 20 | NaN 21 | ================ 22 | 16 23 | 16777216 24 | 0 25 | -1 26 | =============== 27 | true 28 | undefined 29 | false 30 | true 31 | false 32 | false 33 | true 34 | true 35 | false 36 | false 37 | true 38 | true 39 | false 40 | true 41 | true 42 | true 43 | =============== 44 | true 45 | false 46 | false 47 | true 48 | false 49 | true 50 | true 51 | =================== 52 | false 53 | false 54 | false 55 | true 56 | true 57 | ============ 58 | 31 59 | 106 60 | 1190 61 | =============== 62 | 16 63 | 12 64 | 3 65 | 12 66 | 0 67 | 0 68 | 0 69 | 1 70 | 1fock 71 | { a:124 } 72 | { a:120 } 73 | { a:30 } 74 | { a:120 } 75 | { a:0 } 76 | { a:0 } 77 | { a:0 } 78 | { a:1 } 79 | { a:"1fock" } 80 | =!EXPECTEND!= 81 | */ 82 | 83 | //test void expr 84 | puts(void 1); 85 | 86 | //test - expr 87 | puts(-1); 88 | puts(-0); 89 | puts(-NaN); 90 | puts(-Infinity); 91 | puts(- true); 92 | puts(- "123" ); 93 | 94 | //wrong: NaN, not 0 95 | puts(- {a:1}); 96 | 97 | //test + expr 98 | puts(1 + 2); 99 | puts(1.3 + 2.3); 100 | puts(1.2 + "12.3"); 101 | puts(4 + true); 102 | puts("2342" + true); 103 | puts({} + 12); 104 | puts(NaN + NaN); 105 | puts(NaN + "NaN"); 106 | puts(Infinity - Infinity); 107 | puts(NaN + 3); 108 | 109 | puts("================"); 110 | puts(1<<4); 111 | puts(1<<344.3); 112 | puts(2>>4); 113 | puts(-200000 >> -4); 114 | 115 | puts("==============="); 116 | puts(1.0 < 2.3); 117 | puts(NaN < NaN); 118 | puts(Infinity < -Infinity); 119 | puts(Infinity > -Infinity); 120 | puts(10000.456 < 10000.456); 121 | puts(10000.456 > 10000.456); 122 | puts(10000.456 <= 10000.456); 123 | puts(10000.456 >= 10000.456); 124 | puts("10000.456" < "10000.456"); 125 | puts("10000.456" > "10000.456"); 126 | puts("10000.456" <= "10000.456"); 127 | puts("10000.456" >= "10000.456"); 128 | puts("a" > "b"); 129 | puts("a" >= "a"); 130 | puts("a" < "aa"); 131 | puts("a" < "b"); 132 | puts("==============="); 133 | puts(1 == 1); 134 | puts(2 == 1); 135 | puts(NaN == NaN); 136 | puts("2" == 2); 137 | puts(true == null); 138 | puts("234234" == "234234"); 139 | puts(true == 1); 140 | 141 | puts("==================="); 142 | puts(1 === true); 143 | puts(1 === "1"); 144 | puts(NaN === NaN); 145 | puts("abc" === "abc"); 146 | puts(3.1415926 === 3.1415926); 147 | 148 | puts("============"); 149 | puts(1 | 2 | 4 | 8 | 16); 150 | puts(123 & 234); 151 | puts(3456 ^ 2342); 152 | 153 | puts("==============="); 154 | var a = 12; 155 | a += 4; 156 | puts(a); 157 | a -= 4; 158 | puts(a); 159 | a /= 4; 160 | puts(a); 161 | a *= 4; 162 | puts(a); 163 | a %= 4; 164 | puts(a); 165 | a <<= 4; 166 | puts(a); 167 | a >>= 3; 168 | puts(a); 169 | a += true; 170 | puts(a); 171 | a += "fock"; 172 | puts(a); 173 | 174 | a = { a: 120 }; 175 | a.a += 4; 176 | puts(a); 177 | a.a -= 4; 178 | puts(a); 179 | a.a /= 4; 180 | puts(a); 181 | a.a *= 4; 182 | puts(a); 183 | a.a %= 4; 184 | puts(a); 185 | a.a <<= 4; 186 | puts(a); 187 | a.a >>= 3; 188 | puts(a); 189 | a.a += true; 190 | puts(a); 191 | a.a += "fock"; 192 | puts(a); 193 | -------------------------------------------------------------------------------- /.depend: -------------------------------------------------------------------------------- 1 | jsiLexer.o: jsiLexer.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 2 | jsiLexer.h 3 | jsiFunc.o: jsiFunc.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 4 | jsiLexer.h 5 | jsiValue.o: jsiValue.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 6 | jsiLexer.h 7 | jsiRegexp.o: jsiRegexp.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 8 | jsiLexer.h 9 | jsiPstate.o: jsiPstate.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 10 | jsiLexer.h 11 | jsiInterp.o: jsiInterp.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 12 | jsiLexer.h 13 | jsiUtils.o: jsiUtils.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 14 | jsiLexer.h 15 | jsiProto.o: jsiProto.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 16 | jsiLexer.h 17 | jsiFilesys.o: jsiFilesys.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 18 | jsiLexer.h 19 | jsiChar.o: jsiChar.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 20 | jsiLexer.h 21 | jsiString.o: jsiString.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 22 | jsiLexer.h 23 | jsiBool.o: jsiBool.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 24 | jsiLexer.h 25 | jsiNumber.o: jsiNumber.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 26 | jsiLexer.h 27 | jsiArray.o: jsiArray.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 28 | jsiLexer.h 29 | jsiLoad.o: jsiLoad.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 30 | jsiLexer.h 31 | jsiHash.o: jsiHash.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 32 | jsiLexer.h 33 | jsiOptions.o: jsiOptions.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 34 | jsiLexer.h 35 | jsiStubs.o: jsiStubs.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 36 | jsiLexer.h jsiStubs.h 37 | jsiFormat.o: jsiFormat.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 38 | jsiLexer.h jsiUtf8.h 39 | jsiExec.o: jsiExec.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 40 | jsiLexer.h 41 | jsiJSON.o: jsiJSON.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 42 | jsiLexer.h jsmn.h 43 | jsiTclUtil.o: jsiTclUtil.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 44 | jsiLexer.h jsiUtf8.h 45 | jsiCmds.o: jsiCmds.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 46 | jsiLexer.h 47 | jsiFileCmds.o: jsiFileCmds.c jsiInt.h jsi.h jsiPstate.h parser.h \ 48 | jsiCode.h jsiLexer.h 49 | jsiObj.o: jsiObj.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 50 | jsiLexer.h 51 | jsiSignal.o: jsiSignal.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 52 | jsiLexer.h 53 | jsiTree.o: jsiTree.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 54 | jsiLexer.h 55 | jsiMD5.o: jsiMD5.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 56 | jsiLexer.h 57 | jsiDString.o: jsiDString.c jsi.h 58 | jsiMath.o: jsiMath.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 59 | jsiLexer.h 60 | jsmn.o: jsmn.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h jsiLexer.h \ 61 | jsmn.h 62 | jsiZvfs.o: jsiZvfs.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 63 | jsiLexer.h 64 | jsiUtf8.o: jsiUtf8.c jsiUtf8.h jsiInt.h jsi.h jsiPstate.h parser.h \ 65 | jsiCode.h jsiLexer.h 66 | jsiUserObj.o: jsiUserObj.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 67 | jsiLexer.h 68 | parser.o: parser.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 69 | jsiLexer.h jsiCode.c 70 | jsiWebsocket.o: jsiWebsocket.c jsi.h 71 | jsiSqlite.o: jsiSqlite.c jsi.h 72 | jsiEval.o: jsiEval.c jsiInt.h jsi.h jsiPstate.h parser.h jsiCode.h \ 73 | jsiLexer.h 74 | -------------------------------------------------------------------------------- /jsmn.h: -------------------------------------------------------------------------------- 1 | #ifndef __JSMN_H__ 2 | #define __JSMN_H__ 3 | 4 | #define JSMN_STATIC_DEFAULT 100 5 | 6 | #define JSMN_DECLARE(p,token) \ 7 | jsmn_parser p = {0}; \ 8 | jsmntok_t tokens[JSMN_STATIC_DEFAULT]; \ 9 | jsmn_init(&p, tokens, JSMN_STATIC_DEFAULT) 10 | 11 | /** 12 | * JSON type identifier. Basic types are: 13 | * o Object 14 | * o Array 15 | * o String 16 | * o Other primitive: number, boolean (true/false) or null 17 | */ 18 | typedef enum { 19 | JSMN_PRIMITIVE = 0, 20 | JSMN_OBJECT = 1, 21 | JSMN_ARRAY = 2, 22 | JSMN_STRING = 3 23 | } jsmntype_t; 24 | 25 | typedef enum { 26 | /* Not enough tokens were provided */ 27 | JSMN_ERROR_NOMEM = -1, 28 | /* Invalid character inside JSON string */ 29 | JSMN_ERROR_INVAL = -2, 30 | /* The string is not a full JSON packet, more bytes expected */ 31 | JSMN_ERROR_PART = -3, 32 | /* Everything was fine */ 33 | JSMN_SUCCESS = 0 34 | } jsmnerr_t; 35 | 36 | /** 37 | * JSON token description. 38 | * @param type type (object, array, string etc.) 39 | * @param start start position in JSON data string 40 | * @param end end position in JSON data string 41 | */ 42 | typedef struct { 43 | jsmntype_t type; 44 | int start; 45 | int end; 46 | int size; 47 | #ifdef JSMN_PARENT_LINKS 48 | int parent; 49 | #endif 50 | } jsmntok_t; 51 | 52 | /** 53 | * JSON parser. Contains an array of token blocks available. Also stores 54 | * the string being parsed now and current position in that string 55 | */ 56 | typedef struct { 57 | unsigned int pos; /* offset in the JSON string */ 58 | int toknext; /* next token to allocate */ 59 | int toksuper; /* superior token node, e.g parent object or array */ 60 | jsmntok_t *tokens, *static_tokens; 61 | unsigned int num_tokens; 62 | int no_malloc; /* Disallow parser to dynamically grow tokens array. */ 63 | unsigned char strict; /* Strict parsing. */ 64 | unsigned char flags; 65 | const char *errStr; 66 | } jsmn_parser; 67 | 68 | /** 69 | * Setup JSON parser with a static array of tokens and size. 70 | * If static_tokens is NULL, malloc array of size num_tokens (0 means use default of 100). 71 | */ 72 | void jsmn_init(jsmn_parser *parser, jsmntok_t *static_tokens, unsigned int num_tokens); 73 | 74 | /** 75 | * Reset parser before another call to parse() 76 | */ 77 | void jsmn_reset(jsmn_parser *parser); 78 | 79 | /** 80 | * Free allocated memory after parse. 81 | */ 82 | void jsmn_free(jsmn_parser *parser); 83 | 84 | /** 85 | * Run JSON parser. It parses a JSON data string into and array of tokens, each describing 86 | * a single JSON object. Called after jsmn_init(). 87 | */ 88 | jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js); 89 | 90 | /** 91 | * Helper functions. 92 | */ 93 | jsmntok_t *jsmn_token(jsmn_parser *parser, unsigned int index); 94 | jsmntype_t jsmn_type(jsmn_parser *parser, unsigned int index); 95 | int jsmn_toklen(jsmn_parser *parser, unsigned int index); 96 | const char* jsmn_tokstr(jsmn_parser *parser, const char *js, unsigned int index, int *len); 97 | const char* jsmn_typename(int type); 98 | const char* jsmn_errname(int code); 99 | void jsmn_dump(jsmn_parser *parser, const char *js); 100 | 101 | #endif /* __JSMN_H_ */ 102 | -------------------------------------------------------------------------------- /www/c-extensions.wiki: -------------------------------------------------------------------------------- 1 | C-API: Extensions 2 | 3 | Jsi can be extended in several ways. 4 |

Embedding C

5 | 6 |
  7 | make USERSRC=demo
  8 | 
9 | 10 |

Dynamic Extensions

11 | 12 | If libjsi.so is being used on your system, you can load shared libraries into Jsi using the load() command. 13 | Or they can be statically compiled in. Basically, all that is required is defining a C function 14 | Jsi_InitXXXX to handle the initialization on load. 15 | 16 | Following is a brief but complete shared library example for Linux. 17 | Given the file user/demo.c: 18 | 19 |
 20 | #include "jsi.h"
 21 | 
 22 | JSI_EXTENSION_INI
 23 | 
 24 | Jsi_CmdProcDecl(DemoCmd) {
 25 |     int i, n = Jsi_ValueGetLength(interp, args);
 26 |     printf("demo called with %d args\n", n);
 27 |     for (i=0; i
 44 | 
 45 | We compile and load it thus:
 46 | 
 47 |     
 48 | cc -g -Wall -DJSI_USE_STUBS -I. -shared -fpic user/demo.c -o user/demo.so
 49 | ./jsish
 50 | load('user/demo.so');
 51 | 
52 | 53 |

Static API Access

54 | 55 | Usually an extension would want to access the Jsi API to create commands, etc. 56 | Here is the sample dyn.c extension included with the distribution: 57 | 58 |
 59 | #include "jsi.h"
 60 | 
 61 | Jsi_CmdProcDecl(DynCmd) {
 62 |    puts("dyn called");
 63 |    return JSI_OK;
 64 | }
 65 | 
 66 | int Jsi_Initdyn(Jsi_Interp *interp) {
 67 |   puts("LOADED DYN");
 68 |   Jsi_CommandCreate(interp, "dyn", DynCmd, NULL);
 69 |   return JSI_OK;
 70 | }
 71 | 
72 | To build this into the application, just type "make dyn". 73 | 74 |

Dynamic API Access

75 | 76 | To load the above dynamically requires using, a shared library version of Jsi (jsish), 77 | and the -ljsi option be added to the link line. Essentially, this requires installing 78 | the shared version of Jsi onto your system. 79 | Builtins 80 | 81 | JSI comes with the following builtin extensions. 82 | 83 | # Sqlite A small database engine 84 | # WebSockets Direct communication with web browsers 85 | # Zvfs A Zip virtual file system 86 | 87 | Although JSI can be compiled without these extensions, they generally come already compiled-in so 88 | that web application development is ready to go 89 | 90 |
 91 | $ time ./jsish tests/prime.js 
 92 | Have native helper: false
 93 | 1999 2999 4999 8999
 94 | 
 95 | real    0m0.384s
 96 | user    0m0.376s
 97 | sys 0m0.004s
 98 | 
 99 | $ make prime.so
100 | cc -g -Wall -I. -shared -fpic user/prime.c -o prime.so
101 | $ time ./jsish tests/prime.js 
102 | Have native helper: true
103 | 1999 2999 4999 8999
104 | 
105 | real    0m0.169s
106 | user    0m0.164s
107 | sys 0m0.004s
108 | 
109 | 110 | -------------------------------------------------------------------------------- /www/license.wiki: -------------------------------------------------------------------------------- 1 | License 2 | 3 | There are broadly speaking 2 licenses to be aware of. 4 | Jsi itself is covered by the following MIT license: 5 | 6 |
 7 | The MIT License (MIT)
 8 | 
 9 | Copyright (c) 2013 Peter MacDonald
10 | 
11 | Permission is hereby granted, free of charge, to any person obtaining a copy
12 | of this software and associated documentation files (the "Software"), to deal
13 | in the Software without restriction, including without limitation the rights
14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | copies of the Software, and to permit persons to whom the Software is
16 | furnished to do so, subject to the following conditions:
17 | 
18 | The above copyright notice and this permission notice shall be included in
19 | all copies or substantial portions of the Software.
20 | 
21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 | THE SOFTWARE.
28 | 
29 | 30 | Note: Jsish is based in part on the work of the libwebsockets project 31 | (http://libwebsockets.org). 32 | 33 |

Libwebsockets

34 | 35 | If you are linking in websocket support (the default) the following license 36 | also applies: 37 | 38 |
39 | Jsi source bundles a version of Libwebockets, which is covered by LGPL, with an additional clause allowing static linking. Here is the preamble:
40 | Libwebsockets and included programs are provided under the terms of the GNU
41 | Library General Public License (LGPL) 2.1, with the following exceptions:
42 | 
43 | 1) Static linking of programs with the libwebsockets library does not
44 | constitute a derivative work and does not require the author to provide
45 | source code for the program, use the shared libwebsockets libraries, or
46 | link their program against a user-supplied version of libwebsockets.
47 | 
48 | If you link the program to a modified version of libwebsockets, then the
49 | changes to libwebsockets must be provided under the terms of the LGPL in
50 | sections 1, 2, and 4.
51 | 
52 | 2) You do not have to provide a copy of the libwebsockets license with
53 | programs that are linked to the libwebsockets library, nor do you have to
54 | identify the libwebsockets license in your program or documentation as
55 | required by section 6 of the LGPL.
56 | 
57 | However, programs must still identify their use of libwebsockets. The
58 | following example statement can be included in user documentation to
59 | satisfy this requirement:
60 | 
61 | "[program] is based in part on the work of the libwebsockets  project
62 | (http://libwebsockets.org)"
63 | 
64 |                   GNU LESSER GENERAL PUBLIC LICENSE
65 |                        Version 2.1, February 1999
66 | ...
67 | 
68 | 69 | Note this seems to to say that as long as libwebsockets is not modified, 70 | all that is required is an acknowledgement in your user documentation. 71 | 72 |

Others

73 | 74 | Other software including sqlite, miniz, jsmn, etc are either public domain, BSD or MIT compatible. 75 | 76 | 77 | -------------------------------------------------------------------------------- /tools/testjs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Driver for jsi test programs. 3 | # Runs *.js files in tests/ and compares output to EXPECTSTART/END in file comment. 4 | RUNVALG=0 5 | QUIET=0 6 | LOUD=0 7 | JSISH=./jsish 8 | INPSTR="input\ntest\nabc@gmail.com\n" 9 | USESTR="Usage: testjs.sh [-loud|-quiet|-memcheck] " 10 | 11 | while [ $# -gt 1 ]; do 12 | case $1 in 13 | "-memcheck") RUNVALG=1; shift;; 14 | "-loud") LOUD=1; shift;; 15 | "-quiet") QUIET=1; shift;; 16 | "-input") INPSTR=$2; shift; shift;; 17 | -*) 18 | if [ ! -e "$1" ]; then 19 | echo "Unknown option: $1." 20 | echo $USESTR 21 | exit 1 22 | fi 23 | break;; 24 | *) 25 | break;; 26 | esac 27 | done 28 | 29 | if [ $# != 1 ]; then 30 | echo "Too many args at: $*." 31 | echo $USESTR 32 | exit 1 33 | fi 34 | if [ ! -e "$1" ]; then 35 | echo "File or directory expected: $1." 36 | echo $USESTR 37 | exit 1 38 | fi 39 | 40 | function test1file() 41 | { 42 | file=$1 43 | awk '{ 44 | if ($0 ~ /^=\!EXPECTSTART\!=$/) start = 1; 45 | else if ($0 ~ /=\!EXPECTEND\!=/) start = 0; 46 | else if (start) print 47 | }' $file >/tmp/ss_expected 48 | 49 | echo -e $INPSTR | "$JSISH" $file g 2 3 2>&1 >/tmp/ss_result 50 | ORC=$? 51 | if [ $ORC != 0 ]; then 52 | echo "[ BADRC ] $file: RC=$ORC" 53 | return; 54 | fi 55 | 56 | if ! diff /tmp/ss_expected /tmp/ss_result >/dev/null; then 57 | DATA=`cat /tmp/ss_expected` 58 | if [ "$DATA" == "" ]; then CM='*'; else CM=' '; fi 59 | echo -e "[ FAILED ] $CM $file" 60 | if [ $LOUD != 0 ]; then 61 | echo "============expected=============" 62 | cat /tmp/ss_expected 63 | echo "------------result---------------" 64 | cat /tmp/ss_result 65 | echo "-------------diff----------------" 66 | diff -u /tmp/ss_expected /tmp/ss_result | tail -n +3 67 | echo "==============end===============" 68 | return 69 | fi 70 | if [ $QUIET != 1 ]; then 71 | echo "-------------diff----------------" 72 | diff -u /tmp/ss_expected /tmp/ss_result | tail -n +3 73 | return 74 | fi 75 | else 76 | echo -e "[ OK ] $file" 77 | fi 78 | } 79 | 80 | function testdir() 81 | { 82 | allfiles=`find "$1" -maxdepth 1 -name "*.js" | sort -r` 83 | for file in $allfiles; do 84 | echo "Executing $file" 85 | test1file $file $2 86 | done 87 | } 88 | 89 | function runvalgind() 90 | { 91 | allfiles=`find "$1" -name "*.js"` 92 | rm -f valgrind.report.txt 93 | 94 | for file in $allfiles; do 95 | echo -n "Executing $file" 96 | echo "**************** $file ******************" >>valgrind.report.txt 97 | f=$(basename $file) 98 | if [ "$f" != "block.js" -a "$f" != "block2.js" ]; then 99 | echo -e "input\ntest\npmacdona@gmail.com\n" | valgrind "$JSISH" $file 1 2 3 >>valgrind.report.txt 2>&1 100 | fi 101 | echo -e "[ DONE ] $file" 102 | done 103 | echo "All done, report: valgrind.report.txt" 104 | } 105 | 106 | if [ "$2" == "-m" ]; then 107 | runvalgind "$1" 108 | return 109 | fi 110 | if [ -d "$1" ]; then 111 | testdir "$1" "$2" 112 | else 113 | test1file "$1" "$2" 114 | fi 115 | -------------------------------------------------------------------------------- /jsiCodeInt.h: -------------------------------------------------------------------------------- 1 | static OpCodes *codes_new(int size); 2 | static OpCodes *codes_join(OpCodes *a, OpCodes *b); 3 | static OpCodes *codes_join3(OpCodes *a, OpCodes *b, OpCodes *c); 4 | static OpCodes *codes_join4(OpCodes *a, OpCodes *b, OpCodes *c, OpCodes *d); 5 | static OpCodes *code_push_undef(); 6 | static OpCodes *code_push_bool(int v); 7 | static OpCodes *code_push_num(Jsi_Number *v); 8 | static OpCodes *code_push_string(jsi_Pstate *p, jsi_Pline *line, const char *str); 9 | static OpCodes *code_push_index(jsi_Pstate *p, jsi_Pline *line, char *varname); 10 | static OpCodes *code_push_this(jsi_Pstate *p, jsi_Pline *line); 11 | static OpCodes *code_push_top(); 12 | static OpCodes *code_push_top2() ; 13 | static OpCodes *code_unref() ; 14 | static OpCodes *code_push_args() ; 15 | static OpCodes *code_push_func(jsi_Pstate *p, jsi_Pline *line, struct Jsi_Func *fun) ; 16 | static OpCodes *code_push_regex(jsi_Pstate *p, jsi_Pline *line, Jsi_Regex *reg) ; 17 | static OpCodes *code_local(jsi_Pstate *p, jsi_Pline *line, const char *varname) ; 18 | static OpCodes *code_nop() ; 19 | static OpCodes *code_neg() ; 20 | static OpCodes *code_pos() ; 21 | static OpCodes *code_bnot() ; 22 | static OpCodes *code_not() ; 23 | static OpCodes *code_mul() ; 24 | static OpCodes *code_div() ; 25 | static OpCodes *code_mod() ; 26 | static OpCodes *code_add() ; 27 | static OpCodes *code_sub() ; 28 | static OpCodes *code_in() ; 29 | static OpCodes *code_less() ; 30 | static OpCodes *code_greater() ; 31 | static OpCodes *code_lessequ() ; 32 | static OpCodes *code_greaterequ() ; 33 | static OpCodes *code_equal() ; 34 | static OpCodes *code_notequal() ; 35 | static OpCodes *code_eequ() ; 36 | static OpCodes *code_nneq() ; 37 | static OpCodes *code_band() ; 38 | static OpCodes *code_bor() ; 39 | static OpCodes *code_bxor() ; 40 | static OpCodes *code_shf(int right) ; 41 | static OpCodes *code_instanceof() ; 42 | static OpCodes *code_assign(jsi_Pstate *p, jsi_Pline *line, int h) ; 43 | static OpCodes *code_subscript(jsi_Pstate *p, jsi_Pline *line, int right_val) ; 44 | static OpCodes *code_inc(jsi_Pstate *p, jsi_Pline *line, int e) ; 45 | static OpCodes *code_dec(jsi_Pstate *p, jsi_Pline *line, int e) ; 46 | static OpCodes *code_typeof(jsi_Pstate *p, jsi_Pline *line, int e) ; 47 | static OpCodes *code_fcall(jsi_Pstate *p, jsi_Pline *line, int argc) ; 48 | static OpCodes *code_newfcall(jsi_Pstate *p, jsi_Pline *line, int argc) ; 49 | static OpCodes *code_ret(int n) ; 50 | static OpCodes *code_delete(int n) ; 51 | static OpCodes *code_chthis(int n) ; 52 | static OpCodes *code_pop(int n) ; 53 | static OpCodes *code_jfalse(int off) ; 54 | static OpCodes *code_jtrue(int off) ; 55 | static OpCodes *code_jfalse_np(int off) ; 56 | static OpCodes *code_jtrue_np(int off) ; 57 | static OpCodes *code_jmp(int off) ; 58 | static OpCodes *code_object(jsi_Pstate *p, jsi_Pline *line, int c) ; 59 | static OpCodes *code_array(jsi_Pstate *p, jsi_Pline *line, int c) ; 60 | static OpCodes *code_key() ; 61 | static OpCodes *code_next() ; 62 | static OpCodes *code_eval(jsi_Pstate *p, jsi_Pline *line, int argc) ; 63 | static OpCodes *code_stry(jsi_Pstate *p, jsi_Pline *line, int trylen, int catchlen, int finlen) 64 | static OpCodes *code_etry(jsi_Pstate *p, jsi_Pline *line) ; 65 | static OpCodes *code_scatch(jsi_Pstate *p, jsi_Pline *line, const char *var) ; 66 | static OpCodes *code_ecatch(jsi_Pstate *p, jsi_Pline *line) ; 67 | static OpCodes *code_sfinal(jsi_Pstate *p, jsi_Pline *line) ; 68 | static OpCodes *code_efinal(jsi_Pstate *p, jsi_Pline *line) ; 69 | static OpCodes *code_throw(jsi_Pstate *p, jsi_Pline *line) ; 70 | static OpCodes *code_with(jsi_Pstate *p, jsi_Pline *line, int withlen) ; 71 | static OpCodes *code_ewith(jsi_Pstate *p, jsi_Pline *line) ; 72 | static OpCodes *code_debug(jsi_Pstate *p, jsi_Pline *line) ; 73 | static OpCodes *code_reserved(jsi_Pstate *p, jsi_Pline *line, int type, char *id); 74 | -------------------------------------------------------------------------------- /tests/block2.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | 2 7 6 4 | 9 5 1 5 | 4 3 8 6 | -------- 7 | 2 9 4 8 | 7 5 3 9 | 6 1 8 10 | -------- 11 | 4 3 8 12 | 9 5 1 13 | 2 7 6 14 | -------- 15 | 4 9 2 16 | 3 5 7 17 | 8 1 6 18 | -------- 19 | 6 1 8 20 | 7 5 3 21 | 2 9 4 22 | -------- 23 | 6 7 2 24 | 1 5 9 25 | 8 3 4 26 | -------- 27 | 8 1 6 28 | 3 5 7 29 | 4 9 2 30 | -------- 31 | 8 3 4 32 | 1 5 9 33 | 6 7 2 34 | -------- 35 | =!EXPECTEND!= 36 | */ 37 | 38 | for (a = 1; a < 10; ++a) { 39 | for (b = 1; b < 10; ++b) { 40 | if (b == a) continue; 41 | for (c = 1; c < 10; ++c) { 42 | if (c == a) continue; 43 | if (c == b) continue; 44 | for (d = 1; d < 10; ++d) { 45 | if (d == a) continue; 46 | if (d == b) continue; 47 | if (d == c) continue; 48 | for (e = 1; e < 10; ++e) { 49 | if (e == a) continue; 50 | if (e == b) continue; 51 | if (e == c) continue; 52 | if (e == d) continue; 53 | for (f = 1; f < 10; ++f) { 54 | if (f == a) continue; 55 | if (f == b) continue; 56 | if (f == c) continue; 57 | if (f == d) continue; 58 | if (f == e) continue; 59 | for (g = 1; g < 10; ++g) { 60 | if (g == a) continue; 61 | if (g == b) continue; 62 | if (g == c) continue; 63 | if (g == d) continue; 64 | if (g == e) continue; 65 | if (g == f) continue; 66 | for (h = 1; h < 10; ++h) { 67 | if (h == a) continue; 68 | if (h == b) continue; 69 | if (h == c) continue; 70 | if (h == d) continue; 71 | if (h == e) continue; 72 | if (h == f) continue; 73 | if (h == g) continue; 74 | for (i = 1; i < 10; ++i) { 75 | if (i == a) continue; 76 | if (i == b) continue; 77 | if (i == c) continue; 78 | if (i == d) continue; 79 | if (i == e) continue; 80 | if (i == f) continue; 81 | if (i == g) continue; 82 | if (i == h) continue; 83 | 84 | if (a + b + c != 15) continue; 85 | if (d + e + f != 15) continue; 86 | if (g + h + i != 15) continue; 87 | if (a + d + g != 15) continue; 88 | if (b + e + h != 15) continue; 89 | if (c + f + i != 15) continue; 90 | if (a + e + i != 15) continue; 91 | if (c + e + g != 15) continue; 92 | 93 | puts(a + " " + b + " " + c); 94 | puts(d + " " + e + " " + f); 95 | puts(g + " " + h + " " + i); 96 | puts("--------"); 97 | } 98 | } 99 | } 100 | } 101 | } 102 | } 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /win/regex.h: -------------------------------------------------------------------------------- 1 | #ifdef __WIN32 2 | #ifndef JSIREGEXP_H 3 | #define JSIREGEXP_H 4 | 5 | #if defined(HAVE_REGCOMP) && !defined(JSI_REGEXP) 6 | /* Use POSIX regex */ 7 | #include 8 | 9 | #else 10 | 11 | #include 12 | 13 | /* 14 | * Definitions etc. for regexp(3) routines. 15 | * 16 | * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], 17 | * not the System V one. 18 | * 19 | * 11/04/02 (seiwald) - const-ing for string literals 20 | */ 21 | 22 | typedef struct { 23 | int rm_so; 24 | int rm_eo; 25 | } regmatch_t; 26 | 27 | /* 28 | * The "internal use only" fields in regexp.h are present to pass info from 29 | * compile to execute that permits the execute phase to run lots faster on 30 | * simple cases. They are: 31 | * 32 | * regstart char that must begin a match; '\0' if none obvious 33 | * reganch is the match anchored (at beginning-of-line only)? 34 | * regmust string (pointer into program) that match must include, or NULL 35 | * regmlen length of regmust string 36 | * 37 | * Regstart and reganch permit very fast decisions on suitable starting points 38 | * for a match, cutting down the work a lot. Regmust permits fast rejection 39 | * of lines that cannot possibly match. The regmust tests are costly enough 40 | * that regcomp() supplies a regmust only if the r.e. contains something 41 | * potentially expensive (at present, the only such thing detected is * or + 42 | * at the start of the r.e., which can involve a lot of backup). Regmlen is 43 | * supplied because the test in regexec() needs it and regcomp() is computing 44 | * it anyway. 45 | */ 46 | 47 | typedef struct regexp { 48 | /* -- public -- */ 49 | int re_nsub; /* number of parenthesized subexpressions */ 50 | 51 | /* -- private -- */ 52 | int cflags; /* Flags used when compiling */ 53 | int err; /* Any error which occurred during compile */ 54 | int regstart; /* Internal use only. */ 55 | int reganch; /* Internal use only. */ 56 | int regmust; /* Internal use only. */ 57 | int regmlen; /* Internal use only. */ 58 | int *program; /* Allocated */ 59 | 60 | /* working state - compile */ 61 | const char *regparse; /* Input-scan pointer. */ 62 | int p; /* Current output pos in program */ 63 | int proglen; /* Allocated program size */ 64 | 65 | /* working state - exec */ 66 | int eflags; /* Flags used when executing */ 67 | const char *start; /* Initial string pointer. */ 68 | const char *reginput; /* Current input pointer. */ 69 | const char *regbol; /* Beginning of input, for ^ check. */ 70 | 71 | /* Input to regexec() */ 72 | regmatch_t *pmatch; /* submatches will be stored here */ 73 | int nmatch; /* size of pmatch[] */ 74 | } regexp; 75 | 76 | typedef regexp regex_t; 77 | 78 | #define REG_EXTENDED 0 79 | #define REG_NEWLINE 1 80 | #define REG_ICASE 2 81 | 82 | #define REG_NOTBOL 16 83 | 84 | enum { 85 | REG_NOERROR, /* Success. */ 86 | REG_NOMATCH, /* Didn't find a match (for regexec). */ 87 | REG_BADPAT, /* >= REG_BADPAT is an error */ 88 | REG_ERR_NULL_ARGUMENT, 89 | REG_ERR_UNKNOWN, 90 | REG_ERR_TOO_BIG, 91 | REG_ERR_NOMEM, 92 | REG_ERR_TOO_MANY_PAREN, 93 | REG_ERR_UNMATCHED_PAREN, 94 | REG_ERR_UNMATCHED_BRACES, 95 | REG_ERR_BAD_COUNT, 96 | REG_ERR_JUNK_ON_END, 97 | REG_ERR_OPERAND_COULD_BE_EMPTY, 98 | REG_ERR_NESTED_COUNT, 99 | REG_ERR_INTERNAL, 100 | REG_ERR_COUNT_FOLLOWS_NOTHING, 101 | REG_ERR_TRAILING_BACKSLASH, 102 | REG_ERR_CORRUPTED, 103 | REG_ERR_NULL_CHAR, 104 | REG_ERR_NUM 105 | }; 106 | 107 | int regcomp(regex_t *preg, const char *regex, int cflags); 108 | int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags); 109 | size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size); 110 | void regfree(regex_t *preg); 111 | 112 | #endif 113 | #endif 114 | #endif 115 | -------------------------------------------------------------------------------- /tools/mkstubs.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env jsish 2 | // Generate stubs file for shared lib loading. 3 | // Unfinished, but can be used to generate stubs for arbitrary libs. 4 | var opts = { prefix:'jsi', inFile:'', outFile:'' }; 5 | 6 | //Parse command line args. 7 | var args = console.args; 8 | for (var i = 0; isig == \\\n'; 83 | rc += ' JSI_STUBS_SIG?jsiStubsPtr->_Jsi_Stubs__initialize(interp, flags, "'+opts.prefix+'", \\\n'; 84 | rc += ' '+opts.preu+'_VERSION, '+opts.preu+'_STUBS_MD5, '+opts.preu+'_STUBS_BLDFLAGS, sizeof('; 85 | rc += opts.pret+'_Stubs), (void**)&'+opts.prefix+'StubsPtr):JSI_ERROR)\n'; 86 | rc += '#endif\n\n'; 87 | rc += fstub; 88 | rc += 'extern '+opts.pret+'_Stubs* '+opts.prefix+'StubsPtr;\n\n'; 89 | rc += '#define __'+opts.preu+'_STUBS_INIT__\\\n'+finit+' NULL\n\n'; 90 | rc += '#ifdef JSI_USE_STUBS\n\n'+fdefs+'\n#endif\n\n#endif\n'; 91 | file.write(opts.outFile, rc); 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /lib/zip.jsi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env jsish 2 | 3 | // Utility for creating and managing zip files, especially when appended to a jsish executable-archive. 4 | 5 | function jsi_zip(args) { 6 | 7 | var rc = 0, iszip = 0; 8 | function usage(str) { 9 | console.log(str); 10 | console.log("usage: list file|truncate file|unzip file.zip ?dir?|zip file.zip dir|fuse file.zip|create ..."); 11 | return 1; 12 | } 13 | 14 | if (!args || args.length < 2) 15 | return usage('missing args'); 16 | 17 | var zdir, fname = args[1], dolib = 0; 18 | if (args[0] !== 'zip' && !file.exists(fname)) 19 | return usage(fname+' does not exist'); 20 | 21 | switch (args[0]) { 22 | case "truncate": // Truncate zip files off of executable. 23 | zvfs.truncate(fname); 24 | break; 25 | 26 | case "list": // List files in zip. 27 | fname = file.realpath(fname); 28 | if (fname === info.executable()) 29 | zdir = '/zvfs'; 30 | else 31 | zdir = zvfs.mount(fname); 32 | puts(file.glob('*', {dir:zdir,recurse:true})); 33 | break; 34 | 35 | case "zip": // Create zip file. 36 | if (argc < 3) 37 | return usage("too few arguments"); 38 | else if (argc > 3) 39 | return usage("too many arguments"); 40 | if (file.extension(fname) !== '.zip') 41 | return usage("must give a .zip file name"); 42 | if (file.isfile(fname)) 43 | file.remove(fname); 44 | iszip = 1; 45 | 46 | case "create": // Create standalone executable. 47 | zdir = args[2]; 48 | if (!file.isdir(zdir)) 49 | return usage("must give a directory to zip"); 50 | var i = 0, zargs = []; 51 | zargs[i++] = file.realpath(fname); 52 | zargs[i++] = file.glob(zdir+'/*', {recurse:true}); 53 | zargs[i++] = zdir; 54 | for (var n = 3; n 3 | #include 4 | #ifdef VALUE_DEBUG 5 | #include "jsiInt.h" 6 | #else 7 | #include "jsi.h" 8 | #endif 9 | 10 | static int deleted = 0, exitCode = 0; 11 | static int InterpDelete(Jsi_Interp *interp, void *ptr) { 12 | exitCode = (int)ptr; 13 | deleted = 1; 14 | return JSI_OK; 15 | } 16 | 17 | int main(int argc, char **argv) 18 | { 19 | int rc = JSI_OK, jsFound = 0; 20 | Jsi_Interp* interp = Jsi_InterpCreate(NULL, argc, argv, 0); 21 | Jsi_InterpOnDelete(interp, &InterpDelete); 22 | 23 | #ifndef NO_JAZ 24 | /* Mount zip at end of executable */ 25 | Jsi_Value *v = Jsi_Executable(interp); 26 | const char *exeFile = Jsi_ValueString(interp, v, NULL); 27 | if (argc != 2 || Jsi_Strcmp(argv[1], "--nozvfs")) { 28 | rc = Jsi_ExecZip(interp, exeFile, JSI_ZVFS_DIR, &jsFound); 29 | if (rc >= 0) { 30 | if (!jsFound) { 31 | #if (!defined(JSI_OMIT_FILESYS)) && (!defined(JSI_OMIT_ZVFS)) 32 | fprintf(stderr, "warning: no main.jsi or jsiIndex.jsi\n"); 33 | #endif 34 | } 35 | if (deleted) 36 | exit(exitCode); 37 | else if (rc != JSI_OK) { 38 | fprintf(stderr, "Error\n"); 39 | exit(1); 40 | } 41 | } 42 | } 43 | #endif 44 | 45 | #ifdef USER_EXTENSION 46 | extern int USER_EXTENSION(Jsi_Interp *interp); 47 | if (USER_EXTENSION (interp) != JSI_OK) { 48 | fprintf(stderr, "extension load failed"); 49 | exit(1); 50 | } 51 | #endif 52 | Jsi_ShiftArgs(interp); 53 | if (argc == 1) { 54 | rc = Jsi_Interactive(interp, JSI_OUTPUT_QUOTE|JSI_OUTPUT_NEWLINES); 55 | } else { 56 | if (argc == 2 && (Jsi_Strcmp(argv[1], "--help")==0 || Jsi_Strcmp(argv[1], "-h" )==0)) { 57 | puts("usage: jsi ?--help | -e SCRIPT | FILE arg arg ...?"); 58 | exit(0); 59 | } 60 | if (argc == 2 && (Jsi_Strcmp(argv[1], "--version")==0 || Jsi_Strcmp(argv[1], "-v" )==0)) { 61 | char str[200] = "\n"; 62 | Jsi_Channel chan = Jsi_Open(interp, Jsi_ValueNewStringKey(interp, "/zvfs/lib/sourceid.txt"), "r"); 63 | if (chan) 64 | Jsi_Read(chan, str, sizeof(str)); 65 | printf("%d.%d.%d (%" JSI_NUMGFMT ") %s", JSI_VERSION_MAJOR, JSI_VERSION_MINOR, JSI_VERSION_RELEASE, Jsi_Version(), str); 66 | exit(0); 67 | } 68 | if (argc > 2 && (Jsi_Strcmp(argv[1], "--invoke")==0 || Jsi_Strcmp(argv[1], "-i" )==0)) { 69 | Jsi_DString dStr = {}; 70 | Jsi_DSAppend(&dStr, "jsi_invokeCmd(\"", argv[2], "\",console.args.slice(1));", NULL); 71 | rc = Jsi_EvalString(interp, Jsi_DSValue(&dStr), JSI_EVAL_NOSKIPBANG); 72 | Jsi_DSFree(&dStr); 73 | } 74 | else if (argc == 3 && (Jsi_Strcmp(argv[1], "--eval")==0 || Jsi_Strcmp(argv[1], "-e" )==0)) 75 | rc = Jsi_EvalString(interp, argv[2], JSI_EVAL_NOSKIPBANG); 76 | else { 77 | Jsi_Value *vf = NULL; 78 | const char *ext = strrchr(argv[1], '.'); 79 | /* Support running "main.jsi" from a zip file. */ 80 | if (ext && (strcmp(ext,".zip")==0 ||strcmp(ext,".jsz")==0 ) ) { 81 | rc = Jsi_ExecZip(interp, argv[1], NULL, &jsFound); 82 | if (rc<0) { 83 | fprintf(stderr, "zip mount failed\n"); 84 | exit(1); 85 | } 86 | if (!(jsFound&JSI_ZIP_MAIN)) { 87 | fprintf(stderr, "main.jsi not found\n"); 88 | exit(1); 89 | } 90 | } else { 91 | if (argc>1) 92 | vf = Jsi_ValueNewStringKey(interp, argv[1]); 93 | rc = Jsi_EvalFile(interp, vf, JSI_EVAL_ARGV0|JSI_EVAL_INDEX); 94 | } 95 | } 96 | if (deleted) 97 | exit(exitCode); 98 | if (rc == 0) { 99 | /* Skip output from an ending semicolon which evaluates to undefined */ 100 | Jsi_Value *ret = Jsi_ReturnValue(interp); 101 | if (!Jsi_ValueIsType(interp, ret, JSI_VT_UNDEF)) { 102 | Jsi_DString dStr = {}; 103 | fputs(Jsi_ValueGetDString(interp, ret, &dStr, 0), stdout); 104 | Jsi_DSFree(&dStr); 105 | fputs("\n", stdout); 106 | } 107 | } else 108 | fputs("ERROR\n", stderr); 109 | 110 | } 111 | if (!deleted) 112 | Jsi_InterpDelete(interp); 113 | return rc; 114 | } 115 | 116 | -------------------------------------------------------------------------------- /lib/websrv.jsi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env jsish 2 | 3 | // Instantiates a simple web server 4 | 5 | function jsi_websrv(args,opts) 6 | { 7 | var that = this; // Give functions access to this[]. 8 | var init = { 9 | // Options 10 | debug:0, // Debugging flag. 11 | local:true, // Accept only local connections. 12 | port: 8765, // Start search for port. 13 | maxPort: 1000, // Max to add to above port. 14 | nowait: false, // Caller will be calling sys.update(); 15 | timeout:0, // Timed timeout (in ms). 16 | closeTimeout:5000, // Grace time after last client closes socket before exit (in ms). 17 | rootdir: null, // Where main.js lives. 18 | url: "/main.ihtml", 19 | browsers: { // Not used, yet. 20 | unix:[ "xdg-open", "gnome-open", "firefox", "google-chrome" ], 21 | win: [ "start" ], 22 | mac: [ "open" ] 23 | } 24 | }; 25 | 26 | function dputs(str) { if (that.debug) console.log(str); } 27 | 28 | function DoExit() // Notify all going down, then exit. 29 | { 30 | WebSend(-1, 'exit'); 31 | setTimeout(function () {that.done = 1; }, 1000); 32 | } 33 | 34 | function CloseNow() 35 | { 36 | that.closeId = null; 37 | if (that.ws.conf('connectCnt')>0) 38 | return; 39 | dputs("Last client has closed"); 40 | that.done = 1; 41 | } 42 | 43 | function CloseLast(now) // Wait around for a while for reconnect or new clients before exiting 44 | { 45 | if (that.closeId) 46 | clearInterval(that.closeId); 47 | if (that.closeTimeout>0) 48 | that.closeId = setTimeout(function () { CloseNow(); }, that.closeTimeout); 49 | return true; 50 | } 51 | 52 | function WebSend (id,label,data,type) 53 | { 54 | if (type === undefined) 55 | type = ""; 56 | var dat = {type: type, label:label, data:data }; 57 | dat = JSON.stringify(dat); 58 | //dputs("SEND: "+dat); 59 | that.ws.send(dat,id); 60 | } 61 | 62 | function WebRecv(data, id) 63 | { 64 | var buf, buf0, buf1, buf2; 65 | dputs("SERVER GOT: "+ id +": "+data); 66 | var dat = JSON.parse(data); 67 | dputs("JSON: "+dat.toString()); 68 | switch (dat.label) { 69 | case 'loadAll': return loadAll(id); 70 | case 'exit': DoExit(); break; 71 | 72 | default: dputs("unknown webmsg: "+dat.label); break; 73 | } 74 | } 75 | 76 | // MAIN BEGIN 77 | if (typeof args !== 'object' || args.length>1) 78 | throw "expected 0 or 1 args"; 79 | jsi_parseOpts(this, opts, init); 80 | if (args.length) { 81 | this.url = file.tail(args[0]); 82 | this.rootdir = file.dirname(args[0]); 83 | } 84 | this.done = 0; 85 | 86 | if (!this.rootdir) 87 | this.rootdir=info.scriptDir(); 88 | if (this.url && this.url.length) { 89 | var ufn = this.rootdir+'/'+this.url; 90 | if (!file.isfile(ufn)) 91 | throw("file not found: "+ufn); 92 | } 93 | this.wsopts = { 94 | port:this.port, rootdir:this.rootdir, callback:WebRecv, 95 | onCloseLast:CloseLast, debug:this.debug 96 | }; 97 | if (this.local) 98 | this.wsopts.interface = 'lo'; 99 | 100 | 101 | /* Try opening websocket on first available port. */ 102 | var i; 103 | for (i=0; i=this.maxPort) { 111 | console.log("Failed to get port"); 112 | return; 113 | } 114 | 115 | this.ws.handler('.ihtml', 'jsi_wpp'); 116 | dputs("Listen on "+this.wsopts.port); 117 | var prog = "xdg-open"; 118 | switch (info.platform().os) { 119 | case 'win': prog = 'start'; break; 120 | } 121 | // Display page in browser. 122 | dputs("URL: "+this.url); 123 | if (this.url && this.url.length) { 124 | sys.exec(prog + " http://127.0.0.1:"+this.wsopts.port+'/'+this.url+" &"); 125 | } 126 | if (this.nowait) return; 127 | if (this.timeout) 128 | setTimeout(function () { that.done = 1; }, this.timeout); 129 | while (this.done == 0 && sys.update(100) ) ; 130 | delete this.ws; 131 | } 132 | 133 | if (info.isInvoked()) { 134 | jsi_invokeCmd('jsi_websrv'); 135 | } 136 | -------------------------------------------------------------------------------- /lib/wpp.jsi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env jsish 2 | // jsi_wpp preprocesses html, evaluating the javascript in between tags (like php). 3 | // Evaluation occurs within a subinterp. Two commands are added: include(file,...) and echo(str). 4 | 5 | function jsi_wpp(files, opts) 6 | { 7 | var that = this; // Give functions access to this[]. 8 | var init = { 9 | rc:'', files:[], chpos:0, curdir:'', data:'', errs:'', 10 | incsMax:1000, noCatch:true, delInterp:true, 11 | starttag:'', interp:null, interpOpts:{} 12 | }; 13 | 14 | function echo(s) // Echo a string to output. 15 | { 16 | that.rc += s; 17 | } 18 | 19 | function error(s) // Format an error with file/line number. 20 | { 21 | var fn = that.files[that.files.length-1]; 22 | var line = that.data.split('\n').length; 23 | return 'Error at '+fn+':'+line+': '+ s; 24 | } 25 | 26 | function include() // Include and evaluate files, recusively. 27 | { 28 | var ai, fn, args = arguments, slen = that.starttag.length, elen = that.starttag.length; 29 | var odata = that.data; 30 | if (args.length == 1 && args[0] != undefined && typeof args[0] == 'object') 31 | args = args[0]; 32 | that.data = ''; 33 | for (ai=0; ai that.incsMax) 35 | throw error("recursive include"); 36 | fn = args[ai]; 37 | if (that.files.length) { 38 | var pfn = that.files[that.files.length-1]; 39 | fn = file.join(file.dirname(pfn), fn); 40 | } else { 41 | fn = file.realpath(fn); 42 | } 43 | if (!file.exists(fn)) { 44 | that.data = odata; 45 | throw error("file not found: "+fn); 46 | } 47 | // Break up on tag boundaries. 48 | var x = file.read(fn); 49 | var s = [], e = []; 50 | var n=0; 51 | while (1) { 52 | n = x.indexOf(that.starttag, n); 53 | if (n<0) break; 54 | s.push(n); 55 | n++; 56 | } 57 | if (s.length<=0) { 58 | return echo(x); 59 | } 60 | that.files.push(fn); 61 | n = 0; 62 | while (1) { 63 | n = x.indexOf(that.endtag, n); 64 | if (n<0) break; 65 | e.push(n); 66 | n++; 67 | } 68 | if (s.length != e.length) 69 | throw error('tags not balanced'); 70 | var pre; 71 | for (var i in s) { 72 | if (s[i]>e[i]) 73 | throw error('begin/end out of order'); 74 | } 75 | // Now do the work: collect data/evaluate code. 76 | n = 0; 77 | var data = ''; 78 | for (var i in s) { 79 | pre = x.substr(n,s[i]-n); 80 | echo(pre); 81 | data += pre; 82 | that.chpos = n = e[i]+elen; 83 | var code = x.substr(s[i]+slen, e[i]-s[i]-elen); 84 | that.data = data; 85 | try { 86 | that.interp.eval(code); 87 | } catch(e) { 88 | throw error('while evaling code:'+code+'\n'+e); 89 | } 90 | data += ''; 91 | that.data = data; 92 | } 93 | var l = s.length-1; 94 | if (e[e.length-1] < x.length-1) { 95 | pre = x.substr(e[i]+elen); 96 | echo(pre); 97 | } 98 | that.files.pop(); 99 | } 100 | that.data = odata; 101 | } 102 | 103 | // Start of main function. 104 | jsi_parseOpts(this, opts, init); 105 | var oint = this.interp; 106 | if (!this.interp) 107 | this.interp = new Interp(this.interpOpts); 108 | if (!this.interp.alias('echo')) 109 | this.interp.alias('echo', echo, null); 110 | if (!this.interp.alias('include')) 111 | this.interp.alias('include', include, null); 112 | 113 | if (this.noCatch) 114 | include(files); 115 | else { 116 | try { 117 | include(files); 118 | } catch(e) { 119 | this.rc = "

JSI ERROR

";
120 |                 this.rc += e;
121 |             this.rc += '\n\n'+this.errs+"
"; 122 | } 123 | } 124 | if (this.delInterp) { 125 | delete this.interp; 126 | this.interp = null; 127 | } 128 | return this.rc; 129 | }; 130 | 131 | 132 | if (info.isInvoked()) { 133 | puts(jsi_invokeCmd('jsi_wpp')); 134 | } 135 | 136 | -------------------------------------------------------------------------------- /tests/sqlite.js: -------------------------------------------------------------------------------- 1 | /* 2 | =!EXPECTSTART!= 3 | B=1, A=99 4 | B=2, A=95 5 | B=3, A=91 6 | [ { a:99, b:1 }, { a:95, b:2 }, { a:91, b:3 } ] 7 | CONF: { bindWarn:false, debug:0, errorCnt:0, execOpts:{ callback:null, cdata:null, headers:false, limit:0, mapundef:false, mode:"rows", nocache:false, nullvalue:null, separator:null, table:null, width:undefined }, forceInt:false, maxStmts:1000, mutex:"default", name:"", nocreate:false, readonly:false, trace:[ ], vfs:null } 8 | 95 9 | EXECING: select * from foo; 10 | [ { a:99, b:1 }, { a:95, b:2 }, { a:91, b:3 } ] 11 | EXECING: select * from foo; 12 | 99|1 13 | 95|2 14 | 91|3 15 | EXECING: select * from foo; 16 | a|b 17 | 99|1 18 | 95|2 19 | 91|3 20 | EXECING: select * from foo; 21 | 991 22 | 952 23 | 913 24 | EXECING: select * from foo; 25 | ab 26 | 991 27 | 952 28 | 913 29 | EXECING: select * from foo; 30 | 99,1 31 | 95,2 32 | 91,3 33 | EXECING: select * from foo; 34 | a,b 35 | 99,1 36 | 95,2 37 | 91,3 38 | EXECING: select * from foo; 39 | a b 99 1 40 | 95 2 41 | 91 3 42 | EXECING: select * from foo; 43 | a b 44 | ---------- ---------- 45 | 99 1 46 | 95 2 47 | 91 3 48 | EXECING: select * from foo; 49 | [ {"a":99, "b":1}, {"a":95, "b":2}, {"a":91, "b":3} ] 50 | EXECING: select * from foo; 51 | [ ["a", "b"], [99, 1], [95, 2], [91, 3] ] 52 | EXECING: select * from foo; 53 | { "names": [ "a", "b" ], "values": [ [99, 1 ], [95, 2 ], [91, 3 ] ] } 54 | EXECING: select * from foo; 55 | 99 1 56 | 95 2 57 | 91 3 58 | EXECING: select * from foo; 59 | a b 60 | 99 1 61 | 95 2 62 | 91 3 63 | EXECING: select * from foo; 64 | a = 99 b = 1 65 | a = 95 66 | b = 2 67 | a = 91 68 | b = 3 69 | EXECING: select * from foo; 70 | INSERT INTO table VALUES(99,NULL); 71 | INSERT INTO table VALUES(95,NULL); 72 | INSERT INTO table VALUES(91,NULL); 73 | TRACING: select bar(a) from foo where b == 2; 74 | 95.000 75 | function (sql) {...} 76 | =!EXPECTEND!= 77 | */ 78 | 79 | 80 | var db = new Sqlite('/tmp/testsql.db',{maxStmts:1000, readonly:false}); 81 | //var db = new Sqlite('/tmp/testsql.db'); 82 | 83 | db.evaluate('drop table IF EXISTS foo;'); 84 | try { 85 | db.exec('drop table foo;', null); 86 | } catch(e) { 87 | //puts("OK"); 88 | }; 89 | 90 | db.evaluate('drop table IF EXISTS foo; create table foo(a,b);'); 91 | //db.evaluate('drop table IF EXISTS foo; create table foo(a,b);'); 92 | var n = 0; 93 | var x = 99; 94 | while (n++ < 3) { 95 | db.exec('insert into foo values(@x,@n);'); 96 | x -= 4; 97 | 98 | //db.exec('insert into foo values("x",' + n + ');'); 99 | } 100 | db.exec('select * from foo;', function (n) { 101 | puts("B="+n.b + ", A="+n.a); 102 | }); 103 | 104 | puts(db.exec('select * from foo;').toString()); 105 | 106 | db.exec('select * from foo;', null); 107 | 108 | puts("CONF: "+db.conf().toString()); 109 | db.profile(function(sql,time) { puts("EXECING: "+sql); }); 110 | 111 | puts(db.onecolumn('select a from foo where b == 2;')); 112 | var s = {}; 113 | s.b = 2; 114 | 115 | puts(db.exec('select * from foo;')); 116 | puts(db.exec('select * from foo;',{mode:'list'})); 117 | puts(db.exec('select * from foo;',{mode:'list',headers:true})); 118 | puts(db.exec('select * from foo;',{mode:'html'})); 119 | puts(db.exec('select * from foo;',{mode:'html',headers:true})); 120 | puts(db.exec('select * from foo;',{mode:'csv'})); 121 | puts(db.exec('select * from foo;',{mode:'csv',headers:true})); 122 | puts(db.exec('select * from foo;',{mode:'column'})); 123 | puts(db.exec('select * from foo;',{mode:'column',headers:true})); 124 | puts(x=db.exec('select * from foo;',{mode:'json'})); 125 | JSON.parse(x); 126 | puts(x=db.exec('select * from foo;',{mode:'json',headers:true})); 127 | JSON.parse(x); 128 | puts(x=db.exec('select * from foo;',{mode:'json2'})); 129 | JSON.parse(x); 130 | puts(db.exec('select * from foo;',{mode:'tabs'})); 131 | puts(db.exec('select * from foo;',{mode:'tabs',headers:true})); 132 | puts(db.exec('select * from foo;',{mode:'line'})); 133 | puts(db.exec('select * from foo;',{mode:'insert'})); 134 | 135 | db.func('bar',function(n) { return n+'.000'; }); 136 | 137 | 138 | db.trace(function(sql) { puts("TRACING: "+sql); }); 139 | puts(db.onecolumn('select bar(a) from foo where b == 2;')); 140 | puts(db.trace()); 141 | 142 | //puts(db.version()); 143 | delete db; 144 | 145 | 146 | /* 147 | var res1 = db.exec('select * from table foo(a,b);'); 148 | for (i in res1) { 149 | puts("CONS: "+i.toString()); 150 | } 151 | 152 | 153 | var curs, n; 154 | for (curs = db.exec('select * from table foo(a,b);'), 155 | (n = db.getresult(curs))!=undefined, 156 | db.nextresult(curs)) { 157 | puts(n.toString()); 158 | } 159 | db.endresult(curs); 160 | 161 | 162 | */ 163 | -------------------------------------------------------------------------------- /lib/parseOpts.jsi: -------------------------------------------------------------------------------- 1 | // Parse command line options. 2 | 3 | /* 4 | =!EXPECTSTART!= 5 | RC=1 { a:2, b:1, c:2 } 6 | RC=1 { a:3, b:1, c:2 } 7 | =!EXPECTEND!= 8 | */ 9 | 10 | 11 | /* Used for command line invocation with the --invoke/-i option, eg: 12 | jsish --invoke command -opt1 val1 -opt2 val2 ... arg1 arg2 ... 13 | which invokes: 14 | command([arg1,arg2,...],{opt1:val1,opt2:val2,...});*/ 15 | function jsi_invokeCmdOld(cmd, opts) { 16 | if (!opts) 17 | opts = console.args; 18 | var i, c = "", n = 1, astr = '', ostr, s0; 19 | for (i=0; opts && iExec 2 |
3 |

Description

4 | 5 | The method sys.exec(cmd?,option?) execute an operating system command and returns the result, eg. 6 | 7 |
  8 | sys.exec('ls -l');
  9 | sys.exec(['ls','-l','/tmp']);
 10 | sys.exec('ls -l > /tmp/ls.txt', false);
 11 | 
12 | 13 | A command pipeline is created with support for redirection. The input command is either an array, 14 | or a string which is split on the space char. Note, this means a string can have one, and only one, 15 | space between each token. 16 | 17 | A command ending in a single & is executed in the background (ie. no waiting). 18 | The second boolean argument if given as false means do not error-out on non-zero result code, 19 | and true means returned value is an object with data in the 'output' property. 20 |
21 |

Details

22 | 23 | This command treats its arguments as the specification of one or more UNIX commands to execute as 24 | subprocesses. The commands take the form of a standard shell pipeline; | arguments separate commands 25 | in the pipeline and cause standard output of the preceding command to be piped into standard input 26 | of the next command (or |& for both standard output and standard error). 27 | 28 | Under normal conditions the result of the exec command consists of the standard output produced 29 | by the last command in the pipeline. 30 | 31 | If any of the commands in the pipeline exit abnormally or are killed or suspended, 32 | then exec will return an error and the error message will include the pipeline’s output 33 | followed by error messages describing the abnormal terminations. 34 | 35 | If any of the commands writes to its standard error file, then exec will return an error, 36 | and the error message will include the pipeline’s output, followed by messages about abnormal 37 | terminations (if any), followed by the standard error output. 38 | 39 | If the last character of the result or error message is a newline then that character is deleted 40 | from the result or error message for consistency with normal Tcl return values. 41 | 42 | An arg may have one of the following special forms: 43 | 44 |
45 | 46 |
>filename
47 |
The standard output of the last command in the pipeline is redirected to the file. 48 | In this situation exec will normally return an empty string. 49 |
50 | 51 |
>>filename
52 |
As above, but append to the file. 53 |
54 | 55 |
>@fileId
56 |
The standard output of the last command in the pipeline is redirected to the given (writable) 57 | File object. In this situation exec will normally return an empty string. 58 |
59 | 60 |
2>filename
61 |
The standard error of the last command in the pipeline is redirected to the file. 62 |
63 | 64 |
2>>filename
65 |
As above, but append to the file. 66 | 67 |
2>@fileId
68 |
The standard error of the last command in the pipeline is redirected to the given (writable) File object. 69 |
70 | 71 |
2>@1
72 |
The standard error of the last command in the pipeline is redirected to the same file descriptor 73 | as the standard output. 74 |
75 | 76 |
>&filename
77 |
Both the standard output and standard error of the last command in the pipeline is redirected to the file. 78 |
79 | 80 |
>>&filename
81 |
As above, but append to the file. 82 |
83 | 84 |
<filename
85 |
The standard input of the first command in the pipeline is taken from the file. 86 |
87 | 88 |
<<string
89 |
The standard input of the first command is taken as the given immediate value. 90 |
91 | 92 |
<@fileId
93 |
The standard input of the first command in the pipeline is taken from the given (readable) file descriptor. 94 |
95 | 96 |
97 |
98 | 99 | If there is no redirection of standard input, standard error or standard output, these are connected 100 | to the corresponding input or output of the application. 101 | 102 | If the last arg is & then the command will be executed in background. In this case the standard output 103 | from the last command in the pipeline will go to the application’s standard output unless redirected 104 | in the command, and error output from all the commands in the pipeline will go to the application’s 105 | standard error file. The return value of exec in this case is a list of process ids (pids) in the pipeline. 106 | 107 | Each arg becomes one word for a command, except for |, <, <<, >, and & arguments, and 108 | the arguments that follow <, <<, and >. 109 | 110 | The first word in each command is taken as the command name; the directories in the PATH environment 111 | variable are searched for an executable by the given name. 112 | 113 | No glob expansion or other shell-like substitutions are performed on the arguments to commands. 114 | -------------------------------------------------------------------------------- /jsiPstate.c: -------------------------------------------------------------------------------- 1 | #ifndef JSI_LITE_ONLY 2 | #ifndef JSI_AMALGAMATION 3 | #include "jsiInt.h" 4 | #endif 5 | 6 | #define MAX_SCOPE (BUFSIZ/2) 7 | 8 | Jsi_ScopeStrs *jsi_ScopeStrsNew(struct jsi_Pstate *ps) 9 | { 10 | Jsi_ScopeStrs *ret = Jsi_Calloc(1, sizeof(*ret)); 11 | return ret; 12 | } 13 | 14 | void jsi_ScopeStrsPush(struct jsi_Pstate *ps, Jsi_ScopeStrs *ss, const char *string) 15 | { 16 | if (ss->count >= ss->_size) { 17 | ss->_size += 5; 18 | ss->strings = Jsi_Realloc(ss->strings, (ss->_size) * sizeof(char *)); 19 | } 20 | ss->strings[ss->count] = (char*)Jsi_KeyAdd(ps->interp, string); 21 | ss->count++; 22 | } 23 | 24 | static Jsi_ScopeStrs *strs_dup(struct jsi_Pstate *ps, Jsi_ScopeStrs *ss) 25 | { 26 | Jsi_ScopeStrs *n = jsi_ScopeStrsNew(ps); 27 | int i; 28 | if (!ss) return n; 29 | for (i = 0; i < ss->count; ++i) { 30 | jsi_ScopeStrsPush(ps, n, ss->strings[i]); 31 | } 32 | return n; 33 | } 34 | 35 | const char *jsi_ScopeStrsGet(Jsi_ScopeStrs *ss, int i) 36 | { 37 | if (i < 0 || i >= ss->count) return NULL; 38 | return ss->strings[i]; 39 | } 40 | 41 | void jsi_ScopeStrsFree(Jsi_ScopeStrs *ss) 42 | { 43 | if (!ss) return; 44 | Jsi_Free(ss->strings); 45 | Jsi_Free(ss); 46 | } 47 | 48 | /* lexical scope */ 49 | static Jsi_ScopeStrs *scopes[MAX_SCOPE]; 50 | static int cur_scope; 51 | 52 | void jsi_ScopePush(struct jsi_Pstate *ps) 53 | { 54 | Jsi_Interp *interp = ps->interp; 55 | if (cur_scope >= MAX_SCOPE - 1) Jsi_LogBug("Scope chain to short\n"); 56 | cur_scope++; 57 | } 58 | 59 | void jsi_ScopePop(struct jsi_Pstate *ps) 60 | { 61 | Jsi_Interp *interp = ps->interp; 62 | if (cur_scope <= 0) Jsi_LogBug("No more scope to pop\n"); 63 | jsi_ScopeStrsFree(scopes[cur_scope]); 64 | scopes[cur_scope] = NULL; 65 | cur_scope--; 66 | } 67 | 68 | void jsi_ScopeAddVar(jsi_Pstate *ps, const char *str) 69 | { 70 | int i; 71 | if (scopes[cur_scope] == NULL) scopes[cur_scope] = jsi_ScopeStrsNew(ps); 72 | 73 | for (i = 0; i < scopes[cur_scope]->count; ++i) { 74 | if (Jsi_Strcmp(str, scopes[cur_scope]->strings[i]) == 0) return; 75 | } 76 | jsi_ScopeStrsPush(ps, scopes[cur_scope], str); 77 | } 78 | 79 | Jsi_ScopeStrs *jsi_ScopeGetVarlist(jsi_Pstate *ps) 80 | { 81 | return strs_dup(ps, scopes[cur_scope]); 82 | } 83 | 84 | 85 | static int fastVarFree(Jsi_Interp *interp, void *ptr) { 86 | FastVar *fv = ptr; 87 | Jsi_Value *v = fv->var.lval; 88 | if (v) { 89 | //printf("FV FREE: %p (%d/%d)\n", fv, v->refCnt, v->vt == JSI_VT_OBJECT?v->d.obj->refcnt:-99); 90 | //Jsi_DecrRefCount(interp, v); 91 | } 92 | return JSI_OK; 93 | } 94 | 95 | jsi_Pstate *jsi_PstateNew(Jsi_Interp *interp) 96 | { 97 | Jsi_Value sval = VALINITS; 98 | jsi_Pstate *ps = Jsi_Calloc(1,sizeof(*ps)); 99 | SIGINIT(ps,PARSER); 100 | ps->lexer = Jsi_Calloc(1,sizeof(*ps->lexer)); 101 | ps->lexer->pstate = ps; 102 | ps->interp = interp; 103 | ps->last_exception = sval; 104 | ps->argsTbl = Jsi_HashNew(interp, JSI_KEYS_ONEWORD, jsi_ArglistFree); 105 | ps->fastVarTbl = Jsi_HashNew(interp, JSI_KEYS_ONEWORD, fastVarFree); 106 | ps->strTbl = Jsi_HashNew(interp, JSI_KEYS_STRING, NULL); 107 | return ps; 108 | } 109 | 110 | const char *jsi_PstateGetFilename(jsi_Pstate *ps) 111 | { 112 | Jsi_Interp *interp = ps->interp; 113 | return interp->curFile; 114 | } 115 | 116 | void jsi_PstateClear(jsi_Pstate *ps) 117 | { 118 | Lexer* l = ps->lexer; 119 | if (l->ltype == LT_FILE) 120 | { 121 | if (l->d.fp) 122 | Jsi_Close(l->d.fp); 123 | l->d.fp = NULL; 124 | } 125 | if (l->ltype == LT_STRING) 126 | { 127 | l->d.str = NULL; 128 | } 129 | l->ltype = LT_NONE; 130 | l->last_token = 0; 131 | l->cur_line = 1; 132 | l->cur_char = 0; 133 | l->cur = 0; 134 | ps->err_count = 0; 135 | } 136 | 137 | int jsi_PstateSetFile(jsi_Pstate *ps, Jsi_Channel fp, int skipbang) 138 | { 139 | Lexer *l = ps->lexer; 140 | jsi_PstateClear(ps); 141 | l->ltype = LT_FILE; 142 | l->d.fp = fp; 143 | Jsi_Rewind(fp); 144 | if (skipbang) { 145 | char buf[1000]; 146 | if (Jsi_Gets(fp, buf, 1000) && (buf[0] != '#' || buf[1] != '!')) { 147 | Jsi_Rewind(fp); 148 | } 149 | } 150 | 151 | return JSI_OK; 152 | } 153 | 154 | 155 | int jsi_PstateSetString(jsi_Pstate *ps, const char *str) 156 | { 157 | Jsi_Interp *interp = ps->interp; 158 | Lexer *l = ps->lexer; 159 | jsi_PstateClear(ps); 160 | l->ltype = LT_STRING; 161 | Jsi_HashEntry *hPtr = Jsi_HashEntryCreate(interp->codeTbl, (void*)str, NULL); 162 | assert(hPtr); 163 | l->d.str = Jsi_HashKeyGet(hPtr); 164 | return JSI_OK; 165 | } 166 | 167 | void jsi_PstateFree(jsi_Pstate *ps) 168 | { 169 | /* TODO: when do we free opcodes */ 170 | jsi_PstateClear(ps); 171 | Jsi_Free(ps->lexer); 172 | if (ps->opcodes) 173 | jsi_FreeOpcodes(ps->opcodes); 174 | if (ps->hPtr) 175 | Jsi_HashEntryDelete(ps->hPtr); 176 | Jsi_HashDelete(ps->argsTbl); 177 | Jsi_HashDelete(ps->strTbl); 178 | Jsi_HashDelete(ps->fastVarTbl); 179 | MEMCLEAR(ps); 180 | Jsi_Free(ps); 181 | } 182 | 183 | #endif 184 | -------------------------------------------------------------------------------- /www/buildjsi.wiki: -------------------------------------------------------------------------------- 1 | Building 2 |

Linux

3 | 4 | In order to build Jsi on Linux, a few packages need to be installed. 5 | On Ubuntu we do this: 6 | 7 |
  8 | sudo apt-get install build-essential bison cmake libreadline-dev
  9 | 
10 | 11 | Then just type make (in the jsi directory). 12 | 13 |

Build Options

14 | 15 | Jsi does not use configure. 16 | Instead, various build options are controled via make command-line options: 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
OptionDescription
EXTSRC=nameRoot name of a .c file to build in as a user extension
EXTNAME=nameUser extension name for above (if different)
NOSQLITE=1Exclude sqlite support
NOWEBSOCK=1Exclude websockets
USEMUSL=1Static, zero dependancy build with Musl-libc
USEMINIZ=1Use the miniz compression extension, instead of builtin -lz
WIN=1Cross-compile to Windows binary
ZIPDIR=nameDirectory to zip to end of binary jsiz (default dir is zdir)
29 |
30 | 31 | For example, the following builds without WebSockets : 32 | 33 |
 34 | make NOWEBSOCK=1
 35 | 
36 | 37 |

Windows

38 | 39 | To build for Windows, first install the Mingw32 package on Linux: 40 | 41 |
 42 | sudo apt-get install gcc-mingw32
 43 | 
44 | 45 | Jsi can be cross compiled to Windows using: 46 | 47 |
 48 | make WIN=1
 49 | 
50 | 51 | Note, you must do this twice, as it will initially fail. 52 | 53 | Note that some features (eg. signals) are currently disabled in the Windows build. 54 | There are also minor differences in some file-system access functions. 55 | 56 |

Static Build

57 | 58 | A static build is useful when you need a standalone executable with no external dependancies. 59 | 60 | To create a static image, Jsi uses the Musl library. 61 | 62 | The first step is to download [http://www.musl-libc.org|Musl] and unpack it. 63 | Then change to the musl dir and: 64 | 65 |
 66 |  ./configure --prefix=$HOME/usr && make install
 67 | 
68 | 69 | Ensure that ~/usr/bin is in your path with export PATH=$PATH:$HOME/usr/bin. 70 | Then back in the jsi dir do the following: 71 | 72 |
 73 | echo '#define __P(x) x' > ~/usr/include/sys/cdefs.h
 74 | echo '#include ' >  ~/usr/include/zlib.h
 75 | cp -pr miniz ~/usr/include/
 76 | 
77 | 78 | A static jsish can be built with: 79 | 80 |
 81 | make USEMUSL=1
 82 | 
83 | 84 | You must do this twice, as it will initially fail. 85 | The resulting executable will require no system libraries. 86 | 87 | 88 |

Basic Extension

89 | 90 | The following steps detail a simple way to add your own code to Jsi. Code is placed in the user directory, 91 | and make invoked with the EXTSRC=name argument. The named code gets linked into the Jsi build. 92 | Example 93 | 94 | The sample extension user/demo.c included with the Jsi distribution. 95 | It simply creates a new javascript method demo() that echo's its arguments. 96 | 97 |
 98 | #include "jsi.h"
 99 | 
100 | Jsi_CmdProcDecl(DemoCmd) {
101 |     int i, n = Jsi_ValueGetLength(interp, args);
102 |     printf("demo called with %d args\n", n);
103 |     for (i=0; i
117 | 
118 | To build this into the application:
119 | 
120 |   make EXTSRC=demo
121 | 
122 | 123 | 124 |

Multi-method Object Extension

125 | 126 | Sometimes in javascript it is desirable to create a new object with a number of related methods, 127 | rather than just single commands. This is achieved by registering a table of methods. 128 | 129 | The sample extension user/demos.c comes included with the 130 | Jsi distribution does this: 131 | 132 |
133 | #include "jsi.h"
134 | 
135 | Jsi_CmdProcDecl(DemoCmd) {
136 |     int i, n = Jsi_ValueGetLength(interp, args);
137 |     printf("demo called with %d args\n", n);
138 |     for (i=0; i
157 | To build this into the application:
158 | 
159 |     
160 | make EXTSRC=demos
161 | 
162 | 163 | This named code gets linked into the Jsi build. At startup it simply creates new javascript methods 164 | demos.foo() and demos.bar(). 165 | 166 | -------------------------------------------------------------------------------- /tools/mkref.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env jsish 2 | // Generate documentation for Jsi builtin cmds in fossil wiki format. 3 | 4 | function jsi_mkref() { 5 | 6 | function DumpOpts(opts, nam, isconf) { 7 | //if (cnam.indexOf('.')<0) cnam=cnam+'.conf'; 8 | var rv = '';//, opts = info.cmds(cnam).options; 9 | rv += '\n\n
\n'; 10 | rv += '

Options for "'+nam+'"

\n'; 11 | rv += "\nThe following options are available for \""+nam+"\"\n\n"; 12 | rv += "\n"; 13 | rv += "\n"; 14 | //puts(opts); 15 | for (var o in opts) { 16 | ci = opts[o]; 17 | if (isconf && ci.initOnly) continue; 18 | var help = (ci.help?ci.help+'.':''); 19 | if (ci.readOnly) help += " (readonly)"; 20 | if (ci.customArg && ci.customArg.data) 21 | help += ' '+ ci.customArg.data; 22 | rv += "\n'; 23 | } 24 | rv += "
Option Type Description Default
"+ci.name+""+ci.type+""+ help +""+ (ci.init?ci.init:'') +'
\n"; 25 | return rv; 26 | } 27 | 28 | function DumpCmd(cinf) { 29 | var rv = ''; 30 | var cnam = sprintf("%s(%s)", cinf.name, cinf.argStr); 31 | index += "
  • "+cnam+"
  • \n"; 32 | rv += '\n'; 33 | rv += '\n
    \n'; 34 | rv += 'Return to top\n'; 35 | rv += '\n\n

    '+cinf.name+'

    \n\n'; 36 | rv += sprintf("Synopsis: %s(%s)

    \n\n", cinf.name, cinf.argStr); 37 | if (cinf.help) 38 | rv += cinf.help+".\n\n"; 39 | if (cinf.info) 40 | rv += cinf.info+'\n\n'; 41 | if (cinf.options != NULL) { 42 | rv += DumpOpts(cinf.options, cinf.name, false); 43 | } 44 | rv += '\n'; 45 | return rv+'\n'; 46 | } 47 | function LinkOpts(astr,name) { 48 | var ii; 49 | if ((ii=astr.indexOf('options'))<0) 50 | return astr; 51 | var ss = ''; 52 | if (ii>0) 53 | ss += astr.slice(0, ii); 54 | ss += "options"; 55 | ss += astr.slice(ii+7); 56 | return ss; 57 | } 58 | 59 | function DumpObj(tinf) { 60 | var hasconf, ro = '', rv = '', ci, cnam = tinf.name, cmds = info.cmds(cnam+'.*'); 61 | index += "

  • "+cnam+"
  • \n"; 62 | rv += '\n'; 63 | rv += '\n
    \n'; 64 | rv += 'Return to top\n'; 65 | rv += '\n\n

    '+cnam+'

    \n\n'; 66 | rv += "Synopsis:"; 67 | if (tinf.constructor) { 68 | rv += 'new '+cnam+"("+tinf.argStr+")\n\n"; 69 | } else { 70 | rv += cnam+".method(...)\n\n"; 71 | } 72 | rv += "

    "; 73 | if (tinf.help) 74 | rv += tinf.help+".\n\n"; 75 | if (tinf.info) 76 | rv += tinf.info+'\n\n'; 77 | rv += '\n

    Methods

    \n'; 78 | rv += "\nThe following methods are available in \""+cnam+"\":\n\n"; 79 | rv += "\n"; 80 | rv += '\n'; 81 | if (tinf.constructor) { 82 | ci = info.cmds(cnam+'.'+cnam,true); 83 | var conhelp = (ci.help?ci.help+'.':''), aastr; 84 | if (ci.info) conhelp += ci.info; 85 | aastr = tinf.argStr; 86 | if (tinf.options) { 87 | aastr = LinkOpts(aastr, "new "+cnam); 88 | } 89 | rv += "\n'; 90 | } 91 | if (cmds !== undefined) { 92 | for (var cmd in cmds) { 93 | var nam = cmds[cmd].split('.')[1]; 94 | if (nam == cnam) 95 | continue; 96 | ci = info.cmds(cnam+'.'+nam); 97 | var conhelp = (ci.help?ci.help+'.':''); 98 | if (ci.info) conhelp += ' '+ci.info; 99 | if (ci.options) { 100 | ro += DumpOpts(ci.options, cnam+'.'+nam, (nam === 'conf')); 101 | aastr = LinkOpts(ci.argStr, cnam+'.'+nam); 102 | } else { 103 | aastr = ci.argStr; 104 | } 105 | //if (nam == 'conf') hasconf = ci.options; 106 | rv += "\n'; 107 | } 108 | } 109 | rv += "
    Method Description
    new "+cnam+"("+aastr+") "+conhelp+'
    "+nam+"("+aastr+") "+conhelp+'
    \n"; 110 | if (tinf.options) 111 | rv += DumpOpts(tinf.options, 'new '+cnam, (nam === 'conf')); 112 | rv += ro; 113 | rv += '\n'; 114 | return rv; 115 | } 116 | 117 | 118 | //*************** BEGIN MAIN ************** 119 | var rv = '', tinf, lst = info.cmds(); 120 | var vv = info.version(true); 121 | var ver = vv.major+'.'+vv.minor+'.'+vv.release; 122 | 123 | puts("Reference"); 124 | var index = "
      "; 125 | 126 | for (var i in lst) { 127 | tinf = info.cmds(lst[i]); 128 | switch (tinf.type) { 129 | case 'object': 130 | rv += DumpObj(tinf); 131 | break; 132 | case 'command': 133 | rv += DumpCmd(tinf); 134 | break; 135 | default: 136 | throw("bad id"); 137 | continue; 138 | } 139 | } 140 | rv += ""; 141 | index + "
    \n"; 142 | return '

    JSI Command Reference: version '+ver+'

    \n\n' + index + rv; 143 | } 144 | 145 | if (info.isInvoked()) { 146 | puts(jsi_mkref()); 147 | } 148 | --------------------------------------------------------------------------------