From ef29b7b51acfe028f08347d8e84a18851f735b2c Mon Sep 17 00:00:00 2001 From: VapireMox <3449326235@qq.com> Date: Tue, 10 Jun 2025 21:46:20 +0800 Subject: [PATCH 01/21] =?UTF-8?q?=E6=B7=BB=E5=8A=A0"static"=E4=BF=AE?= =?UTF-8?q?=E9=A5=B0=E7=AC=A6=20-=20=E6=B5=8B=E8=AF=95=E7=9A=84=E6=97=B6?= =?UTF-8?q?=E5=80=99=E8=BF=98=E6=98=AF=E6=9C=89=E7=82=B9=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E7=9A=84=20-=20=E6=AF=94=E5=A6=82=E6=90=AD=E9=85=8D"inline"?= =?UTF-8?q?=E4=BC=9A=E6=9C=89=E8=AF=AD=E6=B3=95=E6=8A=A5=E9=94=99=EF=BC=8C?= =?UTF-8?q?=E4=BD=BF=E7=94=A8"final"=E4=BC=9A=E4=B8=A7=E5=A4=B1"=E7=A6=81?= =?UTF-8?q?=E6=AD=A2setter"=E7=9A=84=E5=8A=9F=E8=83=BD=20-=20=E5=8F=8D?= =?UTF-8?q?=E6=AD=A3=E5=90=8E=E9=9D=A2=E4=BC=9A=E8=AE=A4=E7=9C=9F=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E7=9A=84=EF=BC=8C=E6=85=A2=E6=85=A2=E6=9D=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crowplexus/hscript/Expr.hx | 4 ++-- crowplexus/hscript/Interp.hx | 25 +++++++++++++++++------ crowplexus/hscript/Parser.hx | 39 ++++++++++++++++++++++++++++++++---- 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/crowplexus/hscript/Expr.hx b/crowplexus/hscript/Expr.hx index 9d8a8a2..f7657fe 100644 --- a/crowplexus/hscript/Expr.hx +++ b/crowplexus/hscript/Expr.hx @@ -64,7 +64,7 @@ enum Expr EConst(c:Const); EIdent(v:String); EImport(v:String, as:String); - EVar(n:String, ?t:CType, ?e:Expr, ?isConst:Bool); + EVar(n:String, ?t:CType, ?e:Expr, ?isConst:Bool, ?staticModifer: Bool); EParent(e:Expr); EBlock(e:Array); EField(e:Expr, f:String, s:Bool); @@ -76,7 +76,7 @@ enum Expr EFor(v:String, it:Expr, e:Expr); EBreak; EContinue; - EFunction(args:Array, e:Expr, ?name:String, ?ret:CType); + EFunction(args:Array, e:Expr, ?name:String, ?ret:CType, ?staticModifer: Bool); EReturn(?e:Expr); EArray(e:Expr, index:Expr); EArrayDecl(e:Array); diff --git a/crowplexus/hscript/Interp.hx b/crowplexus/hscript/Interp.hx index 751c9bd..8e18600 100644 --- a/crowplexus/hscript/Interp.hx +++ b/crowplexus/hscript/Interp.hx @@ -50,6 +50,8 @@ class DeclaredVar { } class Interp { + public var staticVariables:Map; + #if haxe3 public var variables: Map; public var imports: Map; @@ -87,6 +89,7 @@ class Interp { } private function resetVariables() { + staticVariables = new Map(); #if haxe3 variables = new Map(); imports = new Map(); @@ -162,7 +165,8 @@ class Interp { } public inline function setVar(name: String, v: Dynamic) { - variables.set(name, v); + if(staticVariables.exists(name)) staticVariables.set(name, v); + else variables.set(name, v); } function assign(e1: Expr, e2: Expr): Dynamic { @@ -383,6 +387,9 @@ class Interp { } function resolve(id: String): Dynamic { + if(staticVariables.exists(id)) + return staticVariables.get(id); + if (locals.exists(id)) { var l = locals.get(id); return l.r; @@ -427,9 +434,13 @@ class Interp { } case EIdent(id): return resolve(id); - case EVar(n, _, v, isConst): - declared.push({n: n, old: locals.get(n)}); - locals.set(n, {r: (v == null) ? null : expr(v), const: isConst}); + case EVar(n, _, v, isConst, s): + var v = (v == null) ? null : expr(v); + if(s == true) if(!staticVariables.exists(n)) staticVariables.set(n, v); + else { + declared.push({n: n, old: locals.get(n)}); + locals.set(n, {r: v, const: isConst}); + } return null; case EParent(e): return expr(e); @@ -528,7 +539,7 @@ class Interp { } return null; // yeah. -Crow - case EFunction(params, fexpr, name, _): + case EFunction(params, fexpr, name, _, s): var capturedLocals = duplicate(locals); var me = this; var hasOpt = false, minParams = 0; @@ -590,7 +601,9 @@ class Interp { if (name != null) { if (depth == 0) { // global function - variables.set(name, f); + if(s == true) { + if(!staticVariables.exists(name)) staticVariables.set(name, f); + } else variables.set(name, f); } else { // function-in-function is a local function declared.push({n: name, old: locals.get(name)}); diff --git a/crowplexus/hscript/Parser.hx b/crowplexus/hscript/Parser.hx index 2a53001..9107d94 100644 --- a/crowplexus/hscript/Parser.hx +++ b/crowplexus/hscript/Parser.hx @@ -113,6 +113,9 @@ class Parser { var ops: Array; var idents: Array; var uid: Int = 0; + var abductCount:Int = 0; + var abducts = ["function", "if", "for", "while", "try", "switch"]; + var sureStaticModifier:Bool = false; #if hscriptPos var origin: String; @@ -182,6 +185,9 @@ class Parser { } public inline function error(err, pmin, pmax) { + if(sureStaticModifier) sureStaticModifier = false; + if(abductCount > 0) abductCount = 0; + if (!resumeErrors) #if hscriptPos throw new Error(err, pmin, pmax, origin, line); @@ -413,7 +419,9 @@ class Parser { #end switch (tk) { case TId(id): + if(abducts.contains(id)) abductCount++; var e = parseStructure(id); + if(abducts.contains(id)) abductCount--; if (e == null) e = mk(EIdent(id)); return parseExprNext(e); @@ -423,7 +431,9 @@ class Parser { tk = token(); if (tk == TPClose) { ensureToken(TOp("->")); + abductCount++; var eret = parseExpr(); + abductCount--; return mk(EFunction([], mk(EReturn(eret), p1)), p1); } push(tk); @@ -487,13 +497,15 @@ class Parser { push(tk); } var a = new Array(); - while (true) { + abductCount++; + while( true ) { parseFullExpr(a); tk = token(); - if (tk == TBrClose || (resumeErrors && tk == TEof)) + if( tk == TBrClose || (resumeErrors && tk == TEof) ) break; push(tk); } + abductCount--; return mk(EBlock(a), p1); case TOp(op): if (op == "-") { @@ -659,6 +671,21 @@ class Parser { push(TSemicolon); } mk(EIf(cond, e1, e2), p1, (e2 == null) ? tokenMax : pmax(e2)); + case "static": + if(abductCount == 0) { + var t = token(); + switch(t) { + case TId(byd): + if(byd == "var" || byd == "final" || byd == "function") { + sureStaticModifier = true; + var ret = parseStructure(byd); + sureStaticModifier = false; + return ret; + } else unexpected(TId(id)); + default: unexpected(TId(id)); + } + } else error(ECustom('Cannot Set-up "$id" In Local.'), tokenMin, tokenMax); + null; case "var", "final": var ident = getIdent(); var tk = token(); @@ -672,7 +699,7 @@ class Parser { e = parseExpr(); else push(tk); - mk(EVar(ident, t, e, id == "final"), p1, (e == null) ? tokenMax : pmax(e)); + mk(EVar(ident, t, e, id == "final", if(abductCount == 0) sureStaticModifier else false), p1, (e == null) ? tokenMax : pmax(e)); case "while": var econd = parseExpr(); var e = parseExpr(); @@ -709,7 +736,7 @@ class Parser { default: push(tk); } var inf = parseFunctionDecl(); - mk(EFunction(inf.args, inf.body, name, inf.ret), p1, pmax(inf.body)); + mk(EFunction(inf.args, inf.body, name, inf.ret, if(abductCount == 0) sureStaticModifier else false), p1, pmax(inf.body)); case "return": var tk = token(); push(tk); @@ -996,10 +1023,14 @@ class Parser { // single arg reinterpretation of `f -> e` , `(f) -> e` and `(f:T) -> e` switch (expr(e1)) { case EIdent(i), EParent(expr(_) => EIdent(i)): + abductCount++; var eret = parseExpr(); + abductCount--; return mk(EFunction([{name: i}], mk(EReturn(eret), pmin(eret))), pmin(e1)); case ECheckType(expr(_) => EIdent(i), t): + abductCount++; var eret = parseExpr(); + abductCount--; return mk(EFunction([{name: i, t: t}], mk(EReturn(eret), pmin(eret))), pmin(e1)); default: } From 3467b6fd987f10de677dcc2bc56f20a1944761f9 Mon Sep 17 00:00:00 2001 From: VapireMox <3449326235@qq.com> Date: Tue, 10 Jun 2025 23:36:41 +0800 Subject: [PATCH 02/21] =?UTF-8?q?=E7=B4=A7=E6=80=A5=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E4=BD=BF=E7=94=A8var=E7=9A=84getter=E5=92=8C?= =?UTF-8?q?setter=20-=20666=EF=BC=8C=E7=A7=BB=E8=BF=87=E6=9D=A5=E7=9A=84?= =?UTF-8?q?=E6=97=B6=E5=80=99=E8=AF=AD=E6=B3=95=E5=86=99=E9=94=99=E4=BA=86?= =?UTF-8?q?=EF=BC=8C=E7=8E=B0=E5=9C=A8=E5=BA=94=E8=AF=A5=E6=B2=A1=E5=95=A5?= =?UTF-8?q?=E9=97=AE=E9=A2=98=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crowplexus/hscript/Interp.hx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/crowplexus/hscript/Interp.hx b/crowplexus/hscript/Interp.hx index 8e18600..2bba780 100644 --- a/crowplexus/hscript/Interp.hx +++ b/crowplexus/hscript/Interp.hx @@ -387,14 +387,14 @@ class Interp { } function resolve(id: String): Dynamic { - if(staticVariables.exists(id)) - return staticVariables.get(id); - if (locals.exists(id)) { var l = locals.get(id); return l.r; } + if(staticVariables.exists(id)) + return staticVariables.get(id); + if (variables.exists(id)) { var v = variables.get(id); return v; @@ -435,9 +435,10 @@ class Interp { case EIdent(id): return resolve(id); case EVar(n, _, v, isConst, s): - var v = (v == null) ? null : expr(v); - if(s == true) if(!staticVariables.exists(n)) staticVariables.set(n, v); - else { + var v = (v == null ? null : expr(v)); + if(s == true) { + if(!staticVariables.exists(n)) staticVariables.set(n, v); + } else { declared.push({n: n, old: locals.get(n)}); locals.set(n, {r: v, const: isConst}); } From 3f17c6a066c234356ee2430951b324fa230d2d92 Mon Sep 17 00:00:00 2001 From: VapireMox <3449326235@qq.com> Date: Wed, 11 Jun 2025 01:49:25 +0800 Subject: [PATCH 03/21] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E4=BB=A5=E5=8F=8A=E6=94=AF=E6=8C=81getter=E5=92=8Csetter?= =?UTF-8?q?=E7=9A=84=E4=B9=A6=E5=86=99=20-=20=E4=BF=AE=E5=A4=8D=E4=BA=86?= =?UTF-8?q?=E4=B8=8A=E4=B8=8A=E4=B8=80=E6=AC=A1commit=E6=89=80=E6=8F=90?= =?UTF-8?q?=E5=88=B0=E7=9A=84=E9=97=AE=E9=A2=98=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=BA=86=E5=AF=B9getter=E5=92=8Csetter=E4=B9=A6=E5=86=99?= =?UTF-8?q?=E7=9A=84=E6=94=AF=E6=8C=81=EF=BC=8C=E4=BD=86=E4=BB=85=E9=99=90?= =?UTF-8?q?=E4=B9=A6=E5=86=99=F0=9F=91=87=20-=20haxe```=20-=20//=E6=94=AF?= =?UTF-8?q?=E6=8C=81=20-=20var=20byd(default,=20null):Dynamic=20=3D=2010;?= =?UTF-8?q?=20-=20{=20-=20=09//=E6=8A=A5=E9=94=99=EF=BC=8C=E4=B8=8D?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=9C=A8local=E4=B8=AD=E8=AE=BE=E7=BD=AEgett?= =?UTF-8?q?er=E5=92=8Csetter=20-=20=09var=20byd(default,=20null):Dynamic?= =?UTF-8?q?=20=3D=2010;=20-=20}=20-=20```?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crowplexus/hscript/Interp.hx | 17 +++++---- crowplexus/hscript/Parser.hx | 74 ++++++++++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 11 deletions(-) diff --git a/crowplexus/hscript/Interp.hx b/crowplexus/hscript/Interp.hx index 2bba780..468b5f0 100644 --- a/crowplexus/hscript/Interp.hx +++ b/crowplexus/hscript/Interp.hx @@ -165,8 +165,11 @@ class Interp { } public inline function setVar(name: String, v: Dynamic) { - if(staticVariables.exists(name)) staticVariables.set(name, v); - else variables.set(name, v); + if(staticVariables.exists(name)) { + staticVariables.set(name, v); + } else if(staticVariables.exists('$name;const')) { + warn(ECustom("Cannot reassign final, for constant expression -> " + name)); + } else variables.set(name, v); } function assign(e1: Expr, e2: Expr): Dynamic { @@ -387,13 +390,13 @@ class Interp { } function resolve(id: String): Dynamic { - if (locals.exists(id)) { - var l = locals.get(id); - return l.r; - } + var l = locals.get(id); + if (l != null) return l.r; if(staticVariables.exists(id)) return staticVariables.get(id); + else if(staticVariables.exists('$id;const')) + return staticVariables.get('$id;const'); if (variables.exists(id)) { var v = variables.get(id); @@ -437,7 +440,7 @@ class Interp { case EVar(n, _, v, isConst, s): var v = (v == null ? null : expr(v)); if(s == true) { - if(!staticVariables.exists(n)) staticVariables.set(n, v); + if(!staticVariables.exists(n)) staticVariables.set((isConst ? '$n;const' : n), v); } else { declared.push({n: n, old: locals.get(n)}); locals.set(n, {r: v, const: isConst}); diff --git a/crowplexus/hscript/Parser.hx b/crowplexus/hscript/Parser.hx index 9107d94..7452496 100644 --- a/crowplexus/hscript/Parser.hx +++ b/crowplexus/hscript/Parser.hx @@ -681,7 +681,14 @@ class Parser { var ret = parseStructure(byd); sureStaticModifier = false; return ret; - } else unexpected(TId(id)); + } else if(byd == "inline") { + if(!maybe(TId("function"))) + return unexpected(TId(byd)); + sureStaticModifier = true; + var ret = parseStructure("function"); + sureStaticModifier = false; + return ret; + } else unexpected(TId(byd)); default: unexpected(TId(id)); } } else error(ECustom('Cannot Set-up "$id" In Local.'), tokenMin, tokenMax); @@ -690,6 +697,42 @@ class Parser { var ident = getIdent(); var tk = token(); var t = null; + if(tk == TPOpen) { + if(abductCount == 0 && id == "var") { + var getter:Null = null; + var setter:Null = null; + var displayComma:Bool = false; + var closed:Bool = false; + while(true) { + var t = token(); + switch(t) { + case TComma: + if(getter != null && !displayComma) { + displayComma = true; + } else unexpected(t); + case TId(byd): + if(getter == null && !displayComma) { + if(byd == "get" || byd == "never" || byd == "default" || byd == "null") { + getter = byd; + } else unexpected(t); + } else if(setter == null && displayComma) { + if(byd == "set" || byd == "never" || byd == "default" || byd == "null") { + setter = byd; + } else unexpected(t); + } else unexpected(t); + case TPClose: + if(getter != null && setter != null) closed = true; + else unexpected(t); + default: + unexpected(t); + } + + if(closed) break; + } + trace('getter: $getter, setter: $setter'); + tk = token(); + } else unexpected(tk); + } if (tk == TDoubleDot && allowTypes) { t = parseType(); tk = token(); @@ -725,9 +768,32 @@ class Parser { case "continue": mk(EContinue); case "else": unexpected(TId(id)); case "inline": - if (!maybe(TId("function"))) - unexpected(TId("inline")); - return parseStructure("function"); + var t = token(); + switch(t) { + case TId(id): + if(id == "static") { + if(!sureStaticModifier && abductCount == 0) { + if(abductCount == 0) { + var t = token(); + switch(t) { + case TId(byd): + if(byd == "function") { + sureStaticModifier = true; + var ret = parseStructure(byd); + sureStaticModifier = false; + return ret; + } else unexpected(TId(id)); + default: unexpected(TId(id)); + } + } else error(ECustom('Cannot Set-up "$id" In Local.'), tokenMin, tokenMax); + return null; + } + } else if(id == "function") { + return parseStructure("function"); + } + default: //nothing here + } + unexpected(t); case "function": var tk = token(); var name = null; From d46761583a08c64c16058d1efabbee92aa8c8ff4 Mon Sep 17 00:00:00 2001 From: VapireMox <3449326235@qq.com> Date: Thu, 12 Jun 2025 14:03:57 +0800 Subject: [PATCH 04/21] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AF=B9getter=E4=BB=A5=E5=8F=8Asetter?= =?UTF-8?q?=E7=9A=84=E5=8A=9F=E8=83=BD=E6=94=AF=E6=8C=81=20-=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E9=83=A8=E5=88=86=E9=97=AE=E9=A2=98=EF=BC=88=E5=B0=BD?= =?UTF-8?q?=E7=AE=A1=E8=82=AF=E5=AE=9A=E8=BF=98=E6=9C=89=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=89=20-=20=E6=B7=BB=E5=8A=A0=E4=BA=86=E5=AF=B9getter?= =?UTF-8?q?=E4=BB=A5=E5=8F=8Asetter=E7=9A=84=E6=94=AF=E6=8C=81=EF=BC=88?= =?UTF-8?q?=E4=B8=8D=E5=8C=85=E5=90=ABstatic=E5=8F=98=E9=87=8F=E7=9A=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81=EF=BC=8C=E8=80=8C=E4=B8=94=E8=BF=98=E6=9C=89?= =?UTF-8?q?bug=EF=BC=8C=E6=85=A2=E6=85=A2=E6=9D=A5=E5=90=A7=EF=BC=89=20-?= =?UTF-8?q?=20TODO:=20[=20-=20=09=E6=B7=BB=E5=8A=A0Regex=E7=9A=84=E4=B9=A6?= =?UTF-8?q?=E5=86=99=E6=A0=BC=E5=BC=8F=E6=94=AF=E6=8C=81=EF=BC=8C=20-=20?= =?UTF-8?q?=09=E8=BF=98=E6=9C=89`setParent`=20-=20]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/main.yml | 19 ++++++ crowplexus/hscript/Expr.hx | 2 +- crowplexus/hscript/Interp.hx | 119 +++++++++++++++++++++++++++++++--- crowplexus/hscript/Parser.hx | 23 ++++--- crowplexus/hscript/Printer.hx | 4 +- crowplexus/hscript/Tools.hx | 4 +- 6 files changed, 149 insertions(+), 22 deletions(-) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..381c523 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,19 @@ +name: Main + +on: [push, workflow_dispatch] +jobs: + SEX: + runs-on: ubuntu-22.04 + steps: + - name: Checkout Commit + uses: actions/checkout@v2 + + - name: Install Haxe + uses: krdlab/setup-haxe@v1 + with: + haxe-version: 4.3.6 + + - name: Testing + runs: | + cd ./tests + haxe linux.hxml \ No newline at end of file diff --git a/crowplexus/hscript/Expr.hx b/crowplexus/hscript/Expr.hx index f7657fe..a1922a9 100644 --- a/crowplexus/hscript/Expr.hx +++ b/crowplexus/hscript/Expr.hx @@ -64,7 +64,7 @@ enum Expr EConst(c:Const); EIdent(v:String); EImport(v:String, as:String); - EVar(n:String, ?t:CType, ?e:Expr, ?isConst:Bool, ?staticModifer: Bool); + EVar(n:String, ?t:CType, ?e:Expr, ?getter:String, ?setter:String, ?isConst:Bool, ?staticModifer: Bool); EParent(e:Expr); EBlock(e:Array); EField(e:Expr, f:String, s:Bool); diff --git a/crowplexus/hscript/Interp.hx b/crowplexus/hscript/Interp.hx index 468b5f0..725e638 100644 --- a/crowplexus/hscript/Interp.hx +++ b/crowplexus/hscript/Interp.hx @@ -40,7 +40,7 @@ private enum Stop { @:structInit class LocalVar { public var r: Dynamic; - public var const: Bool; + public var const:Bool; } @:structInit @@ -49,21 +49,26 @@ class DeclaredVar { public var old: LocalVar; } +@:allow(crowplexus.hscript.PropertyAccessor) class Interp { - public var staticVariables:Map; - #if haxe3 + public var staticVariables:Map; public var variables: Map; public var imports: Map; var locals: Map; + var props:Map; var binops: MapExpr->Dynamic>; + var propertyLinks:Map; #else + public var staticVariables:Hash; public var variables: Hash; public var imports: Hash; var locals: Hash; + var props:Hash; var binops: HashExpr->Dynamic>; + var propertyLinks:Hash; #end var depth: Int; @@ -79,8 +84,10 @@ class Interp { public function new() { #if haxe3 + staticVariables = new Map(); locals = new Map(); #else + staticVariables = new Hash(); locals = new Hash(); #end declared = new Array(); @@ -89,12 +96,15 @@ class Interp { } private function resetVariables() { - staticVariables = new Map(); #if haxe3 + propertyLinks = new Map(); variables = new Map(); + props = new Map(); imports = new Map(); #else + propertyLinks = new Hash(); variables = new Hash(); + props = new Hash(); imports = new Hash(); #end @@ -165,6 +175,13 @@ class Interp { } public inline function setVar(name: String, v: Dynamic) { + if(propertyLinks.get(name) != null) { + var l = propertyLinks.get(name); + if(l.inState) l.set(name, v); + else l.link_setFunc(v); + return; + } + if(staticVariables.exists(name)) { staticVariables.set(name, v); } else if(staticVariables.exists('$name;const')) { @@ -393,6 +410,12 @@ class Interp { var l = locals.get(id); if (l != null) return l.r; + if(propertyLinks.get(id) != null) { + var l = propertyLinks.get(id); + if(l.inState) return l.get(id); + else return l.link_getFunc(); + } + if(staticVariables.exists(id)) return staticVariables.get(id); else if(staticVariables.exists('$id;const')) @@ -437,13 +460,29 @@ class Interp { } case EIdent(id): return resolve(id); - case EVar(n, _, v, isConst, s): + case EVar(n, _, v, getter, setter, isConst, s): + if(getter == null) getter = "default"; + if(setter == null) setter = "default"; + var v = (v == null ? null : expr(v)); if(s == true) { - if(!staticVariables.exists(n)) staticVariables.set((isConst ? '$n;const' : n), v); + if(!staticVariables.exists(n)) staticVariables.set(n, v); } else { - declared.push({n: n, old: locals.get(n)}); - locals.set(n, {r: v, const: isConst}); + if(!isConst && (getter != "default" || setter != "default")) { + props.set(n, v); + propertyLinks.set(n, new PropertyAccessor(this, () -> { + if(props.exists(n)) return props.get(n); + else throw error(EUnknownVariable(n)); + return null; + }, (val) -> { + if(props.exists(n)) props.set(n, val); + else throw error(EUnknownVariable(n)); + return val; + }, getter, setter)); + } else { + declared.push({n: n, old: locals.get(n)}); + locals.set(n, {r: v, const: isConst}); + } } return null; case EParent(e): @@ -1013,3 +1052,67 @@ class Interp { return Type.createInstance(c, args); } } + +//呵呵,我乱命名的,别在意 +class PropertyAccessor { + public var getter(default, null):String; + public var setter(default, null):String; + public var proxy(default, null):Interp; + public var inState(default, null):Bool = true; + public var link_getFunc(default, null):Void->Dynamic; + public var link_setFunc(default, null):Dynamic->Dynamic; + + public function new(proxy:Interp, link_getFunc:Void->Dynamic, link_setFunc:Dynamic->Dynamic, getter1:String = "default", setter1:String = "default") { + this.proxy = proxy; + this.link_getFunc = link_getFunc; + this.link_setFunc = link_setFunc; + this.getter = getter1; + this.setter = setter1; + } + + public function get(name:String):Dynamic { + if(link_getFunc == null && proxy == null) return null; + return switch(getter) { + case "default": + link_getFunc(); + case "never": + throw proxy.error(ECustom('Cannot Access Read This Property -> "$name"')); + null; + case "null": + link_getFunc(); + case "get": + if(Reflect.isFunction(proxy.variables.get('get_$name'))) { + inState = false; + var ret:Dynamic = Reflect.callMethod(null, proxy.variables.get('get_$name'), []); + inState = true; + return ret; + } else proxy.error(ECustom('Cannot Access Read This Property "$name" Due To Dose Not Exist Function -> "get_$name"')); + null; + default: + null; + } + } + + public function set(name:String, value:Dynamic) { + if(link_setFunc == null && proxy == null) return null; + return switch(setter) { + case "default": + link_setFunc(value); + case "never": + throw proxy.error(ECustom('Cannot Access Write This Property -> "$name"')); + null; + case "null": + link_setFunc(value); + case "set": + if(Reflect.isFunction(proxy.variables.get('set_$name'))) { + inState = false; + var ret:Dynamic = Reflect.callMethod(null, proxy.variables.get('set_$name'), [value]); + inState = true; + return ret; + } else proxy.error(ECustom('Cannot Access Write This Property "$name" Due To Dose Not Exist Function -> "set_$name"')); + null; + default: + null; + } + } +} \ No newline at end of file diff --git a/crowplexus/hscript/Parser.hx b/crowplexus/hscript/Parser.hx index 7452496..7c4caa3 100644 --- a/crowplexus/hscript/Parser.hx +++ b/crowplexus/hscript/Parser.hx @@ -694,13 +694,15 @@ class Parser { } else error(ECustom('Cannot Set-up "$id" In Local.'), tokenMin, tokenMax); null; case "var", "final": + var getter:String = "default"; + var setter:String = "default"; var ident = getIdent(); var tk = token(); var t = null; if(tk == TPOpen) { if(abductCount == 0 && id == "var") { - var getter:Null = null; - var setter:Null = null; + var getter1:Null = null; + var setter1:Null = null; var displayComma:Bool = false; var closed:Bool = false; while(true) { @@ -711,17 +713,17 @@ class Parser { displayComma = true; } else unexpected(t); case TId(byd): - if(getter == null && !displayComma) { + if(getter1 == null && !displayComma) { if(byd == "get" || byd == "never" || byd == "default" || byd == "null") { - getter = byd; + getter1 = byd; } else unexpected(t); - } else if(setter == null && displayComma) { + } else if(setter1 == null && displayComma) { if(byd == "set" || byd == "never" || byd == "default" || byd == "null") { - setter = byd; + setter1 = byd; } else unexpected(t); } else unexpected(t); case TPClose: - if(getter != null && setter != null) closed = true; + if(getter1 != null && setter1 != null) closed = true; else unexpected(t); default: unexpected(t); @@ -729,7 +731,10 @@ class Parser { if(closed) break; } - trace('getter: $getter, setter: $setter'); + + if(getter1 != null) getter = getter1; + if(setter1 != null) setter = setter1; + tk = token(); } else unexpected(tk); } @@ -742,7 +747,7 @@ class Parser { e = parseExpr(); else push(tk); - mk(EVar(ident, t, e, id == "final", if(abductCount == 0) sureStaticModifier else false), p1, (e == null) ? tokenMax : pmax(e)); + mk(EVar(ident, t, e, getter, setter, (id == "final"), if(abductCount == 0) sureStaticModifier else false), p1, (e == null) ? tokenMax : pmax(e)); case "while": var econd = parseExpr(); var e = parseExpr(); diff --git a/crowplexus/hscript/Printer.hx b/crowplexus/hscript/Printer.hx index 19a4764..a795dd1 100644 --- a/crowplexus/hscript/Printer.hx +++ b/crowplexus/hscript/Printer.hx @@ -186,7 +186,7 @@ class Printer { } case EIdent(v): add(v); - case EVar(n, t, e, c): + case EVar(n, t, e, gt, st, c, s): if (c) { add("final " + n); } else { @@ -287,7 +287,7 @@ class Printer { add("break"); case EContinue: add("continue"); - case EFunction(params, e, name, ret): + case EFunction(params, e, name, ret, s): add("function"); if (name != null) add(" " + name); diff --git a/crowplexus/hscript/Tools.hx b/crowplexus/hscript/Tools.hx index 67513a6..4c07dca 100644 --- a/crowplexus/hscript/Tools.hx +++ b/crowplexus/hscript/Tools.hx @@ -28,7 +28,7 @@ class Tools { public static function iter(e: Expr, f: Expr->Void) { switch (expr(e)) { case EConst(_), EIdent(_): - case EVar(_, _, e, _): + case EVar(_, _, e, getter, setter, _, s): if (e != null) f(e); case EParent(e): @@ -62,7 +62,7 @@ class Tools { f(it); f(e); case EBreak, EContinue: - case EFunction(_, e, _, _): + case EFunction(_, e, _, _, s): f(e); case EReturn(e): if (e != null) From 59a6da6b99157892f099cb61f8cfb4e9d6eda50b Mon Sep 17 00:00:00 2001 From: GeXie <3449326235@qq.com> Date: Thu, 12 Jun 2025 14:13:14 +0800 Subject: [PATCH 05/21] =?UTF-8?q?=E8=A7=A3=E5=86=B3yml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 381c523..66dab89 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,10 +3,10 @@ name: Main on: [push, workflow_dispatch] jobs: SEX: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - name: Checkout Commit - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install Haxe uses: krdlab/setup-haxe@v1 @@ -14,6 +14,6 @@ jobs: haxe-version: 4.3.6 - name: Testing - runs: | + run: | cd ./tests - haxe linux.hxml \ No newline at end of file + haxe linux.hxml From 53cb0c02b2ea683e423fa297375a7451635e969e Mon Sep 17 00:00:00 2001 From: VapireMox <3449326235@qq.com> Date: Thu, 12 Jun 2025 14:15:59 +0800 Subject: [PATCH 06/21] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E6=97=B6=E5=87=BA=E7=8E=B0=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/main.yml | 1 + crowplexus/hscript/Bytes.hx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 66dab89..d51336a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,6 +1,7 @@ name: Main on: [push, workflow_dispatch] + jobs: SEX: runs-on: ubuntu-latest diff --git a/crowplexus/hscript/Bytes.hx b/crowplexus/hscript/Bytes.hx index d3df742..0c3c2e7 100644 --- a/crowplexus/hscript/Bytes.hx +++ b/crowplexus/hscript/Bytes.hx @@ -371,7 +371,7 @@ class Bytes { case EIdent(v): doEncodeExprType(EIdent); doEncodeString(v); - case EVar(n, _, e, c): + case EVar(n, _, e, getter, setter, c, s): doEncodeExprType(EVar); doEncodeString(n); if (e == null) From 73dbcb273f92bee71f8d955e5020aa7756abc055 Mon Sep 17 00:00:00 2001 From: VapireMox <3449326235@qq.com> Date: Thu, 12 Jun 2025 14:21:15 +0800 Subject: [PATCH 07/21] =?UTF-8?q?=E5=BF=98=E5=8A=A0=E5=BA=93=E4=BA=86?= =?UTF-8?q?=F0=9F=98=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/main.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d51336a..f00821a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,6 +14,11 @@ jobs: with: haxe-version: 4.3.6 + #忘加库了😅 + - name: Add Lib + run: | + haxelib install hxcpp --quiet + - name: Testing run: | cd ./tests From 830dd925565296049c02f8c4b3974e0daa6598d7 Mon Sep 17 00:00:00 2001 From: VapireMox <3449326235@qq.com> Date: Fri, 13 Jun 2025 00:34:14 +0800 Subject: [PATCH 08/21] =?UTF-8?q?=E6=B7=BB=E5=8A=A0ParentInstance=E4=BB=A5?= =?UTF-8?q?=E5=8F=8A=E8=87=AA=E5=8A=A8=E8=8E=B7=E5=8F=96=E6=97=A0=E5=8C=85?= =?UTF-8?q?=E8=A3=85=E7=9A=84=E7=B1=BB=20-=20=E8=87=AA=E4=B8=AA=E7=9C=8B?= =?UTF-8?q?=E5=90=A7=EF=BC=8C=E6=88=91=E6=8F=8F=E8=BF=B0=E4=B8=8D=E5=87=BA?= =?UTF-8?q?=E6=9D=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crowplexus/hscript/Interp.hx | 62 ++++++++++++++++++++++++++++++++---- crowplexus/iris/Iris.hx | 4 +-- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/crowplexus/hscript/Interp.hx b/crowplexus/hscript/Interp.hx index 725e638..5203278 100644 --- a/crowplexus/hscript/Interp.hx +++ b/crowplexus/hscript/Interp.hx @@ -51,8 +51,12 @@ class DeclaredVar { @:allow(crowplexus.hscript.PropertyAccessor) class Interp { + /** + * 还是觉得直接包装成静态更好一点(不模仿) + */ + public static var staticVariables:#if haxe3 Map = new Map() #else Hash = new Hash() #end; + #if haxe3 - public var staticVariables:Map; public var variables: Map; public var imports: Map; @@ -61,7 +65,6 @@ class Interp { var binops: MapExpr->Dynamic>; var propertyLinks:Map; #else - public var staticVariables:Hash; public var variables: Hash; public var imports: Hash; @@ -71,6 +74,29 @@ class Interp { var propertyLinks:Hash; #end + /** + * 反狼偷家 + */ + public var parentInstance(default, set):Dynamic; + var _parentFields:Array = []; + @:dox(hide) function set_parentInstance(val:Dynamic):Dynamic { + if(val != null) { + switch(Type.typeof(val)) { + case Type.ValueType.TObject if(!(val is Enum)): + _parentFields = if(val is Class) Type.getClassFields(val); + else Reflect.fields(val); + case Type.ValueType.TClass(_): + _parentFields = Type.getInstanceFields(Type.getClass(val)); + case _: + //nothing + } + } + + if(_parentFields == null) _parentFields = []; + + return parentInstance = val; + } + var depth: Int; var inTry: Bool; var declared: Array; @@ -84,10 +110,8 @@ class Interp { public function new() { #if haxe3 - staticVariables = new Map(); locals = new Map(); #else - staticVariables = new Hash(); locals = new Hash(); #end declared = new Array(); @@ -186,7 +210,12 @@ class Interp { staticVariables.set(name, v); } else if(staticVariables.exists('$name;const')) { warn(ECustom("Cannot reassign final, for constant expression -> " + name)); + } else if(parentInstance != null) { + if(_parentFields.contains(name) || _parentFields.contains('set_$name')) { + Reflect.setProperty(parentInstance, name, v); + } } else variables.set(name, v); + } function assign(e1: Expr, e2: Expr): Dynamic { @@ -195,7 +224,7 @@ class Interp { case EIdent(id): var l = locals.get(id); if (l == null) - setVar(id, v) + setVar(id, v); else { if (l.const != true) l.r = v; @@ -406,6 +435,7 @@ class Interp { #end } + @:noCompletion static var unpackClassCache:#if haxe3 Map = new Map() #else Hash = new Hash() #end; function resolve(id: String): Dynamic { var l = locals.get(id); if (l != null) return l.r; @@ -426,11 +456,28 @@ class Interp { return v; } + if(parentInstance != null) { + if(id == "this") return parentInstance; + if(_parentFields.contains(id) || _parentFields.contains('get_$id')) { + return Reflect.getProperty(parentInstance, id); + } + } + if (imports.exists(id)) { var v = imports.get(id); return v; } + if(unpackClassCache.get(id) is Class) { + return unpackClassCache.get(id); + } else { + final cl = Type.resolveClass(id); + if(cl != null) { + unpackClassCache.set(id, cl); + return cl; + } + } + error(EUnknownVariable(id)); return null; @@ -1038,7 +1085,10 @@ class Interp { if (v != null) return v; } - return call(o, get(o, f), args); + + return { + call(o, get(o, f), args); + } } function call(o: Dynamic, f: Dynamic, args: Array): Dynamic { diff --git a/crowplexus/iris/Iris.hx b/crowplexus/iris/Iris.hx index 6c013d9..776427b 100644 --- a/crowplexus/iris/Iris.hx +++ b/crowplexus/iris/Iris.hx @@ -289,9 +289,9 @@ class Iris { * Appends Default Classes/Enums for the Script to use. **/ public function preset(): Void { - set("Std", Std); // TODO: add a proxy for std + /*set("Std", Std); set("StringTools", StringTools); - set("Math", Math); + set("Math", Math);*/ #if hscriptPos // overriding trace for good measure. // if you're a game developer or a fnf modder (hi guys), From 5fe65ec8022ed687b13606cbfe9c1b0c764bce80 Mon Sep 17 00:00:00 2001 From: VapireMox <3449326235@qq.com> Date: Fri, 13 Jun 2025 02:28:13 +0800 Subject: [PATCH 09/21] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AF=B9static?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E7=9A=84getter=E4=BB=A5=E5=8F=8Asetter?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E6=94=AF=E6=8C=81=EF=BC=8C=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E9=83=A8=E5=88=86=E9=97=AE=E9=A2=98=20-=20=E7=8E=B0=E5=9C=A8?= =?UTF-8?q?=E6=94=AF=E6=8C=81static=E5=8F=98=E9=87=8F=E7=9A=84prop?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E8=AE=BE=E7=BD=AE=20-=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E9=83=A8=E5=88=86=E9=97=AE=E9=A2=98=EF=BC=88=E4=B8=8A=E6=AC=A1?= =?UTF-8?q?=E5=AF=BC=E7=AE=A1=E5=8F=88=E8=82=98=E5=87=BB=E5=87=BA=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E9=97=AE=E9=A2=98=EF=BC=8C=E5=B7=B2=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=EF=BC=89=20-=20=E8=AF=A6=E7=BB=86=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E7=9C=8Bsource=20-=20TODO:=20[=20-=20=E7=AB=8B=E4=B8=AA?= =?UTF-8?q?=F0=9F=94=A8=E7=9A=84FLAG=20-=20]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crowplexus/hscript/Interp.hx | 43 ++++++++++++++++++++++++++++------- crowplexus/hscript/Printer.hx | 10 ++++++++ tests/src/Main.hx | 6 ++--- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/crowplexus/hscript/Interp.hx b/crowplexus/hscript/Interp.hx index 5203278..c5e53d6 100644 --- a/crowplexus/hscript/Interp.hx +++ b/crowplexus/hscript/Interp.hx @@ -513,7 +513,23 @@ class Interp { var v = (v == null ? null : expr(v)); if(s == true) { - if(!staticVariables.exists(n)) staticVariables.set(n, v); + if(!staticVariables.exists(n) && !staticVariables.exists(n + ";const")) { + if(isConst) staticVariables.set(n + ";const", v); + else { + staticVariables.set(n, v); + if(getter != "default" || setter != "default") { + propertyLinks.set(n, new PropertyAccessor(this, () -> { + if(staticVariables.exists(n)) return staticVariables.get(n); + else throw error(EUnknownVariable(n)); + return null; + }, (val) -> { + if(staticVariables.exists(n)) staticVariables.set(n, val); + else throw error(EUnknownVariable(n)); + return val; + }, getter, setter, true)); + } + } + } } else { if(!isConst && (getter != "default" || setter != "default")) { props.set(n, v); @@ -1112,12 +1128,15 @@ class PropertyAccessor { public var link_getFunc(default, null):Void->Dynamic; public var link_setFunc(default, null):Dynamic->Dynamic; - public function new(proxy:Interp, link_getFunc:Void->Dynamic, link_setFunc:Dynamic->Dynamic, getter1:String = "default", setter1:String = "default") { + var isStatic:Bool; + + public function new(proxy:Interp, link_getFunc:Void->Dynamic, link_setFunc:Dynamic->Dynamic, getter1:String = "default", setter1:String = "default", isStatic:Bool = false) { this.proxy = proxy; this.link_getFunc = link_getFunc; this.link_setFunc = link_setFunc; this.getter = getter1; this.setter = setter1; + this.isStatic = isStatic; } public function get(name:String):Dynamic { @@ -1131,12 +1150,16 @@ class PropertyAccessor { case "null": link_getFunc(); case "get": - if(Reflect.isFunction(proxy.variables.get('get_$name'))) { + final variables = { + if(this.isStatic) Interp.staticVariables; + else proxy.variables; + } + if(Reflect.isFunction(variables.get('get_$name'))) { inState = false; - var ret:Dynamic = Reflect.callMethod(null, proxy.variables.get('get_$name'), []); + var ret:Dynamic = Reflect.callMethod(null, variables.get('get_$name'), []); inState = true; return ret; - } else proxy.error(ECustom('Cannot Access Read This Property "$name" Due To Dose Not Exist Function -> "get_$name"')); + } else proxy.error(ECustom('Cannot Access Read This Property "$name" Due To Invalid Function -> "get_$name"')); null; default: null; @@ -1154,12 +1177,16 @@ class PropertyAccessor { case "null": link_setFunc(value); case "set": - if(Reflect.isFunction(proxy.variables.get('set_$name'))) { + final variables = { + if(this.isStatic) Interp.staticVariables; + else proxy.variables; + } + if(Reflect.isFunction(variables.get('set_$name'))) { inState = false; - var ret:Dynamic = Reflect.callMethod(null, proxy.variables.get('set_$name'), [value]); + var ret:Dynamic = Reflect.callMethod(null, variables.get('set_$name'), [value]); inState = true; return ret; - } else proxy.error(ECustom('Cannot Access Write This Property "$name" Due To Dose Not Exist Function -> "set_$name"')); + } else proxy.error(ECustom('Cannot Access Read This Property "$name" Due To Invalid Function -> "set_$name"')); null; default: null; diff --git a/crowplexus/hscript/Printer.hx b/crowplexus/hscript/Printer.hx index a795dd1..a7c18fd 100644 --- a/crowplexus/hscript/Printer.hx +++ b/crowplexus/hscript/Printer.hx @@ -187,11 +187,20 @@ class Printer { case EIdent(v): add(v); case EVar(n, t, e, gt, st, c, s): + if(gt == null) gt = "default"; + if(st == null) st = "default"; + + if(s == true) add("static "); if (c) { add("final " + n); } else { add("var " + n); } + if(!c && (gt != "default" || st != "default")) { + add("("); + add(gt + ", " + st); + add(")"); + } addType(t); if (e != null) { add(" = "); @@ -288,6 +297,7 @@ class Printer { case EContinue: add("continue"); case EFunction(params, e, name, ret, s): + if(s == true) add("static "); add("function"); if (name != null) add(" " + name); diff --git a/tests/src/Main.hx b/tests/src/Main.hx index b2db617..365aa0e 100644 --- a/tests/src/Main.hx +++ b/tests/src/Main.hx @@ -14,9 +14,9 @@ using StringTools; @:access(crowplexus.iris.Iris) class Main { static function main() { - // mainTest(); - // mainBytes(); - // testIndenticalNames(); + mainTest(); + mainBytes(); + testIndenticalNames(); testUsing(); } From 2349bd687292cf4b6873a9cd5d8e2a3488eb43d9 Mon Sep 17 00:00:00 2001 From: VapireMox <3449326235@qq.com> Date: Fri, 13 Jun 2025 02:55:43 +0800 Subject: [PATCH 10/21] =?UTF-8?q?=E4=B8=BAPropertyAccessor=E5=8D=95?= =?UTF-8?q?=E7=8B=AC=E5=88=86=E5=87=BA=E4=B8=80=E4=B8=AA=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=20-=20=E5=85=B6=E5=AE=9E=E5=B0=B1=E5=8F=AA=E6=98=AF=E6=83=B3?= =?UTF-8?q?=E7=BA=A0=E6=AD=A3=E4=B8=80=E4=BA=9B=E4=B8=9C=E8=A5=BF=E7=BD=A2?= =?UTF-8?q?=E4=BA=86=20-=20=E6=B5=8B=E8=AF=95=E6=9F=90=E4=BA=9B=E4=BA=8B?= =?UTF-8?q?=E7=89=A9=EF=BC=8C=E7=9C=8B=E7=9C=8B=E8=A1=8C=E4=B8=8D=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crowplexus/hscript/Interp.hx | 75 ------------------------- crowplexus/hscript/PropertyAccessor.hx | 77 ++++++++++++++++++++++++++ tests/assets/static_test1.hx | 11 ++++ tests/assets/static_test2.hx | 11 ++++ tests/build-generic.hxml | 2 + tests/src/Main.hx | 9 +++ 6 files changed, 110 insertions(+), 75 deletions(-) create mode 100644 crowplexus/hscript/PropertyAccessor.hx create mode 100644 tests/assets/static_test1.hx create mode 100644 tests/assets/static_test2.hx diff --git a/crowplexus/hscript/Interp.hx b/crowplexus/hscript/Interp.hx index c5e53d6..474dc42 100644 --- a/crowplexus/hscript/Interp.hx +++ b/crowplexus/hscript/Interp.hx @@ -1118,78 +1118,3 @@ class Interp { return Type.createInstance(c, args); } } - -//呵呵,我乱命名的,别在意 -class PropertyAccessor { - public var getter(default, null):String; - public var setter(default, null):String; - public var proxy(default, null):Interp; - public var inState(default, null):Bool = true; - public var link_getFunc(default, null):Void->Dynamic; - public var link_setFunc(default, null):Dynamic->Dynamic; - - var isStatic:Bool; - - public function new(proxy:Interp, link_getFunc:Void->Dynamic, link_setFunc:Dynamic->Dynamic, getter1:String = "default", setter1:String = "default", isStatic:Bool = false) { - this.proxy = proxy; - this.link_getFunc = link_getFunc; - this.link_setFunc = link_setFunc; - this.getter = getter1; - this.setter = setter1; - this.isStatic = isStatic; - } - - public function get(name:String):Dynamic { - if(link_getFunc == null && proxy == null) return null; - return switch(getter) { - case "default": - link_getFunc(); - case "never": - throw proxy.error(ECustom('Cannot Access Read This Property -> "$name"')); - null; - case "null": - link_getFunc(); - case "get": - final variables = { - if(this.isStatic) Interp.staticVariables; - else proxy.variables; - } - if(Reflect.isFunction(variables.get('get_$name'))) { - inState = false; - var ret:Dynamic = Reflect.callMethod(null, variables.get('get_$name'), []); - inState = true; - return ret; - } else proxy.error(ECustom('Cannot Access Read This Property "$name" Due To Invalid Function -> "get_$name"')); - null; - default: - null; - } - } - - public function set(name:String, value:Dynamic) { - if(link_setFunc == null && proxy == null) return null; - return switch(setter) { - case "default": - link_setFunc(value); - case "never": - throw proxy.error(ECustom('Cannot Access Write This Property -> "$name"')); - null; - case "null": - link_setFunc(value); - case "set": - final variables = { - if(this.isStatic) Interp.staticVariables; - else proxy.variables; - } - if(Reflect.isFunction(variables.get('set_$name'))) { - inState = false; - var ret:Dynamic = Reflect.callMethod(null, variables.get('set_$name'), [value]); - inState = true; - return ret; - } else proxy.error(ECustom('Cannot Access Read This Property "$name" Due To Invalid Function -> "set_$name"')); - null; - default: - null; - } - } -} \ No newline at end of file diff --git a/crowplexus/hscript/PropertyAccessor.hx b/crowplexus/hscript/PropertyAccessor.hx new file mode 100644 index 0000000..ca0ddb1 --- /dev/null +++ b/crowplexus/hscript/PropertyAccessor.hx @@ -0,0 +1,77 @@ +package crowplexus.hscript; + +//我又干了 +//呵呵,我乱命名的,别在意 +class PropertyAccessor { + public var getter(default, null):String; + public var setter(default, null):String; + public var proxy(default, null):Interp; + public var inState(default, null):Bool = true; + public var link_getFunc(default, null):Void->Dynamic; + public var link_setFunc(default, null):Dynamic->Dynamic; + + var isStatic:Bool; + + public function new(proxy:Interp, link_getFunc:Void->Dynamic, link_setFunc:Dynamic->Dynamic, getter1:String = "default", setter1:String = "default", isStatic:Bool = false) { + this.proxy = proxy; + this.link_getFunc = link_getFunc; + this.link_setFunc = link_setFunc; + this.getter = getter1; + this.setter = setter1; + this.isStatic = isStatic; + } + + public function get(name:String):Dynamic { + if(link_getFunc == null && proxy == null) return null; + return switch(getter) { + case "default": + link_getFunc(); + case "never": + throw proxy.error(ECustom('Cannot Access Read This Property -> "$name"')); + null; + case "null": + link_getFunc(); + case "get": + final variables = { + if(this.isStatic) Interp.staticVariables; + else proxy.variables; + } + if(Reflect.isFunction(variables.get('get_$name'))) { + inState = false; + var ret:Dynamic = Reflect.callMethod(null, variables.get('get_$name'), []); + inState = true; + return ret; + } else proxy.error(ECustom('Cannot Access Read This Property "$name" Due To Invalid Function -> "get_$name"')); + null; + default: + null; + } + } + + public function set(name:String, value:Dynamic) { + if(link_setFunc == null && proxy == null) return null; + return switch(setter) { + case "default": + link_setFunc(value); + case "never": + throw proxy.error(ECustom('Cannot Access Write This Property -> "$name"')); + null; + case "null": + link_setFunc(value); + case "set": + final variables = { + if(this.isStatic) Interp.staticVariables; + else proxy.variables; + } + if(Reflect.isFunction(variables.get('set_$name'))) { + inState = false; + var ret:Dynamic = Reflect.callMethod(null, variables.get('set_$name'), [value]); + inState = true; + return ret; + } else proxy.error(ECustom('Cannot Access Read This Property "$name" Due To Invalid Function -> "set_$name"')); + null; + default: + null; + } + } +} \ No newline at end of file diff --git a/tests/assets/static_test1.hx b/tests/assets/static_test1.hx new file mode 100644 index 0000000..10bf496 --- /dev/null +++ b/tests/assets/static_test1.hx @@ -0,0 +1,11 @@ +static var allRight = "Come Heaven"; +static final allBad = "Go on The Hell"; + +function new() { + //reading + trace("static_test2 static var fan: " + fan); + var old = sad; + sad += " forever"; + trace("static_test2 static var sad: " + sad); + trace("writing sad compare: [" + old + "<=>" + sad + "]"); +} \ No newline at end of file diff --git a/tests/assets/static_test2.hx b/tests/assets/static_test2.hx new file mode 100644 index 0000000..2a6e9df --- /dev/null +++ b/tests/assets/static_test2.hx @@ -0,0 +1,11 @@ +static final fan:Int = 666; +static var sad:String = "alive"; + +function new() { + //reading + trace("static_test1 static var allbad: " + allBad); + var old = allRight; + allRight += " forever"; + trace("static_test1 static var allright: " + allRight); + trace("writing sad compare: [" + old + "<=>" + allRight + "]"); +} \ No newline at end of file diff --git a/tests/build-generic.hxml b/tests/build-generic.hxml index 7701093..aee6974 100644 --- a/tests/build-generic.hxml +++ b/tests/build-generic.hxml @@ -21,6 +21,8 @@ --resource assets/using.hx@assets/using.hx --resource assets/bytes.hx@assets/bytes.hx +--resource assets/static_test1.hx@assets/static_test1.hx +--resource assets/static_test2.hx@assets/static_test2.hx --resource assets/test.hx@assets/test.hx ../extraParams.hxml diff --git a/tests/src/Main.hx b/tests/src/Main.hx index 365aa0e..1b9e37e 100644 --- a/tests/src/Main.hx +++ b/tests/src/Main.hx @@ -18,6 +18,15 @@ class Main { mainBytes(); testIndenticalNames(); testUsing(); + mainStatic(); + } + + static function mainStatic() { + var sm1:Iris = new Iris(Resource.getString("assets/static_test1.hx")); + var sm2:Iris = new Iris(Resource.getString("assets/static_test2.hx")); + sm1.call("new"); + sm2.call("new"); + trace("Static State: " + Interp.staticVariables); } /** From 1ab44c455ea763de0da46c7c0567489406af9f07 Mon Sep 17 00:00:00 2001 From: GeXie <3449326235@qq.com> Date: Fri, 13 Jun 2025 03:02:07 +0800 Subject: [PATCH 11/21] =?UTF-8?q?=E8=A1=A5=E5=85=85=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/src/Main.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/src/Main.hx b/tests/src/Main.hx index 1b9e37e..d3fe058 100644 --- a/tests/src/Main.hx +++ b/tests/src/Main.hx @@ -4,6 +4,7 @@ import sys.io.File; import haxe.io.Path; import sys.FileSystem; import crowplexus.iris.Iris; +import crowplexus.hscript.Interp; import crowplexus.hscript.Parser; import crowplexus.hscript.Printer; import crowplexus.hscript.Bytes; From cab9cbdb7cac86bba6ea5257ca483edc2731c0b7 Mon Sep 17 00:00:00 2001 From: VapireMox <3449326235@qq.com> Date: Fri, 13 Jun 2025 03:05:56 +0800 Subject: [PATCH 12/21] =?UTF-8?q?=E6=88=91=E5=8F=88=E5=B9=B2=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crowplexus/hscript/PropertyAccessor.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crowplexus/hscript/PropertyAccessor.hx b/crowplexus/hscript/PropertyAccessor.hx index ca0ddb1..5ffcc41 100644 --- a/crowplexus/hscript/PropertyAccessor.hx +++ b/crowplexus/hscript/PropertyAccessor.hx @@ -68,7 +68,7 @@ class PropertyAccessor { var ret:Dynamic = Reflect.callMethod(null, variables.get('set_$name'), [value]); inState = true; return ret; - } else proxy.error(ECustom('Cannot Access Read This Property "$name" Due To Invalid Function -> "set_$name"')); + } else proxy.error(ECustom('Cannot Access Write This Property "$name" Due To Invalid Function -> "set_$name"')); null; default: null; From f9081623ca62f469548cf06b062f643a841a78c4 Mon Sep 17 00:00:00 2001 From: bananaTiko <111482265+bananaTiko@users.noreply.github.com> Date: Thu, 12 Jun 2025 17:20:50 -0700 Subject: [PATCH 13/21] Update Parser.hx --- crowplexus/hscript/Parser.hx | 245 +++++++++++++---------------------- 1 file changed, 93 insertions(+), 152 deletions(-) diff --git a/crowplexus/hscript/Parser.hx b/crowplexus/hscript/Parser.hx index 7c4caa3..569e3b9 100644 --- a/crowplexus/hscript/Parser.hx +++ b/crowplexus/hscript/Parser.hx @@ -78,10 +78,10 @@ class Parser { /** allows to check for #if / #else in code **/ - public var preprocesorValues: Map = new Map(); + public var preprocessorValues: Map = new Map(); /** - activate JSON compatiblity + activate JSON compatibility **/ public var allowJSON: Bool; @@ -113,9 +113,9 @@ class Parser { var ops: Array; var idents: Array; var uid: Int = 0; - var abductCount:Int = 0; + var abductCount: Int = 0; var abducts = ["function", "if", "for", "while", "try", "switch"]; - var sureStaticModifier:Bool = false; + var sureStaticModifier: Bool = false; #if hscriptPos var origin: String; @@ -135,6 +135,7 @@ class Parser { var tokens: haxe.FastList; #end #end + public function new() { line = 1; opChars = "+*/-=!><&|^%~"; @@ -185,8 +186,8 @@ class Parser { } public inline function error(err, pmin, pmax) { - if(sureStaticModifier) sureStaticModifier = false; - if(abductCount > 0) abductCount = 0; + if (sureStaticModifier) sureStaticModifier = false; + if (abductCount > 0) abductCount = 0; if (!resumeErrors) #if hscriptPos @@ -201,7 +202,7 @@ class Parser { } function initParser(origin) { - // line=1 - don't reset line : it might be set manualy + // line=1 - don't reset line : it might be set manually preprocStack = []; #if hscriptPos this.origin = origin; @@ -338,8 +339,8 @@ class Parser { return false; return switch (expr(e)) { case EBlock(_), EObject(_), ESwitch(_), EEnum(_, _): true; - case EFunction(_, e, _, _): isBlock(e); - case EVar(_, t, e, _): e != null ? isBlock(e) : t != null ? t.match(CTAnon(_)) : false; + case EFunction(_, e, _, _, _): isBlock(e); + case EVar(_, t, e, _, _, _, _): e != null ? isBlock(e) : t != null ? t.match(CTAnon(_)) : false; case EIf(_, e1, e2): if (e2 != null) isBlock(e2) else isBlock(e1); case EBinop(_, _, e): isBlock(e); case EUnop(_, prefix, e): !prefix && isBlock(e); @@ -419,9 +420,9 @@ class Parser { #end switch (tk) { case TId(id): - if(abducts.contains(id)) abductCount++; + if (abducts.contains(id)) abductCount++; var e = parseStructure(id); - if(abducts.contains(id)) abductCount--; + if (abducts.contains(id)) abductCount--; if (e == null) e = mk(EIdent(id)); return parseExprNext(e); @@ -498,10 +499,10 @@ class Parser { } var a = new Array(); abductCount++; - while( true ) { + while (true) { parseFullExpr(a); tk = token(); - if( tk == TBrClose || (resumeErrors && tk == TEof) ) + if (tk == TBrClose || (resumeErrors && tk == TEof)) break; push(tk); } @@ -672,69 +673,66 @@ class Parser { } mk(EIf(cond, e1, e2), p1, (e2 == null) ? tokenMax : pmax(e2)); case "static": - if(abductCount == 0) { + if (abductCount == 0) { var t = token(); - switch(t) { + switch (t) { case TId(byd): - if(byd == "var" || byd == "final" || byd == "function") { + if (byd == "var" || byd == "final" || byd == "function") { sureStaticModifier = true; var ret = parseStructure(byd); sureStaticModifier = false; return ret; - } else if(byd == "inline") { - if(!maybe(TId("function"))) + } else if (byd == "inline") { + if (!maybe(TId("function"))) return unexpected(TId(byd)); sureStaticModifier = true; var ret = parseStructure("function"); sureStaticModifier = false; return ret; } else unexpected(TId(byd)); - default: unexpected(TId(id)); + default: unexpected(t); } } else error(ECustom('Cannot Set-up "$id" In Local.'), tokenMin, tokenMax); null; case "var", "final": - var getter:String = "default"; - var setter:String = "default"; + var getter: String = "default"; + var setter: String = "default"; var ident = getIdent(); var tk = token(); var t = null; - if(tk == TPOpen) { - if(abductCount == 0 && id == "var") { - var getter1:Null = null; - var setter1:Null = null; - var displayComma:Bool = false; - var closed:Bool = false; - while(true) { + if (tk == TPOpen) { + if (abductCount == 0 && id == "var") { + var getter1: Null = null; + var setter1: Null = null; + var displayComma: Bool = false; + var closed: Bool = false; + while (true) { var t = token(); - switch(t) { + switch (t) { case TComma: - if(getter != null && !displayComma) { + if (getter1 != null && !displayComma) { displayComma = true; } else unexpected(t); case TId(byd): - if(getter1 == null && !displayComma) { - if(byd == "get" || byd == "never" || byd == "default" || byd == "null") { + if (getter1 == null && !displayComma) { + if (byd == "get" || byd == "never" || byd == "default" || byd == "null") { getter1 = byd; } else unexpected(t); - } else if(setter1 == null && displayComma) { - if(byd == "set" || byd == "never" || byd == "default" || byd == "null") { + } else if (setter1 == null && displayComma) { + if (byd == "set" || byd == "never" || byd == "default" || byd == "null") { setter1 = byd; } else unexpected(t); } else unexpected(t); case TPClose: - if(getter1 != null && setter1 != null) closed = true; + if (getter1 != null && setter1 != null) closed = true; else unexpected(t); default: unexpected(t); } - - if(closed) break; + if (closed) break; } - - if(getter1 != null) getter = getter1; - if(setter1 != null) setter = setter1; - + if (getter1 != null) getter = getter1; + if (setter1 != null) setter = setter1; tk = token(); } else unexpected(tk); } @@ -747,7 +745,7 @@ class Parser { e = parseExpr(); else push(tk); - mk(EVar(ident, t, e, getter, setter, (id == "final"), if(abductCount == 0) sureStaticModifier else false), p1, (e == null) ? tokenMax : pmax(e)); + mk(EVar(ident, t, e, getter, setter, id == "final", abductCount == 0 ? sureStaticModifier : false), p1, (e == null) ? tokenMax : pmax(e)); case "while": var econd = parseExpr(); var e = parseExpr(); @@ -774,29 +772,26 @@ class Parser { case "else": unexpected(TId(id)); case "inline": var t = token(); - switch(t) { + switch (t) { case TId(id): - if(id == "static") { - if(!sureStaticModifier && abductCount == 0) { - if(abductCount == 0) { - var t = token(); - switch(t) { - case TId(byd): - if(byd == "function") { - sureStaticModifier = true; - var ret = parseStructure(byd); - sureStaticModifier = false; - return ret; - } else unexpected(TId(id)); - default: unexpected(TId(id)); - } - } else error(ECustom('Cannot Set-up "$id" In Local.'), tokenMin, tokenMax); - return null; + if (id == "static") { + if (!sureStaticModifier && abductCount == 0) { + var t = token(); + switch (t) { + case TId(byd): + if (byd == "function") { + sureStaticModifier = true; + var ret = parseStructure(byd); + sureStaticModifier = false; + return ret; + } else unexpected(TId(id)); + default: unexpected(t); + } } - } else if(id == "function") { + } else if (id == "function") { return parseStructure("function"); } - default: //nothing here + default: } unexpected(t); case "function": @@ -807,7 +802,7 @@ class Parser { default: push(tk); } var inf = parseFunctionDecl(); - mk(EFunction(inf.args, inf.body, name, inf.ret, if(abductCount == 0) sureStaticModifier else false), p1, pmax(inf.body)); + mk(EFunction(inf.args, inf.body, name, inf.ret, abductCount == 0 ? sureStaticModifier : false), p1, pmax(inf.body)); case "return": var tk = token(); push(tk); @@ -865,9 +860,6 @@ class Parser { case TComma: // next expr case TId("if"): - // if( Type.enumEq(e, EIdent("_")) ) - // unexpected(TId("if")); - var e = parseExpr(); c.ifExpr = e; switch tk = token() { @@ -899,7 +891,6 @@ class Parser { } c.expr = if (exprs.length == 1) exprs[0]; else if (exprs.length == 0) mk(EBlock([]), tokenMin, tokenMin); else mk(EBlock(exprs), pmin(exprs[0]), pmax(exprs[exprs.length - 1])); - for (i in c.values) { switch Tools.expr(i) { case EIdent("_"): @@ -938,7 +929,6 @@ class Parser { var path = [getIdent()]; var asStr: String = null; var star: Bool = false; - while (true) { var t = token(); if (t != TDot) { @@ -952,9 +942,7 @@ class Parser { default: unexpected(t); } } - final asErr = " -> " + path.join(".") + " as " + asStr; - if (maybe(TId("as"))) { asStr = getIdent(); final uppercased: Bool = asStr.charAt(0) == asStr.charAt(0).toUpperCase(); @@ -963,25 +951,13 @@ class Parser { if (!uppercased) error(ECustom("Import aliases must begin with an uppercase letter." + asErr), readPos, readPos); } - // trace(asStr); - /* - if (token() != TSemicolon) { - error(ECustom("Missing semicolon at the end of a \"import\" declaration. -> "+asErr), readPos, readPos); - null; - } - */ mk(EImport(path.join('.'), asStr)); - case "enum": var name = getIdent(); - ensure(TBrOpen); - var fields = []; - var currentName = ""; var currentArgs: Array = null; - while (true) { var tk = token(); switch (tk) { @@ -990,7 +966,6 @@ class Parser { case TSemicolon | TComma: if (currentName == "") continue; - if (currentArgs != null && currentArgs.length > 0) { fields.push(EnumType.EConstructor(currentName, currentArgs)); currentArgs = null; @@ -1013,27 +988,11 @@ class Parser { currentName = name; } } - mk(EEnum(name, fields)); case "typedef": - // typedef Name = Type; - - /* - Ignore parsing if its, typedef Name = { - > Person - var name:String; - var age:Int; - } - - If the value is a class then it will be parsed as a EVar(Name, value); - */ - var name = getIdent(); - ensureToken(TOp("=")); - var t = parseType(); - switch (t) { case CTAnon(_) | CTExtend(_) | CTIntersection(_) | CTFun(_): mk(EIgnore(true)); @@ -1042,10 +1001,8 @@ class Parser { var params = tp.params; if (params != null && params.length > 1) error(ECustom("Typedefs can't have parameters"), tokenMin, tokenMax); - if (path.length == 0) error(ECustom("Typedefs can't be empty"), tokenMin, tokenMax); - { var className = path.join("."); var cl = Tools.getClass(className); @@ -1053,33 +1010,26 @@ class Parser { return mk(EVar(name, null, mk(EDirectValue(cl)))); } } - var expr = mk(EIdent(path.shift())); while (path.length > 0) { expr = mk(EField(expr, path.shift(), false)); } - - // todo? add import to the beginning of the file? mk(EVar(name, null, expr)); default: error(ECustom("Typedef, unknown type " + t), tokenMin, tokenMax); null; } - case "using": var path = parsePath(); mk(EUsing(path.join("."))); case "package": - // ignore package var tk = token(); push(tk); packageName = ""; if (tk == TSemicolon) return mk(EIgnore(false)); - var path = parsePath(); - // mk(EPackage(path.join("."))); - packageName = path.join("."); + PACKAGE: path.join("."); mk(EIgnore(false)); default: null; @@ -1091,7 +1041,6 @@ class Parser { switch (tk) { case TOp(op): if (op == "->") { - // single arg reinterpretation of `f -> e` , `(f) -> e` and `(f:T) -> e` switch (expr(e1)) { case EIdent(i), EParent(expr(_) => EIdent(i)): abductCount++; @@ -1107,7 +1056,6 @@ class Parser { } unexpected(tk); } - if (opPriority.get(op) == -1) { if (isBlock(e1) || switch (expr(e1)) { case EParent(_): true; @@ -1115,7 +1063,7 @@ class Parser { }) { push(tk); return e1; - } + } return parseExprNext(mk(EUnop(op, false, e1), pmin(e1))); } return makeBinop(op, e1, parseExpr()); @@ -1256,20 +1204,16 @@ class Parser { })); case TPOpen: var a = token(), b = token(); - push(b); push(a); - function withReturn(args) { - switch token() { // I think it wouldn't hurt if ensure used enumEq + switch token() { case TOp('->'): case t: unexpected(t); } - return CTFun(args, parseType()); } - switch [a, b] { case [TPClose, _] | [TId(_), TDoubleDot]: var args = [ @@ -1279,18 +1223,15 @@ class Parser { case v: error(ECustom('Default values not allowed in function types'), #if hscriptPos v.pmin, v.pmax #else 0, 0 #end); } - CTNamed(arg.name, if (arg.opt) CTOpt(arg.t) else arg.t); } ]; - return withReturn(args); default: var t = parseType(); return switch token() { case TComma: var args = [t]; - while (true) { args.push(parseType()); if (!maybe(TComma)) @@ -1304,7 +1245,6 @@ class Parser { } } case TBrOpen: - var curType = null; var fields = []; var tps = []; var meta = null; @@ -1318,6 +1258,14 @@ class Parser { fields.push({name: name, t: parseType(), meta: meta}); meta = null; ensure(TSemicolon); + case TId("final"): + var name = getIdent(); + ensure(TDoubleDot); + if (meta == null) meta = []; + meta.push({name: ":final", params: []}); + fields.push({name: name, t: parseType(), meta: meta}); + meta = null; + ensure(TSemicolon); case TId(name): ensure(TDoubleDot); fields.push({name: name, t: parseType(), meta: meta}); @@ -1430,6 +1378,8 @@ class Parser { switch (tk) { case TMeta(name): meta.push({name: name, params: parseMetaArgs()}); + case TId("final"): + meta.push({name: ":final", params: []}); default: push(tk); break; @@ -1491,7 +1441,6 @@ class Parser { var params = parseParams(); var extend = null; var implement = []; - while (true) { var t = token(); switch (t) { @@ -1504,12 +1453,10 @@ class Parser { break; } } - var fields = []; ensure(TBrOpen); while (!maybe(TBrClose)) fields.push(parseField()); - return DClass({ name: name, meta: meta, @@ -1580,7 +1527,6 @@ class Parser { } var type = maybe(TDoubleDot) ? parseType() : null; var expr = maybe(TOp("=")) ? parseExpr() : null; - if (expr != null) { if (isBlock(expr)) maybe(TSemicolon); @@ -1590,7 +1536,6 @@ class Parser { maybe(TSemicolon); } else ensure(TSemicolon); - return { name: name, meta: meta, @@ -1688,24 +1633,24 @@ class Parser { } function token() { - #if hscriptPos - var t = tokens.pop(); - if (t != null) { - tokenMin = t.min; - tokenMax = t.max; - return t.t; - } - oldTokenMin = tokenMin; - oldTokenMax = tokenMax; - tokenMin = (this.char < 0) ? readPos : readPos - 1; - var t = _token(); - tokenMax = (this.char < 0) ? readPos - 1 : readPos - 2; - return t; - } function _token() { - #else - if (!tokens.isEmpty()) - return tokens.pop(); - #end + #if hscriptPos + var t = tokens.pop(); + if (t != null) { + tokenMin = t.min; + tokenMax = t.max; + return t.t; + } + oldTokenMin = tokenMin; + oldTokenMax = tokenMax; + tokenMin = (this.char < 0) ? readPos : readPos - 1; + var t = _token(); + tokenMax = (this.char < 0) ? readPos - 1 : readPos - 2; + return t; + } function _token() { + #else + if (!tokens.isEmpty()) + return tokens.pop(); + #end var char; if (this.char < 0) char = readChar(); @@ -1803,9 +1748,6 @@ class Parser { case '_'.code: default: this.char = char; - // we allow to parse hexadecimal Int32 in Neko, but when the value will be - // evaluated by Interpreter, a failure will occur if no Int32 operation is - // performed var v = try CInt(haxe.Int32.toInt(n)) catch (e:Dynamic) CInt32(n); return TConst(v); } @@ -1838,9 +1780,6 @@ class Parser { case '_'.code: default: this.char = char; - // we allow to parse binary Int32 in Neko, but when the value will be - // evaluated by Interpreter, a failure will occur if no Int32 operation is - // performed var v = try CInt(haxe.Int32.toInt(n)) catch (e:Dynamic) CInt32(n); return TConst(v); } @@ -1988,7 +1927,7 @@ class Parser { } function preprocValue(id: String): Dynamic { - return preprocesorValues.get(id); + return preprocessorValues.get(id); } var preprocStack: Array; @@ -2066,11 +2005,9 @@ class Parser { while (true) { var tk = token(); if (tk == TEof) { - // @see https://github.com/CodenameCrew/hscript-improved/pull/5/ if (preprocStack.length != 0) { error(EInvalidPreprocessor("Unclosed"), pos, pos); } else { - // trace("line: " + pos); break; } } @@ -2158,6 +2095,10 @@ class Parser { case TQuestionDot: "?."; } } + + @:noCompletion public var preprocessorValues(get, set): Map; + inline function get_preprocessorValues() return this.preprocessorValues; + inline function set_preprocessorValues(v) return this.preprocessorValues = v; } @:structInit From 72f84dc50c42e94af776dccde9048c563448edf6 Mon Sep 17 00:00:00 2001 From: bananaTiko <111482265+bananaTiko@users.noreply.github.com> Date: Thu, 12 Jun 2025 18:14:35 -0700 Subject: [PATCH 14/21] Update Interp.hx --- crowplexus/hscript/Interp.hx | 500 ++++++++++++++--------------------- 1 file changed, 196 insertions(+), 304 deletions(-) diff --git a/crowplexus/hscript/Interp.hx b/crowplexus/hscript/Interp.hx index 474dc42..8792612 100644 --- a/crowplexus/hscript/Interp.hx +++ b/crowplexus/hscript/Interp.hx @@ -40,7 +40,7 @@ private enum Stop { @:structInit class LocalVar { public var r: Dynamic; - public var const:Bool; + public var const: Bool; } @:structInit @@ -51,87 +51,85 @@ class DeclaredVar { @:allow(crowplexus.hscript.PropertyAccessor) class Interp { - /** - * 还是觉得直接包装成静态更好一点(不模仿) - */ - public static var staticVariables:#if haxe3 Map = new Map() #else Hash = new Hash() #end; + public static var staticVariables: #if haxe3 Map = new Map() #else Hash = new Hash() #end; + public var scriptObject(default, set): Dynamic; + public var parentInstance(default, set): Dynamic; + #if haxe3 public var variables: Map; public var imports: Map; - + public var props: Map; var locals: Map; - var props:Map; var binops: MapExpr->Dynamic>; - var propertyLinks:Map; + var propertyLinks: Map; #else public var variables: Hash; public var imports: Hash; - + public var props: Hash; var locals: Hash; - var props:Hash; var binops: HashExpr->Dynamic>; - var propertyLinks:Hash; + var propertyLinks: Hash; #end - /** - * 反狼偷家 - */ - public var parentInstance(default, set):Dynamic; - var _parentFields:Array = []; - @:dox(hide) function set_parentInstance(val:Dynamic):Dynamic { - if(val != null) { - switch(Type.typeof(val)) { - case Type.ValueType.TObject if(!(val is Enum)): - _parentFields = if(val is Class) Type.getClassFields(val); - else Reflect.fields(val); - case Type.ValueType.TClass(_): - _parentFields = Type.getInstanceFields(Type.getClass(val)); - case _: - //nothing - } - } - - if(_parentFields == null) _parentFields = []; - - return parentInstance = val; - } - + var _parentFields: Array = []; + var __instanceFields: Array = []; var depth: Int; var inTry: Bool; var declared: Array; var returnValue: Dynamic; + @:noCompletion static var unpackClassCache: #if haxe3 Map = new Map() #else Hash = new Hash() #end; + public static var getRedirects: MapString->Dynamic> = []; + public static var setRedirects: MapString->Dynamic->Dynamic> = []; + #if hscriptPos var curExpr: Expr; #end public var showPosOnLog: Bool = true; - public function new() { - #if haxe3 - locals = new Map(); - #else - locals = new Hash(); - #end - declared = new Array(); - resetVariables(); - initOps(); + function set_scriptObject(v: Dynamic) { + __instanceFields = Type.getInstanceFields(Type.getClass(v)); + return scriptObject = v; } - private function resetVariables() { + function set_parentInstance(val: Dynamic): Dynamic { + if (val != null) { + switch (Type.typeof(val)) { + case Type.ValueType.TObject if (!(val is Enum)): + _parentFields = if (val is Class) Type.getClassFields(val) else Reflect.fields(val); + case Type.ValueType.TClass(_): + _parentFields = Type.getInstanceFields(Type.getClass(val)); + case _: + } + } + if (_parentFields == null) _parentFields = []; + return parentInstance = val; + } + + public function new() { #if haxe3 - propertyLinks = new Map(); + locals = new Map(); variables = new Map(); props = new Map(); imports = new Map(); + binops = new Map(); + propertyLinks = new Map(); #else - propertyLinks = new Hash(); + locals = new Hash(); variables = new Hash(); props = new Hash(); imports = new Hash(); + binops = new Hash(); + propertyLinks = new Hash(); #end + declared = new Array(); + resetVariables(); + initOps(); + } + private function resetVariables() { variables.set("null", null); variables.set("true", true); variables.set("false", false); @@ -154,11 +152,6 @@ class Interp { function initOps() { var me = this; - #if haxe3 - binops = new Map(); - #else - binops = new Hash(); - #end binops.set("+", function(e1, e2) return me.expr(e1) + me.expr(e2)); binops.set("-", function(e1, e2) return me.expr(e1) - me.expr(e2)); binops.set("*", function(e1, e2) return me.expr(e1) * me.expr(e2)); @@ -173,6 +166,7 @@ class Interp { binops.set("==", function(e1, e2) return me.expr(e1) == me.expr(e2)); binops.set("!=", function(e1, e2) return me.expr(e1) != me.expr(e2)); binops.set(">=", function(e1, e2) return me.expr(e1) >= me.expr(e2)); + binops.set红包: 2/3/2023 18:43:54 binops.set("<=", function(e1, e2) return me.expr(e1) <= me.expr(e2)); binops.set(">", function(e1, e2) return me.expr(e1) > me.expr(e2)); binops.set("<", function(e1, e2) return me.expr(e1) < me.expr(e2)); @@ -195,27 +189,38 @@ class Interp { assignOp("<<=", function(v1, v2) return v1 << v2); assignOp(">>=", function(v1, v2) return v1 >> v2); assignOp(">>>=", function(v1, v2) return v1 >>> v2); - assignOp("??" + "=", function(v1, v2) return v1 == null ? v2 : v1); + assignOp("??=", function(v1, v2) return v1 == null ? v2 : v1); } public inline function setVar(name: String, v: Dynamic) { - if(propertyLinks.get(name) != null) { + if (propertyLinks.exists(name)) { var l = propertyLinks.get(name); - if(l.inState) l.set(name, v); - else l.link_setFunc(v); + if (l.inState) + l.set(name, v); + else + l.link_setFunc(v); return; } - if(staticVariables.exists(name)) { + if (staticVariables.exists(name)) { staticVariables.set(name, v); - } else if(staticVariables.exists('$name;const')) { + } else if (staticVariables.exists('$name;const')) { warn(ECustom("Cannot reassign final, for constant expression -> " + name)); - } else if(parentInstance != null) { - if(_parentFields.contains(name) || _parentFields.contains('set_$name')) { - Reflect.setProperty(parentInstance, name, v); + } else if (parentInstance != null && (_parentFields.contains(name) || _parentFields.contains('set_$name'))) { + Reflect.setProperty(parentInstance, name, v); + } else if (scriptObject != null) { + if (Type.typeof(scriptObject) == TObject) { + Reflect.setField(scriptObject, name, v); + } else if (__instanceFields.contains(name)) { + Reflect.setProperty(scriptObject, name, v); + } else if (__instanceFields.contains('set_$name')) { + Reflect.getProperty(scriptObject, 'set_$name')(v); + } else { + variables.set(name, v); } - } else variables.set(name, v); - + } else { + variables.set(name, v); + } } function assign(e1: Expr, e2: Expr): Dynamic { @@ -247,7 +252,6 @@ class Interp { } else { arr[index] = v; } - default: error(EInvalidOp("=")); } @@ -265,9 +269,15 @@ class Interp { case EIdent(id): var l = locals.get(id); v = fop(expr(e1), expr(e2)); - if (l == null) - setVar(id, v) - else { + if (l == null) { + if (parentInstance != null && (_parentFields.contains(id) || _parentFields.contains('set_$id'))) { + Reflect.setProperty(parentInstance, id, v); + } else if (scriptObject != null && (__instanceFields.contains(id) || __instanceFields.contains('set_$id'))) { + Reflect.setProperty(scriptObject, id, v); + } else { + setVar(id, v); + } + } else { if (l.const != true) l.r = v; else @@ -309,7 +319,7 @@ class Interp { var v: Dynamic = (l == null) ? resolve(id) : l.r; function setTo(a) { if (l == null) - setVar(id, a) + setVar(id, a); else { if (l.const != true) l.r = a; @@ -317,13 +327,11 @@ class Interp { error(ECustom("Cannot reassign final, for constant expression -> " + id)); } } - if (l == null) { - if (prefix) { - v += delta; - setTo(v); - } else - setTo(v + delta); - } + if (prefix) { + v += delta; + setTo(v); + } else + setTo(v + delta); return v; case EField(e, f, s): var obj = expr(e); @@ -379,7 +387,7 @@ class Interp { function exprReturn(e): Dynamic { try { return expr(e); - } catch (e:Stop) { + } catch (e: Stop) { switch (e) { case SBreak: throw "Invalid break"; @@ -435,51 +443,57 @@ class Interp { #end } - @:noCompletion static var unpackClassCache:#if haxe3 Map = new Map() #else Hash = new Hash() #end; function resolve(id: String): Dynamic { var l = locals.get(id); if (l != null) return l.r; - if(propertyLinks.get(id) != null) { + if (propertyLinks.exists(id)) { var l = propertyLinks.get(id); - if(l.inState) return l.get(id); - else return l.link_getFunc(); + if (l.inState) + return l.get(id); + else + return l.link_getFunc(); } - if(staticVariables.exists(id)) + if (staticVariables.exists(id)) return staticVariables.get(id); - else if(staticVariables.exists('$id;const')) + else if (staticVariables.exists('$id;const')) return staticVariables.get('$id;const'); - if (variables.exists(id)) { - var v = variables.get(id); - return v; - } + if (variables.exists(id)) + return variables.get(id); - if(parentInstance != null) { - if(id == "this") return parentInstance; - if(_parentFields.contains(id) || _parentFields.contains('get_$id')) { + if (parentInstance != null) { + if (id == "this") + return parentInstance; + if (_parentFields.contains(id) || _parentFields.contains('get_$id')) return Reflect.getProperty(parentInstance, id); - } } - if (imports.exists(id)) { - var v = imports.get(id); - return v; + if (scriptObject != null) { + if (id == "this") + return scriptObject; + if (Type.typeof(scriptObject) == TObject && Reflect.hasField(scriptObject, id)) + return Reflect.field(scriptObject, id); + if (__instanceFields.contains(id)) + return Reflect.getProperty(scriptObject, id); + if (__instanceFields.contains('get_$id')) + return Reflect.getProperty(scriptObject, 'get_$id')(); } - if(unpackClassCache.get(id) is Class) { + if (imports.exists(id)) + return imports.get(id); + + if (unpackClassCache.exists(id)) return unpackClassCache.get(id); - } else { - final cl = Type.resolveClass(id); - if(cl != null) { - unpackClassCache.set(id, cl); - return cl; - } + + var cl = Type.resolveClass(id); + if (cl != null) { + unpackClassCache.set(id, cl); + return cl; } error(EUnknownVariable(id)); - return null; } @@ -508,38 +522,46 @@ class Interp { case EIdent(id): return resolve(id); case EVar(n, _, v, getter, setter, isConst, s): - if(getter == null) getter = "default"; - if(setter == null) setter = "default"; - + if (getter == null) getter = "default"; + if (setter == null) setter = "default"; var v = (v == null ? null : expr(v)); - if(s == true) { - if(!staticVariables.exists(n) && !staticVariables.exists(n + ";const")) { - if(isConst) staticVariables.set(n + ";const", v); + if (s == true) { + if (!staticVariables.exists(n) && !staticVariables.exists(n + ";const")) { + if (isConst) + staticVariables.set(n + ";const", v); else { staticVariables.set(n, v); - if(getter != "default" || setter != "default") { + if (getter != "default" || setter != "default") { propertyLinks.set(n, new PropertyAccessor(this, () -> { - if(staticVariables.exists(n)) return staticVariables.get(n); - else throw error(EUnknownVariable(n)); + if (staticVariables.exists(n)) + return staticVariables.get(n); + else + throw error(EUnknownVariable(n)); return null; }, (val) -> { - if(staticVariables.exists(n)) staticVariables.set(n, val); - else throw error(EUnknownVariable(n)); + if (staticVariables.exists(n)) + staticVariables.set(n, val); + else + throw error(EUnknownVariable(n)); return val; }, getter, setter, true)); } } } } else { - if(!isConst && (getter != "default" || setter != "default")) { + if (!isConst && (getter != "default" || setter != "default")) { props.set(n, v); propertyLinks.set(n, new PropertyAccessor(this, () -> { - if(props.exists(n)) return props.get(n); - else throw error(EUnknownVariable(n)); + if (props.exists(n)) + return props.get(n); + else + throw error(EUnknownVariable(n)); return null; }, (val) -> { - if(props.exists(n)) props.set(n, val); - else throw error(EUnknownVariable(n)); + if (props.exists(n)) + props.set(n, val); + else + throw error(EUnknownVariable(n)); return val; }, getter, setter)); } else { @@ -571,29 +593,22 @@ class Interp { return fop(e1, e2); case EUnop(op, prefix, e): return switch (op) { - case "!": - expr(e) != true; - case "-": - -expr(e); - case "++": - increment(e, prefix, 1); - case "--": - increment(e, prefix, -1); + case "!": expr(e) != true; + case "-": -expr(e); + case "++": increment(e, prefix, 1); + case "--": increment(e, prefix, -1); case "~": #if (neko && !haxe3) haxe.Int32.complement(expr(e)); #else ~expr(e); #end - default: - error(EInvalidOp(op)); - null; + default: error(EInvalidOp(op)); null; } case ECall(e, params): var args = new Array(); for (p in params) args.push(expr(p)); - switch (Tools.expr(e)) { case EField(e, f, s): var obj = expr(e); @@ -623,28 +638,23 @@ class Interp { returnValue = e == null ? null : expr(e); throw SReturn; case EImport(v, as): - final aliasStr = (as != null ? " named " + as : ""); // for errors + final aliasStr = (as != null ? " named " + as : ""); if (Iris.blocklistImports.contains(v)) { error(ECustom("You cannot add a blacklisted import, for class " + v + aliasStr)); return null; } - var n = Tools.last(v.split(".")); if (imports.exists(n)) return imports.get(n); - var c: Dynamic = getOrImportClass(v); - if (c == null) // if it's still null then throw an error message. + if (c == null) return warn(ECustom("Import" + aliasStr + " of class " + v + " could not be added")); else { imports.set(n, c); if (as != null) imports.set(as, c); - // resembles older haxe versions where you could use both the alias and the import - // for all the "Colour" enjoyers :D } - return null; // yeah. -Crow - + return null; case EFunction(params, fexpr, name, _, s): var capturedLocals = duplicate(locals); var me = this; @@ -662,7 +672,6 @@ class Interp { str += " for function '" + name + "'"; error(ECustom(str)); } - // make sure mandatory args are forced var args2 = []; var extraParams = args.length - minParams; var pos = 0; @@ -687,7 +696,7 @@ class Interp { if (inTry) try { r = me.exprReturn(fexpr); - } catch (e:Dynamic) { + } catch (e: Dynamic) { me.locals = old; me.depth = depth; #if neko @@ -706,16 +715,16 @@ class Interp { var f = Reflect.makeVarArgs(f); if (name != null) { if (depth == 0) { - // global function - if(s == true) { - if(!staticVariables.exists(name)) staticVariables.set(name, f); - } else variables.set(name, f); + if (s == true) { + if (!staticVariables.exists(name)) + staticVariables.set(name, f); + } else + variables.set(name, f); } else { - // function-in-function is a local function declared.push({n: name, old: locals.get(name)}); var ref: LocalVar = {r: f, const: false}; locals.set(name, ref); - capturedLocals.set(name, ref); // allow self-recursion + capturedLocals.set(name, ref); } } return f; @@ -730,15 +739,15 @@ class Interp { for (e in arr) { switch (Tools.expr(e)) { case EBinop("=>", eKey, eValue): { - var key: Dynamic = expr(eKey); - var value: Dynamic = expr(eValue); - isAllString = isAllString && (key is String); - isAllInt = isAllInt && (key is Int); - isAllObject = isAllObject && Reflect.isObject(key); - isAllEnum = isAllEnum && Reflect.isEnumValue(key); - keys.push(key); - values.push(value); - } + var key: Dynamic = expr(eKey); + var value: Dynamic = expr(eValue); + isAllString = isAllString && (key is String); + isAllInt = isAllInt && (key is Int); + isAllObject = isAllObject && Reflect.isObject(key); + isAllEnum = isAllEnum && Reflect.isEnumValue(key); + keys.push(key); + values.push(value); + } default: throw("=> expected"); } } @@ -789,14 +798,12 @@ class Interp { restore(old); inTry = oldTry; return v; - } catch (err:Stop) { + } catch (err: Stop) { inTry = oldTry; throw err; - } catch (err:Dynamic) { - // restore vars + } catch (err: Dynamic) { restore(old); inTry = oldTry; - // declare 'v' declared.push({n: n, old: locals.get(n)}); locals.set(n, {r: err, const: false}); var v: Dynamic = expr(ecatch); @@ -852,7 +859,6 @@ class Interp { str += " for enum '" + enumName + "'"; error(ECustom(str)); } - // make sure mandatory args are forced var args2 = []; var extraParams = args.length - minParams; var pos = 0; @@ -870,11 +876,9 @@ class Interp { return new EnumValue(enumName, name, index, args); }; var f = Reflect.makeVarArgs(f); - Reflect.setField(obj, name, f); } } - variables.set(enumName, obj); case EDirectValue(value): return value; @@ -889,7 +893,7 @@ class Interp { do { try { expr(e); - } catch (err:Stop) { + } catch (err: Stop) { switch (err) { case SContinue: case SBreak: @@ -907,7 +911,7 @@ class Interp { while (expr(econd) == true) { try { expr(e); - } catch (err:Stop) { + } catch (err: Stop) { switch (err) { case SContinue: case SBreak: @@ -927,7 +931,7 @@ class Interp { #else try v = v.iterator() - catch (e:Dynamic) {}; + catch (e: Dynamic) {}; #end if (v.hasNext == null || v.next == null) error(EInvalidIterator(v)); @@ -944,7 +948,7 @@ class Interp { locals.set(n, {r: _itNext(), const: false}); try { expr(e); - } catch (err:Stop) { + } catch (err: Stop) { switch (err) { case SContinue: case SBreak: @@ -972,149 +976,37 @@ class Interp { function get(o: Dynamic, f: String): Dynamic { if (o == null) error(EInvalidAccess(f)); - return { - #if php - // https://github.com/HaxeFoundation/haxe/issues/4915 - try { - Reflect.getProperty(o, f); - } catch (e:Dynamic) { - Reflect.field(o, f); - } - #else - Reflect.getProperty(o, f); - #end + var cl: String = switch (Type.typeof(o)) { + case TNull: "Null"; + case TInt: "Int"; + case TFloat: "Float"; + case TBool: "Bool"; + case _: null; + }; + var redirect: Dynamic->String->Dynamic = getRedirects.exists(cl = Type.getClassName(Type.getClass(o))) ? getRedirects[cl] : null; + if (redirect != null) + return redirect(o, f); + #if php + try { + return Reflect.getProperty(o, f); + } catch (e: Dynamic) { + return Reflect.field(o, f); } + #else + return Reflect.getProperty(o, f); + #end } function set(o: Dynamic, f: String, v: Dynamic): Dynamic { if (o == null) error(EInvalidAccess(f)); - Reflect.setProperty(o, f, v); - return v; - } - - /** - * Meant for people to add their own usings. - **/ - function registerUsingLocal(name: String, call: UsingCall): UsingEntry { - var entry = new UsingEntry(name, call); - usings.push(entry); - return entry; - } - - function useUsing(name: String): Void { - for (us in Iris.registeredUsingEntries) { - if (us.name == name) { - if (usings.indexOf(us) == -1) - usings.push(us); - return; - } - } - - var cls = Tools.getClass(name); - if (cls != null) { - var fieldName = '__irisUsing_' + StringTools.replace(name, ".", "_"); - if (Reflect.hasField(cls, fieldName)) { - var fields = Reflect.field(cls, fieldName); - if (fields == null) - return; - - var entry = new UsingEntry(name, function(o: Dynamic, f: String, args: Array): Dynamic { - if (!fields.exists(f)) - return null; - var type: ValueType = Type.typeof(o); - var valueType: ValueType = fields.get(f); - - // If we figure out a better way to get the types as the real ValueType, we can use this instead - // if (Type.enumEq(valueType, type)) - // return Reflect.callMethod(cls, Reflect.field(cls, f), [o].concat(args)); - - var canCall = valueType == null ? true : switch (valueType) { - case TEnum(null): - type.match(TEnum(_)); - case TClass(null): - type.match(TClass(_)); - case TClass(IMap): // if we don't check maps like this, it just doesn't work - type.match(TClass(IMap) | TClass(haxe.ds.ObjectMap) | TClass(haxe.ds.StringMap) | TClass(haxe.ds.IntMap) | TClass(haxe.ds.EnumValueMap)); - default: - Type.enumEq(type, valueType); - } - - return canCall ? Reflect.callMethod(cls, Reflect.field(cls, f), [o].concat(args)) : null; - }); - - #if IRIS_DEBUG - trace("Registered macro based using entry for " + name); - #end - - Iris.registeredUsingEntries.push(entry); - usings.push(entry); - return; - } - - // Use reflection to generate the using entry - var entry = new UsingEntry(name, function(o: Dynamic, f: String, args: Array): Dynamic { - if (!Reflect.hasField(cls, f)) - return null; - var field = Reflect.field(cls, f); - if (!Reflect.isFunction(field)) - return null; - - // invalid if the function has no arguments - var totalArgs = Tools.argCount(field); - if (totalArgs == 0) - return null; - - // todo make it check if the first argument is the correct type - - return Reflect.callMethod(cls, field, [o].concat(args)); - }); - - #if IRIS_DEBUG - trace("Registered reflection based using entry for " + name); - #end - - Iris.registeredUsingEntries.push(entry); - usings.push(entry); - return; - } - warn(ECustom("Unknown using class " + name)); - } - - /** - * List of components that allow using static methods on objects. - * This only works if you do - * ```haxe - * var result = "Hello ".trim(); - * ``` - * and not - * ```haxe - * var trim = "Hello ".trim; - * var result = trim(); - * ``` - */ - var usings: Array = []; - - function fcall(o: Dynamic, f: String, args: Array): Dynamic { - for (_using in usings) { - var v = _using.call(o, f, args); - if (v != null) - return v; - } - - return { - call(o, get(o, f), args); - } - } - - function call(o: Dynamic, f: Dynamic, args: Array): Dynamic { - return Reflect.callMethod(o, f, args); - } - - function cnew(cl: String, args: Array): Dynamic { - var c = Type.resolveClass(cl); - if (c == null) - c = resolve(cl); - return Type.createInstance(c, args); - } -} + var cl: String = switch (Type.typeof(o)) { + case TNull: "Null"; + case TInt: "Int"; + case TFloat: "Float"; + case TBool: "Bool"; + case _: null; + }; + var redirect: Dynamic->String->Dynamic->Dynamic = setRedirects.exists(cl = Type.getClassName(Type.getClass(o))) ? setRedirects[cl] : null; + if (redirect != null) + return redirect(o, f, From 4cdf6596e03af4d41456567af4c860619b23bb54 Mon Sep 17 00:00:00 2001 From: bananaTiko <111482265+bananaTiko@users.noreply.github.com> Date: Thu, 12 Jun 2025 18:19:23 -0700 Subject: [PATCH 15/21] Update Interp.hx --- crowplexus/hscript/Interp.hx | 148 ++++++++++++++++++++++++++++++++--- 1 file changed, 135 insertions(+), 13 deletions(-) diff --git a/crowplexus/hscript/Interp.hx b/crowplexus/hscript/Interp.hx index 8792612..032442b 100644 --- a/crowplexus/hscript/Interp.hx +++ b/crowplexus/hscript/Interp.hx @@ -24,11 +24,13 @@ package crowplexus.hscript; import Type.ValueType; import crowplexus.hscript.Expr; +import crowplexus.hscript.IHScriptCustomBehaviour; import crowplexus.hscript.Tools; import crowplexus.iris.Iris; import crowplexus.iris.IrisUsingClass; import crowplexus.iris.utils.UsingEntry; import haxe.Constraints.IMap; +import haxe.EnumTools; import haxe.PosInfos; private enum Stop { @@ -52,10 +54,12 @@ class DeclaredVar { @:allow(crowplexus.hscript.PropertyAccessor) class Interp { public static var staticVariables: #if haxe3 Map = new Map() #else Hash = new Hash() #end; + public static var getRedirects: MapString->Dynamic> = []; + public static var setRedirects: MapString->Dynamic->Dynamic> = []; public var scriptObject(default, set): Dynamic; public var parentInstance(default, set): Dynamic; - + #if haxe3 public var variables: Map; public var imports: Map; @@ -80,8 +84,6 @@ class Interp { var returnValue: Dynamic; @:noCompletion static var unpackClassCache: #if haxe3 Map = new Map() #else Hash = new Hash() #end; - public static var getRedirects: MapString->Dynamic> = []; - public static var setRedirects: MapString->Dynamic->Dynamic> = []; #if hscriptPos var curExpr: Expr; @@ -166,7 +168,6 @@ class Interp { binops.set("==", function(e1, e2) return me.expr(e1) == me.expr(e2)); binops.set("!=", function(e1, e2) return me.expr(e1) != me.expr(e2)); binops.set(">=", function(e1, e2) return me.expr(e1) >= me.expr(e2)); - binops.set红包: 2/3/2023 18:43:54 binops.set("<=", function(e1, e2) return me.expr(e1) <= me.expr(e2)); binops.set(">", function(e1, e2) return me.expr(e1) > me.expr(e2)); binops.set("<", function(e1, e2) return me.expr(e1) < me.expr(e2)); @@ -189,7 +190,7 @@ class Interp { assignOp("<<=", function(v1, v2) return v1 << v2); assignOp(">>=", function(v1, v2) return v1 >> v2); assignOp(">>>=", function(v1, v2) return v1 >>> v2); - assignOp("??=", function(v1, v2) return v1 == null ? v2 : v1); + assignOp("??" + "=", function(v1, v2) return v1 == null ? v2 : v1); } public inline function setVar(name: String, v: Dynamic) { @@ -228,9 +229,23 @@ class Interp { switch (Tools.expr(e1)) { case EIdent(id): var l = locals.get(id); - if (l == null) - setVar(id, v); - else { + if (l == null) { + if (parentInstance != null && (_parentFields.contains(id) || _parentFields.contains('set_$id'))) { + Reflect.setProperty(parentInstance, id, v); + } else if (scriptObject != null) { + if (Type.typeof(scriptObject) == TObject) { + Reflect.setField(scriptObject, id, v); + } else if (__instanceFields.contains(id)) { + Reflect.setProperty(scriptObject, id, v); + } else if (__instanceFields.contains('set_$id')) { + Reflect.getProperty(scriptObject, 'set_$id')(v); + } else { + setVar(id, v); + } + } else { + setVar(id, v); + } + } else { if (l.const != true) l.r = v; else @@ -272,8 +287,14 @@ class Interp { if (l == null) { if (parentInstance != null && (_parentFields.contains(id) || _parentFields.contains('set_$id'))) { Reflect.setProperty(parentInstance, id, v); - } else if (scriptObject != null && (__instanceFields.contains(id) || __instanceFields.contains('set_$id'))) { - Reflect.setProperty(scriptObject, id, v); + } else if (scriptObject != null) { + if (__instanceFields.contains(id)) { + Reflect.setProperty(scriptObject, id, v); + } else if (__instanceFields.contains('set_$id')) { + Reflect.getProperty(scriptObject, 'set_$id')(v); + } else { + setVar(id, v); + } } else { setVar(id, v); } @@ -486,7 +507,7 @@ class Interp { if (unpackClassCache.exists(id)) return unpackClassCache.get(id); - + var cl = Type.resolveClass(id); if (cl != null) { unpackClassCache.set(id, cl); @@ -986,6 +1007,10 @@ class Interp { var redirect: Dynamic->String->Dynamic = getRedirects.exists(cl = Type.getClassName(Type.getClass(o))) ? getRedirects[cl] : null; if (redirect != null) return redirect(o, f); + if (o is IHScriptCustomBehaviour) { + var obj = cast(o, IHScriptCustomBehaviour); + return obj.hget(f); + } #if php try { return Reflect.getProperty(o, f); @@ -993,7 +1018,10 @@ class Interp { return Reflect.field(o, f); } #else - return Reflect.getProperty(o, f); + var v = Reflect.getProperty(o, f); + if (v == null) + v = Reflect.getProperty(Type.getClass(o), f); + return v; #end } @@ -1009,4 +1037,98 @@ class Interp { }; var redirect: Dynamic->String->Dynamic->Dynamic = setRedirects.exists(cl = Type.getClassName(Type.getClass(o))) ? setRedirects[cl] : null; if (redirect != null) - return redirect(o, f, + return redirect(o, f, v); + if (o is IHScriptCustomBehaviour) { + var obj = cast(o, IHScriptCustomBehaviour); + return obj.hset(f, v); + } + Reflect.setProperty(o, f, v); + return v; + } + + function registerUsingLocal(name: String, call: UsingCall): UsingEntry { + var entry = new UsingEntry(name, call); + usings.push(entry); + return entry; + } + + function useUsing(name: String): Void { + for (us in Iris.registeredUsingEntries) { + if (us.name == name) { + if (usings.indexOf(us) == -1) + usings.push(us); + return; + } + } + var cls = Tools.getClass(name); + if (cls != null) { + var fieldName = '__irisUsing_' + StringTools.replace(name, ".", "_"); + if (Reflect.hasField(cls, fieldName)) { + var fields = Reflect.field(cls, fieldName); + if (fields == null) + return; + var entry = new UsingEntry(name, function(o: Dynamic, f: String, args: Array): Dynamic { + if (!fields.exists(f)) + return null; + var type: ValueType = Type.typeof(o); + var valueType: ValueType = fields.get(f); + var canCall = valueType == null ? true : switch (valueType) { + case TEnum(null): type.match(TEnum(_)); + case TClass(null): type.match(TClass(_)); + case TClass(IMap): + type.match(TClass(IMap) | TClass(haxe.ds.ObjectMap) | TClass(haxe.ds.StringMap) | TClass(haxe.ds.IntMap) | TClass(haxe.ds.EnumValueMap)); + default: Type.enumEq(type, valueType); + } + return canCall ? Reflect.callMethod(cls, Reflect.field(cls, f), [o].concat(args)) : null; + }); + #if IRIS_DEBUG + trace("Registered macro based using entry for " + name); + #end + Iris.registeredUsingEntries.push(entry); + usings.push(entry); + return; + } + var entry = new UsingEntry(name, function(o: Dynamic, f: String, args: Array): Dynamic { + if (!Reflect.hasField(cls, f)) + return null; + var field = Reflect.field(cls, f); + if (!Reflect.isFunction(field)) + return null; + var totalArgs = Tools.argCount(field); + if (totalArgs == 0) + return null; + return Reflect.callMethod(cls, field, [o].concat(args)); + }); + #i + f IRIS_DEBUG + trace("Registered reflection based using entry for " + name); + #end + Iris.registeredUsingEntries.push(entry); + usings.push(entry); + return; + } + warn(ECustom("Unknown using class " + name)); + } + + var usings: Array = []; + + function fcall(o: Dynamic, f: String, args: Array): Dynamic { + for (_using in usings) { + var v = _using.call(o, f, args); + if (v != null) + return v; + } + return call(o, get(o, f), args); + } + + function call(o: Dynamic, f: Dynamic, args: Array): Dynamic { + return Reflect.callMethod(o, f, args); + } + + function cnew(cl: String, args: Array): Dynamic { + var c = Type.resolveClass(cl); + if (c == null) + c = resolve(cl); + return Type.createInstance(c, args); + } + } From d9212d0dfb5b98f4342bb57fe13a10e57ed55aa1 Mon Sep 17 00:00:00 2001 From: bananaTiko <111482265+bananaTiko@users.noreply.github.com> Date: Thu, 12 Jun 2025 18:22:42 -0700 Subject: [PATCH 16/21] Add files via upload --- crowplexus/hscript/IHScriptCustomBehaviour.hx | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 crowplexus/hscript/IHScriptCustomBehaviour.hx diff --git a/crowplexus/hscript/IHScriptCustomBehaviour.hx b/crowplexus/hscript/IHScriptCustomBehaviour.hx new file mode 100644 index 0000000..570bb0b --- /dev/null +++ b/crowplexus/hscript/IHScriptCustomBehaviour.hx @@ -0,0 +1,6 @@ +package crowplexus.hscript; + +interface IHScriptCustomBehaviour { + public function hset(name:String, val:Dynamic):Dynamic; + public function hget(name:String):Dynamic; +} \ No newline at end of file From 08b349d1b5120ddc5dc4ce067e4ac434f0cdb865 Mon Sep 17 00:00:00 2001 From: bananaTiko <111482265+bananaTiko@users.noreply.github.com> Date: Thu, 12 Jun 2025 18:27:24 -0700 Subject: [PATCH 17/21] Update Interp.hx --- crowplexus/hscript/Interp.hx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crowplexus/hscript/Interp.hx b/crowplexus/hscript/Interp.hx index 032442b..a7651c4 100644 --- a/crowplexus/hscript/Interp.hx +++ b/crowplexus/hscript/Interp.hx @@ -1099,8 +1099,7 @@ class Interp { return null; return Reflect.callMethod(cls, field, [o].concat(args)); }); - #i - f IRIS_DEBUG + #if IRIS_DEBUG trace("Registered reflection based using entry for " + name); #end Iris.registeredUsingEntries.push(entry); From 65853a391d05ff4209b42ea5eeee2f9f9e241910 Mon Sep 17 00:00:00 2001 From: bananaTiko <111482265+bananaTiko@users.noreply.github.com> Date: Thu, 12 Jun 2025 21:17:43 -0700 Subject: [PATCH 18/21] Update Parser.hx --- crowplexus/hscript/Parser.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crowplexus/hscript/Parser.hx b/crowplexus/hscript/Parser.hx index 569e3b9..ccc3580 100644 --- a/crowplexus/hscript/Parser.hx +++ b/crowplexus/hscript/Parser.hx @@ -1029,7 +1029,7 @@ class Parser { if (tk == TSemicolon) return mk(EIgnore(false)); var path = parsePath(); - PACKAGE: path.join("."); + packageName: path.join("."); mk(EIgnore(false)); default: null; From 20d489a4b42e6fdf019cf22662cd09ddb4642601 Mon Sep 17 00:00:00 2001 From: bananaTiko <111482265+bananaTiko@users.noreply.github.com> Date: Thu, 12 Jun 2025 21:21:56 -0700 Subject: [PATCH 19/21] Update Parser.hx --- crowplexus/hscript/Parser.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/crowplexus/hscript/Parser.hx b/crowplexus/hscript/Parser.hx index ccc3580..815c1c4 100644 --- a/crowplexus/hscript/Parser.hx +++ b/crowplexus/hscript/Parser.hx @@ -1030,6 +1030,7 @@ class Parser { return mk(EIgnore(false)); var path = parsePath(); packageName: path.join("."); + expect(TSemicolon); mk(EIgnore(false)); default: null; From e90fabe11d393b931cc60c623f0acd1946b9471e Mon Sep 17 00:00:00 2001 From: bananaTiko <111482265+bananaTiko@users.noreply.github.com> Date: Thu, 12 Jun 2025 21:24:47 -0700 Subject: [PATCH 20/21] Update Parser.hx --- crowplexus/hscript/Parser.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crowplexus/hscript/Parser.hx b/crowplexus/hscript/Parser.hx index 815c1c4..a07aa66 100644 --- a/crowplexus/hscript/Parser.hx +++ b/crowplexus/hscript/Parser.hx @@ -1029,7 +1029,7 @@ class Parser { if (tk == TSemicolon) return mk(EIgnore(false)); var path = parsePath(); - packageName: path.join("."); + packageName = path.join("."); expect(TSemicolon); mk(EIgnore(false)); default: From 1ec7c40e726dea504f5861640d4ae8dd2a8dcb19 Mon Sep 17 00:00:00 2001 From: bananaTiko <111482265+bananaTiko@users.noreply.github.com> Date: Thu, 12 Jun 2025 21:27:18 -0700 Subject: [PATCH 21/21] Update Parser.hx --- crowplexus/hscript/Parser.hx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crowplexus/hscript/Parser.hx b/crowplexus/hscript/Parser.hx index a07aa66..9f7cfe4 100644 --- a/crowplexus/hscript/Parser.hx +++ b/crowplexus/hscript/Parser.hx @@ -1030,7 +1030,6 @@ class Parser { return mk(EIgnore(false)); var path = parsePath(); packageName = path.join("."); - expect(TSemicolon); mk(EIgnore(false)); default: null; @@ -2097,7 +2096,7 @@ class Parser { } } - @:noCompletion public var preprocessorValues(get, set): Map; + // @:noCompletion public var preprocessorValues(get, set): Map; inline function get_preprocessorValues() return this.preprocessorValues; inline function set_preprocessorValues(v) return this.preprocessorValues = v; }