From 61edb9cc5c90f4d969eae10b35a2b8212fa9025e Mon Sep 17 00:00:00 2001 From: HEIHUAa <112499486+HEIHUAa@users.noreply.github.com> Date: Thu, 9 Apr 2026 20:12:53 +0800 Subject: [PATCH] exprReturn repair --- PerfTest.hx | 63 +++ hscript/Interp.hx | 12 +- hscript/Printer.hx | 988 ++++++++++++++++++++++----------------------- hscript/Tools.hx | 286 ++++++------- 4 files changed, 708 insertions(+), 641 deletions(-) create mode 100644 PerfTest.hx diff --git a/PerfTest.hx b/PerfTest.hx new file mode 100644 index 0000000..0b9c160 --- /dev/null +++ b/PerfTest.hx @@ -0,0 +1,63 @@ +import haxe.Timer; +import hscript.Interp; +import hscript.Parser; + +class PerfTest { + static function main() { + var parser = new Parser(); + parser.allowTypes = true; + + var testScript = " + var sum = 0; + var a = 1; + var b = 2; + var c = 3; + for (i in 0...10000) { + sum = sum + a * b + c - a / b; + a = a + 1; + b = b + 1; + c = c + 1; + if (sum > 1000000) sum = 0; + if (a > 100) a = 1; + if (b > 200) b = 2; + if (c > 300) c = 3; + } + sum; + "; + + var program = parser.parseString(testScript); + + var interp = new Interp(); + interp.variables.set("Math", Math); + + var iterations = 100; + + Sys.println("=== Fast Binops (switch) Mode ==="); + + var totalTests = 5; + var times:Array = []; + + for (testNum in 0...totalTests) { + var interp = new Interp(); + interp.variables.set("Math", Math); + + var startTime = Timer.stamp(); + for (i in 0...iterations) { + interp.execute(program); + } + var endTime = Timer.stamp(); + var elapsed = endTime - startTime; + times.push(elapsed); + Sys.println('Test ${testNum + 1}: ${Std.string(elapsed * 1000).substr(0, 8)} ms'); + } + + var avg = Lambda.fold(times, function(a, b) return a + b, 0.0) / times.length; + var minTime = Lambda.fold(times, function(a, b) return a < b ? a : b, times[0]); + var maxTime = Lambda.fold(times, function(a, b) return a > b ? a : b, times[0]); + + Sys.println(""); + Sys.println('Average: ${Std.string(avg * 1000).substr(0, 8)} ms'); + Sys.println('Min: ${Std.string(minTime * 1000).substr(0, 8)} ms'); + Sys.println('Max: ${Std.string(maxTime * 1000).substr(0, 8)} ms'); + } +} diff --git a/hscript/Interp.hx b/hscript/Interp.hx index 33c751c..5769bf8 100644 --- a/hscript/Interp.hx +++ b/hscript/Interp.hx @@ -538,11 +538,15 @@ class Interp { } return null; } catch (e:Dynamic) { - if (printCallStack) { - var stack = CallStack.exceptionStack(true); - error(ECustom(Std.string(e) + "\n" + CallStack.toString(stack))); + var errStr = printCallStack ? Std.string(e) + "\n" + CallStack.toString(CallStack.exceptionStack(true)) : Std.string(e); + if (errorHandler != null) { + #if hscriptPos + errorHandler(new Error(ECustom(errStr), curExpr.pmin, curExpr.pmax, curExpr.origin, curExpr.line)); + #else + errorHandler(new Error(ECustom(errStr))); + #end } else { - error(ECustom(Std.string(e))); + throw e; } return null; } diff --git a/hscript/Printer.hx b/hscript/Printer.hx index 45905bc..8861f47 100644 --- a/hscript/Printer.hx +++ b/hscript/Printer.hx @@ -1,494 +1,494 @@ -/* - * Copyright (C)2008-2017 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -package hscript; -import hscript.Expr; - -class Printer { - - var buf : StringBuf; - var tabs : String; - - public function new() { - } - - public function exprToString( e : Expr ):String { - buf = new StringBuf(); - tabs = ""; - expr(e); - return buf.toString(); - } - - public function typeToString( t : CType ):String { - buf = new StringBuf(); - tabs = ""; - type(t); - return buf.toString(); - } - - inline function add(s:T):Void buf.add(s); - - function type( t : CType ):Void { - switch( t ) { - case CTOpt(t): - add('?'); - type(t); - case CTPath(path, params): - add(path.join(".")); - if( params != null ) { - add("<"); - var first = true; - for( p in params ) { - if( first ) first = false else add(", "); - type(p); - } - add(">"); - } - case CTNamed(name, t): - add(name); - add(':'); - type(t); - case CTFun(args, ret) if (Lambda.exists(args, function (a) return a.match(CTNamed(_, _)))): - add('('); - for (a in args) - switch a { - case CTNamed(_, _): type(a); - default: type(CTNamed('_', a)); - } - add(')->'); - type(ret); - case CTFun(args, ret): - if( args.length == 0 ) - add("Void -> "); - else { - for( a in args ) { - type(a); - add(" -> "); - } - } - type(ret); - case CTAnon(fields): - add("{"); - var first = true; - for( f in fields ) { - if( first ) { first = false; add(" "); } else add(", "); - add(f.name + " : "); - type(f.t); - } - add(first ? "}" : " }"); - case CTParent(t): - add("("); - type(t); - add(")"); - case CTExpr(e): - expr(e); - } - } - - function addType( t : CType ):Void { - if( t != null ) { - add(" : "); - type(t); - } - } - - function expr( e : Expr ):Void { - if( e == null ) { - add("??NULL??"); - return; - } - switch(Tools.expr(e)) { - case EPackage(n): - add('package'); - if(n != null) - add(' $n'); - add(';\n'); - case EImport(c, n, u): - add('${u ? 'using' : 'import'} $c'); - if(n != null) - add(' as $n'); - case EClass(name, fields, extend, interfaces, fnal): - var isFinal = fnal != null && fnal; - if(isFinal) - add('final '); - add('class $name'); - if (extend != null) - add(' extends $extend'); - for(_interface in interfaces) { - add(' implements $_interface'); - } - tabs += "\t"; - add(" {\n"); - for( e in fields ) { - add(tabs); - expr(e); - //add(";\n"); - } - //for(field in fields) { - // expr(field); - //} - - tabs = tabs.substr(1); - add("}"); - case EEnum(en, isAbstract): - if(isAbstract) { - add('enum abstract ${en.name}('); - if(en.underlyingType != null) - type(en.underlyingType); - else - add('Int'); - add(')'); - if(en.fields.length == 0) { - add(' {}'); - return; - } - tabs += "\t"; - add(" {\n"); - for(e in en.fields) { - add(tabs); - add(e.name); - if(e.value != null) { - add(" = "); - expr(e.value); - } - add(";\n"); - } - tabs = tabs.substr(1); - add("}"); - } else { - add('enum ${en.name}'); - if(en.fields.length == 0) { - add(' {}'); - return; - } - tabs += "\t"; - add(" {\n"); - for(e in en.fields) { - add(tabs); - add(e.name); - if(e.args.length > 0) { - add("("); - var first = true; - for( a in e.args ) { - if( first ) first = false else add(", "); - if( a.opt ) add("?"); - add(a.name); - addType(a.t); - } - add(')'); - } - add(";\n"); - } - tabs = tabs.substr(1); - add("}"); - } - case ECast(e, t): - var safe = t != null; - add("cast "); - if(safe) add("("); - expr(e); - if(safe) { - add(", "); - addType(t); - add(")"); - } - case ERegex(e, f): - add('~/$e/$f'); - add(';\n'); - case EConst(c): - switch( c ) { - case CInt(i): add(i); - case CFloat(f): add(f); - case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"'); - } - case EIdent(v): - add(v); - case EVar(n, t, e, p, s, pr, isFinal, isInline, get, set, _): - if(p) add("public "); - else if(pr) add("private "); - if(s) add("static "); - if(isInline) add("inline "); - if(isFinal) add("final " + n); - else add("var " + n); - - if(get != null || set != null) { - add("("); - switch(get) { - case ADefault: add("default, "); - case ANull: add("null, "); - case AGet: add("get, "); - case ADynamic: add("dynamic, "); - case ANever: add("never, "); - default: - } - switch(set) { - case ADefault: add("default"); - case ANull: add("null"); - case ASet: add("set"); - case ADynamic: add("dynamic"); - case ANever: add("never"); - default: - } - add(")"); - } - - addType(t); - if( e != null ) { - add(" = "); - expr(e); - } - case EParent(e): - add("("); expr(e); add(")"); - case EBlock(el): - if( el.length == 0 ) { - add("{}"); - } else { - tabs += "\t"; - add("{\n"); - for( e in el ) { - add(tabs); - expr(e); - add(";\n"); - } - tabs = tabs.substr(1); - add("}"); - } - case EField(e, f, s): - expr(e); - add((s == true ? "?." : ".") + f); - case EBinop(op, e1, e2): - expr(e1); - add(" " + op.toString() + " "); - expr(e2); - case EUnop(op, pre, e): - if( pre ) { - add(op); - expr(e); - } else { - expr(e); - add(op); - } - case ECall(e, args): - if( e == null ) - expr(e); - else switch( Tools.expr(e)) { - case EField(_), EIdent(_), EConst(_): - expr(e); - default: - add("("); - expr(e); - add(")"); - } - add("("); - var first = true; - for( a in args ) { - if( first ) first = false else add(", "); - expr(a); - } - add(")"); - case EIf(cond,e1,e2): - add("if( "); - expr(cond); - add(" ) "); - expr(e1); - if( e2 != null ) { - add(" else "); - expr(e2); - } - case EWhile(cond,e): - add("while( "); - expr(cond); - add(" ) "); - expr(e); - case EDoWhile(cond,e): - add("do "); - expr(e); - add(" while ( "); - expr(cond); - add(" )"); - case EFor(v, it, e, ithv): - if(ithv != null) - add("for( "+ithv+" => "+v+" in "); - else - add("for( "+v+" in "); - expr(it); - add(" ) "); - expr(e); - case EBreak: - add("break"); - case EContinue: - add("continue"); - case EFunction(params, e, name, ret): // TODO: static, public, override - add("function"); - if( name != null ) - add(" " + name); - add("("); - var first = true; - for( a in params ) { - if( first ) first = false else add(", "); - if( a.opt ) add("?"); - add(a.name); - addType(a.t); - } - add(")"); - addType(ret); - add(" "); - expr(e); - case EReturn(e): - add("return"); - if( e != null ) { - add(" "); - expr(e); - } - case EArray(e,index): - expr(e); - add("["); - expr(index); - add("]"); - case EArrayDecl(el, _): - add("["); - var first = true; - for( e in el ) { - if( first ) first = false else add(", "); - expr(e); - } - add("]"); - case ENew(cl, args, params): - add("new " + cl); - if(params != null) { - add("<"); - var first = true; - for( p in params ) { - if( first ) first = false else add(", "); - type(p); - } - add(">"); - } - add("("); - var first = true; - for( e in args ) { - if( first ) first = false else add(", "); - expr(e); - } - add(")"); - case EThrow(e): - add("throw "); - expr(e); - case ETry(e, v, t, ecatch): - add("try "); - expr(e); - add(" catch( " + v); - addType(t); - add(") "); - expr(ecatch); - case EObject(fl): - if( fl.length == 0 ) { - add("{}"); - } else { - tabs += "\t"; - add("{\n"); - for( f in fl ) { - add(tabs); - add(f.name+" : "); - expr(f.e); - add(",\n"); - } - tabs = tabs.substr(1); - add("}"); - } - case ETernary(c,e1,e2): - expr(c); - add(" ? "); - expr(e1); - add(" : "); - expr(e2); - case ESwitch(e, cases, def): - add("switch( "); - expr(e); - add(") {"); - for( c in cases ) { - add("case "); - var first = true; - for( v in c.values ) { - if( first ) first = false else add(", "); - expr(v); - } - add(": "); - expr(c.expr); - add(";\n"); - } - if( def != null ) { - add("default: "); - expr(def); - add(";\n"); - } - add("}"); - case EMeta(name, args, e): - add("@"); - add(name); - if( args != null && args.length > 0 ) { - add("("); - var first = true; - for( a in args ) { - if( first ) first = false else add(", "); - expr(e); - } - add(")"); - } - add(" "); - expr(e); - case ECheckType(e, t): - add("("); - expr(e); - add(" : "); - addType(t); - add(")"); - } - } - - public static function toString( e : Expr ):String { - return new Printer().exprToString(e); - } - - public static function errorToString( e : Expr.Error ):String { - var message = switch( #if hscriptPos e.e #else e #end ) { - case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")"; - case EUnexpected(s): "Unexpected token: \""+s+"\""; - case EUnterminatedString: "Unterminated string"; - case EUnterminatedComment: "Unterminated comment"; - case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")"; - case EUnknownVariable(v): "Unknown variable: "+v; - case EInvalidIterator(v): "Invalid iterator: "+v; - case EInvalidOp(op): "Invalid operator: "+op; - case EInvalidAccess(f): "Invalid access to field " + f; - case ECustom(msg): msg; - case EInvalidClass(cla): "Invalid class: " + cla + " was not found."; - case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.'; - }; - #if hscriptPos - return e.origin + ":" + e.line + ": " + message; - #else - return message; - #end - } - - -} +/* + * Copyright (C)2008-2017 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +package hscript; +import hscript.Expr; + +class Printer { + + var buf : StringBuf; + var tabs : String; + + public function new() { + } + + public function exprToString( e : Expr ):String { + buf = new StringBuf(); + tabs = ""; + expr(e); + return buf.toString(); + } + + public function typeToString( t : CType ):String { + buf = new StringBuf(); + tabs = ""; + type(t); + return buf.toString(); + } + + inline function add(s:T):Void buf.add(s); + + function type( t : CType ):Void { + switch( t ) { + case CTOpt(t): + add('?'); + type(t); + case CTPath(path, params): + add(path.join(".")); + if( params != null ) { + add("<"); + var first = true; + for( p in params ) { + if( first ) first = false else add(", "); + type(p); + } + add(">"); + } + case CTNamed(name, t): + add(name); + add(':'); + type(t); + case CTFun(args, ret) if (Lambda.exists(args, function (a) return a.match(CTNamed(_, _)))): + add('('); + for (a in args) + switch a { + case CTNamed(_, _): type(a); + default: type(CTNamed('_', a)); + } + add(')->'); + type(ret); + case CTFun(args, ret): + if( args.length == 0 ) + add("Void -> "); + else { + for( a in args ) { + type(a); + add(" -> "); + } + } + type(ret); + case CTAnon(fields): + add("{"); + var first = true; + for( f in fields ) { + if( first ) { first = false; add(" "); } else add(", "); + add(f.name + " : "); + type(f.t); + } + add(first ? "}" : " }"); + case CTParent(t): + add("("); + type(t); + add(")"); + case CTExpr(e): + expr(e); + } + } + + function addType( t : CType ):Void { + if( t != null ) { + add(" : "); + type(t); + } + } + + function expr( e : Expr ):Void { + if( e == null ) { + add("??NULL??"); + return; + } + switch(Tools.expr(e)) { + case EPackage(n): + add('package'); + if(n != null) + add(' $n'); + add(';\n'); + case EImport(c, n, u): + add('${u ? 'using' : 'import'} $c'); + if(n != null) + add(' as $n'); + case EClass(name, fields, extend, interfaces, fnal): + var isFinal = fnal != null && fnal; + if(isFinal) + add('final '); + add('class $name'); + if (extend != null) + add(' extends $extend'); + for(_interface in interfaces) { + add(' implements $_interface'); + } + tabs += "\t"; + add(" {\n"); + for( e in fields ) { + add(tabs); + expr(e); + //add(";\n"); + } + //for(field in fields) { + // expr(field); + //} + + tabs = tabs.substr(1); + add("}"); + case EEnum(en, isAbstract): + if(isAbstract) { + add('enum abstract ${en.name}('); + if(en.underlyingType != null) + type(en.underlyingType); + else + add('Int'); + add(')'); + if(en.fields.length == 0) { + add(' {}'); + return; + } + tabs += "\t"; + add(" {\n"); + for(e in en.fields) { + add(tabs); + add(e.name); + if(e.value != null) { + add(" = "); + expr(e.value); + } + add(";\n"); + } + tabs = tabs.substr(1); + add("}"); + } else { + add('enum ${en.name}'); + if(en.fields.length == 0) { + add(' {}'); + return; + } + tabs += "\t"; + add(" {\n"); + for(e in en.fields) { + add(tabs); + add(e.name); + if(e.args.length > 0) { + add("("); + var first = true; + for( a in e.args ) { + if( first ) first = false else add(", "); + if( a.opt ) add("?"); + add(a.name); + addType(a.t); + } + add(')'); + } + add(";\n"); + } + tabs = tabs.substr(1); + add("}"); + } + case ECast(e, t): + var safe = t != null; + add("cast "); + if(safe) add("("); + expr(e); + if(safe) { + add(", "); + addType(t); + add(")"); + } + case ERegex(e, f): + add('~/$e/$f'); + add(';\n'); + case EConst(c): + switch( c ) { + case CInt(i): add(i); + case CFloat(f): add(f); + case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"'); + } + case EIdent(v): + add(v); + case EVar(n, t, e, p, s, pr, isFinal, isInline, get, set, _): + if(p) add("public "); + else if(pr) add("private "); + if(s) add("static "); + if(isInline) add("inline "); + if(isFinal) add("final " + n); + else add("var " + n); + + if(get != null || set != null) { + add("("); + switch(get) { + case ADefault: add("default, "); + case ANull: add("null, "); + case AGet: add("get, "); + case ADynamic: add("dynamic, "); + case ANever: add("never, "); + default: + } + switch(set) { + case ADefault: add("default"); + case ANull: add("null"); + case ASet: add("set"); + case ADynamic: add("dynamic"); + case ANever: add("never"); + default: + } + add(")"); + } + + addType(t); + if( e != null ) { + add(" = "); + expr(e); + } + case EParent(e): + add("("); expr(e); add(")"); + case EBlock(el): + if( el.length == 0 ) { + add("{}"); + } else { + tabs += "\t"; + add("{\n"); + for( e in el ) { + add(tabs); + expr(e); + add(";\n"); + } + tabs = tabs.substr(1); + add("}"); + } + case EField(e, f, s): + expr(e); + add((s == true ? "?." : ".") + f); + case EBinop(op, e1, e2): + expr(e1); + add(" " + op.toString() + " "); + expr(e2); + case EUnop(op, pre, e): + if( pre ) { + add(op); + expr(e); + } else { + expr(e); + add(op); + } + case ECall(e, args): + if( e == null ) + expr(e); + else switch( Tools.expr(e)) { + case EField(_), EIdent(_), EConst(_): + expr(e); + default: + add("("); + expr(e); + add(")"); + } + add("("); + var first = true; + for( a in args ) { + if( first ) first = false else add(", "); + expr(a); + } + add(")"); + case EIf(cond,e1,e2): + add("if( "); + expr(cond); + add(" ) "); + expr(e1); + if( e2 != null ) { + add(" else "); + expr(e2); + } + case EWhile(cond,e): + add("while( "); + expr(cond); + add(" ) "); + expr(e); + case EDoWhile(cond,e): + add("do "); + expr(e); + add(" while ( "); + expr(cond); + add(" )"); + case EFor(v, it, e, ithv): + if(ithv != null) + add("for( "+ithv+" => "+v+" in "); + else + add("for( "+v+" in "); + expr(it); + add(" ) "); + expr(e); + case EBreak: + add("break"); + case EContinue: + add("continue"); + case EFunction(params, e, name, ret): // TODO: static, public, override + add("function"); + if( name != null ) + add(" " + name); + add("("); + var first = true; + for( a in params ) { + if( first ) first = false else add(", "); + if( a.opt ) add("?"); + add(a.name); + addType(a.t); + } + add(")"); + addType(ret); + add(" "); + expr(e); + case EReturn(e): + add("return"); + if( e != null ) { + add(" "); + expr(e); + } + case EArray(e,index): + expr(e); + add("["); + expr(index); + add("]"); + case EArrayDecl(el, _): + add("["); + var first = true; + for( e in el ) { + if( first ) first = false else add(", "); + expr(e); + } + add("]"); + case ENew(cl, args, params): + add("new " + cl); + if(params != null) { + add("<"); + var first = true; + for( p in params ) { + if( first ) first = false else add(", "); + type(p); + } + add(">"); + } + add("("); + var first = true; + for( e in args ) { + if( first ) first = false else add(", "); + expr(e); + } + add(")"); + case EThrow(e): + add("throw "); + expr(e); + case ETry(e, v, t, ecatch): + add("try "); + expr(e); + add(" catch( " + v); + addType(t); + add(") "); + expr(ecatch); + case EObject(fl): + if( fl.length == 0 ) { + add("{}"); + } else { + tabs += "\t"; + add("{\n"); + for( f in fl ) { + add(tabs); + add(f.name+" : "); + expr(f.e); + add(",\n"); + } + tabs = tabs.substr(1); + add("}"); + } + case ETernary(c,e1,e2): + expr(c); + add(" ? "); + expr(e1); + add(" : "); + expr(e2); + case ESwitch(e, cases, def): + add("switch( "); + expr(e); + add(") {"); + for( c in cases ) { + add("case "); + var first = true; + for( v in c.values ) { + if( first ) first = false else add(", "); + expr(v); + } + add(": "); + expr(c.expr); + add(";\n"); + } + if( def != null ) { + add("default: "); + expr(def); + add(";\n"); + } + add("}"); + case EMeta(name, args, e): + add("@"); + add(name); + if( args != null && args.length > 0 ) { + add("("); + var first = true; + for( a in args ) { + if( first ) first = false else add(", "); + expr(e); + } + add(")"); + } + add(" "); + expr(e); + case ECheckType(e, t): + add("("); + expr(e); + add(" : "); + addType(t); + add(")"); + } + } + + public static function toString( e : Expr ):String { + return new Printer().exprToString(e); + } + + public static function errorToString( e : Expr.Error ):String { + var message = switch( #if hscriptPos e.e #else e #end ) { + case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")"; + case EUnexpected(s): "Unexpected token: \""+s+"\""; + case EUnterminatedString: "Unterminated string"; + case EUnterminatedComment: "Unterminated comment"; + case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")"; + case EUnknownVariable(v): "Unknown variable: "+v; + case EInvalidIterator(v): "Invalid iterator: "+v; + case EInvalidOp(op): "Invalid operator: "+op; + case EInvalidAccess(f): "Invalid access to field " + f; + case ECustom(msg): msg; + case EInvalidClass(cla): "Invalid class: " + cla + " was not found."; + case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.'; + }; + #if hscriptPos + return e.origin + ":" + e.line + ": " + message; + #else + return message; + #end + } + + +} diff --git a/hscript/Tools.hx b/hscript/Tools.hx index 0d3dd3e..af5c28e 100644 --- a/hscript/Tools.hx +++ b/hscript/Tools.hx @@ -1,144 +1,144 @@ -/* - * Copyright (C)2008-2017 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -package hscript; -import hscript.Expr; - -class Tools { - - public static function iter( e : Expr, f : Expr -> Void ):Void { - switch( expr(e) ) { - case EConst(_), EIdent(_): - case EImport(c): f(e); - case EClass(_, e, _, _): for( a in e ) f(a); - case EVar(_, _, e): if( e != null ) f(e); - case EParent(e): f(e); - case EBlock(el): for( e in el ) f(e); - case EField(e, _): f(e); - case EBinop(_, e1, e2): f(e1); f(e2); - case EUnop(_, _, e): f(e); - case ECall(e, args): f(e); for( a in args ) f(a); - case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2); - case EWhile(c, e): f(c); f(e); - case EDoWhile(c, e): f(c); f(e); - case EFor(_, it, e): f(it); f(e); - case EBreak,EContinue: - case EFunction(_, e, _, _): f(e); - case EReturn(e): if( e != null ) f(e); - case EArray(e, i): f(e); f(i); - case EArrayDecl(el): for( e in el ) f(e); - case ENew(_,el): for( e in el ) f(e); - case EThrow(e): f(e); - case ETry(e, _, _, c): f(e); f(c); - case EObject(fl): for( fi in fl ) f(fi.e); - case ETernary(c, e1, e2): f(c); f(e1); f(e2); - case ESwitch(e, cases, def): - f(e); - for( c in cases ) { - for( v in c.values ) f(v); - f(c.expr); - } - if( def != null ) f(def); - case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e); - case ECheckType(e,_): f(e); - default: - } - } - - public static function map( e : Expr, f : Expr -> Expr ):Expr { - var edef = switch( expr(e) ) { - case EConst(_), EIdent(_), EBreak, EContinue: expr(e); - case EVar(n, t, e, isPublic, isStatic, isPrivate): EVar(n, t, if( e != null ) f(e) else null, isPublic, isStatic, isPrivate); - case EParent(e): EParent(f(e)); - case EBlock(el): EBlock([for( e in el ) f(e)]); - case EField(e, fi): EField(f(e),fi); - case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2)); - case EUnop(op, pre, e): EUnop(op, pre, f(e)); - case ECall(e, args): ECall(f(e),[for( a in args ) f(a)]); - case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null); - case EWhile(c, e): EWhile(f(c),f(e)); - case EDoWhile(c, e): EDoWhile(f(c),f(e)); - case EFor(v, it, e): EFor(v, f(it), f(e)); - case EFunction(args, e, name, t, isPublic, isStatic, isOverride, isPrivate): EFunction(args, f(e), name, t, isPublic, isStatic, isOverride, isPrivate); - case EReturn(e): EReturn(if( e != null ) f(e) else null); - case EArray(e, i): EArray(f(e),f(i)); - case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]); - case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]); - case EThrow(e): EThrow(f(e)); - case ETry(e, v, t, c): ETry(f(e), v, t, f(c)); - case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]); - case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2)); - case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) { values : [for( v in c.values ) f(v)], expr : f(c.expr) } ], def == null ? null : f(def)); - case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e)); - case ECheckType(e,t): ECheckType(f(e), t); - case EImport(c): EImport(c); - case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces); - default: expr(e); - } - return mk(edef, e); - } - - public static inline function expr( e : Expr ) : ExprDef { - #if hscriptPos - return e.e; - #else - return e; - #end - } - - public static inline function mk( e : ExprDef, p : Expr ):Expr { - #if hscriptPos - return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line }; - #else - return e; - #end - } - - /** - * DO NOT USE INLINE ON THIS FUNCTION - **/ - public static function argCount(func: haxe.Constraints.Function): Int { - // https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/hscript/Tools.hx#L206 - #if cpp - return untyped __cpp__("{0}->__ArgCount()", func); - #elseif js - return untyped js.Syntax.code("{0}.length", func); - #elseif hl - var ft = hl.Type.getDynamic(func); - if (ft.kind != HFun) - return -1; - return ft.getArgsCount(); - #else - return -1; - #end - } - - public static function isUppercase(s:String) { - if(s.length == 0) return false; - var c:Int = StringTools.fastCodeAt(s, 0); - if(StringTools.isEof(c)) return false; // Just in case :3 - return c >= 65 && c <= 90; // A-Z - } - - public static inline function isCustomAbstract(obj:Dynamic):Bool - return obj != null && obj is IHScriptAbstractBehaviour; - +/* + * Copyright (C)2008-2017 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +package hscript; +import hscript.Expr; + +class Tools { + + public static function iter( e : Expr, f : Expr -> Void ):Void { + switch( expr(e) ) { + case EConst(_), EIdent(_): + case EImport(c): f(e); + case EClass(_, e, _, _): for( a in e ) f(a); + case EVar(_, _, e): if( e != null ) f(e); + case EParent(e): f(e); + case EBlock(el): for( e in el ) f(e); + case EField(e, _): f(e); + case EBinop(_, e1, e2): f(e1); f(e2); + case EUnop(_, _, e): f(e); + case ECall(e, args): f(e); for( a in args ) f(a); + case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2); + case EWhile(c, e): f(c); f(e); + case EDoWhile(c, e): f(c); f(e); + case EFor(_, it, e): f(it); f(e); + case EBreak,EContinue: + case EFunction(_, e, _, _): f(e); + case EReturn(e): if( e != null ) f(e); + case EArray(e, i): f(e); f(i); + case EArrayDecl(el): for( e in el ) f(e); + case ENew(_,el): for( e in el ) f(e); + case EThrow(e): f(e); + case ETry(e, _, _, c): f(e); f(c); + case EObject(fl): for( fi in fl ) f(fi.e); + case ETernary(c, e1, e2): f(c); f(e1); f(e2); + case ESwitch(e, cases, def): + f(e); + for( c in cases ) { + for( v in c.values ) f(v); + f(c.expr); + } + if( def != null ) f(def); + case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e); + case ECheckType(e,_): f(e); + default: + } + } + + public static function map( e : Expr, f : Expr -> Expr ):Expr { + var edef = switch( expr(e) ) { + case EConst(_), EIdent(_), EBreak, EContinue: expr(e); + case EVar(n, t, e, isPublic, isStatic, isPrivate): EVar(n, t, if( e != null ) f(e) else null, isPublic, isStatic, isPrivate); + case EParent(e): EParent(f(e)); + case EBlock(el): EBlock([for( e in el ) f(e)]); + case EField(e, fi): EField(f(e),fi); + case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2)); + case EUnop(op, pre, e): EUnop(op, pre, f(e)); + case ECall(e, args): ECall(f(e),[for( a in args ) f(a)]); + case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null); + case EWhile(c, e): EWhile(f(c),f(e)); + case EDoWhile(c, e): EDoWhile(f(c),f(e)); + case EFor(v, it, e): EFor(v, f(it), f(e)); + case EFunction(args, e, name, t, isPublic, isStatic, isOverride, isPrivate): EFunction(args, f(e), name, t, isPublic, isStatic, isOverride, isPrivate); + case EReturn(e): EReturn(if( e != null ) f(e) else null); + case EArray(e, i): EArray(f(e),f(i)); + case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]); + case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]); + case EThrow(e): EThrow(f(e)); + case ETry(e, v, t, c): ETry(f(e), v, t, f(c)); + case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]); + case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2)); + case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) { values : [for( v in c.values ) f(v)], expr : f(c.expr) } ], def == null ? null : f(def)); + case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e)); + case ECheckType(e,t): ECheckType(f(e), t); + case EImport(c): EImport(c); + case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces); + default: expr(e); + } + return mk(edef, e); + } + + public static inline function expr( e : Expr ) : ExprDef { + #if hscriptPos + return e.e; + #else + return e; + #end + } + + public static inline function mk( e : ExprDef, p : Expr ):Expr { + #if hscriptPos + return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line }; + #else + return e; + #end + } + + /** + * DO NOT USE INLINE ON THIS FUNCTION + **/ + public static function argCount(func: haxe.Constraints.Function): Int { + // https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/hscript/Tools.hx#L206 + #if cpp + return untyped __cpp__("{0}->__ArgCount()", func); + #elseif js + return untyped js.Syntax.code("{0}.length", func); + #elseif hl + var ft = hl.Type.getDynamic(func); + if (ft.kind != HFun) + return -1; + return ft.getArgsCount(); + #else + return -1; + #end + } + + public static function isUppercase(s:String) { + if(s.length == 0) return false; + var c:Int = StringTools.fastCodeAt(s, 0); + if(StringTools.isEof(c)) return false; // Just in case :3 + return c >= 65 && c <= 90; // A-Z + } + + public static inline function isCustomAbstract(obj:Dynamic):Bool + return obj != null && obj is IHScriptAbstractBehaviour; + } \ No newline at end of file