/ Check-in [18db6a96d4]
DEMO | DOWNLOAD | DEPLOY | SEARCH
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Release "2.8.38". Fix win/c++ build.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:18db6a96d4fc9665b12bb13432edf53d3a7e6140
User & Date: pmacdona 2019-07-01 22:32:36
Context
2019-07-02
22:30
Fix jsi.jsi bug check-in: 78045b0aa0 user: pmacdona tags: trunk
2019-07-01
22:32
Release "2.8.38". Fix win/c++ build. check-in: 18db6a96d4 user: pmacdona tags: trunk
2019-06-25
18:05
Do autoload of pwd/autoload.jsi check-in: a2e5903813 user: pmacdona tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to lib/Module.jsi.

18
19
20
21
22
23
24
25
26
27
28
29

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
    parseOpts(self, options, conf);
    
    function main() {
        LogDebug('Starting');
        if (self.rootdir === '')
            self.rootdir=Info.scriptDir();
        debugger;
        var fn = self.create;
        if (fn === '') {
            var lst = File.glob('/zvfs/lib/*'), rc = [];
            for (var i of lst) {
                var ft = File.tail(i), fr = File.rootname(ft), ext = File.extension(ft);

                if (File.isdir(i) && File.exists(i+'/'+fr+'.jsi'))
                    rc.push(fr);
                else if (ext === '.jsi' && ft !== 'Jsish.jsi' && ft !=='autoload.jsi')
                    rc.push(fr);
            }
            throw('missing required module name or builtin:\n    '+rc.sort().join(', ')+'\n');
        }
        var ext = File.extension(fn);
        if (ext !== '.jsi')
            fn += '.jsi';
        if (self.output !== '')
            fn = self.output;
        if (File.exists(fn)) {
            if (!self.force)
                throw('file exists: '+fn);







|



|
>







|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    parseOpts(self, options, conf);
    
    function main() {
        LogDebug('Starting');
        if (self.rootdir === '')
            self.rootdir=Info.scriptDir();
        debugger;
        var ext, fn = self.create;
        if (fn === '') {
            var lst = File.glob('/zvfs/lib/*'), rc = [];
            for (var i of lst) {
                var ft = File.tail(i), fr = File.rootname(ft);
                ext = File.extension(ft);
                if (File.isdir(i) && File.exists(i+'/'+fr+'.jsi'))
                    rc.push(fr);
                else if (ext === '.jsi' && ft !== 'Jsish.jsi' && ft !=='autoload.jsi')
                    rc.push(fr);
            }
            throw('missing required module name or builtin:\n    '+rc.sort().join(', ')+'\n');
        }
        ext = File.extension(fn);
        if (ext !== '.jsi')
            fn += '.jsi';
        if (self.output !== '')
            fn = self.output;
        if (File.exists(fn)) {
            if (!self.force)
                throw('file exists: '+fn);

Changes to lib/web/jsi.js.

1
2
3
4
5
6
7
8
9
10
11
12
13
14




























15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47













48
49
50
51
52
53
54
55
56
..
67
68
69
70
71
72
73

74
75

76
77
78
79
80
81
82
..
87
88
89
90
91
92
93
94
95







96
97
98
99
100
101
102
...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
...
143
144
145
146
147
148
149



















150
151
152
153
154
155
156
...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
...
174
175
176
177
178
179
180

181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225


226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
...
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273


274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
...
478
479
480
481
482
483
484

























































485
486
487
488
489
490
491
492
493

494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516

517
518





































































































519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
// jsi.js:  Typed function arguments. https://jsish.org/jsig
// Mostly emulates the builtin typechecking (sans return types) in Jsi.

(function () {
"use strict";

if (window) {
    var LogDebug = function(){},
    LogTrace = function(){},
    LogTest = function(){},
    LogWarn = console.warn.bind(console),
    LogError = console.error.bind(console);
}





























function parseError(msg) {
    errorCmd('PARSERR: '+msg+' ==> '+jsi._state.curSig);
    return [];
}

function errorCmd(msg) { // Handle error condition.
    jsi._state.errCnt++;
    switch (jsi._config.mode) {
        case 'error': if (console.error) console.error(msg); return;
        case 'throw': console.log(msg); throw(msg);
        case 'log': break;
        case 'alert': alert(msg); break;
        default: console.log('unknown mode: '+jsi._config.mode);
    }
    return console.log(msg);
}

function typeValidate(typ) {
    if (typ === '') return null;
    var tlst = typ.split('|');
    var i = -1;
    if (!jsi._state.typeNames)
        jsi._state.typeNames = jsi._state.typeNameStr.split(',');
    for (i = 0; i<tlst.length; i++)
        if (jsi._state.typeNames.indexOf(tlst[i])<0) {
            parseError("type unknown '"+tlst[i]+'" not one of: '+jsi._state.typeNameStr);
            return null;
        }
    if (tlst.length===1 && tlst[0] === 'any')
        return null;
    return tlst;
}














function SigParse(sig) { // Parse string signature and return info.
    jsi._state.curSig = sig;
    var reg = /^([a-zA-Z0-9_]*)\s*\(([^)]*)\)(:[\|a-z]+|)(\s*)$/;
    var vals = reg.exec(sig);
    var sargs = '';
    if (!vals)
        throw "invalid method: "+sig;
    LogTrace(vals);
    var fnam = vals[1];
................................................................................
        var last = alst.length-1;
        for (var i = 0; i<=last; i++) {
            var aval = alst[i].trim();
            if (aval === '...') {
                if (i != last)
                    return parseError("expected ... to be at end");
                maxargs = -1;

                minargs--;
                continue;

            }
            var rega = /^([a-zA-Z0-9_]+)(:[|a-z]+|)(=.+|)$/;
            var avals = rega.exec(aval);
            if (!avals)
                return parseError("invalid argument: "+aval);
            LogTrace(avals);
            if (i)
................................................................................
            sargs += afnam;
            var defval=undefined, atyp = '';
            if (avals.length>2)
                atyp = avals[2].substr(1);
            var tlst = typeValidate(atyp);
            var hasDef = (avals[3] && avals[3] !== '');
            if (hasDef) { // Default value
                if (avals[3] !== '=void')
                    defval = avals[3].substr(1);







                if (minargs===alst.length)
                    minargs = i;
            }
            else if (minargs!==alst.length)
                return parseError("non-default value follows default: "+aval+' in: '+str);
            acall.push({name:afnam, typ:tlst, def:defval});
        }
................................................................................
        if (!vals) {
            LogWarn("invalid method: "+str);
            return str;
        }
        LogTrace(vals);
        var fnam = vals[1];
        if (fnam !== '' && fnam[0] !== '_')
            jsi._state.funcLst.push(fnam);
        var someDflt = str.indexOf('=')>=0;
        if (str.indexOf(':')<0 && !someDflt) // Skip functions with no types or defaults
            return str;
        var res = 'function '+fnam+'(';
    
        var astr = vals[2].trim();
        if (astr === '')
................................................................................
        }

        return res;
    }
    var reg = /function\s*[a-zA-Z0-9_]*\s*\([^)]*\)(:[\|a-z]+|)\s*\{/g;
    return code.replace(reg, reMethod) + '\n<!--JSIG GEN-->';
}




















function fileext(fn) {
    var i = fn.lastIndexOf('.');
    if (i<0) return '';
    return fn.substr(i+1);
}

................................................................................
function addScript(fn, asData) { // Add script into page.
    var f=document.createElement('script');
    f.setAttribute("type","text/javascript");
    if (asData)
        f.innerHTML = fn;
    else {
        f.setAttribute("src", fn);
        jsi._state.srcCnt++;
        f.setAttribute("onload", "$jsi._state.srcCnt--;");
    }
    var h = document.querySelector("head");
    h.appendChild(f);
}

function errHandler(msg, url, lineNumber) {  
    //save error and send to server for example.
................................................................................
    $jsi.htmladd('<p style="color:red">'+msg+'</p>\n');
    //$jsi.htmladd(msg);
    return true;
}


var jsi = {

    _config: {
        mode:'error', 
        disabled:false,
        insert:false,
        inline:false,
        onload:null
    },
    _state:{ // Internal state information.
        typeNameStr:'number,string,boolean,array,function,object,regexp,any,userobj,void,null,undefined',
        typeNames:null,
        sigs:{},
        uuid:0,
        srcList:[],
        srcCnt:0,
        errCnt:0,
        errCur:null,
        funcLst:[]
    },
    setopts: function(obj, opts) { // Set options in object.
        for (var i in obj)
            if (opts[i] === undefined)
                throw("unknown option: "+i+' is not one of: '+Object.keys(opts).join(', '));
        for (var i in opts)
            if (obj[i] === undefined)
                obj[i] = opts[i];
        return obj;
    },

    conf: function(vals) { // Configure jsi options.



        if (!vals)
            return jsi._config;
        for (var i in vals) {
            var tt = typeof jsi._config[i];
            if (tt == 'undefined')
                errorCmd("Option "+i+" not one of: "+Object.keys(jsi._config).join(', '));
            else {
                switch (i) {
                    case 'mode':
                        var modes = ['error', 'log', 'throw', 'alert'];
                        if (modes.indexOf(vals[i])<0)
                            errorCmd('invalid mode '+vals[i]+': not one of: '+modes.join(','));
                        break;
                    case 'insert':
                        window.onerror = (vals[i]?errHandler:undefined);
                        break;


                }
                if (jsi._config[i] !== null && tt !== typeof vals[i])
                    errorCmd('type mismatch in conf of '+i+': '+tt+'!='+typeof vals[i]);
                jsi._config[i] = vals[i];
            }
        }
    },
    
    $jsig: function(sig, args) { // Check function arguments
        if (jsi._config.disabled)
            return;
            
        function ArgCheckType(o, aind, val) {
            var af = o.args[aind];
            var tlst = af.typ;
            if (!tlst) return;
            var nam = af.name;
            var vtyp = typeof(val);
            for (var i = 0; i<tlst.length; i++) {
                switch (tlst[i]) {
                    case "number":  if (vtyp === 'number') return; break;
                    case "string":  if (vtyp === 'string') return; break;
                    case "boolean": if (vtyp === 'boolean') return; break;
                    case "function":if (vtyp === 'function') return; break;
                    case "array":   if (vtyp === 'object' && val && val.constructor === Array) return; break;
................................................................................
                    case "regexp":  if (vtyp === 'object' && val && val.constructor === RegExp) return; break;
                    case "object":  if (vtyp === 'object' && val && val.constructor !== Array) return; break;
                    case "any":     return; break;
                    case "userobj": if (vtyp === 'object') return; break;
                    case "undefined": case "void": if (val === undefined) return; break;
                    case "null": if (val === null) return; break;
                    default:
                        errorCmd("type '"+tlst[i]+'" is unknown: not one of: '+jsi._state.typeNameStr);
                        return;
                }
            }
            return 'type mismatch for arg '+(aind+1)+' "'+nam+'" expected "'+tlst.join('|')+'" got "'+vtyp+'" '+val;
        }


        var o = sig;
        if (typeof sig === 'string') {
            o = jsi._state.sigs[sig];
            if (!o)
                o = jsi._state.sigs[sig] = SigParse(sig);        
        }
        if (typeof o !== 'object' || typeof args !== 'object')
            throw('bad sig or arguments:'+sig+args);


        
        var len = args.length, msg;
        var pre = 'In "'+o.name+'()" ';
        if (o.max>=0 && len>o.max)
            msg = "extra arguments: expected "+o.max+" got "+len;
        else if (len<o.min)
            msg = "missing arguments: expected "+o.min+" got "+len;
        for (var aind = 0; aind<args.length && !msg; aind++)
            msg = ArgCheckType(o, aind, args[aind]);
        if (msg) {
            msg+=': calling '+o.name+'('+o.astr+')'+o.retval;
            if (!jsi._config.inline)
                errorCmd(msg);
            jsi._state.errCur = msg;
        }
        return msg;
    },

    filesave: function(filename, data, mime) { // Save data as filename.

        var blob = new Blob([data], {type: (mime?mime:'text/html')});
        if(window.navigator.msSaveOrOpenBlob) {
            window.navigator.msSaveBlob(blob, filename);
        } else {
            var elem = window.document.createElement('a');
            elem.href = window.URL.createObjectURL(blob);
            elem.download = filename;
            document.body.appendChild(elem);
            elem.click();
            document.body.removeChild(elem);
        }
    },
    
    schema: function(obj, schm) { // Check schema, or generate when schm null/ommited.
        
        function gettype(m) {
            var typ = typeof m;
            if (m==='object' && Array === m.constructor)
                return 'array';
        }
                
        function gen(obj) {
            function sub(m,name) {
                var p, i, typ = gettype(m), rc = {type:typ};
                switch (typ) {
                    case 'integer':
                    case 'number':
                    case 'boolean':
                    case 'string':
                    case 'null':
                        break;
                    case 'array':
                        if (m[0]===undefined) throw('array must be non-empty '+name);
                        rc.items = sub(m[0], name);
                        break;
                    case 'object':
                        rc.properties = {};
                        var req = [];
                        for (i in m) {
                            rc.properties[i] = sub(m[i], i);
                            req.push(i);
                        }
                        if (req.length)
                            rc.required = req;
                        break;
                        
                    default:
                        console.log('ignoring unsupported type:', typ);
                }
                return rc;
            }
            return sub(obj,'');
        }
    
        function ref(ref, sch, s) {
            if (ref.substr(0,2) === '#/') {
                s = sch;
                ref = ref.substr(2);
            }
            var rlst = ref.split('/');
            for (var i in rlst)
                s = s[rlst[i]];
            return s;
        }

        function check(m, s, name) {
            if (m === undefined) throw('missing value: '+name);
            if (s === undefined) throw('missing schema for: '+name);
            var p, i, typ = gettype(m);
            switch (s.type) {
                case 'integer':
                case 'number':
                case 'string':
                case 'boolean':
                case 'null':
                    if (typ !== s.type) throw('type mismatch: '+typ+'!='+s.type+' at '+name);
                    break;
                case 'array':
                    if (typ !== s.type) throw('type mismatch: '+typ+'!='+s.type+' at '+name);
                    var nn = name+'[]';
                    for (i=0; i<m.length; i++)
                        check(m[i], s.items, name+'['+i+']');
                    break;
                case 'object':
                    var req = s.required;
                    if (req && req.length) {
                        for (p in req) {
                            i = req[p];
                            if (m[i] === undefined) throw('missing required value : "'+i+'" at '+name);
                        }
                    }
                    var keys = Object.keys(m);
                    if (keys.length===1 && keys[0] === '$ref')
                        m = ref(m[keys[0]], sch, s);
                    for (i in m) {
                        if (!m.hasOwnProperty(i)) continue;
                        var spi = s.properties[i];
                        if (!spi) throw('object property not in schema: "'+i+'" at '+name);
                        sub(m[i], spi, name+'.'+i);
                    }
                    break;
                    
                default:
                    throw('unsupported schema type '+s.type);
            }
        }
        if (schm === null || arguments.length==1)
            return gen(obj);
        check(obj, schm, '#');
    },

    guid: function() { // Return unique UUID
        if (!jsi._state.uuid)
            jsi._state.uuid = Date.now();
        return '_uuid'+(jsi._state.uuid++).toString(16);
    },
    ajax:function(opts) { // Ajax
        function none(){};
            
        opts = jsi.setopts(opts, {
            success:    null,
            error:      null,
            complete:   null,
................................................................................
        }
        default:
            throw('dataType not one of: json, jsonp, script, text');
        }
        return req;
    },
    

























































    include: function(fns) { // Dyanmic file include, uses ajax when jsish is not the webserver.
        if (typeof fns === 'string')
            fns = [fns];
        for (var i in fns) {
            var fn = fns[i];
            if (window.jsiWebSocket)
                return addScript(fn);
            jsi._state.srcList.push(fn);
            jsi._state.srcCnt++;

            jsi.ajax({url:fn,
                success: function(str, txt, req) {
                    jsi._state.srcCnt--;
                    LogDebug('Src Success: '+str);
                    var hdrs = req.getAllResponseHeaders();
                    if (!hdrs || hdrs.indexOf('jsiWebSocket')<0) {
                        str = SigConvert(str);
                        LogDebug('Src xlate: '+str);
                    }
                    addScript(str, true);
                    //eval.call({}, str);
                },
                error:function(str) {
                    jsi._state.srcCnt--;
                    LogWarn('Src Error: '+str);
                }
            });
        }
    },
    htmladd: function(str) { // Insert html into page.
        var f=document.createElement('div');
        f.innerHTML = str;
        var h = document.querySelector("body");

        h.appendChild(f);
    },





































































































    websock:function(prot) { // Create websocket connection.
        var url = document.URL.replace(/^http/,'ws');
        return new WebSocket(url, (prot?prot:'ws'));
    },
    
    onload: function(f) { // Set user function to invoke when page/files loaded.
        if (typeof f !== 'function') {
            throw('onload expects a function');
        }
        jsi._config.onload = f;
    },
    _main: function(f) { // Startup.
        if (jsi._state.srcCnt>0) {
            LogDebug("waiting for src");
            setTimeout("$jsi._main()", 1000);
            return;
        }
        var mode = location.search.match(/^\?jsi.mode=(.+)$/);
        if (mode && mode[1])
            jsi.conf({mode:mode[1]});
    
        if (jsi._config.onload)
            jsi._config.onload();
    }

};

if (window) {
    window['$jsi'] = jsi;
    window['$jsig']= jsi.$jsig;
    
    if (typeof window['puts'] === 'undefined')
        window['puts'] = console.log.bind(console);    
    if (typeof window['$'] === 'undefined')
        window['$'] = document.querySelectorAll.bind(document);
    if (typeof window['$$'] === 'undefined')
        window['$$'] = document.querySelector.bind(document);
    
    if (document.readyState !== 'loading')
        jsi._main();
    else
        document.addEventListener("DOMContentLoaded", function () {jsi._main();}, false); 
}

}());

|












>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|




|
|




|








|
|

|
|







>
>
>
>
>
>
>
>
>
>
>
>
>

|







 







>
|
<
>







 







|

>
>
>
>
>
>
>







 







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
|







 







>
|
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

<
>
>
>
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>
>
|
<
<
<
|
<
<
<

|




|


|







 







|









|

|

|
|
>
>











|

|




<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|






|
|
>


|










|





|
|
|
<
>
|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





<
<
<
<
<
<

|








|
|











|
<
<








1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
...
108
109
110
111
112
113
114
115
116

117
118
119
120
121
122
123
124
...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
...
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
...
242
243
244
245
246
247
248
249
250

251
























252

253
254
255
256















257
258
259



260



261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320






















































































































321
322
323
324
325
326
327
...
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484

485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593






594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617


618
619
620
621
622
623
624
625
// jsi.js:  Typed function arguments. https://jsish.org/jsig
// Implements  builtin typechecking (sans return types) in Jsi.

(function () {
"use strict";

if (window) {
    var LogDebug = function(){},
    LogTrace = function(){},
    LogTest = function(){},
    LogWarn = console.warn.bind(console),
    LogError = console.error.bind(console);
}

var config = {
    mode:'error', 
    disabled:false,
    insert:false,
    inline:false,
    onload:null
};
var state = { // Internal state information.
    typeNameStr:'number,string,boolean,array,function,object,regexp,any,userobj,void,null,undefined',
    typeNames:null,
    sigs:{},
    uuid:0,
    srcList:[],
    srcCnt:0,
    errCnt:0,
    errCur:null,
    funcLst:[]
};
    


function gettype(m) {
    var typ = typeof m;
    if (m==='object' && Array === m.constructor)
        return 'array';
    return typ;
}

function parseError(msg) {
    errorCmd('PARSERR: '+msg+' ==> '+jsi.state.curSig);
    return [];
}

function errorCmd(msg) { // Handle error condition.
    jsi.state.errCnt++;
    switch (jsi.config.mode) {
        case 'error': if (console.error) console.error(msg); return;
        case 'throw': console.log(msg); throw(msg);
        case 'log': break;
        case 'alert': alert(msg); break;
        default: console.log('unknown mode: '+jsi.config.mode);
    }
    return console.log(msg);
}

function typeValidate(typ) {
    if (typ === '') return null;
    var tlst = typ.split('|');
    var i = -1;
    if (!jsi.state.typeNames)
        jsi.state.typeNames = jsi.state.typeNameStr.split(',');
    for (i = 0; i<tlst.length; i++)
        if (jsi.state.typeNames.indexOf(tlst[i])<0) {
            parseError("type unknown '"+tlst[i]+'" not one of: '+jsi.state.typeNameStr);
            return null;
        }
    if (tlst.length===1 && tlst[0] === 'any')
        return null;
    return tlst;
}

function getType(val) {
    switch (val) {
        case 'true': case 'false': return 'boolean';
        case 'null': return 'null';
        case 'undefined': return 'undefined';
        default:
            if (val[0] === "'" || val[0] === '"')
                return 'string';
            if (parseFloat(val))
                return 'number';
    }
}

function SigParse(sig) { // Parse string signature and return info.
    jsi.state.curSig = sig;
    var reg = /^([a-zA-Z0-9_]*)\s*\(([^)]*)\)(:[\|a-z]+|)(\s*)$/;
    var vals = reg.exec(sig);
    var sargs = '';
    if (!vals)
        throw "invalid method: "+sig;
    LogTrace(vals);
    var fnam = vals[1];
................................................................................
        var last = alst.length-1;
        for (var i = 0; i<=last; i++) {
            var aval = alst[i].trim();
            if (aval === '...') {
                if (i != last)
                    return parseError("expected ... to be at end");
                maxargs = -1;
                if (minargs>0)
                    minargs--;

                break;
            }
            var rega = /^([a-zA-Z0-9_]+)(:[|a-z]+|)(=.+|)$/;
            var avals = rega.exec(aval);
            if (!avals)
                return parseError("invalid argument: "+aval);
            LogTrace(avals);
            if (i)
................................................................................
            sargs += afnam;
            var defval=undefined, atyp = '';
            if (avals.length>2)
                atyp = avals[2].substr(1);
            var tlst = typeValidate(atyp);
            var hasDef = (avals[3] && avals[3] !== '');
            if (hasDef) { // Default value
                if (avals[3] !== '=void') {
                    defval = avals[3].substr(1);
                    var defType = getType(defval);
                    if (defType)
                        if (tlst === null)
                            tlst = [defType];
                        else if (tlst.indexOf(defType)<0)
                            tlst.push(defType);
                }
                if (minargs===alst.length)
                    minargs = i;
            }
            else if (minargs!==alst.length)
                return parseError("non-default value follows default: "+aval+' in: '+str);
            acall.push({name:afnam, typ:tlst, def:defval});
        }
................................................................................
        if (!vals) {
            LogWarn("invalid method: "+str);
            return str;
        }
        LogTrace(vals);
        var fnam = vals[1];
        if (fnam !== '' && fnam[0] !== '_')
            jsi.state.funcLst.push(fnam);
        var someDflt = str.indexOf('=')>=0;
        if (str.indexOf(':')<0 && !someDflt) // Skip functions with no types or defaults
            return str;
        var res = 'function '+fnam+'(';
    
        var astr = vals[2].trim();
        if (astr === '')
................................................................................
        }

        return res;
    }
    var reg = /function\s*[a-zA-Z0-9_]*\s*\([^)]*\)(:[\|a-z]+|)\s*\{/g;
    return code.replace(reg, reMethod) + '\n<!--JSIG GEN-->';
}

