Fixed Printer + Added more optimizations

This commit is contained in:
NeeEoo
2024-04-23 22:40:07 +02:00
parent 8c1aaf5454
commit df1c5ad97c
8 changed files with 312 additions and 29 deletions
+101 -7
View File
@@ -10,11 +10,10 @@ class Optimizer {
if(s == null)
return null;
#if hscriptPos
var e = s.e;
#else
var e = s;
#end
var e = Tools.expr(s);
// TODO: Convert EBinOp(+, a, EUnop(-, b)) to EBinOp(-, a, b) aka (a - b)
switch(e) {
// Parse all expressions and recreate the AST
case EBlock(exprs):
@@ -22,7 +21,34 @@ class Optimizer {
if(Tools.expr(v).match(EBlock([]))) return false; // Remove empty blocks
return true;
});
return mk(EBlock(exprs), s);
var newExprs = [];
for(e in exprs) {
switch(Tools.expr(e)) {
case EBlock(iex):
var declares = false;
for(ie in iex) {
declares = switch(Tools.expr(ie)) {
case EVar(_): true;// has a declaration
case EFunction(_): true;// has a declaration
default: declares;
}
if(declares) break;
}
if(!declares) {
for(ex in iex)
newExprs.push(ex);
} else {
newExprs.push(e);
}
case EReturn(_): // remove stuff that are after a return
newExprs.push(e);
break;
default:
newExprs.push(e);
}
}
return mk(EBlock(newExprs), s);
case EIf(econd, e1, e2):
var econd = optimize(econd);
@@ -41,6 +67,24 @@ class Optimizer {
}
}
return mk(EIf(econd, e1, e2), s);
case ETernary(econd, e1, e2):
var econd = optimize(econd);
var e1 = optimize(e1);
var e2 = optimize(e2);
if(isConstant(econd)) {
var econd = getConstant(econd);
if(econd == true) {
if(e1 == null)
return mk(EBlock([]), s);
return mk(EParent(e1), s);
} else {
if(e2 == null)
return mk(EBlock([]), s);
return mk(EParent(e2), s);
}
}
return mk(ETernary(econd, e1, e2), s);
case EWhile(econd, e):
var econd = optimize(econd);
var e = optimize(e);
@@ -105,7 +149,16 @@ class Optimizer {
case EParent(e):
e = optimize(e);
return mk(EParent(e), s);
//return mk(EParent(e), s);
return mk(Tools.expr(e), s);
case ECheckType(e, t):
e = optimize(e);
return mk(ECheckType(e, t), s);
case EMeta(name, args, e):
e = optimize(e);
return mk(EMeta(name, args, e), s);
case ENew(cl, args):
args = args.map((v) -> optimize(v));
@@ -117,6 +170,13 @@ class Optimizer {
});
return mk(EObject(fl), s);
case EImport(c, n):
return mk(EImport(c, n), s);
case EClass(name, fields, extend, interfaces): // Possible code not working
fields = fields.map((v) -> optimize(v));
return mk(EClass(name, fields, extend, interfaces), s);
case EFunction(args, e, name, ret, isPublic, isStatic, isOverride):
args.map((v) -> {
v.name = v.name;
@@ -132,6 +192,40 @@ class Optimizer {
v.expr = optimize(v.expr);
});
def = optimize(def);
if(isConstant(e)) {
var econd = getConstant(e);
for(c in cases) {
for(v in c.values) {
if(isConstant(v)) {
var value = getConstant(v);
if(value == econd)
return mk(Tools.expr(c.expr), s);
}
}
}
var isAllCasesConstant = true;
for(c in cases) {
for(v in c.values) {
if(!isConstant(v)) {
isAllCasesConstant = false;
break;
}
}
}
if(isAllCasesConstant) {
#if debug
//trace("Didnt find any cases that match");
#end
if(def != null)
return mk(Tools.expr(def), s);
else
return mk(EBlock([]), s);
}
}
return mk(ESwitch(e, cases, def), s);
case EArrayDecl(arr, wantedType):
+3 -3
View File
@@ -44,7 +44,7 @@ enum Token {
}
class Parser {
public static var optimize = true;
public static var optimize = #if NO_HSCRIPT_OPTIMIZE false #else true #end;
// config / variables
public var line : Int;
@@ -474,7 +474,7 @@ class Parser {
if( opPriority.get(op) < 0 )
return makeUnop(op,parseExpr());
return unexpected(tk);
case TBkOpen:
case TBkOpen: // [
var a = new Array();
tk = token();
while( tk != TBkClose && (!resumeErrors || tk != TEof) ) {
@@ -487,7 +487,7 @@ class Parser {
if( tk == TComma )
tk = token();
}
if( a.length == 1 && a[0] != null ) // What is this for???
if( a.length == 1 && a[0] != null ) // Checks if its a for comprehension
switch( expr(a[0]) ) {
case EFor(_), EForKeyValue(_), EWhile(_), EDoWhile(_):
var tmp = "__a_" + (uid++);
+49 -13
View File
@@ -113,7 +113,7 @@ class Printer {
add("??NULL??");
return;
}
switch( #if hscriptPos e.e #else e #end ) {
switch( Tools.expr(e) ) {
case EImport(c, n):
add("import " + c);
if(n != null)
@@ -127,6 +127,7 @@ class Printer {
}
add(' {\n');
tabs += "\t";
// TODO: Print fields
//for(field in fields) {
// expr(field);
//}
@@ -162,15 +163,43 @@ class Printer {
add(";\n");
}
tabs = tabs.substr(1);
add(tabs);
add("}");
}
case EField(e, f, s):
expr(e);
add((s == true ? "?." : ".") + f);
case EBinop(op, e1, e2):
expr(e1);
var shouldParen = false;
var op1 = switch(Tools.expr(e1)) {
case EBinop(op, _, _): op;
case EConst(_): "_";
case EIdent(_): "_";
default: null;
}
var op2 = switch(Tools.expr(e2)) {
case EBinop(op, _, _): op;
case EConst(_): "_";
case EIdent(_): "_";
default: null;
}
var paran = Tools.checkOpPrecedence(op, op1, op2);
if(paran == 0 || paran == 2) {
add("(");
expr(e1);
add(")");
} else {
expr(e1);
}
add(" " + op + " ");
expr(e2);
if(paran == 1 || paran == 2) {
add("(");
expr(e2);
add(")");
} else {
expr(e2);
}
case EUnop(op, pre, e):
if( pre ) {
add(op);
@@ -182,13 +211,13 @@ class Printer {
case ECall(e, args):
if( e == null )
expr(e);
else switch( #if hscriptPos e.e #else e #end ) {
case EField(_), EIdent(_), EConst(_):
expr(e);
default:
add("(");
expr(e);
add(")");
else switch( Tools.expr(e) ) {
case EField(_), EIdent(_), EConst(_):
expr(e);
default:
add("(");
expr(e);
add(")");
}
add("(");
var first = true;
@@ -290,13 +319,15 @@ class Printer {
} else {
tabs += "\t";
add("{\n");
for( f in fl ) {
for( i=>f in fl ) {
add(tabs);
add(f.name+" : ");
expr(f.e);
add(",\n");
if( i != fl.length - 1 ) add(",");
add("\n");
}
tabs = tabs.substr(1);
add(tabs);
add("}");
}
case ETernary(c,e1,e2):
@@ -308,8 +339,10 @@ class Printer {
case ESwitch(e, cases, def):
add("switch( ");
expr(e);
add(") {");
add(" ) {\n");
tabs += "\t";
for( c in cases ) {
add(tabs);
add("case ");
var first = true;
for( v in c.values ) {
@@ -321,10 +354,13 @@ class Printer {
add(";\n");
}
if( def != null ) {
add(tabs);
add("default: ");
expr(def);
add(";\n");
}
tabs = tabs.substr(1);
add(tabs);
add("}");
case EMeta(name, args, e):
add("@");
+72
View File
@@ -122,4 +122,76 @@ class Tools {
}
}
static var priorities = [
["%"],
["*", "/"],
["+", "-"],
["<<", ">>", ">>>"],
["|", "&", "^"],
["==", "!=", ">", "<", ">=", "<="],
["..."],
["&&"],
["||"],
["=","+=","-=","*=","/=","%=","<<=",">>=",">>>=","|=","&=","^=","=>","??"+"="],
["->", "??"],
["is"]
];
public static function checkOpPrecedence(mainOp:String, leftOp:String, rightOp:String):Int {
var mainOpGroup = getOpGroup(mainOp);
var leftOpGroup = getOpGroup(leftOp);
var rightOpGroup = getOpGroup(rightOp);
var leftParam = false;
var rightParam = false;
if(leftOpGroup > mainOpGroup && leftOpGroup != -1) leftParam = true;
if(rightOpGroup > mainOpGroup && rightOpGroup != -1) rightParam = true;
if(!leftParam && !rightParam) {
var mainOpIndex = getOpIndex(mainOp);
var leftOpIndex = getOpIndex(leftOp);
var rightOpIndex = getOpIndex(rightOp);
if(mainOpGroup == rightOpGroup) {
if(rightOpIndex < mainOpIndex) rightParam = true;
}
if(leftOpGroup == mainOpGroup) {
if(leftOpIndex < mainOpIndex) leftParam = true;
}
}
// Convert to index
if(!leftParam && !rightParam) return -1;
if(leftParam && rightParam) return 2;
if(leftParam) return 0;
if(rightParam) return 1;
return -1;
}
public static function getOpIndex(op:String):Int {
if(op == "_") return -1;
var i = 0;
for(p in priorities) {
for(pp in p) {
if(op == pp)
return i;
i++;
}
}
return -1;
}
public static function getOpGroup(op:String):Int {
if(op == "_") return -1;
var i = 0;
for(p in priorities) {
for(pp in p) {
if(op == pp)
return i;
}
i++;
}
return -1;
}
}
+7
View File
@@ -13,12 +13,19 @@
--define HXCPP_CHECK_POINTER
--define HXCPP_STACK_LINE
--define HXCPP_DEBUG_LINK
# -D HXCPP_M64
# -D HXCPP_ARM64
--dce no
# File Specific Defines
--define macos
--define mac
--macro keep('IntIterator')
# --macro hscript.macros.UsingHandler.init()
# --macro hscript.macros.ClassExtendMacro.init()
# Copying the assets from source code to bin folder
--cmd rm -rf bin/cpp/assets
--cmd cp -r assets bin/cpp/assets
+1
View File
@@ -38,6 +38,7 @@ class Main {
runTest("SwitchStatement", new SwitchCase());
// TODO: UnicodeCase.hx?
// TODO: UnicodeStringCase.hx?
runTest("Final", new FinalCase());
Util.printTestResults();
#end
}
+32 -6
View File
@@ -6,20 +6,46 @@ class TestBenchmark extends Benchmark {
super("Test", 10000);
}
var hscript = "var a:Array<Float> = []; for (i in 0...1000) a.push(i * 2 + 1 / 6); if(true == true) a.push(1);";
//var hscript = "var a:Array<Float> = []; for (i in 0...1000) a.push(i * 2 + 1 / 6); if(true == true) a.push(1);";
var hscript = "
var a:Array<Float> = [];
for(i in 0...1000)
switch(5) {
case true: a.push(1);
default: a.push(2);
}
if(('a' == 'a') ? true : false) a.push(1);
if(true == true)
a.push(1);";
function test() {
return 5;
}
var aaa = null;
public override function reset() {
super.reset();
a = [];
if(interp != null)
interp.variables.remove("a");
aaa = {
test: test
};
if(expr == null)
cacheExpr(hscript);
interp.variables.remove("a");
//interp.variables.set("aaa", aaa);
interp.variables.set("test", test);
}
public var a:Array<Float> = [];
public override function haxeBenchmark() {
for (i in 0...1000) a.push(i * 2 + 1 / 6);
var a:Array<Float> = [];
//for (i in 0...1000) a.push(i * 2 + 1 / 6);
//for (i in 0...1000) a.push(i / 2 + 3 / 6);
for(i in 0...1000)
switch(5) {
case 0: a.push(1);
default: a.push(2);
}
if(('a' == 'a') ? true : false) a.push(1);
if(true == true) a.push(1);
}
+47
View File
@@ -0,0 +1,47 @@
package tests;
class FinalCase extends TestCase {
override function setup() {
super.setup();
}
override function getNewInterp() {
var interp = super.getNewInterp();
interp.variables.set("Std", Std);
interp.variables.set("String", String);
interp.variables.set("Bool", Bool);
interp.variables.set("Float", Float);
interp.variables.set("Array", Array);
interp.variables.set("Int", Int);
interp.variables.set("IntIterator", IntIterator);
return interp;
}
override function run() {
headerCode = "var i = 5; var x = 10;";
var i = 5; var x = 10;
hscript.Parser.optimize = false;
assertDisplay("(i - x) * 30 + 90", ((i-x) * 30) + 90);
assertDisplay("i - x * 30 + 90", i-x * 30 + 90);
// Test operator precedence
assertDisplay("i / x * 30 + 90", i / x * 30 + 90);
assertDisplay("i / (x * 30) + 90", i / (x * 30) + 90);
assertDisplay("x * 30 / i + 90", x * 30 / i + 90);
//assertEq("(x * 30) / i + 90", x * 30 / i + 90);
}
function assertDisplay(script:String, expected:Dynamic) {
var _script = script;
script = '"${script}";\n' + script;
assertEq(script, expected, _script);
}
override function teardown() {
super.teardown();
}
}