Skip to content

Commit

Permalink
added ctx and properties, and a few fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
ncannasse committed Oct 6, 2024
1 parent 3785ec9 commit 2a18e3a
Showing 1 changed file with 81 additions and 16 deletions.
97 changes: 81 additions & 16 deletions hscript/JsInterp.hx
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,60 @@ package hscript;

class JsInterp extends Interp {

/**
Variables declared in `ctx` are directly accessed without going through the `variables` map, which is faster
**/
public var ctx : {};

/**
If properties are defined, all calls to get/set are only done for fields accesses which are listed here.
**/
public var properties : Map<String,Bool>;


override function execute( expr : Expr ) : Dynamic {
depth = 0;
locals = new Map();
var str = '({ _exec : ($$i) => ${exprValue(expr)} })';
trace(str);
var obj : Dynamic = js.Lib.eval(str);
return obj._exec(this);
var str = '(($$i) => ${exprValue(expr)})';
var f : Dynamic -> Dynamic = js.Lib.eval(str);
return f(this);
}

function escapeString(s:String) {
return s.split("\\").join("\\\\").split("\r").join("\\r").split("\n").join("\\n").split('"').join('\\"');
}

function handleRBC( e : Expr ) {
// todo : return/break/continue inside expr here won't work !
return e;
}

function exprValue( expr : Expr ) {
switch( Tools.expr(expr) ) {
case EBlock([]):
return "null";
case EIf(cond,e1,e2):
return exprJS(Tools.mk(ETernary(cond,e1,e2),expr));
case EBlock(el):
var el = el.copy();
var el = [for( e in el ) handleRBC(e)];
var last = el[el.length-1];
el[el.length - 1] = Tools.mk(EReturn(last),last);
switch( Tools.expr(last) ) {
case EFunction(_,_,name,_) if( name != null ): // don't return latest named function
default:
el[el.length - 1] = Tools.mk(EReturn(last),last);
}
var ebl = Tools.mk(EBlock(el),expr);
return '(() => ${exprJS(ebl)})()'; // todo : return/break/continue inside expr here won't work !
return '(() => ${exprJS(ebl)})()';
case ETry(e,v,t,ecatch):
e = handleRBC(e);
ecatch = handleRBC(ecatch);
var expr = Tools.mk(ETry(Tools.mk(EReturn(e),e),v,t,Tools.mk(EReturn(ecatch),ecatch)),expr);
return '(() => { ${exprJS(expr)} })()'; // todo : return/break/continue inside expr here won't work !
return '(() => { ${exprJS(expr)} })()';
case EVar(_,_,e):
return e == null ? "null" : '(${exprValue(e)},null)';
case EWhile(_), EFor(_), EDoWhile(_), EThrow(_):
return '(() => {${exprJS(expr)}})()'; // todo : return/break/continue inside expr here won't work !
expr = handleRBC(expr);
return '(() => {${exprJS(expr)}})()';
case EMeta(_,_,e), ECheckType(e,_):
return exprValue(e);
default:
Expand All @@ -60,9 +82,17 @@ class JsInterp extends Interp {
#end
}

function isContext(v:String) {
return ctx != null && Reflect.hasField(ctx,v);
}

function isProperty(f:String) {
return properties == null || properties.get(f);
}

function exprJS( expr : Expr ) : String {
#if hscriptPos
curExpr = e;
curExpr = expr;
var expr = expr.e;
#end
switch( expr ) {
Expand All @@ -75,6 +105,8 @@ class JsInterp extends Interp {
case EIdent(v):
if( locals.exists(v) )
return v;
if( isContext(v) )
return '$$i.ctx.$v';
switch( v ) {
case "null", "true", "false": return v;
default:
Expand All @@ -87,6 +119,12 @@ class JsInterp extends Interp {
return '(${exprValue(e)})';
case EBlock(el):
var old = locals.copy();
// pre define name functions
for( e in el )
switch( Tools.expr(e) ) {
case EFunction(_,_,name,_): locals.set(name,null);
default:
}
var buf = new StringBuf();
buf.add('{');
for( e in el ) {
Expand All @@ -96,6 +134,8 @@ class JsInterp extends Interp {
buf.add('}');
locals = old;
return buf.toString();
case EField(e,f) if( !isProperty(f) ):
return exprValue(e)+"."+f;
case EField(e, f):
return '$$i.get(${exprValue(e)},"$f")';
case EBinop(op, e1, e2):
Expand All @@ -108,6 +148,8 @@ class JsInterp extends Interp {
switch( Tools.expr(e1) ) {
case EIdent(id) if( locals.exists(id) ):
return id+" = "+exprValue(e2);
case EIdent(id) if( isContext(id) ):
return '$$i.ctx.$id = ${exprValue(e2)}';
case EIdent(id):
return '$$i.setVar("$id",${exprValue(e2)})';
case EField(e,f):
Expand All @@ -122,6 +164,8 @@ class JsInterp extends Interp {
switch( Tools.expr(e1) ) {
case EIdent(id) if( locals.exists(id) ):
return id+" "+op+" "+exprValue(e2);
case EIdent(id) if( isContext(id) ):
return '$$i.ctx.$id $op ${exprValue(e2)}';
case EIdent(id):
return '$$i.setVar("$id",$$i.resolve("$id") $aop (${exprValue(e2)}))';
case EField(e, f):
Expand All @@ -148,6 +192,8 @@ class JsInterp extends Interp {
switch( Tools.expr(e) ) {
case EIdent(id) if( locals.exists(id) ):
return prefix ? op + id : id + op;
case EIdent(id) if( isContext(id) ):
return prefix ? op + "$i.ctx."+id : "$i.ctx."+id + op;
case _ if( prefix ):
var one = Tools.mk(EConst(CInt(1)),e);
return exprJS(Tools.mk(EBinop(op.charAt(0)+"=",e,one),e));
Expand All @@ -168,8 +214,23 @@ class JsInterp extends Interp {
case ECall(e, params):
var args = [for( p in params ) exprValue(p)];
switch( Tools.expr(e) ) {
case EField(e,f):
return addPos('$$i.fcall2(${exprValue(e)},"$f",[${args.join(',')}])');
case EField(eobj,f):
var isCtx = false;
var obj = eobj;
while( true ) {
switch( Tools.expr(obj) ) {
case EField(o,_): obj = o;
case EIdent(i) if( isContext(i) ): isCtx = true; break;
default: break;
}
}
if( isCtx )
return '${exprValue(e)}(${args.join(',')})';
return addPos('$$i.fcall2(${exprValue(eobj)},"$f",[${args.join(',')}])');
case EIdent(id) if( locals.exists(id) ):
return '$id(${args.join(',')})';
case EIdent(id) if( isContext(id) ):
return '$$i.ctx.$id(${args.join(',')})';
default:
return '$$i.call(null,${exprValue(e)},[${args.join(',')}])';
}
Expand Down Expand Up @@ -233,15 +294,19 @@ class JsInterp extends Interp {
case EMeta(_, _, e), ECheckType(e,_):
return exprJS(e);
case EFunction(args, e, name, ret):
if( name != null )
locals.set(name, null);
var prev = locals.copy();
for( a in args )
locals.set(a.name, null);
var bl = exprBlock(e);
locals = prev;
var fname = if( name == null ) "" else { locals.set(name,null); " "+name; }
return 'function$fname(${[for( a in args ) a.name].join(",")}) $bl';
var fstr = 'function(${[for( a in args ) a.name].join(",")}) $bl';
if( name != null )
fstr = 'var $name = $$i.setVar("$name",$fstr)';
return fstr;
case ESwitch(e, cases, defaultExpr):
var checks = [for( c in cases ) 'if( ${[for( v in c.values ) '$$v == ${exprValue(v)}'].join(" || ")} ) return ${exprValue(c.expr)};'];
var checks = [for( c in cases ) 'if( ${[for( v in c.values ) '$$v == ${exprValue(v)}'].join(" || ")} ) return ${exprValue(handleRBC(c.expr))};'];
if( defaultExpr != null )
checks.push('return '+exprValue(defaultExpr));
return '(($$v) => { ${[for( c in checks ) c+";"].join(" ")} })(${exprValue(e)})';
Expand Down Expand Up @@ -280,7 +345,7 @@ class JsInterp extends Interp {

#if hscriptPos
function _p( pmin, pmax, origin, line ) {
curExpr = { expr : null, pmin : pmin, pmax: pmax, origin:origin, line:line };
curExpr = { e : null, pmin : pmin, pmax: pmax, origin:origin, line:line };
}
#end

Expand Down

0 comments on commit 2a18e3a

Please sign in to comment.