function convertTest(s) {
    var rs = '', lst = s.split('\n');
    for (var i in lst) {
        var u, l = lst[i], len = l.length;
        if (l[0] == ';' && l[len-1]==';') {
            if (l[1]=='/' && l[2]=='/') {
                u = l.substr(3,len-4);
                rs += "puts(\""+u+"\" ==> \");";
                    + "try { puts(JSON.stringify("+u+")); puts('\\nFAIL!\\n'); } "
                    + "catch(err) { puts('\\nPASS!: err =',err); }\n";
            } else {
                u = l.substr(1,len-2);
                rs += "puts(\""+u+" ==> \"+JSON.stringify("+u+"));\n";
        }
        rs += '\n';
    }
    return rs;
}

function fileext(fn) {
    var i = fn.lastIndexOf('.');
    if (i<0) return '';
    return fn.substr(i+1);
}

................................................................................
function addScript(fn, asData) { // Add script into page.
    var f=document.createElement('script');
    f.setAttribute("type","text/javascript");
    if (asData)
        f.innerHTML = fn;
    else {
        f.setAttribute("src", fn);
        jsi.state.srcCnt++;
        f.setAttribute("onload", "$jsi.state.srcCnt--;");
    }
    var h = document.querySelector("head");
    h.appendChild(f);
}

function errHandler(msg, url, lineNumber) {  
    //save error and send to server for example.
................................................................................
    $jsi.htmladd('<p style="color:red">'+msg+'</p>\n');
    //$jsi.htmladd(msg);
    return true;
}


var jsi = {
    unittest:0,
    config:config,

    state:state,


























    $: function(sel, top) {
        if (typeof sel !== 'string') throw('expected string, got '+typeof sel);
        var rc;
        if (!top)















            top = document; 
        return top.querySelectorAll(sel);
    },



    



    $jsig: function(sig, args) { // Check function arguments
        if (jsi.config.disabled)
            return;
            
        function ArgCheckType(o, aind, val) {
            var af = o.args[aind];
            var tlst = (af?af.typ:null);
            if (!tlst) return;
            var nam = af.name;
            var vtyp = gettype(val);
            for (var i = 0; i<tlst.length; i++) {
                switch (tlst[i]) {
                    case "number":  if (vtyp === 'number') return; break;
                    case "string":  if (vtyp === 'string') return; break;
                    case "boolean": if (vtyp === 'boolean') return; break;
                    case "function":if (vtyp === 'function') return; break;
                    case "array":   if (vtyp === 'object' && val && val.constructor === Array) return; break;
................................................................................
                    case "regexp":  if (vtyp === 'object' && val && val.constructor === RegExp) return; break;
                    case "object":  if (vtyp === 'object' && val && val.constructor !== Array) return; break;
                    case "any":     return; break;
                    case "userobj": if (vtyp === 'object') return; break;
                    case "undefined": case "void": if (val === undefined) return; break;
                    case "null": if (val === null) return; break;
                    default:
                        errorCmd("type '"+tlst[i]+'" is unknown: not one of: '+jsi.state.typeNameStr);
                        return;
                }
            }
            return 'type mismatch for arg '+(aind+1)+' "'+nam+'" expected "'+tlst.join('|')+'" got "'+vtyp+'" '+val;
        }


        var o = sig;
        if (typeof sig === 'string') {
            o = jsi.state.sigs[sig];
            if (!o)
                o = jsi.state.sigs[sig] = SigParse(sig);        
        }
        if (typeof o !== 'object')
            throw('$jsig arg 1: bad sig:'+sig);
        if (typeof args !== 'object')
            throw('$jsig arg 2: expected arguments:'+args);
        
        var len = args.length, msg;
        var pre = 'In "'+o.name+'()" ';
        if (o.max>=0 && len>o.max)
            msg = "extra arguments: expected "+o.max+" got "+len;
        else if (len<o.min)
            msg = "missing arguments: expected "+o.min+" got "+len;
        for (var aind = 0; aind<args.length && !msg; aind++)
            msg = ArgCheckType(o, aind, args[aind]);
        if (msg) {
            msg+=': calling '+o.name+'('+o.astr+')'+o.retval;
            if (!jsi.config.inline)
                errorCmd(msg);
            jsi.state.errCur = msg;
        }
        return msg;
    },























































































































    ajax:function(opts) { // Ajax
        function none(){};
            
        opts = jsi.setopts(opts, {
            success:    null,
            error:      null,
            complete:   null,
................................................................................
        }
        default:
            throw('dataType not one of: json, jsonp, script, text');
        }
        return req;
    },
    
    conf: function(vals) { $jsig('conf(vals:object)', arguments);
        // Configure jsi options.
        if (!vals)
            return jsi.config;
        for (var i in vals) {
            var ti, tt = gettype(jsi.config[i]);
            if (tt == 'undefined')
                errorCmd("Option "+i+" not one of: "+Object.keys(jsi.config).join(', '));
            else {
                switch (i) {
                    case 'mode':
                        var modes = ['error', 'log', 'throw', 'alert'];
                        if (modes.indexOf(vals[i])<0)
                            errorCmd('invalid mode '+vals[i]+': not one of: '+modes.join(','));
                        break;
                    case 'insert':
                        window.onerror = (vals[i]?errHandler:undefined);
                        break;
                }
                if (jsi.config[i] !== null && tt !== (ti=gettype(vals[i])))
                    errorCmd('type mismatch in conf of '+i+': '+tt+'!='+ti);
                jsi.config[i] = vals[i];
            }
        }
    },
    
    filesave: function(filename, data, mime) {  $jsig("filename:string, data:string, mime='text/html'", arguments);
        // Save data as filename in browser.

        var blob = new Blob([data], {type: (mime?mime:'text/html')});
        if(window.navigator.msSaveOrOpenBlob) {
            window.navigator.msSaveBlob(blob, filename);
        } else {
            var elem = window.document.createElement('a');
            elem.href = window.URL.createObjectURL(blob);
            elem.download = filename;
            document.body.appendChild(elem);
            elem.click();
            document.body.removeChild(elem);
        }
    },
    
    guid: function() { // Return unique UUID.
        if (!jsi.state.uuid)
            jsi.state.uuid = Date.now();
        return '_uuid'+(jsi.state.uuid++).toString(16);
    },
    
    htmladd: function(str) { $jsig('htmladd(str:string)', arguments);
        // Insert html into page.
        var f=document.createElement('div');
        f.innerHTML = str;
        var h = document.querySelector("body");
        h.appendChild(f);
    },
    
    include: function(fns) { $jsig('include(fns:string|array)', arguments);
        // Dyanmic file include, uses ajax for .jsi files when jsish is not the webserver.
        if (typeof fns === 'string')
            fns = [fns];
        for (var i in fns) {
            var fn = fns[i];
            if (window.jsiWebSocket)
                return addScript(fn);
            jsi.state.srcList.push(fn);
            jsi.state.srcCnt++;
            //jsi.ajax({url:fn+'?id='+jsi.guid() ...});
            jsi.ajax({url:fn,
                success: function(str, txt, req) {
                    jsi.state.srcCnt--;
                    LogDebug('Src Success: '+str);
                    var hdrs = req.getAllResponseHeaders();
                    if (!hdrs || hdrs.indexOf('jsiWebSocket')<0) {
                        str = SigConvert(str);
                        LogDebug('Src xlate: '+str);
                    }
                    addScript(str, true);
                    //eval.call({}, str);
                },
                error:function(str) {
                    jsi.state.srcCnt--;
                    LogWarn('Src Error: '+str);
                }
            });
        }
    },
    onload: function(f) { // Set user function to invoke when page/files loaded.
        if (typeof f !== 'function') {
            throw('onload expects a function');

        }
        jsi.config.onload = f;
    },
    
    schema: function(obj, schm) { // Check object/json schema, or generate when schm null/ommited.
                        
        function gen(obj) {
            function sub(m,name) {
                var p, i, typ = gettype(m), rc = {type:typ};
                switch (typ) {
                    case 'number':
                    case 'boolean':
                    case 'string':
                    case 'null':
                        break;
                    case 'array':
                        if (m[0]===undefined) throw('array must be non-empty '+name);
                        rc.items = sub(m[0], name);
                        break;
                    case 'object':
                        rc.properties = {};
                        var req = [];
                        for (i in m) {
                            rc.properties[i] = sub(m[i], i);
                            req.push(i);
                        }
                        if (req.length)
                            rc.required = req;
                        break;
                        
                    default:
                        console.log('ignoring unsupported type:', typ);
                }
                return rc;
            }
            return sub(obj,'');
        }
    
        function ref(ref, sch, s) {
            if (ref.substr(0,2) === '#/') {
                s = sch;
                ref = ref.substr(2);
            }
            var rlst = ref.split('/');
            for (var i in rlst)
                s = s[rlst[i]];
            return s;
        }

        function check(m, s, name) {
            if (m === undefined) throw('missing value: '+name);
            if (s === undefined) throw('missing schema for: '+name);
            var p, i, typ = gettype(m);
            switch (s.type) {
                case 'number':
                case 'string':
                case 'boolean':
                case 'null':
                    if (typ !== s.type) throw('type mismatch: '+typ+'!='+s.type+' at '+name);
                    break;
                case 'array':
                    if (typ !== s.type) throw('type mismatch: '+typ+'!='+s.type+' at '+name);
                    var nn = name+'[]';
                    for (i=0; i<m.length; i++)
                        check(m[i], s.items, name+'['+i+']');
                    break;
                case 'object':
                    var req = s.required;
                    if (req && req.length) {
                        for (p in req) {
                            i = req[p];
                            if (m[i] === undefined) throw('missing required value : "'+i+'" at '+name);
                        }
                    }
                    var keys = Object.keys(m);
                    if (keys.length===1 && keys[0] === '$ref')
                        m = ref(m[keys[0]], sch, s);
                    for (i in m) {
                        if (!m.hasOwnProperty(i)) continue;
                        var spi = s.properties[i];
                        if (!spi) throw('object property not in schema: "'+i+'" at '+name);
                        sub(m[i], spi, name+'.'+i);
                    }
                    break;
                    
                default:
                    throw('unsupported schema type '+s.type);
            }
        }
        if (schm === null || arguments.length==1)
            return gen(obj);
        check(obj, schm, '#');
    },

    setopts: function(obj, opts) { // Set opts in obj and return.
        for (var i in obj)
            if (opts[i] === undefined)
                throw("unknown option: "+i+' is not one of: '+Object.keys(opts).join(', '));
        for (var i in opts)
            if (obj[i] === undefined)
                obj[i] = opts[i];
        return obj;
    },

    websock:function(prot) { // Create websocket connection.
        var url = document.URL.replace(/^http/,'ws');
        return new WebSocket(url, (prot?prot:'ws'));
    },
    






    _main: function(f) { // Startup.
        if (jsi.state.srcCnt>0) {
            LogDebug("waiting for src");
            setTimeout("$jsi._main()", 1000);
            return;
        }
        var mode = location.search.match(/^\?jsi.mode=(.+)$/);
        if (mode && mode[1])
            jsi.conf({mode:mode[1]});
    
        if (jsi.config.onload)
            jsi.config.onload();
    }

};

if (window) {
    window['$jsi'] = jsi;
    window['$jsig']= jsi.$jsig;
    
    if (typeof window['puts'] === 'undefined')
        window['puts'] = console.log.bind(console);    
    if (typeof window['$'] === 'undefined')
        window['$'] = $jsi.$;


    
    if (document.readyState !== 'loading')
        jsi._main();
    else
        document.addEventListener("DOMContentLoaded", function () {jsi._main();}, false); 
}

}());

Changes to md/Reference.md.

1642
1643
1644
1645
1646
1647
1648

1649
1650
1651
1652
1653
1654
1655
....
1759
1760
1761
1762
1763
1764
1765

1766
1767
1768
1769

1770
1771
1772
1773
1774
1775
1776
<tr><td>onCloseLast</td><td><i>FUNC</i></td><td>Function to call when last websock connection closes. On object delete arg is null. @function(ws:userobj|null)</td><td><i></i></td></tr>
<tr><td>onFilter</td><td><i>FUNC</i></td><td>Function to call on a new connection: return false to kill connection. @function(ws:userobj, id:number, url:string, ishttp:boolean)</td><td><i></i></td></tr>
<tr><td>onGet</td><td><i>FUNC</i></td><td>Function to call to server handle http-get. @function(ws:userobj, id:number, url:string, query:array)</td><td><i></i></td></tr>
<tr><td>onOpen</td><td><i>FUNC</i></td><td>Function to call when the websocket connection occurs. @function(ws:userobj, id:number)</td><td><i></i></td></tr>
<tr><td>onUnknown</td><td><i>FUNC</i></td><td>Function to call to server out content when no file exists. @function(ws:userobj, id:number, url:string, query:array)</td><td><i></i></td></tr>
<tr><td>onUpload</td><td><i>FUNC</i></td><td>Function to call handle http-post. @function(ws:userobj, id:number, filename:string, data:string, startpos:number, complete:boolean)</td><td><i></i></td></tr>
<tr><td>onRecv</td><td><i>FUNC</i></td><td>Function to call when websock data recieved. @function(ws:userobj, id:number, data:string)</td><td><i></i></td></tr>

<tr><td>port</td><td><i>INT</i></td><td>Port for server to listen on (8080).</td><td><i>initOnly</i></td></tr>
<tr><td>post</td><td><i>STRING</i></td><td>Post string to serve.</td><td><i>initOnly</i></td></tr>
<tr><td>protocol</td><td><i>STRKEY</i></td><td>Name of protocol (ws/wss).</td><td><i></i></td></tr>
<tr><td>realm</td><td><i>STRKEY</i></td><td>Realm for basic auth (jsish).</td><td><i></i></td></tr>
<tr><td>recvBufMax</td><td><i>INT</i></td><td>Size limit of a websocket message.</td><td><i>initOnly</i></td></tr>
<tr><td>recvBufTimeout</td><td><i>INT</i></td><td>Timeout for recv of a websock msg.</td><td><i>initOnly</i></td></tr>
<tr><td>redirMax</td><td><i>BOOL</i></td><td>Temporarily disable redirects when see more than this in 10 minutes.</td><td><i></i></td></tr>
................................................................................
</font><p>Console input and output to stderr.


<h2>Methods for "console"</h2>
<table border="1"class="cmdstbl table">
<tr><th>Method</th><th>Prototype</th><th>Description</th></tr>
<tr><td>assert</td><td>assert(expr:boolean|number|function, msg:string=void, <a href='#console.assertOptions'>options</a>:object=void):void </td><td>Same as System.assert().</td></tr>

<tr><td>input</td><td>input():string|void </td><td>Read input from the console.</td></tr>
<tr><td>log</td><td>log(val, ...):void </td><td>Same as System.puts, but goes to stderr and includes file:line.</td></tr>
<tr><td>printf</td><td>printf(format:string, ...):void </td><td>Same as System.printf but goes to stderr.</td></tr>
<tr><td>puts</td><td>puts(val, ...):void </td><td>Same as System.puts, but goes to stderr.</td></tr>

</table>


<a name="console.assertOptions"></a>
<a name="console.confOptions"></a>
<h2>Options for "console.assert"</h2>
<table border="1" class="optstbl table">







>







 







>




>







1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
....
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
<tr><td>onCloseLast</td><td><i>FUNC</i></td><td>Function to call when last websock connection closes. On object delete arg is null. @function(ws:userobj|null)</td><td><i></i></td></tr>
<tr><td>onFilter</td><td><i>FUNC</i></td><td>Function to call on a new connection: return false to kill connection. @function(ws:userobj, id:number, url:string, ishttp:boolean)</td><td><i></i></td></tr>
<tr><td>onGet</td><td><i>FUNC</i></td><td>Function to call to server handle http-get. @function(ws:userobj, id:number, url:string, query:array)</td><td><i></i></td></tr>
<tr><td>onOpen</td><td><i>FUNC</i></td><td>Function to call when the websocket connection occurs. @function(ws:userobj, id:number)</td><td><i></i></td></tr>
<tr><td>onUnknown</td><td><i>FUNC</i></td><td>Function to call to server out content when no file exists. @function(ws:userobj, id:number, url:string, query:array)</td><td><i></i></td></tr>
<tr><td>onUpload</td><td><i>FUNC</i></td><td>Function to call handle http-post. @function(ws:userobj, id:number, filename:string, data:string, startpos:number, complete:boolean)</td><td><i></i></td></tr>
<tr><td>onRecv</td><td><i>FUNC</i></td><td>Function to call when websock data recieved. @function(ws:userobj, id:number, data:string)</td><td><i></i></td></tr>
<tr><td>pathAliases</td><td><i>OBJ</i></td><td>Path alias lookups.</td><td><i>initOnly</i></td></tr>
<tr><td>port</td><td><i>INT</i></td><td>Port for server to listen on (8080).</td><td><i>initOnly</i></td></tr>
<tr><td>post</td><td><i>STRING</i></td><td>Post string to serve.</td><td><i>initOnly</i></td></tr>
<tr><td>protocol</td><td><i>STRKEY</i></td><td>Name of protocol (ws/wss).</td><td><i></i></td></tr>
<tr><td>realm</td><td><i>STRKEY</i></td><td>Realm for basic auth (jsish).</td><td><i></i></td></tr>
<tr><td>recvBufMax</td><td><i>INT</i></td><td>Size limit of a websocket message.</td><td><i>initOnly</i></td></tr>
<tr><td>recvBufTimeout</td><td><i>INT</i></td><td>Timeout for recv of a websock msg.</td><td><i>initOnly</i></td></tr>
<tr><td>redirMax</td><td><i>BOOL</i></td><td>Temporarily disable redirects when see more than this in 10 minutes.</td><td><i></i></td></tr>
................................................................................
</font><p>Console input and output to stderr.


<h2>Methods for "console"</h2>
<table border="1"class="cmdstbl table">
<tr><th>Method</th><th>Prototype</th><th>Description</th></tr>
<tr><td>assert</td><td>assert(expr:boolean|number|function, msg:string=void, <a href='#console.assertOptions'>options</a>:object=void):void </td><td>Same as System.assert().</td></tr>
<tr><td>error</td><td>error(val, ...):void </td><td>Same as log.</td></tr>
<tr><td>input</td><td>input():string|void </td><td>Read input from the console.</td></tr>
<tr><td>log</td><td>log(val, ...):void </td><td>Same as System.puts, but goes to stderr and includes file:line.</td></tr>
<tr><td>printf</td><td>printf(format:string, ...):void </td><td>Same as System.printf but goes to stderr.</td></tr>
<tr><td>puts</td><td>puts(val, ...):void </td><td>Same as System.puts, but goes to stderr.</td></tr>
<tr><td>warn</td><td>warn(val, ...):void </td><td>Same as log.</td></tr>
</table>


<a name="console.assertOptions"></a>
<a name="console.confOptions"></a>
<h2>Options for "console.assert"</h2>
<table border="1" class="optstbl table">

Changes to md/jsi.js.md.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
..
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

59
60
61
62



63
64









65
66
67
68
69
70
71
..
75
76
77
78
79
80
81
82
83

84
85

86


87
88


89
90
91





92


93
94
95



96
97



98
99



100

101
102
103
104

105

106



jsi.js
====

<div id="sectmenu"></div>
The javascript package [jsi.js](/file/lib/web/jsi.js) supports (among other things)
type-checking of function arguments in the browser.

$jsig: ƒ (sig, args)
----
Function argument [type-checking](Types.md) is provided by **$jsig**:

    <script src="/jsi/web/jsi.js"></script>
    <script>
    function bark(s, n) { $jsig('bark(s:string, n:number)', arguments);
       console.log("BARK: "+s);
    }
    </script>


### Pre-process

More convenient is to use preprocessed **.jsi** files, as seen in action [here](../js-demos/jsig.html):

    // FILE: bark.jsi
    function bark(s:string, n:number) {
       console.log("BARK: "+s);
    }

used like so:

    <script src="/jsi/web/jsi.js"></script>
    <script>
        $jsi.include('bark.jsi');
        $jsi.onload(function() {
            bark('abc',0);
            bark(9,0);
................................................................................
            bark('9','0');
            bark(9);
            bark(9,0,0);
        });
        
    </script>

which outputs to the console:

    BARK: abc
    jsi.js:23 type mismatch for arg 1 "s" expected "string" got "number" 9: calling bark(s:string, n:number)
    BARK: 9
    jsi.js:23 type mismatch for arg 2 "n" expected "number" got "string" 0: calling bark(s:string, n:number)
    BARK: 9
    jsi.js:23 missing arguments: expected 2 got 1: calling bark(s:string, n:number)
    BARK: 9
    jsi.js:23 extra arguments: expected 2 got 3: calling bark(s:string, n:number)
    BARK: 9

### Server-side

When using **jsish** as the web server, **.jsi** files will already be preprocessed,
making **include** unnecessary, eg.


    <script src="/jsi/web/jsi.js"></script>
    <script src="bark.js"></script>





ajax: ƒ (opts)









----

Compatiable with a subset of JQuery **ajax**.  Supported opts are:

Option    | Default | Description
----------|---------|-----
success   | none    | Called on success
................................................................................
dataType  | 'text'  | One of json, jsonp, script, text.
data      | {}      | Query data.
headers   | {}      | Headers to pass
async     | true    | Is asyncronous
url       | null    | Url of resources


conf: ƒ (vals)
----


filesave: ƒ (filename, data, mime)

----


guid: ƒ ()
----


htmladd: ƒ (str)
----
include: ƒ (fns)





----


onload: ƒ (f)
----
schema: ƒ (obj, schm)



----
setopts: ƒ (obj, opts)



----
websock: ƒ (prot)



----


Globals
====
$jsi

----

$







|
|
<
<
<
<




|

<
|
>
|

|

|




|







 







|











<

<
<
>




>
>
>

<
>
>
>
>
>
>
>
>
>







 







|

>

<
>

>
>
|

>
>
|

<
>
>
>
>
>

>
>
|

<
>
>
>

<
>
>
>

<
>
>
>

>

<
<
<
>

>
|
>
>
>
1
2
3
4
5
6




7
8
9
10
11
12

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
..
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

51


52
53
54
55
56
57
58
59
60

61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
..
80
81
82
83
84
85
86
87
88
89
90

91
92
93
94
95
96
97
98
99
100

101
102
103
104
105
106
107
108
109
110

111
112
113
114

115
116
117
118

119
120
121
122
123
124



125
126
127
128
129
130
131
jsi.js
====

<div id="sectmenu"></div>
[jsi.js](/file/lib/web/jsi.js) provides [type-checking](Types.md) for
javascript function arguments, eg:





    <script src="/jsi/web/jsi.js"></script>
    <script>
    function bark(s, n) { $jsig('bark(s:string, n:number)', arguments);
       console.log("BARK: "+s+n);
    }

    
    bark('husky',2);
    </script>

Alternatively, signature arguments can be preprocessed ([example](../js-demos/jsig.html)):

    // bark.jsi
    function bark(s:string, n:number) {
       console.log("BARK: "+s);
    }

loaded via **include()**:

    <script src="/jsi/web/jsi.js"></script>
    <script>
        $jsi.include('bark.jsi');
        $jsi.onload(function() {
            bark('abc',0);
            bark(9,0);
................................................................................
            bark('9','0');
            bark(9);
            bark(9,0,0);
        });
        
    </script>

Mismatches are output to the console:

    BARK: abc
    jsi.js:23 type mismatch for arg 1 "s" expected "string" got "number" 9: calling bark(s:string, n:number)
    BARK: 9
    jsi.js:23 type mismatch for arg 2 "n" expected "number" got "string" 0: calling bark(s:string, n:number)
    BARK: 9
    jsi.js:23 missing arguments: expected 2 got 1: calling bark(s:string, n:number)
    BARK: 9
    jsi.js:23 extra arguments: expected 2 got 3: calling bark(s:string, n:number)
    BARK: 9





Or use the **jsish** web server to preprocess **.jsi** files:

    <script src="/jsi/web/jsi.js"></script>
    <script src="bark.js"></script>

$jsi
====
The **$jsi** object contains the following commands:


$(selector:string, top:string=void)
----
Jquery-like querySelectorAll functionality.

$jsig(sig:string, args:array)
----
Type checks function arguments. This function is also global: **$jsig** or **$jsi.$jsig**.

ajax(options:object)
----

Compatiable with a subset of JQuery **ajax**.  Supported opts are:

Option    | Default | Description
----------|---------|-----
success   | none    | Called on success
................................................................................
dataType  | 'text'  | One of json, jsonp, script, text.
data      | {}      | Query data.
headers   | {}      | Headers to pass
async     | true    | Is asyncronous
url       | null    | Url of resources


conf(vals:object)
----
Configure jsi options.


filesave(filename:string, data:string, mime='text/html')
----
Save data as filename in browser.

guid()
----
Return unique UUID.

htmladd(str:string)
----

Insert html into page.

    $jsi.htmladd('<b>Hello World</b>');

include(fns:string|array)
----
Dyanmic file include, uses ajax for .jsi files when jsish is not the webserver.

onload(f:function)
----

Function to invoke after page is loaded and all **include** processing is complete.

puts(str:string,...)
----

A bind alias for console.log.

schema(obj:object, schm:object=null)
----

Check object/json schema, or generate when schm null/ommited.

setopts(obj:object, opts:object)
----
Set opts in obj and return.




websock(prot='ws')
----
Open new websocket.

Details
====
Aside from **$jsi**, the following are global: **$jsig**, **$**, **puts**.

Changes to src/jsi.c.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
....
7469
7470
7471
7472
7473
7474
7475

7476

7477
7478
7479
7480
7481
7482
7483
.....
16159
16160
16161
16162
16163
16164
16165
16166
16167
16168
16169
16170
16171
16172
16173
.....
18669
18670
18671
18672
18673
18674
18675










18676
18677
18678
18679
18680
18681
18682
.....
20590
20591
20592
20593
20594
20595
20596
20597
20598
20599
20600
20601
20602
20603
20604
.....
20684
20685
20686
20687
20688
20689
20690
20691
20692
20693
20694
20695
20696
20697
20698
.....
34860
34861
34862
34863
34864
34865
34866
34867
34868
34869
34870
34871
34872
34873
34874
34875
34876
34877

34878
34879



34880
34881
34882
34883
34884
34885
34886
.....
38718
38719
38720
38721
38722
38723
38724

38725
38726
38727
38728

38729
38730
38731
38732
38733
38734
38735
.....
39561
39562
39563
39564
39565
39566
39567
39568
39569
39570
39571
39572
39573
39574
39575
.....
43383
43384
43385
43386
43387
43388
43389

43390
43391

43392
43393
43394
43395
43396
43397
43398
.....
52791
52792
52793
52794
52795
52796
52797
52798
52799
52800
52801
52802
52803
52804
52805
.....
52807
52808
52809
52810
52811
52812
52813
52814
52815
52816
52817
52818
52819
52820
52821
.....
52990
52991
52992
52993
52994
52995
52996

52997
52998
52999
53000
53001
53002
53003
.....
53593
53594
53595
53596
53597
53598
53599





































53600
53601
53602
53603
53604
53605
53606
.....
53720
53721
53722
53723
53724
53725
53726
53727
53728
53729
53730
53731
53732
53733
53734
53735
53736
53737
53738
53739
53740
53741
53742
53743
53744
53745

53746
53747
53748
53749
53750
53751
53752
.....
53928
53929
53930
53931
53932
53933
53934

53935
53936
53937
53938
53939
53940
53941
.....
68826
68827
68828
68829
68830
68831
68832


68833
68834
68835
68836
68837
68838
68839
.....
69067
69068
69069
69070
69071
69072
69073





69074
69075
69076
69077
69078
69079
69080
.....
69123
69124
69125
69126
69127
69128
69129
69130
69131
69132
69133
69134
69135
69136
69137
69138
69139
.....
69156
69157
69158
69159
69160
69161
69162
69163
69164
69165
69166
69167
69168
69169
69170
69171
69172
.....
70519
70520
70521
70522
70523
70524
70525
70526
70527
70528
70529
70530
70531
70532
70533
.....
70566
70567
70568
70569
70570
70571
70572
70573
70574
70575
70576
70577
70578
70579
70580
70581
70582
70583
70584
70585
70586
70587
.....
70751
70752
70753
70754
70755
70756
70757
70758
70759
70760
70761
70762
70763
70764
70765
70766
70767
70768
/* jsi.h : External API header file for Jsi. */
#ifndef __JSI_H__
#define __JSI_H__

#define JSI_VERSION_MAJOR   2
#define JSI_VERSION_MINOR   8
#define JSI_VERSION_RELEASE 37

#define JSI_VERSION (JSI_VERSION_MAJOR + ((Jsi_Number)JSI_VERSION_MINOR/100.0) + ((Jsi_Number)JSI_VERSION_RELEASE/10000.0))

#ifndef JSI_EXTERN
#define JSI_EXTERN extern
#endif

................................................................................
#ifndef JSI__INFO
#define JSI__INFO 1
#endif
#ifndef JSI__CDATA
#define JSI__CDATA 1
#endif
#ifndef JSI__SOCKET

#define JSI__SOCKET 1

#endif
#ifndef JSI__MATH
#define JSI__MATH 1
#endif
#ifndef JSI__UTF8
#define JSI__UTF8 1
#endif
................................................................................
    }
done:
    if (buf != unibuf)
        Jsi_Free(buf);
    lex->inStr = 0;
    if (!ret)
        return NULL;
    Jsi_String *s = Jsi_Calloc(1, sizeof(*s));
    s->str = ret;
    s->len = bufi;
    s->flags = flags;
    Jsi_HashSet(lex->pstate->strTbl, s, s);
    return s;
}

................................................................................
                    break;
                case JSI_OT_BOOL:
                    cp = "Boolean";
                    break;
                case JSI_OT_STRING:
                    cp = "String";
                    break;










                default:
                    Jsi_ValueMakeUndef(interp, ret);
                    return *ret;
            }
            v = Jsi_ValueObjLookup(interp, interp->csc, cp, 0);
            if (v==NULL || v->vt != JSI_VT_OBJECT)
                return NULL;
................................................................................
    return JSI_OK;
}

Jsi_Interp* Jsi_Main(Jsi_InterpOpts *opts)
{
    int rc = 0;
    Jsi_Interp* interp = NULL;
    int argc = 0;
    char **argv = NULL;
    if (opts) {
        interp = opts->interp;
        argc = opts->argc;
        argv = opts->argv;
    }
    if (!interp)
................................................................................
          "  -W\t\tWebsrv: web server to serve out content.\n"
          "\nInterp options may also be set via the environment eg. JSI_INTERP_OPTS='{coverage:true}'\n"
           );
        return jsi_DoExit(interp, 1);
    }
    if (!Jsi_Strcmp(ai1, "-version"))
        ai1 = "-v";
    int first = 1;
    if (ai1[0] == '-') {
        switch (ai1[1]) {
            case 'a':
                rc = Jsi_EvalString(interp, "runModule('Archive');", JSI_EVAL_ISMAIN);
                break;
            case 'c':
                rc = Jsi_EvalString(interp, "runModule('Cdata');", JSI_EVAL_ISMAIN);
................................................................................
        Jsi_DecrRefCount(interp, fpath);
    if (rc == JSI_ERROR && needErr)
        Jsi_LogError("within require('%s') in file: %s", name, Jsi_DSValue(&dStr));
    Jsi_DSFree(&dStr);
    return rc;
}

// Load package from pkgDirs or executable path.  Note. ver is unused.
static Jsi_RC jsi_PkgLoad(Jsi_Interp *interp, const char *name, Jsi_Number ver) {
    Jsi_RC rc;
    const char *cp = NULL, *path;
    int len;
    uint i;
    Jsi_Value *fval = NULL;
    Jsi_Value *pval = interp->pkgDirs;
    if (pval) {
        Jsi_Obj* obj = pval->d.obj;
        

        for (i=0; i<obj->arrCnt; i++) {
            rc = jsi_PkgLoadOne(interp, name, Jsi_ValueString(interp, obj->arr[i], NULL), -1, &fval, ver);



            if (rc != JSI_CONTINUE)
                goto done;
        }
    }
    // Check executable dir.
    path = jsiIntData.execName;
    if (path)
................................................................................
        }
    }
    return rc;
}

static Jsi_CmdSpec consoleCmds[] = {
    { "assert", jsi_AssertCmd,      1,  3, "expr:boolean|number|function, msg:string=void, options:object=void",  .help="Same as System.assert()", .retType=(uint)JSI_TT_VOID, .flags=0, .info=0, .opts=AssertOptions},

    { "input",  consoleInputCmd,    0,  0, "", .help="Read input from the console", .retType=(uint)JSI_TT_STRING|JSI_TT_VOID },
    { "log",    consoleLogCmd,      1, -1, "val, ...", .help="Same as System.puts, but goes to stderr and includes file:line", .retType=(uint)JSI_TT_VOID, .flags=0 },
    { "printf", consolePrintfCmd,   1, -1, "format:string, ...", .help="Same as System.printf but goes to stderr", .retType=(uint)JSI_TT_VOID, .flags=0 },
    { "puts",   consolePutsCmd,     1, -1, "val, ...", .help="Same as System.puts, but goes to stderr", .retType=(uint)JSI_TT_VOID, .flags=0 },

    { NULL, 0,0,0,0,  .help="Console input and output to stderr" }
};

#ifndef JSI_OMIT_EVENT
static Jsi_CmdSpec eventCmds[] = {
    { "clearInterval",clearIntervalCmd, 1,  1, "id:number", .help="Delete an event (created with setInterval/setTimeout)", .retType=(uint)JSI_TT_VOID },
    { "info",       eventInfoCmd,       1,  1, "id:number", .help="Return info for the given event id", .retType=(uint)JSI_TT_OBJECT },
................................................................................
    else if (p == path) {
        Jsi_ValueMakeStringKey(interp, ret, "/");
    }
#if defined(__MINGW32__) || defined(_MSC_VER)
    else if (p[-1] == ':') {
        int olen = -1;
        char *ostr = jsi_SubstrDup(path, -1, 0, p-path+1, &olen);
        Jsi_ValueMakeString(interp, ret, (uchar*)ostr, olen);
    }
#endif
    else {
        int olen = -1;
        char *ostr = jsi_SubstrDup(path, -1, 0, p-path, &olen);
        Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
    }
................................................................................
    return JSI_OK;
}

static Jsi_RC MathSrandCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    Jsi_Number n = 0;

    Jsi_GetNumberFromValue(interp, Jsi_ValueArrayIndex(interp, args, 0), &n);
    srand48((long)n);

    jsi_SrandInit = 1;
    Jsi_ValueMakeNumber(interp, ret, n);
    return JSI_OK;
}

MFUNC1(MathAbsCmd,  fabs)
MFUNC1(MathAcosCmd, acos)
................................................................................

typedef struct { /* Per server (or client) data. */
    uint sig;
    Jsi_Interp *interp;
    ws_ObjCmd *_;
    Jsi_Hash *pssTable;
    Jsi_Value *onAuth, *onCloseLast, *onClose, *onFilter, *onOpen, *onRecv,
        *onUpload, *onGet, *onUnknown,
        *rootdir, *interface, *address, *mimeTypes, *extArgs, *headers;
    bool client, noUpdate, noWebsock, noWarn, use_ssl, local, extHandlers, handlersPkg, inUpdate, noCompress, noConfig, echo;
    Jsi_Value* version;
    int idx;
    int port;
    int maxUpload;
    int maxDownload;
................................................................................
    jsi_wsStatData stats;
    char *iface;
    const char* urlPrefix, *urlRedirect;
    const char *localhostName;
    const char *clientName;
    const char *clientIP;
    const char *useridPass, *server;
    const char *realm, *includeFile, *jsiFnPattern;
    struct lws_context *instCtx;
    Jsi_Value *getRegexp, *post;
    unsigned int oldus;
    int opts;
    int hasOpts;
    int debug;
    int maxConnects;
................................................................................
    JSI_OPT(FUNC,   jsi_wsCmdObj, onCloseLast,.help="Function to call when last websock connection closes. On object delete arg is null", .flags=0, .custom=0, .data=(void*)"ws:userobj|null"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onFilter,   .help="Function to call on a new connection: return false to kill connection", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, url:string, ishttp:boolean"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onGet,      .help="Function to call to server handle http-get", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, url:string, query:array"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onOpen,     .help="Function to call when the websocket connection occurs", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onUnknown,  .help="Function to call to server out content when no file exists", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, url:string, query:array"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onUpload,   .help="Function to call handle http-post", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, filename:string, data:string, startpos:number, complete:boolean"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onRecv,     .help="Function to call when websock data recieved", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, data:string"),

    JSI_OPT(INT,    jsi_wsCmdObj, port,       .help="Port for server to listen on (8080)", jsi_IIOF),
    JSI_OPT(STRING, jsi_wsCmdObj, post,       .help="Post string to serve", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, protocol,   .help="Name of protocol (ws/wss)"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, realm,      .help="Realm for basic auth (jsish)", ),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufMax, .help="Size limit of a websocket message", jsi_IIOF),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufTimeout,.help="Timeout for recv of a websock msg", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, redirMax,   .help="Temporarily disable redirects when see more than this in 10 minutes"),
................................................................................
        if (*cs == '\n')
            cs++;
    }
    Jsi_DSFree(&tStr);
    return rc;

}






































// Handle http GET/POST
static int jsi_wsHttp(Jsi_Interp *interp, jsi_wsCmdObj *cmdPtr, struct lws *wsi, void *user,
    struct lws_context *context, const char* inPtr, Jsi_DString *tStr, jsi_wsPss *pss)
{
    const char *ext = NULL;
    unsigned char buffer[JSI_BUFSIZ];
................................................................................
            }
        }
    }
    ext = Jsi_Strrchr(inPtr, '.');

    Jsi_Value *rdir = (pss->rootdir?pss->rootdir:cmdPtr->rootdir);
    cmdPtr->curRoot = (rdir?Jsi_ValueString(cmdPtr->interp, rdir, NULL):"./");
    char statPath[PATH_MAX];
    if (!Jsi_Strncmp(inPtr, "/jsi/", 5)) {
        // Get the path for system files, eg /zvfs or /usr/local/lib/jsi (TODO: cache)
        const char *loadFile = NULL;
        Jsi_PkgRequire(interp, "Jsish", 0);
        if (Jsi_PkgVersion(interp, "Jsish", &loadFile)>=0) {
            if (loadFile) {
                snprintf(statPath, sizeof(statPath), "%s", loadFile);
                char *lcp = Jsi_Strrchr(statPath, '/');
                if (lcp) {
                    *lcp = 0;
                    inPtr += 5;
                    cmdPtr->curRoot = statPath;
                }
            }
        }
    }

    snprintf(buf, sizeof(buf), "%s/%s", cmdPtr->curRoot, inPtr);

    if (cmdPtr->debug>1)
        fprintf(stderr, "FILE: %s in %s | %s\n", buf, cmdPtr->curRoot, Jsi_ValueString(interp, cmdPtr->rootdir, NULL));
    char extBuf[100], *cpde = Jsi_Strrchr(buf, '/');
    isJsiWeb = (cpde && cmdPtr->jsiFnPattern && Jsi_GlobMatch(cmdPtr->jsiFnPattern, cpde+1, 0));
    bool isgzip = 0;
    if (!ext || !ext[1])
        mime = "text/html";
................................................................................
        }

        if (Jsi_Strstr(buf, "favicon.ico"))
            rc = jsi_wsServeString(pss, wsi, "data:;base64,iVBORw0KGgo=", 200, NULL, "image/icon");
        else {
            const char *cp = Jsi_Strrchr(buf,'/');
            if (cp && cp[1]) {

                snprintf(statPath, sizeof(statPath), "/zvfs/lib/web%s", cp);
                Jsi_DecrRefCount(interp, fname);
                fname = Jsi_ValueNewStringDup(interp, statPath);
                Jsi_IncrRefCount(interp, fname);
                if (!Jsi_Stat(interp, fname, &jsb) && jsb.st_size>0) {
                    native = 0;
                    goto serve;
................................................................................
    Jsi_TreeEntry *hPtr;
    Jsi_TreeSearch srch;
    Jsi_Value *v;
    int m = 0;
    Jsi_DSInit(dStr);
    if (obj->isarrlist)
        obj = interp->Array_prototype->d.obj;


    for (hPtr=Jsi_TreeSearchFirst(obj->tree, &srch,  JSI_TREE_ORDER_IN, NULL); hPtr; hPtr=Jsi_TreeSearchNext(&srch)) {
        v = (Jsi_Value*)Jsi_TreeValueGet(hPtr);
        if (!v) continue;
        if ((flags&JSI_NAME_FUNCTIONS) && !Jsi_ValueIsFunction(interp,v)) {
            continue;
        }
        if ((flags&JSI_NAME_DATA) && Jsi_ValueIsFunction(interp,v)) {
................................................................................
Jsi_RC jsi_FunctionSubCall(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Value *tocall, int discard)
{
    Jsi_RC rc = JSI_OK;
    const char *oldCurFunc = interp->curFunction, *spnam = "";
    jsi_OpCode *ip = interp->curIp;
    int adds, as_constructor = (ip->op == OP_NEWFCALL);





    
    //char *lpv = interp->lastPushStr;
    if (tocall->vt == JSI_VT_UNDEF && tocall->f.bits.lookupfailed && tocall->d.lookupFail && !interp->noAutoLoad) {
        spnam = tocall->d.lookupFail;
        tocall->f.bits.lookupfailed = 0;
        tocall = jsi_LoadFunction(interp, spnam, tocall);
        interp->lastPushStr = (char*)spnam;
................................................................................
    rc = jsi_SharedArgs(interp, args, funcPtr, 1); /* make arg vars to share arguments */
    if (rc != JSI_OK)
        goto bail;
    funcPtr->callflags.bits.addargs = 0;
    jsi_InitLocalVar(interp, args, funcPtr);
    jsi_SetCallee(interp, args, tocall);
    
    int calltrc = 0, profile = interp->profile, coverage = interp->coverage;
    jsi_PkgInfo *pkg = funcPtr->pkg;
    int tc = interp->traceCall;
    if (pkg) {
        tc |= pkg->popts.modConf.traceCall;
        profile |= pkg->popts.modConf.profile;
        coverage |= pkg->popts.modConf.coverage;
    }

    if (as_constructor) {                       /* new Constructor */
................................................................................
    else
        calltrc = (tc&jsi_callTraceCmds);
    if (calltrc && funcPtr->name)
        jsi_TraceFuncCall(interp, funcPtr, ip, _this, args, 0, tc);

    //Jsi_Value *spretPtr = *ret;
 
    double timStart = 0;
    interp->activeFunc = funcPtr;
    int docall = (rc==JSI_OK);
    if (profile || coverage) {
        interp->profileCnt++;
        timStart = jsi_GetTimestamp();
    }
    if (funcPtr->type == FC_NORMAL) {
        if (docall) {
            rc = jsi_evalcode(interp->ps, funcPtr, funcPtr->opcodes, tocall->d.obj->d.fobj->scope, 
................................................................................
    interp->curIp = frame.ip;
    if (interp->exited)
        rc = JSI_ERROR;
    return rc;
}

Jsi_RC jsi_JsPreprocessLine(Jsi_Interp* interp, char *buf, size_t bsiz, uint ilen, int jOpts[4], int lineNo) {
    if (interp->unitTest&1 && buf[0]==';' && buf[1] && buf[2]) {
        // Wrap ";XXX;" in a puts("XXX ==> ", XXX)
        if (!jOpts[0]) {
            if (!Jsi_Strcmp(buf, "=!EXPECTSTART!=\n") || !Jsi_Strcmp(buf, "=!INPUTSTART!=\n") ) {
                return JSI_OK;
            }
        } else {
            if (!Jsi_Strcmp(buf, "=!EXPECTEND!=\n") || !Jsi_Strcmp(buf, "=!INPUTEND!=\n")) {
................................................................................
                char *ecp = ubuf+2;
                while (*ecp && isspace(*ecp)) ecp++;
                snprintf(buf, bsiz, "printf(\"%%s ==>\", \"%s\"); try { %s; puts('\\nFAIL!\\n'); } "
                    "catch(err) { puts('\\nPASS!: err =',err); }\n", ecp, ecp);
            } else {
                snprintf(buf, bsiz, "printf(\"%%s ==> \",\"%s\"),puts(%s);\n", ucp, ucp);
            }


        }
    }
    return JSI_OK;
}

Jsi_RC jsi_JsPreprocessLine2(Jsi_Interp* interp, char *buf, size_t bsiz, uint ilen, int jOpts[4], int lineNo) {
    const char *jpp = interp->jsppChars;
    if (!jpp[0] || !jpp[1])
        return JSI_OK;
    if (buf[0] && jpp[0] == buf[0] && ilen>2 && buf[ilen-2]==jpp[1]) {
        Jsi_DString dStr = {};
        buf[ilen-2] = 0; // Remove last char and newline.
        Jsi_Value *inStr = Jsi_ValueNewStringDup(interp, buf+1);
................................................................................
                }
                if (!noncmt++)
                    fncOfs = Jsi_DSLength(&dStr)-uskip;
                jpp = interp->jsppChars;
                if (jpp || interp->unitTest)
                    ilen = Jsi_Strlen(buf);
                if (interp->unitTest && buf[0]==';' && buf[1] && buf[2]) {
                    if (jsi_JsPreprocessLine(interp, buf, sizeof(buf), ilen, jppOpts, cnt) != JSI_OK)
                        goto bail;
                } else if (interp->jsppCallback && interp->jsppChars) {
                    if (jsi_JsPreprocessLine2(interp, buf, sizeof(buf), ilen, jppOpts, cnt) != JSI_OK)
                        goto bail;
                }
cont:
                Jsi_DSAppend(&dStr, buf,  NULL);
            }
            if (cnt>=MAX_LOOP_COUNT)
                Jsi_LogError("source file too large");






|







 







>

>







 







|







 







>
>
>
>
>
>
>
>
>
>







 







|







 







<







 







|




|




<
>
|
|
>
>
>







 







>




>







 







|







 







>


>







 







|







 







|







 







>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
|
|
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<

>







 







>







 







>
>







 







>
>
>
>
>







 







<
|
|







 







<

|







 







|







 







<
<





|







 







|


|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
....
7469
7470
7471
7472
7473
7474
7475
7476
7477
7478
7479
7480
7481
7482
7483
7484
7485
.....
16161
16162
16163
16164
16165
16166
16167
16168
16169
16170
16171
16172
16173
16174
16175
.....
18671
18672
18673
18674
18675
18676
18677
18678
18679
18680
18681
18682
18683
18684
18685
18686
18687
18688
18689
18690
18691
18692
18693
18694
.....
20602
20603
20604
20605
20606
20607
20608
20609
20610
20611
20612
20613
20614
20615
20616
.....
20696
20697
20698
20699
20700
20701
20702

20703
20704
20705
20706
20707
20708
20709
.....
34871
34872
34873
34874
34875
34876
34877
34878
34879
34880
34881
34882
34883
34884
34885
34886
34887

34888
34889
34890
34891
34892
34893
34894
34895
34896
34897
34898
34899
34900
.....
38732
38733
38734
38735
38736
38737
38738
38739
38740
38741
38742
38743
38744
38745
38746
38747
38748
38749
38750
38751
.....
39577
39578
39579
39580
39581
39582
39583
39584
39585
39586
39587
39588
39589
39590
39591
.....
43399
43400
43401
43402
43403
43404
43405
43406
43407
43408
43409
43410
43411
43412
43413
43414
43415
43416
.....
52809
52810
52811
52812
52813
52814
52815
52816
52817
52818
52819
52820
52821
52822
52823
.....
52825
52826
52827
52828
52829
52830
52831
52832
52833
52834
52835
52836
52837
52838
52839
.....
53008
53009
53010
53011
53012
53013
53014
53015
53016
53017
53018
53019
53020
53021
53022
.....
53612
53613
53614
53615
53616
53617
53618
53619
53620
53621
53622
53623
53624
53625
53626
53627
53628
53629
53630
53631
53632
53633
53634
53635
53636
53637
53638
53639
53640
53641
53642
53643
53644
53645
53646
53647
53648
53649
53650
53651
53652
53653
53654
53655
53656
53657
53658
53659
53660
53661
53662
.....
53776
53777
53778
53779
53780
53781
53782
53783
53784
53785










53786




53787
53788
53789
53790
53791
53792
53793
53794
53795
.....
53971
53972
53973
53974
53975
53976
53977
53978
53979
53980
53981
53982
53983
53984
53985
.....
68870
68871
68872
68873
68874
68875
68876
68877
68878
68879
68880
68881
68882
68883
68884
68885
.....
69113
69114
69115
69116
69117
69118
69119
69120
69121
69122
69123
69124
69125
69126
69127
69128
69129
69130
69131
.....
69174
69175
69176
69177
69178
69179
69180

69181
69182
69183
69184
69185
69186
69187
69188
69189
.....
69206
69207
69208
69209
69210
69211
69212

69213
69214
69215
69216
69217
69218
69219
69220
69221
.....
70568
70569
70570
70571
70572
70573
70574
70575
70576
70577
70578
70579
70580
70581
70582
.....
70615
70616
70617
70618
70619
70620
70621


70622
70623
70624
70625
70626
70627
70628
70629
70630
70631
70632
70633
70634
.....
70798
70799
70800
70801
70802
70803
70804
70805
70806
70807
70808
70809
70810
70811
70812
70813
70814
70815
/* jsi.h : External API header file for Jsi. */
#ifndef __JSI_H__
#define __JSI_H__

#define JSI_VERSION_MAJOR   2
#define JSI_VERSION_MINOR   8
#define JSI_VERSION_RELEASE 38

#define JSI_VERSION (JSI_VERSION_MAJOR + ((Jsi_Number)JSI_VERSION_MINOR/100.0) + ((Jsi_Number)JSI_VERSION_RELEASE/10000.0))

#ifndef JSI_EXTERN
#define JSI_EXTERN extern
#endif

................................................................................
#ifndef JSI__INFO
#define JSI__INFO 1
#endif
#ifndef JSI__CDATA
#define JSI__CDATA 1
#endif
#ifndef JSI__SOCKET
#ifndef __WIN32 
#define JSI__SOCKET 1
#endif
#endif
#ifndef JSI__MATH
#define JSI__MATH 1
#endif
#ifndef JSI__UTF8
#define JSI__UTF8 1
#endif
................................................................................
    }
done:
    if (buf != unibuf)
        Jsi_Free(buf);
    lex->inStr = 0;
    if (!ret)
        return NULL;
    Jsi_String *s = (typeof(s))Jsi_Calloc(1, sizeof(*s));
    s->str = ret;
    s->len = bufi;
    s->flags = flags;
    Jsi_HashSet(lex->pstate->strTbl, s, s);
    return s;
}

................................................................................
                    break;
                case JSI_OT_BOOL:
                    cp = "Boolean";
                    break;
                case JSI_OT_STRING:
                    cp = "String";
                    break;
                case JSI_OT_REGEXP:
                    cp = "RegExp";
                    break;
                case JSI_OT_OBJECT:
                    if (target->d.obj->isarrlist) {
                        cp = "Array";
                        break;
                    }
                    cp = "Object";
                    break;
                default:
                    Jsi_ValueMakeUndef(interp, ret);
                    return *ret;
            }
            v = Jsi_ValueObjLookup(interp, interp->csc, cp, 0);
            if (v==NULL || v->vt != JSI_VT_OBJECT)
                return NULL;
................................................................................
    return JSI_OK;
}

Jsi_Interp* Jsi_Main(Jsi_InterpOpts *opts)
{
    int rc = 0;
    Jsi_Interp* interp = NULL;
    int argc = 0, first = 1;
    char **argv = NULL;
    if (opts) {
        interp = opts->interp;
        argc = opts->argc;
        argv = opts->argv;
    }
    if (!interp)
................................................................................
          "  -W\t\tWebsrv: web server to serve out content.\n"
          "\nInterp options may also be set via the environment eg. JSI_INTERP_OPTS='{coverage:true}'\n"
           );
        return jsi_DoExit(interp, 1);
    }
    if (!Jsi_Strcmp(ai1, "-version"))
        ai1 = "-v";

    if (ai1[0] == '-') {
        switch (ai1[1]) {
            case 'a':
                rc = Jsi_EvalString(interp, "runModule('Archive');", JSI_EVAL_ISMAIN);
                break;
            case 'c':
                rc = Jsi_EvalString(interp, "runModule('Cdata');", JSI_EVAL_ISMAIN);
................................................................................
        Jsi_DecrRefCount(interp, fpath);
    if (rc == JSI_ERROR && needErr)
        Jsi_LogError("within require('%s') in file: %s", name, Jsi_DSValue(&dStr));
    Jsi_DSFree(&dStr);
    return rc;
}

// Load package from pkgDirs or executable path.  Note. ver currently unused.
static Jsi_RC jsi_PkgLoad(Jsi_Interp *interp, const char *name, Jsi_Number ver) {
    Jsi_RC rc;
    const char *cp = NULL, *path;
    int len;
    uint i = 0;
    Jsi_Value *fval = NULL;
    Jsi_Value *pval = interp->pkgDirs;
    if (pval) {
        Jsi_Obj* obj = pval->d.obj;

        bool isJsish = !Jsi_Strcmp(name, "Jsish");
        for (; i<obj->arrCnt; i++) {
            const char *pnam = Jsi_ValueString(interp, obj->arr[i], NULL);
            if (isJsish && interp->selfZvfs && Jsi_Strncmp(pnam, JSI_ZVFS_DIR, sizeof(JSI_ZVFS_DIR)-1))
                continue;
            rc = jsi_PkgLoadOne(interp, name, pnam, -1, &fval, ver);
            if (rc != JSI_CONTINUE)
                goto done;
        }
    }
    // Check executable dir.
    path = jsiIntData.execName;
    if (path)
................................................................................
        }
    }
    return rc;
}

static Jsi_CmdSpec consoleCmds[] = {
    { "assert", jsi_AssertCmd,      1,  3, "expr:boolean|number|function, msg:string=void, options:object=void",  .help="Same as System.assert()", .retType=(uint)JSI_TT_VOID, .flags=0, .info=0, .opts=AssertOptions},
    { "error",  consoleLogCmd,      1, -1, "val, ...", .help="Same as log", .retType=(uint)JSI_TT_VOID, .flags=0 },
    { "input",  consoleInputCmd,    0,  0, "", .help="Read input from the console", .retType=(uint)JSI_TT_STRING|JSI_TT_VOID },
    { "log",    consoleLogCmd,      1, -1, "val, ...", .help="Same as System.puts, but goes to stderr and includes file:line", .retType=(uint)JSI_TT_VOID, .flags=0 },
    { "printf", consolePrintfCmd,   1, -1, "format:string, ...", .help="Same as System.printf but goes to stderr", .retType=(uint)JSI_TT_VOID, .flags=0 },
    { "puts",   consolePutsCmd,     1, -1, "val, ...", .help="Same as System.puts, but goes to stderr", .retType=(uint)JSI_TT_VOID, .flags=0 },
    { "warn",   consoleLogCmd,      1, -1, "val, ...", .help="Same as log", .retType=(uint)JSI_TT_VOID, .flags=0 },
    { NULL, 0,0,0,0,  .help="Console input and output to stderr" }
};

#ifndef JSI_OMIT_EVENT
static Jsi_CmdSpec eventCmds[] = {
    { "clearInterval",clearIntervalCmd, 1,  1, "id:number", .help="Delete an event (created with setInterval/setTimeout)", .retType=(uint)JSI_TT_VOID },
    { "info",       eventInfoCmd,       1,  1, "id:number", .help="Return info for the given event id", .retType=(uint)JSI_TT_OBJECT },
................................................................................
    else if (p == path) {
        Jsi_ValueMakeStringKey(interp, ret, "/");
    }
#if defined(__MINGW32__) || defined(_MSC_VER)
    else if (p[-1] == ':') {
        int olen = -1;
        char *ostr = jsi_SubstrDup(path, -1, 0, p-path+1, &olen);
        Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
    }
#endif
    else {
        int olen = -1;
        char *ostr = jsi_SubstrDup(path, -1, 0, p-path, &olen);
        Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
    }
................................................................................
    return JSI_OK;
}

static Jsi_RC MathSrandCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    Jsi_Number n = 0;
#ifndef __WIN32
    Jsi_GetNumberFromValue(interp, Jsi_ValueArrayIndex(interp, args, 0), &n);
    srand48((long)n);
#endif
    jsi_SrandInit = 1;
    Jsi_ValueMakeNumber(interp, ret, n);
    return JSI_OK;
}

MFUNC1(MathAbsCmd,  fabs)
MFUNC1(MathAcosCmd, acos)
................................................................................

typedef struct { /* Per server (or client) data. */
    uint sig;
    Jsi_Interp *interp;
    ws_ObjCmd *_;
    Jsi_Hash *pssTable;
    Jsi_Value *onAuth, *onCloseLast, *onClose, *onFilter, *onOpen, *onRecv,
        *onUpload, *onGet, *onUnknown, *pathAliases,
        *rootdir, *interface, *address, *mimeTypes, *extArgs, *headers;
    bool client, noUpdate, noWebsock, noWarn, use_ssl, local, extHandlers, handlersPkg, inUpdate, noCompress, noConfig, echo;
    Jsi_Value* version;
    int idx;
    int port;
    int maxUpload;
    int maxDownload;
................................................................................
    jsi_wsStatData stats;
    char *iface;
    const char* urlPrefix, *urlRedirect;
    const char *localhostName;
    const char *clientName;
    const char *clientIP;
    const char *useridPass, *server;
    const char *realm, *includeFile, *jsiFnPattern, *jsishPathCache;
    struct lws_context *instCtx;
    Jsi_Value *getRegexp, *post;
    unsigned int oldus;
    int opts;
    int hasOpts;
    int debug;
    int maxConnects;
................................................................................
    JSI_OPT(FUNC,   jsi_wsCmdObj, onCloseLast,.help="Function to call when last websock connection closes. On object delete arg is null", .flags=0, .custom=0, .data=(void*)"ws:userobj|null"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onFilter,   .help="Function to call on a new connection: return false to kill connection", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, url:string, ishttp:boolean"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onGet,      .help="Function to call to server handle http-get", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, url:string, query:array"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onOpen,     .help="Function to call when the websocket connection occurs", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onUnknown,  .help="Function to call to server out content when no file exists", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, url:string, query:array"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onUpload,   .help="Function to call handle http-post", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, filename:string, data:string, startpos:number, complete:boolean"),
    JSI_OPT(FUNC,   jsi_wsCmdObj, onRecv,     .help="Function to call when websock data recieved", .flags=0, .custom=0, .data=(void*)"ws:userobj, id:number, data:string"),
    JSI_OPT(OBJ,    jsi_wsCmdObj, pathAliases,.help="Path alias lookups", jsi_IIOF),
    JSI_OPT(INT,    jsi_wsCmdObj, port,       .help="Port for server to listen on (8080)", jsi_IIOF),
    JSI_OPT(STRING, jsi_wsCmdObj, post,       .help="Post string to serve", jsi_IIOF),
    JSI_OPT(STRKEY, jsi_wsCmdObj, protocol,   .help="Name of protocol (ws/wss)"),
    JSI_OPT(STRKEY, jsi_wsCmdObj, realm,      .help="Realm for basic auth (jsish)", ),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufMax, .help="Size limit of a websocket message", jsi_IIOF),
    JSI_OPT(INT,    jsi_wsCmdObj, recvBufTimeout,.help="Timeout for recv of a websock msg", jsi_IIOF),
    JSI_OPT(BOOL,   jsi_wsCmdObj, redirMax,   .help="Temporarily disable redirects when see more than this in 10 minutes"),
................................................................................
        if (*cs == '\n')
            cs++;
    }
    Jsi_DSFree(&tStr);
    return rc;

}

static void jsi_wsPathAlias(Jsi_Interp *interp, jsi_wsCmdObj *cmdPtr, const char **inPtr, Jsi_DString *dStr) {
    const char *ce, *cp = NULL;
    char *lcp;
    Jsi_Value *val;
    if (!Jsi_Strncmp(*inPtr, "/jsi/", 5)) {
        // Get/cache path for system load file, eg /zvfs/lib/Jsish.jsi.
        if (!(cp = cmdPtr->jsishPathCache)) {
            Jsi_PkgRequire(interp, "Jsish", 0);
            if (Jsi_PkgVersion(interp, "Jsish", &cp)>=0)
                cmdPtr->jsishPathCache = cp;
        }
        if (cp) {
            Jsi_DSAppend(dStr, cp, NULL);
            cp = Jsi_DSValue(dStr);
            if ((lcp = Jsi_Strrchr(cp, '/'))) {
                *lcp = 0;
                *inPtr += 5;
                cmdPtr->curRoot = cp;
            }
        }
    }
    else if (cmdPtr->pathAliases) {
        cp = *inPtr;
        if (*cp == '/') cp++;
        if ((ce = Jsi_Strchr(cp, '/'))) {
            int len = ce-cp;
            Jsi_DSAppendLen(dStr, cp, len);
            cp = Jsi_DSValue(dStr);
            if ((val = Jsi_ValueObjLookup(interp, cmdPtr->pathAliases, cp, 0)) &&
                (cp = Jsi_ValueString(interp, val, NULL))) {
                *inPtr += len;
                cmdPtr->curRoot = cp;
            }
        }
    }
}

// Handle http GET/POST
static int jsi_wsHttp(Jsi_Interp *interp, jsi_wsCmdObj *cmdPtr, struct lws *wsi, void *user,
    struct lws_context *context, const char* inPtr, Jsi_DString *tStr, jsi_wsPss *pss)
{
    const char *ext = NULL;
    unsigned char buffer[JSI_BUFSIZ];
................................................................................
            }
        }
    }
    ext = Jsi_Strrchr(inPtr, '.');

    Jsi_Value *rdir = (pss->rootdir?pss->rootdir:cmdPtr->rootdir);
    cmdPtr->curRoot = (rdir?Jsi_ValueString(cmdPtr->interp, rdir, NULL):"./");
    Jsi_DString sStr;
    Jsi_DSInit(&sStr);
    jsi_wsPathAlias(interp, cmdPtr, &inPtr, &sStr);















    snprintf(buf, sizeof(buf), "%s/%s", cmdPtr->curRoot, inPtr);
    Jsi_DSFree(&sStr);
    if (cmdPtr->debug>1)
        fprintf(stderr, "FILE: %s in %s | %s\n", buf, cmdPtr->curRoot, Jsi_ValueString(interp, cmdPtr->rootdir, NULL));
    char extBuf[100], *cpde = Jsi_Strrchr(buf, '/');
    isJsiWeb = (cpde && cmdPtr->jsiFnPattern && Jsi_GlobMatch(cmdPtr->jsiFnPattern, cpde+1, 0));
    bool isgzip = 0;
    if (!ext || !ext[1])
        mime = "text/html";
................................................................................
        }

        if (Jsi_Strstr(buf, "favicon.ico"))
            rc = jsi_wsServeString(pss, wsi, "data:;base64,iVBORw0KGgo=", 200, NULL, "image/icon");
        else {
            const char *cp = Jsi_Strrchr(buf,'/');
            if (cp && cp[1]) {
                char statPath[PATH_MAX];
                snprintf(statPath, sizeof(statPath), "/zvfs/lib/web%s", cp);
                Jsi_DecrRefCount(interp, fname);
                fname = Jsi_ValueNewStringDup(interp, statPath);
                Jsi_IncrRefCount(interp, fname);
                if (!Jsi_Stat(interp, fname, &jsb) && jsb.st_size>0) {
                    native = 0;
                    goto serve;
................................................................................
    Jsi_TreeEntry *hPtr;
    Jsi_TreeSearch srch;
    Jsi_Value *v;
    int m = 0;
    Jsi_DSInit(dStr);
    if (obj->isarrlist)
        obj = interp->Array_prototype->d.obj;
    else if (!obj->tree->numEntries && obj->__proto__)
        obj = obj->__proto__->d.obj;
    for (hPtr=Jsi_TreeSearchFirst(obj->tree, &srch,  JSI_TREE_ORDER_IN, NULL); hPtr; hPtr=Jsi_TreeSearchNext(&srch)) {
        v = (Jsi_Value*)Jsi_TreeValueGet(hPtr);
        if (!v) continue;
        if ((flags&JSI_NAME_FUNCTIONS) && !Jsi_ValueIsFunction(interp,v)) {
            continue;
        }
        if ((flags&JSI_NAME_DATA) && Jsi_ValueIsFunction(interp,v)) {
................................................................................
Jsi_RC jsi_FunctionSubCall(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Value *tocall, int discard)
{
    Jsi_RC rc = JSI_OK;
    const char *oldCurFunc = interp->curFunction, *spnam = "";
    jsi_OpCode *ip = interp->curIp;
    int adds, as_constructor = (ip->op == OP_NEWFCALL);
    double timStart = 0;
    int docall;
    int calltrc = 0, profile = interp->profile, coverage = interp->coverage;
    jsi_PkgInfo *pkg;
    int tc;
    
    //char *lpv = interp->lastPushStr;
    if (tocall->vt == JSI_VT_UNDEF && tocall->f.bits.lookupfailed && tocall->d.lookupFail && !interp->noAutoLoad) {
        spnam = tocall->d.lookupFail;
        tocall->f.bits.lookupfailed = 0;
        tocall = jsi_LoadFunction(interp, spnam, tocall);
        interp->lastPushStr = (char*)spnam;
................................................................................
    rc = jsi_SharedArgs(interp, args, funcPtr, 1); /* make arg vars to share arguments */
    if (rc != JSI_OK)
        goto bail;
    funcPtr->callflags.bits.addargs = 0;
    jsi_InitLocalVar(interp, args, funcPtr);
    jsi_SetCallee(interp, args, tocall);
    

    pkg = funcPtr->pkg;
    tc = interp->traceCall;
    if (pkg) {
        tc |= pkg->popts.modConf.traceCall;
        profile |= pkg->popts.modConf.profile;
        coverage |= pkg->popts.modConf.coverage;
    }

    if (as_constructor) {                       /* new Constructor */
................................................................................
    else
        calltrc = (tc&jsi_callTraceCmds);
    if (calltrc && funcPtr->name)
        jsi_TraceFuncCall(interp, funcPtr, ip, _this, args, 0, tc);

    //Jsi_Value *spretPtr = *ret;
 

    interp->activeFunc = funcPtr;
    docall = (rc==JSI_OK);
    if (profile || coverage) {
        interp->profileCnt++;
        timStart = jsi_GetTimestamp();
    }
    if (funcPtr->type == FC_NORMAL) {
        if (docall) {
            rc = jsi_evalcode(interp->ps, funcPtr, funcPtr->opcodes, tocall->d.obj->d.fobj->scope, 
................................................................................
    interp->curIp = frame.ip;
    if (interp->exited)
        rc = JSI_ERROR;
    return rc;
}

Jsi_RC jsi_JsPreprocessLine(Jsi_Interp* interp, char *buf, size_t bsiz, uint ilen, int jOpts[4], int lineNo) {
    if (buf[0]==';' && buf[1] && buf[2]) {
        // Wrap ";XXX;" in a puts("XXX ==> ", XXX)
        if (!jOpts[0]) {
            if (!Jsi_Strcmp(buf, "=!EXPECTSTART!=\n") || !Jsi_Strcmp(buf, "=!INPUTSTART!=\n") ) {
                return JSI_OK;
            }
        } else {
            if (!Jsi_Strcmp(buf, "=!EXPECTEND!=\n") || !Jsi_Strcmp(buf, "=!INPUTEND!=\n")) {
................................................................................
                char *ecp = ubuf+2;
                while (*ecp && isspace(*ecp)) ecp++;
                snprintf(buf, bsiz, "printf(\"%%s ==>\", \"%s\"); try { %s; puts('\\nFAIL!\\n'); } "
                    "catch(err) { puts('\\nPASS!: err =',err); }\n", ecp, ecp);
            } else {
                snprintf(buf, bsiz, "printf(\"%%s ==> \",\"%s\"),puts(%s);\n", ucp, ucp);
            }


        }
    }
    return JSI_OK;
}

Jsi_RC jsi_JsPreprocessLineCB(Jsi_Interp* interp, char *buf, size_t bsiz, uint ilen, int jOpts[4], int lineNo) {
    const char *jpp = interp->jsppChars;
    if (!jpp[0] || !jpp[1])
        return JSI_OK;
    if (buf[0] && jpp[0] == buf[0] && ilen>2 && buf[ilen-2]==jpp[1]) {
        Jsi_DString dStr = {};
        buf[ilen-2] = 0; // Remove last char and newline.
        Jsi_Value *inStr = Jsi_ValueNewStringDup(interp, buf+1);
................................................................................
                }
                if (!noncmt++)
                    fncOfs = Jsi_DSLength(&dStr)-uskip;
                jpp = interp->jsppChars;
                if (jpp || interp->unitTest)
                    ilen = Jsi_Strlen(buf);
                if (interp->unitTest && buf[0]==';' && buf[1] && buf[2]) {
                    if (interp->unitTest&1 && jsi_JsPreprocessLine(interp, buf, sizeof(buf), ilen, jppOpts, cnt) != JSI_OK)
                        goto bail;
                } else if (interp->jsppCallback && interp->jsppChars) {
                    if (jsi_JsPreprocessLineCB(interp, buf, sizeof(buf), ilen, jppOpts, cnt) != JSI_OK)
                        goto bail;
                }
cont:
                Jsi_DSAppend(&dStr, buf,  NULL);
            }
            if (cnt>=MAX_LOOP_COUNT)
                Jsi_LogError("source file too large");

Changes to src/jsi.h.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* jsi.h : External API header file for Jsi. */
#ifndef __JSI_H__
#define __JSI_H__

#define JSI_VERSION_MAJOR   2
#define JSI_VERSION_MINOR   8
#define JSI_VERSION_RELEASE 37

#define JSI_VERSION (JSI_VERSION_MAJOR + ((Jsi_Number)JSI_VERSION_MINOR/100.0) + ((Jsi_Number)JSI_VERSION_RELEASE/10000.0))

#ifndef JSI_EXTERN
#define JSI_EXTERN extern
#endif







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* jsi.h : External API header file for Jsi. */
#ifndef __JSI_H__
#define __JSI_H__

#define JSI_VERSION_MAJOR   2
#define JSI_VERSION_MINOR   8
#define JSI_VERSION_RELEASE 38

#define JSI_VERSION (JSI_VERSION_MAJOR + ((Jsi_Number)JSI_VERSION_MINOR/100.0) + ((Jsi_Number)JSI_VERSION_RELEASE/10000.0))

#ifndef JSI_EXTERN
#define JSI_EXTERN extern
#endif

Changes to src/jsiEval.c.

703
704
705
706
707
708
709





710
711
712
713
714
715
716
...
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
...
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
....
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
....
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
....
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
Jsi_RC jsi_FunctionSubCall(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Value *tocall, int discard)
{
    Jsi_RC rc = JSI_OK;
    const char *oldCurFunc = interp->curFunction, *spnam = "";
    jsi_OpCode *ip = interp->curIp;
    int adds, as_constructor = (ip->op == OP_NEWFCALL);





    
    //char *lpv = interp->lastPushStr;
    if (tocall->vt == JSI_VT_UNDEF && tocall->f.bits.lookupfailed && tocall->d.lookupFail && !interp->noAutoLoad) {
        spnam = tocall->d.lookupFail;
        tocall->f.bits.lookupfailed = 0;
        tocall = jsi_LoadFunction(interp, spnam, tocall);
        interp->lastPushStr = (char*)spnam;
................................................................................
    rc = jsi_SharedArgs(interp, args, funcPtr, 1); /* make arg vars to share arguments */
    if (rc != JSI_OK)
        goto bail;
    funcPtr->callflags.bits.addargs = 0;
    jsi_InitLocalVar(interp, args, funcPtr);
    jsi_SetCallee(interp, args, tocall);
    
    int calltrc = 0, profile = interp->profile, coverage = interp->coverage;
    jsi_PkgInfo *pkg = funcPtr->pkg;
    int tc = interp->traceCall;
    if (pkg) {
        tc |= pkg->popts.modConf.traceCall;
        profile |= pkg->popts.modConf.profile;
        coverage |= pkg->popts.modConf.coverage;
    }

    if (as_constructor) {                       /* new Constructor */
................................................................................
    else
        calltrc = (tc&jsi_callTraceCmds);
    if (calltrc && funcPtr->name)
        jsi_TraceFuncCall(interp, funcPtr, ip, _this, args, 0, tc);

    //Jsi_Value *spretPtr = *ret;
 
    double timStart = 0;
    interp->activeFunc = funcPtr;
    int docall = (rc==JSI_OK);
    if (profile || coverage) {
        interp->profileCnt++;
        timStart = jsi_GetTimestamp();
    }
    if (funcPtr->type == FC_NORMAL) {
        if (docall) {
            rc = jsi_evalcode(interp->ps, funcPtr, funcPtr->opcodes, tocall->d.obj->d.fobj->scope, 
................................................................................
    interp->curIp = frame.ip;
    if (interp->exited)
        rc = JSI_ERROR;
    return rc;
}

Jsi_RC jsi_JsPreprocessLine(Jsi_Interp* interp, char *buf, size_t bsiz, uint ilen, int jOpts[4], int lineNo) {
    if (interp->unitTest&1 && buf[0]==';' && buf[1] && buf[2]) {
        // Wrap ";XXX;" in a puts("XXX ==> ", XXX)
        if (!jOpts[0]) {
            if (!Jsi_Strcmp(buf, "=!EXPECTSTART!=\n") || !Jsi_Strcmp(buf, "=!INPUTSTART!=\n") ) {
                return JSI_OK;
            }
        } else {
            if (!Jsi_Strcmp(buf, "=!EXPECTEND!=\n") || !Jsi_Strcmp(buf, "=!INPUTEND!=\n")) {
................................................................................
                char *ecp = ubuf+2;
                while (*ecp && isspace(*ecp)) ecp++;
                snprintf(buf, bsiz, "printf(\"%%s ==>\", \"%s\"); try { %s; puts('\\nFAIL!\\n'); } "
                    "catch(err) { puts('\\nPASS!: err =',err); }\n", ecp, ecp);
            } else {
                snprintf(buf, bsiz, "printf(\"%%s ==> \",\"%s\"),puts(%s);\n", ucp, ucp);
            }


        }
    }
    return JSI_OK;
}

Jsi_RC jsi_JsPreprocessLine2(Jsi_Interp* interp, char *buf, size_t bsiz, uint ilen, int jOpts[4], int lineNo) {
    const char *jpp = interp->jsppChars;
    if (!jpp[0] || !jpp[1])
        return JSI_OK;
    if (buf[0] && jpp[0] == buf[0] && ilen>2 && buf[ilen-2]==jpp[1]) {
        Jsi_DString dStr = {};
        buf[ilen-2] = 0; // Remove last char and newline.
        Jsi_Value *inStr = Jsi_ValueNewStringDup(interp, buf+1);
................................................................................
                }
                if (!noncmt++)
                    fncOfs = Jsi_DSLength(&dStr)-uskip;
                jpp = interp->jsppChars;
                if (jpp || interp->unitTest)
                    ilen = Jsi_Strlen(buf);
                if (interp->unitTest && buf[0]==';' && buf[1] && buf[2]) {
                    if (jsi_JsPreprocessLine(interp, buf, sizeof(buf), ilen, jppOpts, cnt) != JSI_OK)
                        goto bail;
                } else if (interp->jsppCallback && interp->jsppChars) {
                    if (jsi_JsPreprocessLine2(interp, buf, sizeof(buf), ilen, jppOpts, cnt) != JSI_OK)
                        goto bail;
                }
cont:
                Jsi_DSAppend(&dStr, buf,  NULL);
            }
            if (cnt>=MAX_LOOP_COUNT)
                Jsi_LogError("source file too large");







>
>
>
>
>







 







<
|
|







 







<

|







 







|







 







<
<





|







 







|


|







703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
...
764
765
766
767
768
769
770

771
772
773
774
775
776
777
778
779
...
796
797
798
799
800
801
802

803
804
805
806
807
808
809
810
811
....
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
....
2205
2206
2207
2208
2209
2210
2211


2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
....
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
Jsi_RC jsi_FunctionSubCall(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Value *tocall, int discard)
{
    Jsi_RC rc = JSI_OK;
    const char *oldCurFunc = interp->curFunction, *spnam = "";
    jsi_OpCode *ip = interp->curIp;
    int adds, as_constructor = (ip->op == OP_NEWFCALL);
    double timStart = 0;
    int docall;
    int calltrc = 0, profile = interp->profile, coverage = interp->coverage;
    jsi_PkgInfo *pkg;
    int tc;
    
    //char *lpv = interp->lastPushStr;
    if (tocall->vt == JSI_VT_UNDEF && tocall->f.bits.lookupfailed && tocall->d.lookupFail && !interp->noAutoLoad) {
        spnam = tocall->d.lookupFail;
        tocall->f.bits.lookupfailed = 0;
        tocall = jsi_LoadFunction(interp, spnam, tocall);
        interp->lastPushStr = (char*)spnam;
................................................................................
    rc = jsi_SharedArgs(interp, args, funcPtr, 1); /* make arg vars to share arguments */
    if (rc != JSI_OK)
        goto bail;
    funcPtr->callflags.bits.addargs = 0;
    jsi_InitLocalVar(interp, args, funcPtr);
    jsi_SetCallee(interp, args, tocall);
    

    pkg = funcPtr->pkg;
    tc = interp->traceCall;
    if (pkg) {
        tc |= pkg->popts.modConf.traceCall;
        profile |= pkg->popts.modConf.profile;
        coverage |= pkg->popts.modConf.coverage;
    }

    if (as_constructor) {                       /* new Constructor */
................................................................................
    else
        calltrc = (tc&jsi_callTraceCmds);
    if (calltrc && funcPtr->name)
        jsi_TraceFuncCall(interp, funcPtr, ip, _this, args, 0, tc);

    //Jsi_Value *spretPtr = *ret;
 

    interp->activeFunc = funcPtr;
    docall = (rc==JSI_OK);
    if (profile || coverage) {
        interp->profileCnt++;
        timStart = jsi_GetTimestamp();
    }
    if (funcPtr->type == FC_NORMAL) {
        if (docall) {
            rc = jsi_evalcode(interp->ps, funcPtr, funcPtr->opcodes, tocall->d.obj->d.fobj->scope, 
................................................................................
    interp->curIp = frame.ip;
    if (interp->exited)
        rc = JSI_ERROR;
    return rc;
}

Jsi_RC jsi_JsPreprocessLine(Jsi_Interp* interp, char *buf, size_t bsiz, uint ilen, int jOpts[4], int lineNo) {
    if (buf[0]==';' && buf[1] && buf[2]) {
        // Wrap ";XXX;" in a puts("XXX ==> ", XXX)
        if (!jOpts[0]) {
            if (!Jsi_Strcmp(buf, "=!EXPECTSTART!=\n") || !Jsi_Strcmp(buf, "=!INPUTSTART!=\n") ) {
                return JSI_OK;
            }
        } else {
            if (!Jsi_Strcmp(buf, "=!EXPECTEND!=\n") || !Jsi_Strcmp(buf, "=!INPUTEND!=\n")) {
................................................................................
                char *ecp = ubuf+2;
                while (*ecp && isspace(*ecp)) ecp++;
                snprintf(buf, bsiz, "printf(\"%%s ==>\", \"%s\"); try { %s; puts('\\nFAIL!\\n'); } "
                    "catch(err) { puts('\\nPASS!: err =',err); }\n", ecp, ecp);
            } else {
                snprintf(buf, bsiz, "printf(\"%%s ==> \",\"%s\"),puts(%s);\n", ucp, ucp);
            }


        }
    }
    return JSI_OK;
}

Jsi_RC jsi_JsPreprocessLineCB(Jsi_Interp* interp, char *buf, size_t bsiz, uint ilen, int jOpts[4], int lineNo) {
    const char *jpp = interp->jsppChars;
    if (!jpp[0] || !jpp[1])
        return JSI_OK;
    if (buf[0] && jpp[0] == buf[0] && ilen>2 && buf[ilen-2]==jpp[1]) {
        Jsi_DString dStr = {};
        buf[ilen-2] = 0; // Remove last char and newline.
        Jsi_Value *inStr = Jsi_ValueNewStringDup(interp, buf+1);
................................................................................
                }
                if (!noncmt++)
                    fncOfs = Jsi_DSLength(&dStr)-uskip;
                jpp = interp->jsppChars;
                if (jpp || interp->unitTest)
                    ilen = Jsi_Strlen(buf);
                if (interp->unitTest && buf[0]==';' && buf[1] && buf[2]) {
                    if (interp->unitTest&1 && jsi_JsPreprocessLine(interp, buf, sizeof(buf), ilen, jppOpts, cnt) != JSI_OK)
                        goto bail;
                } else if (interp->jsppCallback && interp->jsppChars) {
                    if (jsi_JsPreprocessLineCB(interp, buf, sizeof(buf), ilen, jppOpts, cnt) != JSI_OK)
                        goto bail;
                }
cont:
                Jsi_DSAppend(&dStr, buf,  NULL);
            }
            if (cnt>=MAX_LOOP_COUNT)
                Jsi_LogError("source file too large");

Changes to src/jsiFileCmds.c.

689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
    else if (p == path) {
        Jsi_ValueMakeStringKey(interp, ret, "/");
    }
#if defined(__MINGW32__) || defined(_MSC_VER)
    else if (p[-1] == ':') {
        int olen = -1;
        char *ostr = jsi_SubstrDup(path, -1, 0, p-path+1, &olen);
        Jsi_ValueMakeString(interp, ret, (uchar*)ostr, olen);
    }
#endif
    else {
        int olen = -1;
        char *ostr = jsi_SubstrDup(path, -1, 0, p-path, &olen);
        Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
    }







|







689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
    else if (p == path) {
        Jsi_ValueMakeStringKey(interp, ret, "/");
    }
#if defined(__MINGW32__) || defined(_MSC_VER)
    else if (p[-1] == ':') {
        int olen = -1;
        char *ostr = jsi_SubstrDup(path, -1, 0, p-path+1, &olen);
        Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
    }
#endif
    else {
        int olen = -1;
        char *ostr = jsi_SubstrDup(path, -1, 0, p-path, &olen);
        Jsi_ValueMakeBlob(interp, ret, (uchar*)ostr, olen);
    }

Changes to src/jsiInt.h.

38
39
40
41
42
43
44

45

46
47
48
49
50
51
52
#ifndef JSI__INFO
#define JSI__INFO 1
#endif
#ifndef JSI__CDATA
#define JSI__CDATA 1
#endif
#ifndef JSI__SOCKET

#define JSI__SOCKET 1

#endif
#ifndef JSI__MATH
#define JSI__MATH 1
#endif
#ifndef JSI__UTF8
#define JSI__UTF8 1
#endif







>

>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#ifndef JSI__INFO
#define JSI__INFO 1
#endif
#ifndef JSI__CDATA
#define JSI__CDATA 1
#endif
#ifndef JSI__SOCKET
#ifndef __WIN32 
#define JSI__SOCKET 1
#endif
#endif
#ifndef JSI__MATH
#define JSI__MATH 1
#endif
#ifndef JSI__UTF8
#define JSI__UTF8 1
#endif

Changes to src/jsiInterp.c.

642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
...
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
    return JSI_OK;
}

Jsi_Interp* Jsi_Main(Jsi_InterpOpts *opts)
{
    int rc = 0;
    Jsi_Interp* interp = NULL;
    int argc = 0;
    char **argv = NULL;
    if (opts) {
        interp = opts->interp;
        argc = opts->argc;
        argv = opts->argv;
    }
    if (!interp)
................................................................................
          "  -W\t\tWebsrv: web server to serve out content.\n"
          "\nInterp options may also be set via the environment eg. JSI_INTERP_OPTS='{coverage:true}'\n"
           );
        return jsi_DoExit(interp, 1);
    }
    if (!Jsi_Strcmp(ai1, "-version"))
        ai1 = "-v";
    int first = 1;
    if (ai1[0] == '-') {
        switch (ai1[1]) {
            case 'a':
                rc = Jsi_EvalString(interp, "runModule('Archive');", JSI_EVAL_ISMAIN);
                break;
            case 'c':
                rc = Jsi_EvalString(interp, "runModule('Cdata');", JSI_EVAL_ISMAIN);







|







 







<







642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
...
736
737
738
739
740
741
742

743
744
745
746
747
748
749
    return JSI_OK;
}

Jsi_Interp* Jsi_Main(Jsi_InterpOpts *opts)
{
    int rc = 0;
    Jsi_Interp* interp = NULL;
    int argc = 0, first = 1;
    char **argv = NULL;
    if (opts) {
        interp = opts->interp;
        argc = opts->argc;
        argv = opts->argv;
    }
    if (!interp)
................................................................................
          "  -W\t\tWebsrv: web server to serve out content.\n"
          "\nInterp options may also be set via the environment eg. JSI_INTERP_OPTS='{coverage:true}'\n"
           );
        return jsi_DoExit(interp, 1);
    }
    if (!Jsi_Strcmp(ai1, "-version"))
        ai1 = "-v";

    if (ai1[0] == '-') {
        switch (ai1[1]) {
            case 'a':
                rc = Jsi_EvalString(interp, "runModule('Archive');", JSI_EVAL_ISMAIN);
                break;
            case 'c':
                rc = Jsi_EvalString(interp, "runModule('Cdata');", JSI_EVAL_ISMAIN);

Changes to src/jsiLexer.c.

223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
    }
done:
    if (buf != unibuf)
        Jsi_Free(buf);
    lex->inStr = 0;
    if (!ret)
        return NULL;
    Jsi_String *s = Jsi_Calloc(1, sizeof(*s));
    s->str = ret;
    s->len = bufi;
    s->flags = flags;
    Jsi_HashSet(lex->pstate->strTbl, s, s);
    return s;
}








|







223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
    }
done:
    if (buf != unibuf)
        Jsi_Free(buf);
    lex->inStr = 0;
    if (!ret)
        return NULL;
    Jsi_String *s = (typeof(s))Jsi_Calloc(1, sizeof(*s));
    s->str = ret;
    s->len = bufi;
    s->flags = flags;
    Jsi_HashSet(lex->pstate->strTbl, s, s);
    return s;
}

Changes to src/jsiMath.c.

94
95
96
97
98
99
100

101
102

103
104
105
106
107
108
109
    return JSI_OK;
}

static Jsi_RC MathSrandCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    Jsi_Number n = 0;

    Jsi_GetNumberFromValue(interp, Jsi_ValueArrayIndex(interp, args, 0), &n);
    srand48((long)n);

    jsi_SrandInit = 1;
    Jsi_ValueMakeNumber(interp, ret, n);
    return JSI_OK;
}

MFUNC1(MathAbsCmd,  fabs)
MFUNC1(MathAcosCmd, acos)







>


>







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
    return JSI_OK;
}

static Jsi_RC MathSrandCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this,
    Jsi_Value **ret, Jsi_Func *funcPtr)
{
    Jsi_Number n = 0;
#ifndef __WIN32
    Jsi_GetNumberFromValue(interp, Jsi_ValueArrayIndex(interp, args, 0), &n);
    srand48((long)n);
#endif
    jsi_SrandInit = 1;
    Jsi_ValueMakeNumber(interp, ret, n);
    return JSI_OK;
}

MFUNC1(MathAbsCmd,  fabs)
MFUNC1(MathAcosCmd, acos)

Changes to tools/protos.jsi.

1
2
3
4
5
6
7
8
...
360
361
362
363
364
365
366

367
368
369
370

371
372
373
374
375
376
377
//JSI Command Prototypes: version 2.8.37
throw("NOT EXECUTABLE: USE FILE IN GEANY EDITOR FOR CMD LINE COMPLETION + GOTO TAG");

var Array = function(cmd,args) {};
Array.prototype.concat = function(...):array {};
Array.prototype.every = function(callback:function):any {};
Array.prototype.fill = function(value:any, start:number=0, end:number=-1):array {};
Array.prototype.filter = function(callback:function, this:object=void):array {};
................................................................................
Zvfs.prototype.stat = function(filename:string):object {};
Zvfs.prototype.truncate = function(archive:string, noerror:boolean=false):number {};
Zvfs.prototype.unmount = function(archive:string):void {};
var assert = function(expr:boolean|number|function, msg:string=void, options:object=void):void {};
var clearInterval = function(id:number):void {};
var console = function(cmd,args) {};
console.prototype.assert = function(expr:boolean|number|function, msg:string=void, options:object=void):void {};

console.prototype.input = function():string|void {};
console.prototype.log = function(val, ...):void {};
console.prototype.printf = function(format:string, ...):void {};
console.prototype.puts = function(val, ...):void {};

var decodeURI = function(val:string):string {};
var encodeURI = function(val:string):string {};
var exec = function(val:string, options:string|object=void):any {};
var exit = function(code:number=0):void {};
var format = function(format:string, ...):string {};
var isFinite = function(val):boolean {};
var isMain = function():boolean {};
|







 







>




>







1
2
3
4
5
6
7
8
...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
//JSI Command Prototypes: version 2.8.38
throw("NOT EXECUTABLE: USE FILE IN GEANY EDITOR FOR CMD LINE COMPLETION + GOTO TAG");

var Array = function(cmd,args) {};
Array.prototype.concat = function(...):array {};
Array.prototype.every = function(callback:function):any {};
Array.prototype.fill = function(value:any, start:number=0, end:number=-1):array {};
Array.prototype.filter = function(callback:function, this:object=void):array {};
................................................................................
Zvfs.prototype.stat = function(filename:string):object {};
Zvfs.prototype.truncate = function(archive:string, noerror:boolean=false):number {};
Zvfs.prototype.unmount = function(archive:string):void {};
var assert = function(expr:boolean|number|function, msg:string=void, options:object=void):void {};
var clearInterval = function(id:number):void {};
var console = function(cmd,args) {};
console.prototype.assert = function(expr:boolean|number|function, msg:string=void, options:object=void):void {};
console.prototype.error = function(val, ...):void {};
console.prototype.input = function():string|void {};
console.prototype.log = function(val, ...):void {};
console.prototype.printf = function(format:string, ...):void {};
console.prototype.puts = function(val, ...):void {};
console.prototype.warn = function(val, ...):void {};
var decodeURI = function(val:string):string {};
var encodeURI = function(val:string):string {};
var exec = function(val:string, options:string|object=void):any {};
var exit = function(code:number=0):void {};
var format = function(format:string, ...):string {};
var isFinite = function(val):boolean {};
var isMain = function():boolean {};

Changes to www/reference.wiki.

1675
1676
1677
1678
1679
1680
1681

1682
1683
1684
1685
1686
1687
1688
....
1792
1793
1794
1795
1796
1797
1798

1799
1800
1801
1802

1803
1804
1805
1806
1807
1808
1809
<tr><td>onCloseLast</td><td><i>FUNC</i></td><td>Function to call when last websock connection closes. On object delete arg is null. @function(ws:userobj|null)</td><td><i></i></td></tr>
<tr><td>onFilter</td><td><i>FUNC</i></td><td>Function to call on a new connection: return false to kill connection. @function(ws:userobj, id:number, url:string, ishttp:boolean)</td><td><i></i></td></tr>
<tr><td>onGet</td><td><i>FUNC</i></td><td>Function to call to server handle http-get. @function(ws:userobj, id:number, url:string, query:array)</td><td><i></i></td></tr>
<tr><td>onOpen</td><td><i>FUNC</i></td><td>Function to call when the websocket connection occurs. @function(ws:userobj, id:number)</td><td><i></i></td></tr>
<tr><td>onUnknown</td><td><i>FUNC</i></td><td>Function to call to server out content when no file exists. @function(ws:userobj, id:number, url:string, query:array)</td><td><i></i></td></tr>
<tr><td>onUpload</td><td><i>FUNC</i></td><td>Function to call handle http-post. @function(ws:userobj, id:number, filename:string, data:string, startpos:number, complete:boolean)</td><td><i></i></td></tr>
<tr><td>onRecv</td><td><i>FUNC</i></td><td>Function to call when websock data recieved. @function(ws:userobj, id:number, data:string)</td><td><i></i></td></tr>

<tr><td>port</td><td><i>INT</i></td><td>Port for server to listen on (8080).</td><td><i>initOnly</i></td></tr>
<tr><td>post</td><td><i>STRING</i></td><td>Post string to serve.</td><td><i>initOnly</i></td></tr>
<tr><td>protocol</td><td><i>STRKEY</i></td><td>Name of protocol (ws/wss).</td><td><i></i></td></tr>
<tr><td>realm</td><td><i>STRKEY</i></td><td>Realm for basic auth (jsish).</td><td><i></i></td></tr>
<tr><td>recvBufMax</td><td><i>INT</i></td><td>Size limit of a websocket message.</td><td><i>initOnly</i></td></tr>
<tr><td>recvBufTimeout</td><td><i>INT</i></td><td>Timeout for recv of a websock msg.</td><td><i>initOnly</i></td></tr>
<tr><td>redirMax</td><td><i>BOOL</i></td><td>Temporarily disable redirects when see more than this in 10 minutes.</td><td><i></i></td></tr>
................................................................................
</font><p>Console input and output to stderr.


<h2>Methods for "console"</h2>
<table border="1"class="cmdstbl table">
<tr><th>Method</th><th>Prototype</th><th>Description</th></tr>
<tr><td>assert</td><td>assert(expr:boolean|number|function, msg:string=void, <a href='#console.assertOptions'>options</a>:object=void):void </td><td>Same as System.assert().</td></tr>

<tr><td>input</td><td>input():string|void </td><td>Read input from the console.</td></tr>
<tr><td>log</td><td>log(val, ...):void </td><td>Same as System.puts, but goes to stderr and includes file:line.</td></tr>
<tr><td>printf</td><td>printf(format:string, ...):void </td><td>Same as System.printf but goes to stderr.</td></tr>
<tr><td>puts</td><td>puts(val, ...):void </td><td>Same as System.puts, but goes to stderr.</td></tr>

</table>


<a name="console.assertOptions"></a>
<a name="console.confOptions"></a>
<h2>Options for "console.assert"</h2>
<table border="1" class="optstbl table">







>







 







>




>







1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
....
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
<tr><td>onCloseLast</td><td><i>FUNC</i></td><td>Function to call when last websock connection closes. On object delete arg is null. @function(ws:userobj|null)</td><td><i></i></td></tr>
<tr><td>onFilter</td><td><i>FUNC</i></td><td>Function to call on a new connection: return false to kill connection. @function(ws:userobj, id:number, url:string, ishttp:boolean)</td><td><i></i></td></tr>
<tr><td>onGet</td><td><i>FUNC</i></td><td>Function to call to server handle http-get. @function(ws:userobj, id:number, url:string, query:array)</td><td><i></i></td></tr>
<tr><td>onOpen</td><td><i>FUNC</i></td><td>Function to call when the websocket connection occurs. @function(ws:userobj, id:number)</td><td><i></i></td></tr>
<tr><td>onUnknown</td><td><i>FUNC</i></td><td>Function to call to server out content when no file exists. @function(ws:userobj, id:number, url:string, query:array)</td><td><i></i></td></tr>
<tr><td>onUpload</td><td><i>FUNC</i></td><td>Function to call handle http-post. @function(ws:userobj, id:number, filename:string, data:string, startpos:number, complete:boolean)</td><td><i></i></td></tr>
<tr><td>onRecv</td><td><i>FUNC</i></td><td>Function to call when websock data recieved. @function(ws:userobj, id:number, data:string)</td><td><i></i></td></tr>
<tr><td>pathAliases</td><td><i>OBJ</i></td><td>Path alias lookups.</td><td><i>initOnly</i></td></tr>
<tr><td>port</td><td><i>INT</i></td><td>Port for server to listen on (8080).</td><td><i>initOnly</i></td></tr>
<tr><td>post</td><td><i>STRING</i></td><td>Post string to serve.</td><td><i>initOnly</i></td></tr>
<tr><td>protocol</td><td><i>STRKEY</i></td><td>Name of protocol (ws/wss).</td><td><i></i></td></tr>
<tr><td>realm</td><td><i>STRKEY</i></td><td>Realm for basic auth (jsish).</td><td><i></i></td></tr>
<tr><td>recvBufMax</td><td><i>INT</i></td><td>Size limit of a websocket message.</td><td><i>initOnly</i></td></tr>
<tr><td>recvBufTimeout</td><td><i>INT</i></td><td>Timeout for recv of a websock msg.</td><td><i>initOnly</i></td></tr>
<tr><td>redirMax</td><td><i>BOOL</i></td><td>Temporarily disable redirects when see more than this in 10 minutes.</td><td><i></i></td></tr>
................................................................................
</font><p>Console input and output to stderr.


<h2>Methods for "console"</h2>
<table border="1"class="cmdstbl table">
<tr><th>Method</th><th>Prototype</th><th>Description</th></tr>
<tr><td>assert</td><td>assert(expr:boolean|number|function, msg:string=void, <a href='#console.assertOptions'>options</a>:object=void):void </td><td>Same as System.assert().</td></tr>
<tr><td>error</td><td>error(val, ...):void </td><td>Same as log.</td></tr>
<tr><td>input</td><td>input():string|void </td><td>Read input from the console.</td></tr>
<tr><td>log</td><td>log(val, ...):void </td><td>Same as System.puts, but goes to stderr and includes file:line.</td></tr>
<tr><td>printf</td><td>printf(format:string, ...):void </td><td>Same as System.printf but goes to stderr.</td></tr>
<tr><td>puts</td><td>puts(val, ...):void </td><td>Same as System.puts, but goes to stderr.</td></tr>
<tr><td>warn</td><td>warn(val, ...):void </td><td>Same as log.</td></tr>
</table>


<a name="console.assertOptions"></a>
<a name="console.confOptions"></a>
<h2>Options for "console.assert"</h2>
<table border="1" class="optstbl table">