From 29ac56940b3c92a90d07f86d64865e32999d9238 Mon Sep 17 00:00:00 2001 From: Slava Buynov Date: Mon, 13 Nov 2017 20:54:05 +0300 Subject: [PATCH 001/156] Copied test\issues\Issue261.as to test\issues\Issue261_1.as --- test/issues/Issue261_1.as | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 test/issues/Issue261_1.as diff --git a/test/issues/Issue261_1.as b/test/issues/Issue261_1.as new file mode 100644 index 0000000..be46fe5 --- /dev/null +++ b/test/issues/Issue261_1.as @@ -0,0 +1,8 @@ +package { + public class Issue261 { + public function Issue261() { + var a:Array = [{}]; + a[a.length - 1]["some"] = 10; + } + } +} \ No newline at end of file From 0c216adc187f41aa5ccbd5a52c316e8b5378f1e9 Mon Sep 17 00:00:00 2001 From: Slava Buynov Date: Mon, 13 Nov 2017 20:54:55 +0300 Subject: [PATCH 002/156] Copied test\issues\Issue261.hx to test\issues\Issue261_1.hx --- test/issues/Issue261_1.hx | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 test/issues/Issue261_1.hx diff --git a/test/issues/Issue261_1.hx b/test/issues/Issue261_1.hx new file mode 100644 index 0000000..48d0fcb --- /dev/null +++ b/test/issues/Issue261_1.hx @@ -0,0 +1,9 @@ + +class Issue261 +{ + public function new() + { + var a : Array = [{ }]; + Reflect.setField(a[a.length - 1], "some", 10); + } +} From 4bb96049e9276ac118b8e3851e53be8e2200ccca Mon Sep 17 00:00:00 2001 From: Slava Buynov Date: Mon, 13 Nov 2017 21:31:44 +0300 Subject: [PATCH 003/156] WIP --- src/as3hx/Writer.hx | 337 ++++++++++++++++++----------------- test/issues/Issue261_1.as | 9 +- test/issues/Issue261_1.hx | 10 +- test/unit/as3hx/AS3HXTest.hx | 9 +- 4 files changed, 190 insertions(+), 175 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 14405dd..91e7206 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -42,7 +42,7 @@ class Writer var genTypes : Array; //typedef generated while parsing var imported : Array; // store written imports to prevent duplicated var pack : Array; // stores the haxe file package - + public function new(config:Config) { this.lvl = 0; @@ -79,7 +79,7 @@ class Writer "SecurityError", "SyntaxError", "TypeError", "URIError", "VerifyError" ]; - + for(c in topLevelErrorClasses) { this.typeImportMap.set(c, "flash.errors." + c); } @@ -139,9 +139,9 @@ class Writer f(expr); return result; } - + inline function getColon():String return cfg.spacesOnTypeColon ? " : " : ":"; - + function writeComments(comments : Array) { for(c in comments) { switch(c) { @@ -170,10 +170,10 @@ class Writer if (pack.length > 0) { writeLine("package " + properCaseA(pack,false).join(".") + ";"); - writeNL(); + writeNL(); } } - + function writeImports(imports : Array>) { if (imports.length > 0) @@ -198,7 +198,7 @@ class Writer typeImportMap.set(i[i.length - 1], null); } } - + function writeAdditionalImports(defPackage : Array, allTypes : Array, definedTypes : Array) { // We don't want to import any type that is defined within @@ -207,7 +207,7 @@ class Writer for(d in definedTypes) { typeImportMap.set(d, null); } - + // Now convert each seen type enum into the corresponding // type import string. var uniqueTypes = new Map(); @@ -221,7 +221,7 @@ class Writer } } } - + // Now look up each type import string in the type import // map. var addnImports = new Array(); @@ -250,7 +250,7 @@ class Writer for(d in defs) writeDefinition(d); } - + function writeDefinition(def : Definition) { switch(def) @@ -266,7 +266,7 @@ class Writer return; var isFirstCondComp = true; - + for(d in data) { switch(d) { case EMeta(_): @@ -283,7 +283,7 @@ class Writer } else { write(" && "); - } + } write(v); case EImport(i): writeImport(i); @@ -299,7 +299,7 @@ class Writer var buf = new StringBuf(); this.isInterface = c.isInterface; - + if (!c.isInterface && isFinal(c.kwds)) { buf.add("@:final "); } @@ -307,7 +307,7 @@ class Writer buf.add(c.isInterface ? "interface " : "class "); buf.add(properCase(c.name,true)); - + var parents = []; if (null != c.extend) { parents.push((isInterface ? "implements " : "extends ") + tstring(c.extend)); @@ -319,24 +319,24 @@ class Writer buf.add(openb()); write(buf.toString()); lvl++; - + // process properties writeProperties(c); - + // process fields writeFields(c); // a list of TId(ClassName),TSemicolon pairs that is used to force // compiling/linking classes writeInits(c); - + lvl--; write(closeb()); //close conditional compilation block if needed writeECondCompEnd(getCondComp(c.meta)); } - + function writeProperties(c : ClassDef) { var p = []; @@ -380,32 +380,32 @@ class Writer property.getMeta = field.meta; if (isPublic(field.kwds)) { - property.get = getterDirective; + property.get = getterDirective; property.pub = true; } else { - property.get = getterDirective; + property.get = getterDirective; } } else if (isSetter(field.kwds)) { - var setterDirective : String = "set"; // haxe 3 + var setterDirective : String = "set"; // haxe 3 // haxe 2: cfg.makeSetterName(field.name); var property = getOrCreateProperty(field.name, f.args[0].t, isStatic(field.kwds)); property.setMeta = field.meta; if (isPublic(field.kwds)) { - property.set = setterDirective; + property.set = setterDirective; property.pub = true; } else { - property.set = setterDirective; + property.set = setterDirective; } } default: continue; } } - + if (p.length > 0) { writeNL(); } @@ -423,14 +423,14 @@ class Writer if(cfg.getterSetterStyle == "combined") write("#if !flash "); - if (property.pub) { + if (property.pub) { write("public "); - } + } else { if (! isInterface) { write("private "); } - } + } if (property.sta) write("static "); write("var " + property.name + "(" + property.get + ", " + property.set + ")"); @@ -453,14 +453,14 @@ class Writer writeNL(); } } - + function writeFields(c : ClassDef) { for (field in c.fields) writeField(field, c); if(c.isInterface) return; - + if(!Lambda.exists(c.fields, function(field:ClassField) { switch(field.kind) { @@ -492,7 +492,7 @@ class Writer }, c.extend != null); } } - + function writeField(field : ClassField, c : ClassDef) { var isGet : Bool = isGetter(field.kwds); @@ -505,7 +505,7 @@ class Writer return; writeMetaData(field.meta); - + var start = function(name:String, isFlashNative:Bool=false, isConstructor=false) { if((isGet || isSet) && cfg.getterSetterStyle == "combined") { writeNL(isFlashNative ? "#if flash" : "#else"); @@ -532,8 +532,8 @@ class Writer writeAllow(); if(isOverride(field.kwds)) write((isFlashNative && (isGet || isSet)) ? "" : "override "); - - //coner-case, constructor of internal AS3 class is set to private in + + //coner-case, constructor of internal AS3 class is set to private in //Haxe with a meta allowing access from same package if(isConstructor && isInternal(c.kwds)) { write("private "); @@ -550,7 +550,7 @@ class Writer write("private "); } //check wheter the field is an AS3 constants, which can be inlined in Haxe - //the field must be either a static constant or a private constant. + //the field must be either a static constant or a private constant. //If it is a non-static public constant it can't be inlined as Haxe can only inline //static field. Converting non-static public field to static will likely cause compilation //errors, whereas it won't for private field as they will be accessed in the same way @@ -638,11 +638,11 @@ class Writer null; } - //if this field is not wrapped in conditional compilation, + //if this field is not wrapped in conditional compilation, //do nothing if (field.condVars.length == 0) return; - + //here we will find wether this field is the last field //of some conditional compilation and write the conditional //compilation ending statement if it is @@ -666,12 +666,12 @@ class Writer else if (field == f) { foundSelf = true; } - } + } //close conditional compilation block writeECondCompEnd(condVars); } - + /** * Return a new array containing all the conditional * compilation constants from the provided array @@ -679,7 +679,7 @@ class Writer function getCondComp(exprs : Array) : Array { var condComps = []; - for (expr in exprs) + for (expr in exprs) { switch (expr) { case ECondComp(v,e,e2): @@ -729,7 +729,7 @@ class Writer } /** - * Write closing statement ("#end") for conditional + * Write closing statement ("#end") for conditional * conpilation if any */ function writeECondCompEnd(condComps : Array) : Void @@ -744,7 +744,7 @@ class Writer write(condComps[i]); } } - + function writeArgs(args : Array<{ name : String, t : Null, val : Null, exprs : Array }>, ?varArgs:String) { if(varArgs != null) { @@ -763,9 +763,9 @@ class Writer //store first argument var fst = null; - //set to true at the end of the argument, + //set to true at the end of the argument, //trigger writing a comma for next expression - var pendingComma = false; + var pendingComma = false; for (arg in args) //for each method argument { @@ -782,7 +782,7 @@ class Writer pendingComma = false; write(","); } - + //if arg is not first element on the line, add space //before it, unless first argument which never has space if (lineIsDirty && !isFirst) { @@ -797,7 +797,7 @@ class Writer if(arg.val != null) { write(" = "); switch(tstring(t)) { - case "Int" if(needCastToInt(arg.val)): + case "Int" if(needCastToInt(arg.val)): switch(arg.val) { case EConst(_ => CFloat(f)): var index = f.indexOf('.'); @@ -839,7 +839,7 @@ class Writer lvl -= 2; return fst; } - + function writeConstructor(f:Function, isSubClass:Bool) { //add super if missing, as it is mandatory in Haxe for subclasses if (isSubClass && !constructorHasSuper(f.expr)) { @@ -855,7 +855,7 @@ class Writer var es = formatBlockBody(f.expr); writeExpr(EBlock(es)); } - + /** * Wether constructor method has a super() call */ @@ -864,7 +864,7 @@ class Writer if (expr == null) return false; return switch(expr) { case ECall(EIdent("super"), _): true; - case EBlock(exprs): + case EBlock(exprs): for (expr in exprs) { if (constructorHasSuper(expr)) { return true; @@ -887,7 +887,7 @@ class Writer } return result; } - + function writeFunction(f : Function, isGetter:Bool, isSetter:Bool, isNative:Bool, ?name : Null, ?ret : FunctionRet) { write("function"); if(name != null) @@ -937,7 +937,7 @@ class Writer writeStartStatement(); writeExpr(EBlock(es)); } - + /** * Write the returned typed of a function and all * comments and newline until opening bracket @@ -967,7 +967,7 @@ class Writer write(" "); writeExpr(e); } - + function writeEArray(e:Expr, index:Expr) { //write("/* EArray ("+Std.string(e)+","+Std.string(index)+") " + Std.string(getExprType(e, true)) + " */ "); var old = inArrayAccess; @@ -1029,24 +1029,24 @@ class Writer writeExpr(e); inArrayAccess = old; write("["); - writeExpr(index); + writeExpr(index); write("]"); } } } - + function writeLoop(incrs:Array, f:Void->Void) { var old = loopIncrements; loopIncrements = incrs.slice(0); f(); loopIncrements = old; } - + static function ucfirst(s : String) : String { return s.substr(0, 1).toUpperCase() + s.substr(1); } - + function writeVarType(?t : Null, ?alt : String, isNativeGetSet:Bool=false) { if (t == null) @@ -1076,7 +1076,7 @@ class Writer writeIndent(); writeNL("}"); } - + function getConst(c : Const) : String { return switch(c) @@ -1099,7 +1099,7 @@ class Writer case "descendants", "nodes": "FastXMLList"; case "node": "FastXML"; case "length": "Int"; - case _: "FastXMLList"; + case _: "FastXMLList"; } case "FastXMLList": switch(f) { @@ -1129,7 +1129,7 @@ class Writer } return null; } - + inline function getRegexpType():String return cfg.useCompat ? "as3hx.Compat.Regex" : "flash.utils.RegExp"; /** @@ -1270,7 +1270,7 @@ class Writer f = function(e, els) { switch(e) { case EBreak(lbl): - if(lbl == null) + if(lbl == null) def.el.pop(); // remove break case EBlock(exprs): switch (exprs[exprs.length -1]) { @@ -1293,7 +1293,7 @@ class Writer // default is not in the end, so don't catch fall-through newCases = loopCases(cases.copy(), null, testVar, newCases); } - + if(writeTestVar) { write("var "); writeExpr(testVar); @@ -1312,7 +1312,7 @@ class Writer write("switch ("); writeExpr(testVar); write(")" + openb()); - + lvl++; for(c in newCases) { @@ -1441,7 +1441,7 @@ class Writer for (ex in elist) { writeFinish(writeExpr(ex)); } - case ENL(e): + case ENL(e): writeECondComp(e); case ECommented(s,b,t,e): writeECondComp(e); default: @@ -1473,7 +1473,7 @@ class Writer } return rv; } - + function writeSwitchDefault(def:SwitchDefault) { if(def.vals != null && def.vals.length > 0) { writeNL(); @@ -1528,7 +1528,7 @@ class Writer } return result; } - + function writeEField(fullExpr:Expr, e:Expr, f:String):BlockEnd { var n = checkE4XDescendants(fullExpr); if(n != null) return writeExpr(n); @@ -1599,7 +1599,7 @@ class Writer inArrayAccess = old; return Semi; } - + inline function writeEVars(vars:Array<{name:String, t:Null, val:Null}>):BlockEnd { var result = Semi; for(i in 0...vars.length) { @@ -1656,7 +1656,7 @@ class Writer } return result; } - + inline function writeEParent(e:Expr) { switch(e) { case EParent(e): writeExpr(e); @@ -1666,7 +1666,7 @@ class Writer write(")"); } } - + function writeECall(fullExpr:Expr, expr:Expr, params:Array):BlockEnd { switch(expr) { case EField(expr, f): @@ -1707,11 +1707,11 @@ class Writer default: e; } for(i in 0...params.length) params[i] = f(params[i]); - + //func call use 2 levels of indentation if //spread on multiple lines lvl += 2; - + var handled = false; if(cfg.guessCasts && params.length == 1) { switch(expr) { @@ -1781,7 +1781,7 @@ class Writer default: true; } } - + //check all remaining parameters var i = index; while(i < params.length - 1) { @@ -1791,7 +1791,7 @@ class Writer } return true; } - + writeExpr(expr); write("("); var enl = false; @@ -1820,7 +1820,7 @@ class Writer lvl -= 2; return Semi; } - + function writeEIf(cond:Expr, e1:Expr, ?e2:Expr):BlockEnd { var result = Semi; write("if ("); @@ -1836,7 +1836,7 @@ class Writer writeExpr(rb); } else writeExpr(cond); lvl--; - + //check if if expr is one line //with no block bracket if (isOneLiner(e1)) { @@ -1862,7 +1862,7 @@ class Writer //corner case : comment located //before the "else" keyword in the //source file. - //As to be called recursively, in + //As to be called recursively, in //case of multiple one-line comment //before the "else" var f:Expr->Expr = null; @@ -1920,7 +1920,7 @@ class Writer } return result; } - + inline function writeETernarny(cond:Expr, e1:Expr, ?e2:Expr) { write("("); var rb = rebuildIfExpr(cond); @@ -1931,7 +1931,7 @@ class Writer write(getColon()); writeExpr(e2); } - + inline function writeEWhile(cond:Expr, e:Expr, doWhile:Bool):BlockEnd { var result:BlockEnd; if (doWhile) { @@ -1950,7 +1950,7 @@ class Writer } return result; } - + inline function writeEFor(inits:Array, conds:Array, incrs:Array, e:Expr):BlockEnd { //Sys.println('inits: ${inits}; conds: ${conds}; incrs: ${incrs}'); openContext(); @@ -2046,7 +2046,7 @@ class Writer closeContext(); return None; } - + inline function writeEForEach(ev:Expr, e:Expr, block:Expr):BlockEnd { openContext(); var varName = null; @@ -2096,7 +2096,7 @@ class Writer closeContext(); return result; } - + inline function writeEForIn(ev:Expr, e:Expr, block:Expr):BlockEnd { openContext(); var etype = getExprType(e); @@ -2137,7 +2137,7 @@ class Writer closeContext(); return result; } - + function writeEBinop(op:String, e1:Expr, e2:Expr, newLineAfterOp:Bool):BlockEnd { if(op == "as") { switch(e2) { @@ -2201,21 +2201,26 @@ class Writer } else { // op e1 e2 var eBinop = rebuildBinopExpr(op, e1, e2); if (eBinop != null) return writeExpr(eBinop); - + var oldInLVA = inLvalAssign; - if(op.indexOf("=") != -1) rvalue = e2; + switch(e1) { + case EArray(_, _): if(op.indexOf("=") != -1) rvalue = e2; + case ECall(_, _): rvalue = e1; + case _: + } + if(op.indexOf("=") != -1 || e1.match(EArrayDecl(_))) rvalue = e2; if(op == "=") inLvalAssign = true; - + switch(e1) { case EIdent(s): writeModifiedIdent(s); default: writeExpr(e1); } - + //for right part of indenting, add 2 extra //indenting level if spead on multiple lines if (op == "=") lvl += 2; - + inLvalAssign = oldInLVA; if(rvalue != null) { //check wether newline was found just before @@ -2226,27 +2231,27 @@ class Writer } else { write(" " + op); } - + //minor formatting fix, if right expression starts - //with a newline or comment, no need for extra + //with a newline or comment, no need for extra switch(e2) { case ECommented(_,_,_,_): case ENL(_): default: write(" "); } - + switch(e2) { case EIdent(s): writeModifiedIdent(s); default: writeExpr(e2); } } - + if (op == "=") lvl -= 2; } return Semi; } - + inline function writeEUnop(op:String, prefix:Bool, e:Expr):BlockEnd { var result = Semi; var type = getExprType(e); @@ -2262,7 +2267,7 @@ class Writer } return result; } - + function writeToString(e:Expr) { var type = getExprType(e); if (type != "String") { @@ -2270,9 +2275,9 @@ class Writer } writeExpr(e); } - + inline function getToStringExpr(e:Expr):Expr return ECall(EField(EIdent("Std"), "string"), [e]); - + function writeCastToInt(e:Expr) { var type = getExprType(e); if(type != "Int") { @@ -2280,7 +2285,7 @@ class Writer } writeExpr(e); } - + inline function needCastToInt(e:Expr):Bool { var isCompatParseInt:Expr->Bool = function(e) return e.match(ECall(EField(EIdent("as3hx.Compat"), "parseInt"), _)); return switch(e) { @@ -2291,14 +2296,14 @@ class Writer case _: false; } } - + function getCastToIntExpr(e:Expr):Expr { if(cfg.useCompat) { return getCompatCallExpr("parseInt", [e]); } return ECall(EField(EIdent("Std"), "parseInt"), [getToStringExpr(e)]); } - + function writeCastToFloat(e:Expr) { var type = getExprType(e); if (type != "Float" && type != "Int") { @@ -2306,22 +2311,22 @@ class Writer } writeExpr(e); } - + function getCastToFloatExpr(e:Expr):Expr { if (cfg.useCompat) { return getCompatCallExpr("parseFloat", [e]); } return ECall(EField(EIdent("Std"), "parseFloat"), [getToStringExpr(e)]); } - + inline function getCompatCallExpr(methodName:String, params:Array):Expr { return ECall(getCompatFieldExpr(methodName), params); } - + inline function getCompatFieldExpr(fieldName:String):Expr { return EField(EIdent("as3hx.Compat"), fieldName); } - + // translate FlexUnit to munit meta data, if present. function writeMunitMetadata(m:Metadata) : Bool { var rv : Bool = false; @@ -2427,8 +2432,8 @@ class Writer first = false; } if (arg.name != null) { - write(arg.name); - write("="); + write(arg.name); + write("="); } writeExpr(arg.val); } @@ -2461,9 +2466,9 @@ class Writer context.set(n, "FastXML"); // current context var old = inArrayAccess; inArrayAccess = true; // ensure 'nodes' vs. 'node' - writeExpr(e1); + writeExpr(e1); inArrayAccess = old; - + inE4XFilter = true; write(", function(x:FastXML) {\n"); lvl++; @@ -2501,7 +2506,7 @@ class Writer if(e == null) result = Ret; return result; } - + inline function writeENew(t : T, params : Array):Void { var writeParams = function() { for(i in 0...params.length) { @@ -2518,7 +2523,7 @@ class Writer write(", ["); writeParams(); write("])"); - } + } //in AS3, if Date constructed without argument, uses current time else if (tstring(t) == "Date" && params.empty()) { write("Date.now()"); //use Haxe constructor for current time @@ -2539,7 +2544,7 @@ class Writer if(!isObject) write(")"); } } - + inline function writeETry(e:Expr, catches:Array<{name:String, t:Null, e:Expr}>):BlockEnd { var result = Semi; write("try"); @@ -2556,7 +2561,7 @@ class Writer } return result; } - + inline function writeEDelete(e:Expr) { switch(e) { case EArray(a, i): @@ -2588,14 +2593,14 @@ class Writer writeIndent('delete ${getIdentString(a)}[${getIdentString(i)}]'); } } - default: + default: addWarning("EDelete"); writeNL("This is an intentional compilation error. See the README for handling the delete keyword"); writeIndent("delete "); writeExpr(e); } } - + /** * Rebuilds any E4X expression to check for instances where the string value * is compared to a numerical constant, and change all EIdent instances to @@ -2745,7 +2750,7 @@ class Writer return EParent(r2); case ECall(e2, params): //These would require a full typer case EField(e2, f): null; - case ENL(e): + case ENL(e): var expr = rebuildIfExpr(e); if (expr == null) return null; return ENL(expr); @@ -2762,13 +2767,13 @@ class Writer case EIdent(v): v; default: null; } - + /** * Reconstruct a call expression before writing it if necessary. Used * for example to replace some ActionScript built-in method be Haxe ones. - * + * * This is TiVo specific code - * + * * @return the new expression, or null if no change were needed */ function rebuildCallExpr(fullExpr : Expr, expr : Expr, params : Array) : Expr { @@ -2823,7 +2828,7 @@ class Writer case 1: params.push(EField(e, "length")); result = ECall(EField(e, f), params); - default: + default: if(cfg.useCompat) { var p = [e].concat(params.slice(0, 2)); p.push(EArrayDecl(params.slice(2, params.length))); @@ -2944,8 +2949,8 @@ class Writer //helper to convert an AS3 test case to an Haxe one var getUnitTestExpr = function(rebuiltExpr, params, commentFirstParam) { var result = ECall(rebuiltExpr, params); - - //in some cases, the first param is a description of the test, + + //in some cases, the first param is a description of the test, //which should be converted to a comment if (commentFirstParam) { var comment = getCommentedParam(params.shift()); @@ -2953,7 +2958,7 @@ class Writer } return result; } - + switch (ident) { //replace "hasAnyProperty(myVar)" by "myVar.keys().hasNext()" // "myVar" is assumed to be an iterable @@ -3059,7 +3064,7 @@ class Writer return rvalue != null ? EBinop(op, lvalue, rvalue, false) : null; } else switch(rvalue) { case EBinop(rop, _, _, nl) if(isBooleanOp(rop)): return EBinop(op, lvalue, ETernary(rvalue, EConst(CInt("1")), EConst(CInt("0"))), nl); - case _: + case _: } } switch(rvalue) { @@ -3074,9 +3079,9 @@ class Writer } return null; } - + /** - * For an if statement, return the + * For an if statement, return the * the appropriate block end, based on the * type of the first child expression */ @@ -3086,20 +3091,20 @@ class Writer case EBlock(_): None; case EIf(_,_,_): Semi; case EReturn(_): Semi; - - //comments expression are ignored for this purpose, + + //comments expression are ignored for this purpose, //and instead the first expression //following the comment is used case ECommented(s,b,t,e): getEIfBlockEnd(e); //like comment, wrapped expression used instead - case ENL(e): getEIfBlockEnd(e); + case ENL(e): getEIfBlockEnd(e); default: Semi; } } /** * Return wether the expression contained in an - * "if" statement is a one liner with no block bracket + * "if" statement is a one liner with no block bracket */ function isOneLiner(e : Expr) : Bool { return switch (e) { @@ -3151,50 +3156,50 @@ class Writer var type = getExprType(e); return isArrayType(type); } - + static inline function isArrayType(s:String):Bool { return s != null && StringTools.startsWith(s, "Array<"); } - + static inline function isDynamicType(s:String):Bool return s == "Dynamic"; - + static inline function isMapType(s:String):Bool { return s != null && (s.startsWith("Map") || s.startsWith("haxe.ds.ObjectMap")); } - + inline function isFunctionExpr(e:Expr):Bool return getExprType(e) == "Function"; - + inline function isIntExpr(e:Expr):Bool { var type = getExprType(e); return isIntType(type); } - + inline function isIntType(s:String):Bool return s == "Int"; - + inline function isNumericOp(s:String):Bool return switch(s) { case "/" | "-" | "+" | "*" | "%" | "--" | "++": true; default: false; } - + inline function isBitwiceOp(s:String):Bool return switch(s) { case "<<" | ">>" | ">>>" | "^" | "|" | "&" | "~": true; default: false; } - + inline function isBooleanOp(s:String):Bool return switch(s) { case "||" | "&&" | "!=" | "!==" | "==" | "===": true; case _: false; } - + inline function isBitwiseAndAssignmetnOp(s:String):Bool return switch(s) { case "&=" | "|=" | "^=": true; default: false; } - + function addWarning(type:String, isError = false) { warnings.set(type, isError); } - + static function quote(s : String) : String { return '"' + StringTools.replace(s, '"', '\\"') + '"'; @@ -3204,17 +3209,17 @@ class Writer { return "'" + StringTools.replace(s, "\\", "\\\\") + "'"; } - + function isOverride(kwds : Array) : Bool { return Lambda.has(kwds, "override"); } - + function isStatic(kwds : Array) : Bool { return Lambda.has(kwds, "static"); } - + function isPublic(kwds : Array) : Bool { return Lambda.has(kwds, "public"); @@ -3229,12 +3234,12 @@ class Writer { return Lambda.has(kwds, "internal"); } - + function isFinal(kwds : Array) : Bool { return Lambda.has(kwds, "final"); } - + function isProtected(kwds : Array) : Bool { return Lambda.has(kwds, "protected"); @@ -3244,7 +3249,7 @@ class Writer { return Lambda.has(kwds, "get"); } - + function isSetter(kwds : Array) : Bool { return Lambda.has(kwds, "set"); @@ -3254,7 +3259,7 @@ class Writer { return Lambda.has(kwds, "const"); } - + function istring(t : T, fixCase:Bool = true) : String { if(t == null) return null; return switch(t) { @@ -3268,7 +3273,7 @@ class Writer default: null; } } - + function tstring(t : T, isNativeGetSet:Bool = false, fixCase:Bool = true) : String { if(t == null) return null; return switch(t) { @@ -3296,7 +3301,7 @@ class Writer case TFunction(p): p.map(function(it) return tstring(it)).join("->"); } } - + /** * Write an As3 package level function. As Haxe * does not have this, wrap it in a class definition @@ -3345,10 +3350,10 @@ class Writer inits : [] }; } - + function writeNamespaceDef(n : NamespaceDef) { - + } function loopCases(cases : Array, def: Null>, testVar:Expr, out:Array):Array { @@ -3370,7 +3375,7 @@ class Writer f = function(e, els) { switch(e) { case EBreak(lbl): - if(lbl == null) + if(lbl == null) els.pop(); // remove break falls = false; case EReturn(ex): @@ -3397,12 +3402,12 @@ class Writer el.push(EBreak(null)); nextCase.el.unshift(ESwitch(EParent(testVar), [{val:c.val, el: el, meta:[]}], null)); } - } else { + } else { outCase.vals.push(c .val); for(e in c.el) outCase.el.push(e); for(m in c.meta) - outCase.meta.push(m); + outCase.meta.push(m); if(falls) { // last case before default, add default code since this case has no break if(def != null) @@ -3410,7 +3415,7 @@ class Writer outCase.el.push(e); } out.unshift(outCase); - } + } out = loopCases(cases, null, testVar, out); return out; } @@ -3422,11 +3427,11 @@ class Writer else return " {"; } - + inline function closeb() : String { return cfg.newlineChars + indent() + "}"; } - + function write(s : String) { //set line as dirty if string contains something other @@ -3436,7 +3441,7 @@ class Writer o.writeString(s); } - + /** write Haxe "allow" metadata using current package */ function writeAllow() { write("@:allow("+properCaseA(this.pack,false).join(".")+")"); @@ -3445,7 +3450,7 @@ class Writer } /** - * Writing for block and line comment. If + * Writing for block and line comment. If * comment written on dirty line (not first text on line), * add extra whitespace before and after comment */ @@ -3461,14 +3466,14 @@ class Writer { write(indent() + s); } - + function writeLine(s = "") { lineIsDirty = false; write(indent() + s + cfg.newlineChars); } - + function writeNL(s = "") { lineIsDirty = false; //reset line dirtyness @@ -3476,7 +3481,7 @@ class Writer write(s); write(cfg.newlineChars); } - + inline function writeStartStatement() { if(cfg.bracesOnNewline) { writeNL(); @@ -3485,7 +3490,7 @@ class Writer write(" "); } } - + inline function writeCloseStatement() { if(cfg.bracesOnNewline) { write(")"); @@ -3540,7 +3545,7 @@ class Writer o = old; return rv; } - + function indent() : String { var b = []; @@ -3548,7 +3553,7 @@ class Writer b.push(cfg.indentChars); return b.join(""); } - + public function process(program : Program, writer : Output):Map { warnings = new Map(); @@ -3571,7 +3576,7 @@ class Writer } default: } - + o = writer; genTypes = program.genTypes; pack = program.pack; @@ -3640,7 +3645,7 @@ class Writer var p = path[i]; result[i] = p.charAt(0).toLowerCase() + p.substr(1); } - } + } if(hasClassName) { var f = result[result.length - 1]; var o = ""; @@ -3657,9 +3662,9 @@ class Writer } public static function removeUnderscores(id : String):String { - return id.split("_").map( + return id.split("_").map( function (v:String) return v.length > 0 ? v.charAt(0).toUpperCase() + v.substr(1) : "" ).array().join(""); } - + } diff --git a/test/issues/Issue261_1.as b/test/issues/Issue261_1.as index be46fe5..735e1ac 100644 --- a/test/issues/Issue261_1.as +++ b/test/issues/Issue261_1.as @@ -1,8 +1,9 @@ package { - public class Issue261 { - public function Issue261() { - var a:Array = [{}]; - a[a.length - 1]["some"] = 10; + public class Issue261_1 { + public function randomGen(param1:int) : int + { + var _loc2_:int = Math.floor(Math.random() * param1); + return _loc2_; } } } \ No newline at end of file diff --git a/test/issues/Issue261_1.hx b/test/issues/Issue261_1.hx index 48d0fcb..353451b 100644 --- a/test/issues/Issue261_1.hx +++ b/test/issues/Issue261_1.hx @@ -1,9 +1,13 @@ -class Issue261 +class Issue2611 { + public function randomGen(param1 : Int) : Int + { + var _loc2_ : Int = Math.floor(Math.random() * param1); + return _loc2_; + } + public function new() { - var a : Array = [{ }]; - Reflect.setField(a[a.length - 1], "some", 10); } } diff --git a/test/unit/as3hx/AS3HXTest.hx b/test/unit/as3hx/AS3HXTest.hx index 6834155..5557025 100644 --- a/test/unit/as3hx/AS3HXTest.hx +++ b/test/unit/as3hx/AS3HXTest.hx @@ -481,8 +481,13 @@ class AS3HXTest { generate("Issue257.as", "Issue257.hx"); } - @Test("Issue 261") - public function issue261() { + @Test("Issue 261. Case 1") + public function issue261_1() { + generate("Issue261.as", "Issue261.hx"); + } + + @Test("Issue 261. Case 2") + public function issue261_2() { generate("Issue261.as", "Issue261.hx"); } From 01dc97b80661aba593546275093d7da05fb4d545 Mon Sep 17 00:00:00 2001 From: Slava Buynov Date: Mon, 13 Nov 2017 21:33:25 +0300 Subject: [PATCH 004/156] WIP --- test/unit/as3hx/AS3HXTest.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/as3hx/AS3HXTest.hx b/test/unit/as3hx/AS3HXTest.hx index 5557025..1a56f06 100644 --- a/test/unit/as3hx/AS3HXTest.hx +++ b/test/unit/as3hx/AS3HXTest.hx @@ -488,7 +488,7 @@ class AS3HXTest { @Test("Issue 261. Case 2") public function issue261_2() { - generate("Issue261.as", "Issue261.hx"); + generate("Issue261_1.as", "Issue261_1.hx"); } @Test("v += condition ? 1 : 0") From 48b219adb46ea94bb1422d8d92c0ea95b9a56296 Mon Sep 17 00:00:00 2001 From: Slava Buynov Date: Mon, 13 Nov 2017 21:34:02 +0300 Subject: [PATCH 005/156] Copied test\issues\Issue261_1.as to test\issues\Issue261_2.as --- test/issues/Issue261_2.as | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 test/issues/Issue261_2.as diff --git a/test/issues/Issue261_2.as b/test/issues/Issue261_2.as new file mode 100644 index 0000000..735e1ac --- /dev/null +++ b/test/issues/Issue261_2.as @@ -0,0 +1,9 @@ +package { + public class Issue261_1 { + public function randomGen(param1:int) : int + { + var _loc2_:int = Math.floor(Math.random() * param1); + return _loc2_; + } + } +} \ No newline at end of file From 6a5f51451dacb74c4a8664ea57c52f7b9ee1fe4b Mon Sep 17 00:00:00 2001 From: Slava Buynov Date: Mon, 13 Nov 2017 21:35:43 +0300 Subject: [PATCH 006/156] Copied test\issues\Issue261_1.hx to test\issues\Issue261_2.hx --- test/issues/Issue261_2.hx | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 test/issues/Issue261_2.hx diff --git a/test/issues/Issue261_2.hx b/test/issues/Issue261_2.hx new file mode 100644 index 0000000..353451b --- /dev/null +++ b/test/issues/Issue261_2.hx @@ -0,0 +1,13 @@ + +class Issue2611 +{ + public function randomGen(param1 : Int) : Int + { + var _loc2_ : Int = Math.floor(Math.random() * param1); + return _loc2_; + } + + public function new() + { + } +} From bd01b7fecc723be6c940ca9bd761bf04d24db189 Mon Sep 17 00:00:00 2001 From: Slava Buynov Date: Mon, 13 Nov 2017 21:46:20 +0300 Subject: [PATCH 007/156] Fixes #261 --- test/issues/Issue261_1.as | 2 +- test/issues/Issue261_2.as | 7 +++---- test/issues/Issue261_2.hx | 7 +++---- test/unit/as3hx/AS3HXTest.hx | 5 +++++ 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/test/issues/Issue261_1.as b/test/issues/Issue261_1.as index 735e1ac..c2c5eba 100644 --- a/test/issues/Issue261_1.as +++ b/test/issues/Issue261_1.as @@ -1,5 +1,5 @@ package { - public class Issue261_1 { + public class Issue2611 { public function randomGen(param1:int) : int { var _loc2_:int = Math.floor(Math.random() * param1); diff --git a/test/issues/Issue261_2.as b/test/issues/Issue261_2.as index 735e1ac..cd616ae 100644 --- a/test/issues/Issue261_2.as +++ b/test/issues/Issue261_2.as @@ -1,9 +1,8 @@ package { - public class Issue261_1 { - public function randomGen(param1:int) : int + public class Issue2612 { + function frame1() : * { - var _loc2_:int = Math.floor(Math.random() * param1); - return _loc2_; + gotoAndPlay((this.randomGen(48) + 1) * 4 + 1); } } } \ No newline at end of file diff --git a/test/issues/Issue261_2.hx b/test/issues/Issue261_2.hx index 353451b..a45b074 100644 --- a/test/issues/Issue261_2.hx +++ b/test/issues/Issue261_2.hx @@ -1,10 +1,9 @@ -class Issue2611 +class Issue2612 { - public function randomGen(param1 : Int) : Int + private function frame1() : Dynamic { - var _loc2_ : Int = Math.floor(Math.random() * param1); - return _loc2_; + gotoAndPlay((this.randomGen(48) + 1) * 4 + 1); } public function new() diff --git a/test/unit/as3hx/AS3HXTest.hx b/test/unit/as3hx/AS3HXTest.hx index 1a56f06..1b03694 100644 --- a/test/unit/as3hx/AS3HXTest.hx +++ b/test/unit/as3hx/AS3HXTest.hx @@ -491,6 +491,11 @@ class AS3HXTest { generate("Issue261_1.as", "Issue261_1.hx"); } + @Test("Issue 261. Case 3") + public function issue261_3() { + generate("Issue261_2.as", "Issue261_2.hx"); + } + @Test("v += condition ? 1 : 0") public function issue274() { generate("Issue274.as", "Issue274.hx"); From 54300f951e6912aeeb85cd083278e752fce26b70 Mon Sep 17 00:00:00 2001 From: Slava Buynov Date: Tue, 21 Nov 2017 21:42:28 +0300 Subject: [PATCH 008/156] Small refactoring... --- .editorconfig | 3 +-- test/issues/Issue314.as | 4 ++-- test/issues/Issue314.hx | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.editorconfig b/.editorconfig index 9b85254..c854dfb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,5 +3,4 @@ root = true indent_style = space indent_size = 4 end_of_line = crlf -charset = utf-8 -trim_trailing_whitespace = true \ No newline at end of file +charset = utf-8 \ No newline at end of file diff --git a/test/issues/Issue314.as b/test/issues/Issue314.as index 540e607..852d15a 100644 --- a/test/issues/Issue314.as +++ b/test/issues/Issue314.as @@ -1,6 +1,6 @@ package { - public class Issue303 { - public function Issue303() {} + public class Issue314 { + public function Issue314() {} public function hide1(param1:*) : * { this[param1] = false; diff --git a/test/issues/Issue314.hx b/test/issues/Issue314.hx index 25133df..35c2882 100644 --- a/test/issues/Issue314.hx +++ b/test/issues/Issue314.hx @@ -1,5 +1,5 @@ -class Issue303 +class Issue314 { public function new() { From dbe0bb6b7e622152496034b4481fb9fadaf991cf Mon Sep 17 00:00:00 2001 From: Slava Buynov Date: Tue, 21 Nov 2017 22:13:57 +0300 Subject: [PATCH 009/156] Tests for issue27. closes #27 --- test/issues/Issue27.as | 10 ++++++++++ test/issues/Issue27.hx | 14 ++++++++++++++ test/unit/as3hx/AS3HXTest.hx | 5 +++++ 3 files changed, 29 insertions(+) create mode 100644 test/issues/Issue27.as create mode 100644 test/issues/Issue27.hx diff --git a/test/issues/Issue27.as b/test/issues/Issue27.as new file mode 100644 index 0000000..06d944e --- /dev/null +++ b/test/issues/Issue27.as @@ -0,0 +1,10 @@ +package { + public class Issue27 { + public function Issue27(condition:Boolean) { + if (condition) trace(1); + + //some comment + trace(2); + } + } +} \ No newline at end of file diff --git a/test/issues/Issue27.hx b/test/issues/Issue27.hx new file mode 100644 index 0000000..b6e3e10 --- /dev/null +++ b/test/issues/Issue27.hx @@ -0,0 +1,14 @@ + +class Issue27 +{ + public function new(condition : Bool) + { + if (condition) + { + trace(1); + } + + //some comment + trace(2); + } +} diff --git a/test/unit/as3hx/AS3HXTest.hx b/test/unit/as3hx/AS3HXTest.hx index cbede7b..03fc7b0 100644 --- a/test/unit/as3hx/AS3HXTest.hx +++ b/test/unit/as3hx/AS3HXTest.hx @@ -566,6 +566,11 @@ class AS3HXTest { generate("Issue314.as", "Issue314.hx"); } + @Test("https://github.com/HaxeFoundation/as3hx/issues/27") + public function issue27() { + generate("Issue27.as", "Issue27.hx"); + } + function generate(as3FileName:String, expectedHaxeFileName:String) { var issuesDirectory = FileSystem.absolutePath("test/issues"); var generatedDirectoryPath = '$issuesDirectory/generated'; From e94675b7997685844e2b8610d3150295f0375e93 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 1 Dec 2017 03:53:29 +0300 Subject: [PATCH 010/156] spellcheck --- src/as3hx/ParserUtils.hx | 2 +- src/as3hx/parsers/ProgramParser.hx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/as3hx/ParserUtils.hx b/src/as3hx/ParserUtils.hx index b4558c4..585bbec 100644 --- a/src/as3hx/ParserUtils.hx +++ b/src/as3hx/ParserUtils.hx @@ -76,7 +76,7 @@ class ParserUtils { /** * Takes an expression e and adds the comment 'tk' to it - * as a trailing comment, iif tk is a TCommented, discarding + * as a trailing comment, if tk is a TCommented, discarding * whatever the comment target token is. */ public static function tailComment(e:Expr, tk:Token) : Expr { diff --git a/src/as3hx/parsers/ProgramParser.hx b/src/as3hx/parsers/ProgramParser.hx index 0e6e71f..096c089 100644 --- a/src/as3hx/parsers/ProgramParser.hx +++ b/src/as3hx/parsers/ProgramParser.hx @@ -101,7 +101,7 @@ class ProgramParser { if (!outsidePackage) { meta.push(EImport(impt)); } - //coner case : import for AS3 private class, for those, + //corner case : import for AS3 private class, for those, //need to add them to regular import list or to first //class metadata so that they //get written at the top of file, as in Haxe all imports From 8fadda3a87f67cbd165f4879f785a6ed9b752156 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 1 Dec 2017 05:01:06 +0300 Subject: [PATCH 011/156] spellcheck --- src/as3hx/ParserUtils.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/as3hx/ParserUtils.hx b/src/as3hx/ParserUtils.hx index 585bbec..b8aa25b 100644 --- a/src/as3hx/ParserUtils.hx +++ b/src/as3hx/ParserUtils.hx @@ -200,7 +200,7 @@ class ParserUtils { return null; } - //if the arary is empty, type can't be defined + //if the array is empty, type can't be defined if (arrayDecl.length == 0) { return null; } From 0a9f6c9d3646ca16d3b76b06817948d0290f7b5e Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 1 Dec 2017 05:10:57 +0300 Subject: [PATCH 012/156] fix of possible out of range error --- src/as3hx/parsers/ProgramParser.hx | 59 +++++++++++++++--------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/src/as3hx/parsers/ProgramParser.hx b/src/as3hx/parsers/ProgramParser.hx index 096c089..a098fd8 100644 --- a/src/as3hx/parsers/ProgramParser.hx +++ b/src/as3hx/parsers/ProgramParser.hx @@ -112,40 +112,41 @@ class ProgramParser { //no class def available, put in general import list if (defs.length == 0) { imports.push(impt); - } - //else check if can add to first class meta - switch (defs[0]) { - case CDef(c): - //also put the newline preceding the import - //in the first class meta - if (meta.length > 0) { - switch(meta[meta.length - 1]) { - case ENL(e): - if (e == null) { - c.meta.push(meta.pop()); - } - default: + } else { + //else check if can add to first class meta + switch (defs[0]) { + case CDef(c): + //also put the newline preceding the import + //in the first class meta + if (meta.length > 0) { + switch(meta[meta.length - 1]) { + case ENL(e): + if (e == null) { + c.meta.push(meta.pop()); + } + default: + } } - } - //remove extra new line generated for before - //class generation if not first moved import - if (hasOustidePackageMetaImport) { - c.meta.pop(); - c.meta.pop(); - } - - //put the import in the first class meta - c.meta.push(EImport(impt)); + //remove extra new line generated for before + //class generation if not first moved import + if (hasOustidePackageMetaImport) { + c.meta.pop(); + c.meta.pop(); + } + + //put the import in the first class meta + c.meta.push(EImport(impt)); - //add new line before class definition - c.meta.push(ENL(null)); - c.meta.push(ENL(null)); + //add new line before class definition + c.meta.push(ENL(null)); + c.meta.push(ENL(null)); - hasOustidePackageMetaImport = true; + hasOustidePackageMetaImport = true; - //put in regular import list - default: imports.push(impt); + //put in regular import list + default: imports.push(impt); + } } } } From 2925b964d56525c93c71eeb29bac930f22e28d41 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 1 Dec 2017 05:19:28 +0300 Subject: [PATCH 013/156] applying of escaping of haxe keywords to package names --- src/Run.hx | 3 ++- src/as3hx/parsers/PackageNameParser.hx | 2 +- src/as3hx/parsers/ProgramParser.hx | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Run.hx b/src/Run.hx index 7e8b891..36ce09c 100644 --- a/src/Run.hx +++ b/src/Run.hx @@ -1,5 +1,6 @@ using StringTools; +import as3hx.ParserUtils; import as3hx.Writer; import as3hx.Error; import sys.FileSystem; @@ -71,7 +72,7 @@ class Run { } } for (name in subDirList) { - loop((src.addTrailingSlash() + name), (dst.addTrailingSlash() + name), excludes); + loop((src.addTrailingSlash() + name), (dst.addTrailingSlash() + ParserUtils.escapeName(name)), excludes); } } diff --git a/src/as3hx/parsers/PackageNameParser.hx b/src/as3hx/parsers/PackageNameParser.hx index 3d6ae68..90848e7 100644 --- a/src/as3hx/parsers/PackageNameParser.hx +++ b/src/as3hx/parsers/PackageNameParser.hx @@ -13,7 +13,7 @@ class PackageNameParser { case TDot: tk = tokenizer.token(); switch(tk) { - case TId(id): a.push(id); + case TId(id): a.push(ParserUtils.escapeName(id)); default: ParserUtils.unexpected(tk); } default: diff --git a/src/as3hx/parsers/ProgramParser.hx b/src/as3hx/parsers/ProgramParser.hx index a098fd8..1548501 100644 --- a/src/as3hx/parsers/ProgramParser.hx +++ b/src/as3hx/parsers/ProgramParser.hx @@ -149,6 +149,9 @@ class ProgramParser { } } } + for (i in 0...impt.length) { + impt[i] = ParserUtils.escapeName(impt[i]); + } } tokenizer.end(); continue; From 2529ae024f25f9e31ccf7227c59d6e85fc2e8424 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 1 Dec 2017 05:21:34 +0300 Subject: [PATCH 014/156] handling of "enum" haxe keyword in variable and package naming --- src/as3hx/ParserUtils.hx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/as3hx/ParserUtils.hx b/src/as3hx/ParserUtils.hx index b8aa25b..24dc38b 100644 --- a/src/as3hx/ParserUtils.hx +++ b/src/as3hx/ParserUtils.hx @@ -10,6 +10,9 @@ class ParserUtils { public static inline function escapeName(name:String):String { return switch(name) { case "cast": "__DOLLAR__cast"; + case "enum": "_enum"; + case "_enum": "__enum"; + case "__enum": "___enum"; default: StringTools.replace(name, "$", "__DOLLAR__"); } } From 750c1e2f09d3e582e85c6f6e94eddfb51b9194bb Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 1 Dec 2017 05:32:19 +0300 Subject: [PATCH 015/156] handling of comments in a function call between argument name and comma --- src/as3hx/parsers/FunctionParser.hx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/as3hx/parsers/FunctionParser.hx b/src/as3hx/parsers/FunctionParser.hx index 0edf307..5a2f851 100644 --- a/src/as3hx/parsers/FunctionParser.hx +++ b/src/as3hx/parsers/FunctionParser.hx @@ -61,10 +61,12 @@ class FunctionParser { } f.args.push( { name : name, t : t, val : val, exprs:expressions } ); - expressions = []; // reset for next argument - if( ParserUtils.opt(tokenizer, TPClose) ) // ")" end of arguments + if( ParserUtils.opt2(tokenizer, TPClose, expressions) ) // ")" end of arguments break; + + expressions = []; // reset for next argument + tokenizer.ensure(TComma); case TCommented(s,b,t): //comment in between arguments From 7da5151511bf4f2b89de4ea8710b655bdcc41994 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 1 Dec 2017 05:39:43 +0300 Subject: [PATCH 016/156] handling of parsing of comments and new lines in between native object fields declaration {name/*comment*/:value} --- src/as3hx/parsers/ExprParser.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/as3hx/parsers/ExprParser.hx b/src/as3hx/parsers/ExprParser.hx index d6a604f..bdd5a2b 100644 --- a/src/as3hx/parsers/ExprParser.hx +++ b/src/as3hx/parsers/ExprParser.hx @@ -37,7 +37,7 @@ class ExprParser { Debug.dbgln("parseExpr: " + tk, tokenizer.line); - switch(ParserUtils.removeNewLine(tk, false)) { + switch(ParserUtils.removeNewLine(tk)) { case TBrClose: if(funcStart) return EBlock([]); return parseExprNext(EObject([]), 0); @@ -45,7 +45,7 @@ class ExprParser { var tk2 = tokenizer.token(); tokenizer.add(tk2); tokenizer.add(tk); - switch( tk2 ) { + switch( ParserUtils.removeNewLine(tk2) ) { case TColon: return parseExprNext(parseObject(), 0); default: From 06feab78ea6d42e5e39d61bc32abea2c8d566aea Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 1 Dec 2017 05:58:51 +0300 Subject: [PATCH 017/156] parsing of regexp in a separate method --- src/as3hx/parsers/ExprParser.hx | 38 ++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/as3hx/parsers/ExprParser.hx b/src/as3hx/parsers/ExprParser.hx index bdd5a2b..456cb00 100644 --- a/src/as3hx/parsers/ExprParser.hx +++ b/src/as3hx/parsers/ExprParser.hx @@ -75,23 +75,8 @@ class ExprParser { } return EBlock(a); case TOp(op): - if(op.charAt(0) == "/") { - var str = op.substr(1); - var prevChar = 0; - var c = tokenizer.nextChar(); - while(c != "/".code || prevChar == "\\".code) { - prevChar = c; - str += String.fromCharCode(c); - c = tokenizer.nextChar(); - } - c = tokenizer.nextChar(); - var opts = ""; - while( c >= "a".code && c <= "z".code ) { - opts += String.fromCharCode(c); - c = tokenizer.nextChar(); - } - tokenizer.pushBackChar(c); - return parseExprNext(ERegexp(str, opts), 0); + if (op.charAt(0) == "/") { + return parseExprNext(parseERegexp(tokenizer, op), 0); } for(x in tokenizer.unopsPrefix) if(x == op) @@ -393,4 +378,23 @@ class ExprParser { } return args.filter(function(e) return !e.match(ENL(null))); } + + public static function parseERegexp(tokenizer:Tokenizer, op:String):Expr { + var str = op.substr(1); + var prevChar = 0; + var c = tokenizer.nextChar(); + while(c != "/".code || prevChar == "\\".code) { + prevChar = c; + str += String.fromCharCode(c); + c = tokenizer.nextChar(); + } + c = tokenizer.nextChar(); + var opts = ""; + while( c >= "a".code && c <= "z".code ) { + opts += String.fromCharCode(c); + c = tokenizer.nextChar(); + } + tokenizer.pushBackChar(c); + return ERegexp(str, opts); + } } From 13b833ff82af8fb0d59f10a2757e07cb59431f54 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 1 Dec 2017 06:04:06 +0300 Subject: [PATCH 018/156] fix of parsing of regexp like /[/]/ --- src/as3hx/parsers/ExprParser.hx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/as3hx/parsers/ExprParser.hx b/src/as3hx/parsers/ExprParser.hx index 456cb00..cea41a4 100644 --- a/src/as3hx/parsers/ExprParser.hx +++ b/src/as3hx/parsers/ExprParser.hx @@ -383,9 +383,20 @@ class ExprParser { var str = op.substr(1); var prevChar = 0; var c = tokenizer.nextChar(); - while(c != "/".code || prevChar == "\\".code) { - prevChar = c; + var escapedChar:Bool = false; + var depth:Int = 0; + var inSquareBrackets:Bool = false; + while (depth != 0 || inSquareBrackets || c != "/".code || escapedChar) { str += String.fromCharCode(c); + if (!escapedChar) { + if (c == "(".code) depth++; + if (c == ")".code) depth--; + if (c == "[".code && !inSquareBrackets) inSquareBrackets = true; + if (c == "]".code && inSquareBrackets) inSquareBrackets = false; + escapedChar = c == "\\".code; + } else { + escapedChar = false; + } c = tokenizer.nextChar(); } c = tokenizer.nextChar(); From 950e056b034c5881b91a457212323c12af817449 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 1 Dec 2017 06:08:27 +0300 Subject: [PATCH 019/156] fix of parsing of unop prefix "+": var p:int = +1; // `+` here will be omitted --- src/as3hx/parsers/ExprParser.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/as3hx/parsers/ExprParser.hx b/src/as3hx/parsers/ExprParser.hx index cea41a4..06ff970 100644 --- a/src/as3hx/parsers/ExprParser.hx +++ b/src/as3hx/parsers/ExprParser.hx @@ -78,6 +78,8 @@ class ExprParser { if (op.charAt(0) == "/") { return parseExprNext(parseERegexp(tokenizer, op), 0); } + if (op == "+") // not valid unop prefix in haxe + return parseExpr(false); for(x in tokenizer.unopsPrefix) if(x == op) return ParserUtils.makeUnop(op, parseExpr(false)); From 98d187a1773d0129506728307068731f64204080 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 1 Dec 2017 06:21:19 +0300 Subject: [PATCH 020/156] handling of weird but possible unexpected conditional compilation block end --- src/as3hx/parsers/ExprParser.hx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/as3hx/parsers/ExprParser.hx b/src/as3hx/parsers/ExprParser.hx index 06ff970..c04bdab 100644 --- a/src/as3hx/parsers/ExprParser.hx +++ b/src/as3hx/parsers/ExprParser.hx @@ -153,6 +153,9 @@ class ExprParser { // this is a user supplied conditional compilation variable Debug.openDebug("conditional compilation: " + i + "::" + id, tokenizer.line); switch (tokenizer.peek()) { + case TSemicolon: + Debug.closeDebug("end conditional compilation: " + i + "::" + id, tokenizer.line); + return ECondComp(i + "_" + id, null, null); case TPClose: Debug.closeDebug("end conditional compilation: " + i + "::" + id, tokenizer.line); //corner case, the conditional compilation is within an "if" statement @@ -285,7 +288,7 @@ class ExprParser { addToken(tk); return e1; case TCommented(s,b,t): - addToken(t); + addToken(t); return ECommented(s,b,true, parseExprNext(e1, ++pendingNewLines)); default: tokenizer.add(t); From 1ebc419b788209e6f5566eb19b077d0ce5f3adf0 Mon Sep 17 00:00:00 2001 From: xmitre Date: Fri, 1 Dec 2017 12:50:25 +0300 Subject: [PATCH 021/156] fix of parsing of numbers in scientific notation with capital E failedSample = (1E3); --- src/as3hx/Tokenizer.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/as3hx/Tokenizer.hx b/src/as3hx/Tokenizer.hx index 6ef4f72..acf9f78 100644 --- a/src/as3hx/Tokenizer.hx +++ b/src/as3hx/Tokenizer.hx @@ -155,7 +155,7 @@ class Tokenizer { } pushBackChar(char); return TConst(CInt(buf.toString())); - case 'e'.code: + case 'e'.code | "E".code: if( buf.toString() == '.' ) { pushBackChar(char); return TDot; From 4d9c284b45ea19b1412825d210e6dca7d838fa7a Mon Sep 17 00:00:00 2001 From: xmitre Date: Fri, 1 Dec 2017 12:53:57 +0300 Subject: [PATCH 022/156] ignoring of accidental semicolons in start of a method --- src/as3hx/parsers/ExprParser.hx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/as3hx/parsers/ExprParser.hx b/src/as3hx/parsers/ExprParser.hx index c04bdab..a9e6662 100644 --- a/src/as3hx/parsers/ExprParser.hx +++ b/src/as3hx/parsers/ExprParser.hx @@ -18,6 +18,8 @@ class ExprParser { var tk = tokenizer.token(); Debug.dbgln("parseExpr(" + tk + ")", tokenizer.line); switch( tk ) { + case TSemicolon: + return parseExpr(funcStart); case TId(id): var e = parseStructure(id); if(e == null) @@ -286,11 +288,11 @@ class ExprParser { switch (t) { case TPClose: addToken(tk); - return e1; + return e1; case TCommented(s,b,t): - addToken(t); - return ECommented(s,b,true, parseExprNext(e1, ++pendingNewLines)); - default: + addToken(t); + return ECommented(s, b, true, parseExprNext(e1, ++pendingNewLines)); + default: tokenizer.add(t); return parseExprNext(e1, ++pendingNewLines); } From 54517b39489bbcc2b95b704ee27c9c13efa6707a Mon Sep 17 00:00:00 2001 From: xmitre Date: Fri, 1 Dec 2017 13:12:48 +0300 Subject: [PATCH 023/156] fix of parsing of `break` with label (in as3 new line interrupts `break \n label` expression) --- src/as3hx/parsers/StructureParser.hx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/as3hx/parsers/StructureParser.hx b/src/as3hx/parsers/StructureParser.hx index 5068ef6..609ff50 100644 --- a/src/as3hx/parsers/StructureParser.hx +++ b/src/as3hx/parsers/StructureParser.hx @@ -102,9 +102,10 @@ class StructureParser { EFor(inits, conds, incrs, parseExpr(false)); } case "break": - var label = switch( tokenizer.peek() ) { - case TId(n): tokenizer.token(); n; - default: null; + var t = tokenizer.token(); + var label = switch(ParserUtils.uncomment(t)) { + case TId(n): n; + default: tokenizer.add(t); null; }; EBreak(label); case "continue": EContinue; From 3aece8d5734270b1bc731b542b6a9c9d37870e69 Mon Sep 17 00:00:00 2001 From: xmitre Date: Fri, 1 Dec 2017 15:03:39 +0300 Subject: [PATCH 024/156] handling of try { } catch(e) { } without of argument type declaration --- src/as3hx/parsers/StructureParser.hx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/as3hx/parsers/StructureParser.hx b/src/as3hx/parsers/StructureParser.hx index 609ff50..469648b 100644 --- a/src/as3hx/parsers/StructureParser.hx +++ b/src/as3hx/parsers/StructureParser.hx @@ -162,9 +162,19 @@ class StructureParser { while( ParserUtils.opt(tokenizer, TId("catch")) ) { tokenizer.ensure(TPOpen); var name = tokenizer.id(); - tokenizer.ensure(TColon); - var t = parseType(); - tokenizer.ensure(TPClose); + var t:T = null; + + var next = tokenizer.token(); + switch (ParserUtils.uncomment(ParserUtils.removeNewLine(next))) { + case TColon: + t = parseType(); + tokenizer.ensure(TPClose); + case TPClose: + t = TComplex(EIdent("Dynamic")); + default: + ParserUtils.unexpected(next); + } + var e = parseExpr(false); catches.push( { name : name, t : t, e : e } ); } From 9ade206eb10ffd44608e86341d8083d02164f75b Mon Sep 17 00:00:00 2001 From: xmitre Date: Fri, 1 Dec 2017 15:05:07 +0300 Subject: [PATCH 025/156] handling of empty and one=line conditional compilation blocks --- src/as3hx/Writer.hx | 46 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 66b085d..505e93d 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1452,14 +1452,38 @@ class Writer } } + write("#if " + kwd); - writeECondComp(e); - writeNL(); - if (e2 != null) { - writeIndent("#else"); - writeECondComp(e2); + if (e == null) { writeNL(); + } else { + var oneLiner:Bool = isOneLiner(e, true); + if (oneLiner) { + write(" "); + } + writeECondComp(e); + if (oneLiner) { + write(" "); + } else { + writeNL(indent()); + } + if (e2 != null) { + write("#else"); + oneLiner = isOneLiner(e2, true); + if (oneLiner) { + write(" "); + } else { + writeNL(indent()); + } + writeECondComp(e2); + if (oneLiner) { + write(" "); + } else { + writeNL(indent()); + } + } } + writeIndent("#end // " + kwd); writeNL(); writeIndent(); @@ -3110,15 +3134,21 @@ class Writer * Return wether the expression contained in an * "if" statement is a one liner with no block bracket */ - function isOneLiner(e : Expr) : Bool { + function isOneLiner(e : Expr, threatOneLineBlockAsOneLiner:Bool = false) : Bool { return switch (e) { case ENL(e): //ignore newline - return isOneLiner(e); + return isOneLiner(e, threatOneLineBlockAsOneLiner); case ECommented(s,b,t,e): //ignore comment - return isOneLiner(e); + return isOneLiner(e, threatOneLineBlockAsOneLiner); case EBlock(e): //it is a regular block + if (threatOneLineBlockAsOneLiner && e.length == 1) { + switch(e[0]) { + case ENL(ex)://skip + default: return true; + } + } return false; default: //if it begins with anything but a block, one liner From 541d1910056fab00dc50016195fe2efaf87e3554 Mon Sep 17 00:00:00 2001 From: xmitre Date: Fri, 1 Dec 2017 15:35:27 +0300 Subject: [PATCH 026/156] more precise parsing of new lines and comments inside native object declaration { } --- src/as3hx/parsers/ObjectParser.hx | 34 ++++++++++++++++++------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/as3hx/parsers/ObjectParser.hx b/src/as3hx/parsers/ObjectParser.hx index 5a00e86..8b13eb4 100644 --- a/src/as3hx/parsers/ObjectParser.hx +++ b/src/as3hx/parsers/ObjectParser.hx @@ -34,21 +34,27 @@ class ObjectParser { } tokenizer.ensure(TColon); fl.push({ name : id, e : parseExpr(false) }); - tk = tokenizer.token(); - switch(tk) { - case TCommented(s,b,e): - var o = fl[fl.length-1]; - o.e = ParserUtils.tailComment(o.e, tk); - default: - } - switch( ParserUtils.uncomment(tk) ) { - case TBrClose: - break; - case TComma: - null; - default: - ParserUtils.unexpected(tk); + + var parseNextField:Bool = false; + var finishObject:Bool = false; + while (!parseNextField && !finishObject) { + tk = tokenizer.token(); + switch(tk) { + case TCommented(s,b,e): + var o = fl[fl.length-1]; + o.e = ParserUtils.tailComment(o.e, tk); + tokenizer.add(e); + case TNL(e): + tokenizer.add(e); + case TBrClose: + finishObject = true; + case TComma: + parseNextField = true; + default: + ParserUtils.unexpected(tk); + } } + if (finishObject) break; } var rv = parseExprNext(EObject(fl), 0); Debug.closeDebug("parseObject() -> " + rv, tokenizer.line); From 0ac169bbece39d619ee5c49da991d10ec3267acc Mon Sep 17 00:00:00 2001 From: xmitre Date: Fri, 1 Dec 2017 19:48:18 +0300 Subject: [PATCH 027/156] new config param `useAngleBracketsNotationForDictionaryTyping` which is set to true by default and is responsible for optional dictionary typing format. `true` value corresponds to Dictionary. notation. set by default. `false` value corresponds to Dictionary/*String,int*/ notation which do not break as3 code --- src/as3hx/Config.hx | 4 +++ src/as3hx/parsers/ExprParser.hx | 22 ++++++++++----- src/as3hx/parsers/TypeParser.hx | 48 ++++++++++++++++++++++++++++++--- 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index 80b6237..d438fb2 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -48,6 +48,8 @@ class Config { public var conditionalVars: List; /** Transform Dictionary. to Map **/ public var dictionaryToHash : Bool; + /** if set to false `Dictionary\/*KeyType,ValueType*\/` notation will be used. By default Dictionary. notation is used **/ + public var useAngleBracketsNotationForDictionaryTyping : Bool; /** write inferred type information into output **/ public var debugInferredType : Bool; /** convert flexunit metadata and calls to munit form */ @@ -329,6 +331,7 @@ class Config { case "excludeList": setExcludeField(el, new List()); case "conditionalCompilationList": setConditionalVars(el, new List()); case "dictionaryToHash": setBoolField(el, false); + case "useAngleBracketsNotationForDictionaryTyping": setBoolField(el, true); case "useFastXML": setBoolField(el, true); case "useCompat": setBoolField(el, true); case "importPaths": setImportPaths(el, []); @@ -434,6 +437,7 @@ class Config { + diff --git a/src/as3hx/parsers/ExprParser.hx b/src/as3hx/parsers/ExprParser.hx index a9e6662..55392ac 100644 --- a/src/as3hx/parsers/ExprParser.hx +++ b/src/as3hx/parsers/ExprParser.hx @@ -191,16 +191,24 @@ class ExprParser { if( ParserUtils.opt(tokenizer, TNs) ) field = field + "::" + tokenizer.id(); case TOp(op): - if( op != "<" || switch(e1) { case EIdent(v): v != "Vector" && v != "Dictionary"; default: true; } ) ParserUtils.unexpected(tk); - var t = parseType(); - - var v = switch(e1) { - case EIdent(v): v; - default: null; + if ( op != "<" ) ParserUtils.unexpected(tk); + var parseDictionaryTypes:Bool = false; + var parseVectorType:Bool = false; + switch(e1) { + case EIdent(v): + parseVectorType = v == "Vector"; + parseDictionaryTypes = v == "Dictionary" && cfg.dictionaryToHash && cfg.useAngleBracketsNotationForDictionaryTyping; + if (!parseVectorType && !parseDictionaryTypes) { + ParserUtils.unexpected(tk); + } + default: + ParserUtils.unexpected(tk); } + var t = parseType(); + //for Dictionary, expected syntax is "Dictionary." - if (v == "Dictionary" && cfg.dictionaryToHash) { + if (parseDictionaryTypes) { tokenizer.ensure(TComma); tokenizer.id(); } diff --git a/src/as3hx/parsers/TypeParser.hx b/src/as3hx/parsers/TypeParser.hx index 6f4ee34..4b1f26a 100644 --- a/src/as3hx/parsers/TypeParser.hx +++ b/src/as3hx/parsers/TypeParser.hx @@ -3,6 +3,7 @@ package as3hx.parsers; import as3hx.Tokenizer; import as3hx.As3; import as3hx.Parser; +import neko.Lib; class TypeParser { @@ -36,10 +37,49 @@ class TypeParser { types.seen.push(TVector(t)); return TVector(t); } - if(cfg.dictionaryToHash && t == "Dictionary") { - var k = TPath(["Object"]); - var v = TPath(["Object"]); - types.seen.push(TDictionary(k, v)); + if (t == "Dictionary") { + var k:T = null; + var v:T = null; + if (cfg.useAngleBracketsNotationForDictionaryTyping) { + var t2 = tokenizer.token(); + switch(t2) { + case TDot: + tokenizer.ensure(TOp("<")); + k = parseType(); + tokenizer.ensure(TComma); + v = parseType(); + tokenizer.ensure(TOp(">")); + default: + tokenizer.add(t2); + } + } else { + var t2 = tokenizer.token(); + switch(t2) { + case TCommented(s, true, t3): + var args = s.substring(2, s.length - 2).split(","); + if (args.length == 2) { + k = TPath([args[0]]); + v = TPath([args[1]]); + types.seen.push(TPath(["Dictionary"])); + tokenizer.add(t3); + } + default: + tokenizer.add(t2); + } + } + if (!cfg.dictionaryToHash) { + types.seen.push(TPath(["Dictionary"])); + } + if (k == null) { + k = TPath(["Object"]); + } else { + types.seen.push(k); + } + if (v == null) { + v = TPath(["Object"]); + } else { + types.seen.push(v); + } return TDictionary(k, v); } if(!cfg.functionToDynamic && t == "Function") { From 967166f0339a82ce1589a41b7833704023c72312 Mon Sep 17 00:00:00 2001 From: xmitre Date: Fri, 1 Dec 2017 19:56:29 +0300 Subject: [PATCH 028/156] now when config param `dictionaryToHash` is set to false, class Dictionary is used in haxe instead of flash.utils.Dictionary in flash. so openfl Dictionary or some custom implementation can be used instead. --- src/as3hx/Writer.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 505e93d..0306019 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -3331,7 +3331,7 @@ class Writer default : fixCase ? properCase(c, true) : c; } case TComplex(e): buffer(function() { writeExpr(e); }); - case TDictionary(k, v): "haxe.ds.ObjectMap<" + tstring(k) + ", " + tstring(v) + ">"; + case TDictionary(k, v): (cfg.dictionaryToHash ? "haxe.ds.ObjectMap" : "Dictionary") + "<" + tstring(k) + "," + tstring(v) + ">"; case TFunction(p): p.map(function(it) return tstring(it)).join("->"); } } From 85353deb720db69428e89d4234eca89e58fd489f Mon Sep 17 00:00:00 2001 From: xmitre Date: Mon, 4 Dec 2017 13:18:43 +0300 Subject: [PATCH 029/156] sourceDir is now used as current working directory for app consistently. Previously it was set to outdir when it was provider. Also it seemed invalid that sourceDit path may be derived from outdir path if sourceDir was not defined as absolute path, because outdir is optional, not sourceDir. --- src/as3hx/Config.hx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index d438fb2..971e9db 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -244,14 +244,6 @@ class Config { #else if (args.length == 0) return; #end - var last = new Path(args[args.length - 1]).toString(); - if (((StringTools.endsWith(last, "/") && last != "/") || StringTools.endsWith(last, "\\")) && !StringTools.endsWith(last, ":\\")) { - last = last.substr(0, last.length - 1); - } - if (FileSystem.exists(last) && FileSystem.isDirectory(last)) { - Sys.setCwd(last); - args.pop(); - } var arg = ""; while(true) { arg = args.shift(); @@ -289,6 +281,13 @@ class Config { usage(); Sys.exit(1); } + var cwd = new Path(arg).toString(); + if (((StringTools.endsWith(cwd, "/") && cwd != "/") || StringTools.endsWith(cwd, "\\")) && !StringTools.endsWith(cwd, ":\\")) { + cwd = cwd.substr(0, cwd.length - 1); + } + if (FileSystem.exists(cwd) && FileSystem.isDirectory(cwd)) { + Sys.setCwd(cwd); + } src = Run.directory(arg); dst = Run.directory(args.shift(), "./out"); } From a44f2479c69efd5a4c7f619bd3ec3ba20f26542f Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 6 Dec 2017 00:20:28 +0300 Subject: [PATCH 030/156] RebuildUtils.hx : handy utils for recursive Expr traversing and rebuilding. Will be used for complex lookUp's and type related manipulations --- src/as3hx/RebuildUtils.hx | 293 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 src/as3hx/RebuildUtils.hx diff --git a/src/as3hx/RebuildUtils.hx b/src/as3hx/RebuildUtils.hx new file mode 100644 index 0000000..2c468ed --- /dev/null +++ b/src/as3hx/RebuildUtils.hx @@ -0,0 +1,293 @@ +package as3hx; +import as3hx.As3.Expr; +import as3hx.As3.SwitchCase; +import as3hx.As3.SwitchDefault; +import as3hx.As3.T; +import neko.Lib; + +enum RebuildResult { + RReplace( expr : Expr ); // replace current expression with provided expr + RSkip; // do not iterate through child expressions of current expr + RNull; // no actions needed for this expr, continue recursion + RReplaceArray( es : Array ); // replace current expression with group of expressions. This operation could be applied only to expression in an array + REmpty; // remove current expression. This operation could be applied only to expression in an array +} + +/* + * RebuildUtils methods can iterate all through provided Expr and it's parameters and somehow process all Exprs by provideed method + */ +class RebuildUtils +{ + public static function rebuildArray(es:Array, rebuildMethod:Expr->RebuildResult):Array { + var needRebuild:Bool = false; + var rs:Array = new Array(); + for (i in 0...es.length) { + var e:Expr = es[i]; + var r:RebuildResult = rebuildMethod(e); + switch(r) { + case RReplace(expr): + rs.push(expr); + needRebuild = true; + case RReplaceArray(es): + for (e in es) { + rs.push(e); + } + needRebuild = true; + case REmpty: + needRebuild = true; + case null, RNull: + var expr:Expr = rebuildExprParams(e, rebuildMethod); + if (expr != null) { + rs.push(expr); + needRebuild = true; + } else { + rs.push(e); + } + case RSkip: + rs.push(e); + default: + rs.push(e); + } + } + if (needRebuild) { + return rs; + } else { + return null; + } + } + + public static function rebuild(e:Expr, rebuildMethod:Expr->RebuildResult):Expr { + if (e == null) return null; + var r:RebuildResult = rebuildMethod(e); + switch(r) { + case RReplace(expr): return expr; + case RSkip: return null; + case null, RNull: + default: + } + return rebuildExprParams(e, rebuildMethod); + } + + private static function rebuildExprParams(e:Expr, rebuildMethod:Expr->RebuildResult):Expr { + switch(e) { + case EFunction(f, name): + var rexpr = rebuild(f.expr, rebuildMethod); + if (rexpr == null) return null; + return EFunction({args:f.args, varArgs:f.varArgs, ret:f.ret, expr:rexpr}, name); + case EBlock(es): + var needRebuild:Bool = false; + var r:Array = []; + for (e in es) { + var er:Expr = rebuild(e, rebuildMethod); + if (er != null) { + needRebuild = true; + r.push(er); + } else { + r.push(e); + } + } + if (needRebuild) { + return EBlock(r); + } else { + return null; + } + case EForEach(e1, e2, e3): + var re1:Expr = rebuild(e1, rebuildMethod); + var re2:Expr = rebuild(e2, rebuildMethod); + var re3:Expr = rebuild(e3, rebuildMethod); + if (re1 != null || re2 != null || re3 != null) { + if (re1 == null) re1 = e1; + if (re2 == null) re2 = e2; + if (re3 == null) re3 = e3; + return EForEach(re1, re2, re3); + } else { + return null; + } + case EWhile(e1, e2, e3): + var re1:Expr = rebuild(e1, rebuildMethod); + var re2:Expr = rebuild(e2, rebuildMethod); + if (re1 != null || re2 != null) { + if (re1 == null) re1 = e1; + if (re2 == null) re2 = e2; + return EWhile(re1, re2, e3); + } else { + return null; + } + case EIf(e1, e2, e3): + var re1:Expr = rebuild(e1, rebuildMethod); + var re2:Expr = rebuild(e2, rebuildMethod); + var re3:Expr = rebuild(e3, rebuildMethod); + if (re1 != null || re2 != null || re3 != null) { + if (re1 == null) re1 = e1; + if (re2 == null) re2 = e2; + if (re3 == null) re3 = e3; + return EIf(re1, re2, re3); + } else { + return null; + } + case EFor(e1, e2, e3, e4): + var re1:Array = rebuildArray(e1, rebuildMethod); + var re2:Array = rebuildArray(e2, rebuildMethod); + var re3:Array = rebuildArray(e3, rebuildMethod); + var re4:Expr = rebuild(e4, rebuildMethod); + if (re1 != null || re2 != null || re3 != null || re4 != null) { + if (re1 == null) re1 = e1; + if (re2 == null) re2 = e2; + if (re3 == null) re3 = e3; + if (re4 == null) re4 = e4; + return EFor(re1, re2, re3, re4); + } else { + return null; + } + case ETry(e, catches): //ETry( e : Expr, catches : Array<{ name : String, t : Null, e : Expr }> ) + var re:Expr = rebuild(e, rebuildMethod); + var needRebuild = false; + var rcatches:Array<{ name : String, t : Null, e : Expr }> = []; + for (c in catches) { + var rce:Expr = rebuild(c.e, rebuildMethod); + if (rce != null) { + needRebuild = true; + rcatches.push({ + name:c.name, + t:c.t, + e:rce + }); + } else { + rcatches.push(c); + } + } + if (re != null || needRebuild) { + if (re == null) re = e; + return ETry(e, rcatches); + } else { + return null; + } + case ESwitch(e, cases, def)://ESwitch( e : Expr, cases : Array, def : Null) + var re:Expr = rebuild(e, rebuildMethod); + var needRebuild = false; + var rcases:Array = []; + for (c in cases) { + var rc = rebuildSwitchCase(c, rebuildMethod); + if (rc == null) { + rcases.push(c); + } else { + rcases.push(rc); + needRebuild = true; + } + } + var rdef:SwitchDefault = null; + if (def != null) { + rdef = rebuildSwitchDefault(def, rebuildMethod); + } + if (re != null || rdef != null || needRebuild) { + if (re == null) re = e; + if (rdef == null) rdef = def; + return ESwitch(re, rcases, rdef); + } else { + return null; + } + case ENew(t, params): + var rparams:Array = rebuildArray(params, rebuildMethod); + if (rparams != null) { + if (rparams == null) rparams = params; + return ENew(t, rparams); + } else { + return null; + } + case ENamespaceAccess(e, f): + var re:Expr = rebuild(e, rebuildMethod); + if (re == null) return null; + return ENamespaceAccess(re, f); + case EField(e, f): + var re:Expr = rebuild(e, rebuildMethod); + if (re == null) return null; + return EField(re, f); + case ECall(e, params): + var re:Expr = rebuild(e, rebuildMethod); + var rparams:Array = rebuildArray(params, rebuildMethod); + if (re != null || rparams != null) { + if (re == null) re = e; + if (rparams == null) rparams = params; + return ECall(re, rparams); + } else { + return null; + } + case EUnop(op, prefix, e): + var re:Expr = rebuild(e, rebuildMethod); + if (re == null) return null; + return EUnop(op, prefix, re); + case EBinop(op, e1, e2, newLineAfterOp): + var re1:Expr = rebuild(e1, rebuildMethod); + var re2:Expr = rebuild(e2, rebuildMethod); + if (re1 != null || re2 != null) { + if (re1 == null) re1 = e1; + if (re2 == null) re2 = e2; + return EBinop(op, re1, re2, newLineAfterOp); + } else { + return null; + } + case ENL(e): + e = rebuild(e, rebuildMethod); + if (e == null) return null; + return ENL(e); + case ECommented(a, b, c, e): + e = rebuild(e, rebuildMethod); + if (e == null) return null; + return ECommented(a, b, c, e); + default: + } + return null; + } + + private static function rebuildSwitchDefault(def:SwitchDefault, rebuildMethod:Expr->RebuildResult):SwitchDefault { + var el:Array = rebuildArray(def.el, rebuildMethod); + var meta:Array = rebuildArray(def.meta, rebuildMethod); + var vals:Array = null; + var before:SwitchCase = null; + if (Reflect.hasField(def, "vals") && def.vals != null) { + vals = rebuildArray(def.vals, rebuildMethod); + } + if (Reflect.hasField(def, "before") && def.before != null) { + before = rebuildSwitchCase(def.before, rebuildMethod); + } + if (el != null || meta != null || before != null || vals != null) { + if (el == null) el = def.el; + if (meta == null) meta = def.meta; + var rdef:SwitchDefault = { + el:el, + meta:meta + } + if (vals != null) { + rdef.vals = vals; + } else if (def.vals != null) { + rdef.vals = def.vals; + } + if (before != null) { + rdef.before = before; + } else if (def.before != null) { + rdef.before = def.before; + } + return rdef; + } else { + return null; + } + } + + private static function rebuildSwitchCase(c:SwitchCase, rebuildMethod:Expr->RebuildResult):SwitchCase { + var rval:Expr = rebuild(c.val, rebuildMethod); + var rel:Array = rebuildArray(c.el, rebuildMethod); + var rmeta:Array = rebuildArray(c.meta, rebuildMethod); + if (rval != null || rel != null || rmeta != null) { + if (rval == null) rval = c.val; + if (rel == null) rel = c.el; + if (rmeta == null) rmeta = c.meta; + return { + val: rval, + el: rel, + meta: rmeta + } + } else { + return null; + } + } +} \ No newline at end of file From 3d9a1bd68503baf4432fbe38312f448b16b5362f Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 6 Dec 2017 00:21:23 +0300 Subject: [PATCH 031/156] Typer : rough model of as3 typing. Some methods of as3->haxe type transition are separated from Writer.hx. Duplicated functionality in Writer should be eliminated with further development --- src/as3hx/Typer.hx | 202 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 src/as3hx/Typer.hx diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx new file mode 100644 index 0000000..6dfb7fd --- /dev/null +++ b/src/as3hx/Typer.hx @@ -0,0 +1,202 @@ +package as3hx; +import as3hx.As3.ClassDef; +import as3hx.As3.ClassField; +import as3hx.As3.Expr; +import as3hx.As3.Function; +import as3hx.As3.T; +import as3hx.RebuildUtils.RebuildResult; +import neko.Lib; + +/** + * AS3 typing allows multiple equal variable type declarations in one method and opens new variable context only inside function, not in any {} block + */ +class Typer +{ + var cfg:Config; + var classes : Map> = new Map>(); + var context : Map = new Map(); + var contextStack : Array> = []; + + public function new(cfg:Config) { + this.cfg = cfg; + } + + public function getExprType(e:Expr):Null { + switch(e) { + case ETypedExpr(e2, t): return tstring(t); + case EField(e2, f): + var t2 = getExprType(e2); + //write("/* e2 " + e2 + "."+f+" type: "+t2+" */"); + switch(t2) { + case "FastXML": + return switch(f) { + case "descendants", "nodes": "FastXMLList"; + case "node": "FastXML"; + case "length": "Int"; + case _: "FastXMLList"; + } + case "FastXMLList": + switch(f) { + case "length": return "Int"; + } + default: + } + case EIdent(s): + s = getModifiedIdent(s); + return context.get(s); + case EVars(vars) if(vars.length == 1): return tstring(vars[0].t); + case EArray(n, _): return getExprType(n); + case EArrayDecl(_): return "Array"; + case EUnop(_, _, e2): return getExprType(e2); + case EBinop(_ => "/", _, _, _): return "Float"; + case EBinop(_, e1, e2, _) if(getExprType(e1) != "Float" && getExprType(e2) != "Float"): return "Int"; + case EConst(c): + return switch(c) { + case CInt(_): "Int"; + case CFloat(_): "Float"; + case CString(_): "String"; + } + case ERegexp(_, _): return getRegexpType(); + default: + } + return null; + } + + public function getModifiedIdent(s : String) : String { + return switch(s) { + case "int": "Int"; + case "uint": cfg.uintToInt ? "Int" : "UInt"; + case "Number": "Float"; + case "Boolean": "Bool"; + case "Function": cfg.functionToDynamic ? "Dynamic" : s; + case "Object": "Dynamic"; + case "undefined": "null"; + //case "Error": cfg.mapFlClasses ? "flash.errors.Error" : s; + case "XML": "FastXML"; + case "XMLList": "FastXMLList"; + case "NaN":"Math.NaN"; + case "Dictionary": cfg.dictionaryToHash ? "haxe.ds.ObjectMap" : s; + //case "QName": cfg.mapFlClasses ? "flash.utils.QName" : s; + default: s; + }; + } + + public function tstring(t:T, isNativeGetSet:Bool = false, fixCase:Bool = true) : String { + if(t == null) return null; + return switch(t) { + case TStar: "Dynamic"; + case TVector(t): cfg.vectorToArray ? "Array<" + tstring(t) + ">" : "Vector<" + tstring(t) + ">"; + case TPath(p): + var c = p.join("."); + return switch(c) { + case "Array" : "Array"; + case "Boolean" : "Bool"; + case "Class" : "Class"; + case "int" : "Int"; + case "Number" : "Float"; + case "uint" : cfg.uintToInt ? "Int" : "UInt"; + case "void" : "Void"; + case "Function" : cfg.functionToDynamic ? "Dynamic" : c; + case "Object" : isNativeGetSet ? "{}" : "Dynamic"; + case "XML" : cfg.useFastXML ? "FastXML" : "Xml"; + case "XMLList" : cfg.useFastXML ? "FastXMLList" : "Iterator"; + case "RegExp" : cfg.useCompat ? "as3hx.Compat.Regex" : "flash.utils.RegExp"; + default : fixCase ? properCase(c, true) : c; + } + case TComplex(e): return getExprType(e); // not confirmed + case TDictionary(k, v): (cfg.dictionaryToHash ? "haxe.ds.ObjectMap" : "Dictionary") + "<" + tstring(k) + "," + tstring(v) + ">"; + case TFunction(p): p.map(function(it) return tstring(it)).join("->"); + } + } + + public function addClass(path:String, c:ClassDef):Void { + var classMap:Map = new Map(); + parseClassFields(c, classMap); + classes[path] = classMap; + } + + public function enterClass(c:ClassDef):Void { + parseClassFields(c, context); + } + + public function enterFunction(f:Function):Void { + openContext(); + for (arg in f.args) { + context.set(arg.name, tstring(arg.t)); + } + function lookUpForTyping(expr:Expr):RebuildResult { + switch(expr) { + case EVars(vars): + for (v in vars) { + context.set(v.name, tstring(v.t)); + } + case EFunction(f, name): + if (name != null) { + context.set(name, tstring(getFunctionType(f))); + } + // Stop parsing this branch. We are not interested in variables in another scope + return RSkip; + default: + } + return null; + } + RebuildUtils.rebuild(f.expr, lookUpForTyping); + } + + public function leaveFunction():Void { + closeContext(); + } + + function parseClassFields(c:ClassDef, map:Map):Void { + for (field in c.fields) { + switch(field.kind) { + case FVar(t, val): + map.set(field.name, tstring(t)); + case FFun(f): + if (isSetter(field) || isGetter(field)) { + map.set(field.name, tstring(f.ret.t)); + } else { + map.set(field.name, tstring(getFunctionType(f))); + } + default: + } + } + } + + inline function getRegexpType():String return cfg.useCompat ? "as3hx.Compat.Regex" : "flash.utils.RegExp"; + + inline function isGetter(c:ClassField):Bool return Lambda.has(c.kwds, "get"); + + inline function isSetter(c:ClassField):Bool return Lambda.has(c.kwds, "set"); + + + /** + * Opens a new context for variable typing + */ + function openContext() { + var c = new Map(); + for(k in context.keys()) + c.set(k, context.get(k)); + contextStack.push(context); + context = c; + } + + /** + * Closes the current variable typing context + */ + function closeContext() { + context = contextStack.pop(); + } + + public static function getFunctionType(f:Function):T { + var t = f.args.map(function(it) return it.t); + if(f.varArgs != null) t.push(TPath(["Array"])); + if(t.length == 0) t.push(TPath(["Void"])); + t.push(f.ret.t); + return TFunction(t); + } + + public static function properCase(pkg:String, hasClassName:Bool):String { + return Writer.properCase(pkg, hasClassName); + } +} \ No newline at end of file From 4a234c3b658bdd5fb1deb14617e8d0c12e5279bf Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 6 Dec 2017 00:46:34 +0300 Subject: [PATCH 032/156] Handling of namespaces in appliance to methods. New Expr enum constructor: ENamespaceAccess. Now sentence SomeClass.private_namespace::field should be transformed to SomeClass.field and @:access(SomeClass) metadata should be generated for outer method. --- src/as3hx/As3.hx | 1 + src/as3hx/Writer.hx | 40 +++++++++++++++++++++++++++++++++ src/as3hx/parsers/ExprParser.hx | 5 +++-- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/as3hx/As3.hx b/src/as3hx/As3.hx index 5144631..e0ea40d 100644 --- a/src/as3hx/As3.hx +++ b/src/as3hx/As3.hx @@ -47,6 +47,7 @@ enum Expr { EMeta( m : Metadata ); ETypedExpr( e : Expr, t : Null ); EDelete( e : Expr ); + ENamespaceAccess( e : Expr, f : String ); ECondComp( v : String, e : Expr, e2 : Expr ); ENL( e : Expr); EImport(v : Array); diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 0306019..3151fcc 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1,6 +1,7 @@ package as3hx; import as3hx.As3; +import as3hx.RebuildUtils.RebuildResult; import haxe.io.Output; using Lambda; @@ -508,6 +509,36 @@ class Writer writeMetaData(field.meta); + var namespaceMetadata:Array = null; + var typer:Typer = new Typer(cfg); + typer.enterClass(c); + if (isFun) { + switch(field.kind) { + case FFun(f): typer.enterFunction(f); + default: + }; + } + var lookUpForNamespaces = function(e:Expr):RebuildResult { + switch(e) { + case ENamespaceAccess(e, f): + var type:String = typer.getExprType(e); + if (type == null) return null; + if (typeImportMap.exists(type)) { + var typePath:String = typeImportMap.get(type); + if (typePath != null) { + type = typePath; + } + } + if (namespaceMetadata == null) { + namespaceMetadata = [type]; + } else if (namespaceMetadata.indexOf(type) == -1) { + namespaceMetadata.push(type); + } + default: + } + return null; + } + var start = function(name:String, isFlashNative:Bool=false, isConstructor=false) { if((isGet || isSet) && cfg.getterSetterStyle == "combined") { writeNL(isFlashNative ? "#if flash" : "#else"); @@ -530,6 +561,9 @@ class Writer } if(isFinal(field.kwds)) write("@:final "); + if (namespaceMetadata != null) + for (m in namespaceMetadata) + write("@:access(" + m + ") "); if((isConstructor && isInternal(c.kwds)) || (!isInterface && isInternal(field.kwds))) writeAllow(); if(isOverride(field.kwds)) @@ -600,6 +634,7 @@ class Writer write(";"); case FFun( f ): + RebuildUtils.rebuild(f.expr, lookUpForNamespaces); if (field.name == c.name) { start("new", false, true); @@ -669,6 +704,10 @@ class Writer foundSelf = true; } } + + if (isFun) { + typer.leaveFunction(); + } //close conditional compilation block writeECondCompEnd(condVars); @@ -1248,6 +1287,7 @@ class Writer writeIndent("}"); } case ERegexp(str, opts): write('new ${getExprType(expr)}(' + eregQuote(str) + ', "' + opts + '")'); + case ENamespaceAccess(e, f): writeExpr(e); case ESwitch( e, cases, def): var newCases : Array = new Array(); var writeTestVar = false; diff --git a/src/as3hx/parsers/ExprParser.hx b/src/as3hx/parsers/ExprParser.hx index 55392ac..1f9aa1f 100644 --- a/src/as3hx/parsers/ExprParser.hx +++ b/src/as3hx/parsers/ExprParser.hx @@ -188,8 +188,9 @@ class ExprParser { switch(ParserUtils.uncomment(ParserUtils.removeNewLine(tk))) { case TId(id): field = ParserUtils.escapeName(id); - if( ParserUtils.opt(tokenizer, TNs) ) - field = field + "::" + tokenizer.id(); + if( ParserUtils.opt(tokenizer, TNs) ) { + return parseExprNext(EField(ENamespaceAccess(e1, field), tokenizer.id()), 0); + } case TOp(op): if ( op != "<" ) ParserUtils.unexpected(tk); var parseDictionaryTypes:Bool = false; From 68ebfe275b4f03e69a0b9426e25c1efbf95aa8b0 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 6 Dec 2017 01:38:14 +0300 Subject: [PATCH 033/156] unused. for future implementation of global typing --- src/as3hx/Writer.hx | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 3151fcc..70d0705 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -44,6 +44,7 @@ class Writer var genTypes : Array; //typedef generated while parsing var imported : Array; // store written imports to prevent duplicated var pack : Array; // stores the haxe file package + var typer:Typer; public function new(config:Config) { @@ -61,6 +62,7 @@ class Writer this.typeImportMap = new Map(); this.genTypes = []; this.imported = []; + this.typer = new Typer(config); var doNotImportClasses = [ "Array", "Bool", "Boolean", "Class", "Date", @@ -91,6 +93,17 @@ class Writer this.typeImportMap.set(c, cfg.importTypes.get(c)); } } + + public function register(p:Program):Void { + for (d in p.defs) { + switch(d) { + case CDef(c): typer.addClass(p.pack.join(".") + "." + c.name, c); + case FDef(f): + case NDef(n): + default: + } + } + } /** * Opens a new context for variable typing @@ -3741,4 +3754,4 @@ class Writer ).array().join(""); } -} +} \ No newline at end of file From ef67a77cdf6bbf52410330e4d1474127b4c4ea00 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Sun, 10 Dec 2017 16:35:31 +0300 Subject: [PATCH 034/156] correct handling of as3 conditional compilation constants. optional config param `conditionalCompilationConstantsClass` for custom implementation of compile time constants --- src/as3hx/Config.hx | 4 ++++ src/as3hx/Writer.hx | 20 +++++++++++--------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index 971e9db..da6eebe 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -46,6 +46,8 @@ class Config { public var testCase : Bool; /** conditional compilation variables **/ public var conditionalVars: List; + /** Compile time constants implementation class package path for CONFIG::VAR -> `compile.Time.Constants`.CONFIG_VAR**/ + public var conditionalCompilationConstantsClass : String; /** Transform Dictionary. to Map **/ public var dictionaryToHash : Bool; /** if set to false `Dictionary\/*KeyType,ValueType*\/` notation will be used. By default Dictionary. notation is used **/ @@ -329,6 +331,7 @@ class Config { case "verifyGeneratedFiles": setBoolField(el, false); case "excludeList": setExcludeField(el, new List()); case "conditionalCompilationList": setConditionalVars(el, new List()); + case "conditionalCompilationConstantsClass":setCharField(el, ""); case "dictionaryToHash": setBoolField(el, false); case "useAngleBracketsNotationForDictionaryTyping": setBoolField(el, true); case "useFastXML": setBoolField(el, true); @@ -435,6 +438,7 @@ class Config { + diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 70d0705..ec5bdfd 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1505,11 +1505,16 @@ class Writer } } - - write("#if " + kwd); - if (e == null) { - writeNL(); - } else { + if (e == null) { + // compile time constant + if (cfg.conditionalCompilationConstantsClass != null && cfg.conditionalCompilationConstantsClass.length > 0) { + writeExpr(EField(EIdent(cfg.conditionalCompilationConstantsClass), kwd)); + } else { + write(kwd); + } + } else { + // conditional compilation block + write("#if " + kwd); var oneLiner:Bool = isOneLiner(e, true); if (oneLiner) { write(" "); @@ -1535,11 +1540,8 @@ class Writer writeNL(indent()); } } + writeIndent("#end // " + kwd); } - - writeIndent("#end // " + kwd); - writeNL(); - writeIndent(); rv = Ret; case ENL(e): From 33152f615382cef890b8fb356701b7be689160cc Mon Sep 17 00:00:00 2001 From: Xmitre Date: Sun, 10 Dec 2017 21:34:33 +0300 Subject: [PATCH 035/156] handling of as3 Date instance field access: date.day -> date.getDay() --- src/as3hx/Writer.hx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index ec5bdfd..5e67dd6 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1629,6 +1629,18 @@ class Writer write(".node"); write("." + f + ".innerData"); } else { + if (t2 == "Date") { + switch(f) { + case "fullYear" : return writeExpr(ECall(EField(e, "getFullYear"), [])); + case "month" : return writeExpr(ECall(EField(e, "getMonth"), [])); + case "day" : return writeExpr(ECall(EField(e, "getDay"), [])); + case "hours" : return writeExpr(ECall(EField(e, "getHours"), [])); + case "minutes" : return writeExpr(ECall(EField(e, "getMinutes"), [])); + case "seconds" : return writeExpr(ECall(EField(e, "getSeconds"), [])); + case "milliseconds": return writeExpr(EParent(EBinop("%", ECall(EField(e, "getTime"), []), EConst(CInt("1000")), false))); + default: + } + } inEField = true; switch(e) { case EField(e2, f2): From cff06862eec6f501b11f7b3906f0906f8f247295 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Mon, 11 Dec 2017 01:16:04 +0300 Subject: [PATCH 036/156] whitespaces fix --- src/as3hx/Writer.hx | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 5e67dd6..64b12d8 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -93,7 +93,7 @@ class Writer this.typeImportMap.set(c, cfg.importTypes.get(c)); } } - + public function register(p:Program):Void { for (d in p.defs) { switch(d) { @@ -551,7 +551,7 @@ class Writer } return null; } - + var start = function(name:String, isFlashNative:Bool=false, isConstructor=false) { if((isGet || isSet) && cfg.getterSetterStyle == "combined") { writeNL(isFlashNative ? "#if flash" : "#else"); @@ -717,7 +717,7 @@ class Writer foundSelf = true; } } - + if (isFun) { typer.leaveFunction(); } @@ -1505,15 +1505,15 @@ class Writer } } - if (e == null) { - // compile time constant - if (cfg.conditionalCompilationConstantsClass != null && cfg.conditionalCompilationConstantsClass.length > 0) { - writeExpr(EField(EIdent(cfg.conditionalCompilationConstantsClass), kwd)); - } else { - write(kwd); - } - } else { - // conditional compilation block + if (e == null) { + // compile time constant + if (cfg.conditionalCompilationConstantsClass != null && cfg.conditionalCompilationConstantsClass.length > 0) { + writeExpr(EField(EIdent(cfg.conditionalCompilationConstantsClass), kwd)); + } else { + write(kwd); + } + } else { + // conditional compilation block write("#if " + kwd); var oneLiner:Bool = isOneLiner(e, true); if (oneLiner) { From cac390bc5b7697dccf2f954ce27d8a2c3e12bdc1 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Mon, 11 Dec 2017 01:17:00 +0300 Subject: [PATCH 037/156] whitespaces fix --- src/as3hx/Writer.hx | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 64b12d8..5ae41db 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1629,18 +1629,18 @@ class Writer write(".node"); write("." + f + ".innerData"); } else { - if (t2 == "Date") { - switch(f) { - case "fullYear" : return writeExpr(ECall(EField(e, "getFullYear"), [])); - case "month" : return writeExpr(ECall(EField(e, "getMonth"), [])); - case "day" : return writeExpr(ECall(EField(e, "getDay"), [])); - case "hours" : return writeExpr(ECall(EField(e, "getHours"), [])); - case "minutes" : return writeExpr(ECall(EField(e, "getMinutes"), [])); - case "seconds" : return writeExpr(ECall(EField(e, "getSeconds"), [])); - case "milliseconds": return writeExpr(EParent(EBinop("%", ECall(EField(e, "getTime"), []), EConst(CInt("1000")), false))); - default: - } - } + if (t2 == "Date") { + switch(f) { + case "fullYear" : return writeExpr(ECall(EField(e, "getFullYear"), [])); + case "month" : return writeExpr(ECall(EField(e, "getMonth"), [])); + case "day" : return writeExpr(ECall(EField(e, "getDay"), [])); + case "hours" : return writeExpr(ECall(EField(e, "getHours"), [])); + case "minutes" : return writeExpr(ECall(EField(e, "getMinutes"), [])); + case "seconds" : return writeExpr(ECall(EField(e, "getSeconds"), [])); + case "milliseconds": return writeExpr(EParent(EBinop("%", ECall(EField(e, "getTime"), []), EConst(CInt("1000")), false))); + default: + } + } inEField = true; switch(e) { case EField(e2, f2): From 9455602da85e111020eea33d3d39a79a4ed950c1 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Mon, 11 Dec 2017 01:21:36 +0300 Subject: [PATCH 038/156] handling extraction of type from this.field_name expressions --- src/as3hx/Writer.hx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 5ae41db..f8aa2f8 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1145,6 +1145,10 @@ class Writer switch(e) { case ETypedExpr(e2, t): return tstring(t); case EField(e2, f): + switch(e2) { + case EIdent("this"): return contextStack[0].get(f); + default: + } var t2 = getExprType(e2); //write("/* e2 " + e2 + "."+f+" type: "+t2+" */"); switch(t2) { From 914a50b8f8d51c0ef4f0ac64c1ce269a4e741344 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Mon, 11 Dec 2017 01:30:24 +0300 Subject: [PATCH 039/156] handling of `&&` and `||` operators with objects in typed expr: object = a || b -> object = (a != null) ? a : b logic refactoring --- src/as3hx/Writer.hx | 50 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index f8aa2f8..aa5ed0a 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1242,7 +1242,7 @@ class Writer if(expr == null) return None; var rv = Semi; switch(expr) { - case ETypedExpr(e, t): rv = writeExpr(e); + case ETypedExpr(e, t): rv = writeETypedExpr(e, t); case EConst(c): write(getConst(c)); case EIdent(v): writeModifiedIdent(v); case EVars(vars): rv = writeEVars(vars); @@ -2302,13 +2302,20 @@ class Writer if (eBinop != null) return writeExpr(eBinop); var oldInLVA = inLvalAssign; - switch(e1) { - case EArray(_, _): if(op.indexOf("=") != -1) rvalue = e2; - case ECall(_, _): rvalue = e1; - case _: + if (op.indexOf("=") != -1) { + if (op == "=") inLvalAssign = true; + rvalue = e2; + var t = getExprType(e1); + if (t != null) { + e2 = ETypedExpr(e2, TPath([t])); + } + } else { + switch(e1) { + case EArrayDecl(_): rvalue = e2; + case ECall(_, _): rvalue = e1; + case _: + } } - if(op.indexOf("=") != -1 || e1.match(EArrayDecl(_))) rvalue = e2; - if(op == "=") inLvalAssign = true; switch(e1) { case EIdent(s): writeModifiedIdent(s); @@ -2661,6 +2668,33 @@ class Writer return result; } + function writeETypedExpr(e:Expr, t:T):BlockEnd { + switch(e) { + case ENL(e2): + return writeExpr(ENL(ETypedExpr(e2, t))); + default: + } + // fix of such constructions var tail:Signal = s || p; + switch(tstring(t)) { + case "Bool": + e = rebuildIfExpr(e); + case "Int": + if (getExprType(e) != "Int") { + e = getCastToIntExpr(e); + //e = ECall(EField(EIdent("Std"), "int"), [ETypedExpr(e, null)]); + } + default: + switch (e) { + case EBinop("||", e1, e2, nl): + e = ETernary(EBinop("!=", e1, EIdent("null"), false), e1, e2); + case EBinop("&&", e1, e2, nl): + e = ETernary(EBinop("==", e1, EIdent("null"), false), e1, e2); + default: + } + } + return writeExpr(e); + } + inline function writeEDelete(e:Expr) { switch(e) { case EArray(a, i): @@ -3281,6 +3315,8 @@ class Writer inline function isIntType(s:String):Bool return s == "Int"; + inline function isBoolType(s:String):Bool return s == "Bool"; + inline function isNumericOp(s:String):Bool return switch(s) { case "/" | "-" | "+" | "*" | "%" | "--" | "++": true; default: false; From 7df53bf74d54f2f3c442cbe7de033e5b5fda6240 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Mon, 11 Dec 2017 02:18:12 +0300 Subject: [PATCH 040/156] spellcheck bitwice -> bitwise --- src/as3hx/Writer.hx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index aa5ed0a..4c29586 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1732,12 +1732,12 @@ class Writer switch(rvalue) { case ETypedExpr(e, t) if(needCastToInt(e)): rvalue = switch(e) { - case EBinop(op, e1, e2, newLineAfterOp) if(isBitwiceOp(op)): + case EBinop(op, e1, e2, newLineAfterOp) if(isBitwiseOp(op)): if(needCastToInt(e1)) e1 = getCastToIntExpr(e1); if(needCastToInt(e2)) e2 = getCastToIntExpr(e2); EBinop(op, e1, e2, newLineAfterOp); case EUnop(op, prefix, ex): - if(isBitwiceOp(op) && needCastToInt(ex)) EUnop(op, prefix, getCastToIntExpr(ex)); + if(isBitwiseOp(op) && needCastToInt(ex)) EUnop(op, prefix, getCastToIntExpr(ex)); else e; default: getCastToIntExpr(e); } @@ -2395,7 +2395,7 @@ class Writer inline function needCastToInt(e:Expr):Bool { var isCompatParseInt:Expr->Bool = function(e) return e.match(ECall(EField(EIdent("as3hx.Compat"), "parseInt"), _)); return switch(e) { - case EBinop(op,e1,_,_): !isCompatParseInt(e1) && (isBitwiceOp(op) || isNumericOp(op)); + case EBinop(op,e1,_,_): !isCompatParseInt(e1) && (isBitwiseOp(op) || isNumericOp(op)); case EUnop(op,_,e): op == "~" && !isCompatParseInt(e); case EIdent(_) | EConst(_): getExprType(e) == "Float"; case EParent(e): needCastToInt(e); @@ -2846,7 +2846,7 @@ class Writer default: EBinop("!=", e, EIdent("null"), false); } case EBinop(op, e2, e3, n): - if(isBitwiceOp(op)) return EBinop("!=", EParent(e), EConst(CInt("0")), false); + if(isBitwiseOp(op)) return EBinop("!=", EParent(e), EConst(CInt("0")), false); if(isNumericConst(e2) || isNumericConst(e3)) return null; if(op == "==" || op == "!=" || op == "!==" || op == "===") return null; if(op == "is" || op == "in" || op == "as") return null; @@ -3188,7 +3188,7 @@ class Writer if(isIntExpr(lvalue)) { if(needCastToInt(rvalue)) { switch(rvalue) { - case EBinop(op, e1, e2, newLineAfterOp) if(isBitwiceOp(op)): rvalue = getResultForNumerics(op, e1, e2); + case EBinop(op, e1, e2, newLineAfterOp) if(isBitwiseOp(op)): rvalue = getResultForNumerics(op, e1, e2); case EUnop(op, prefix, e) if(op == "~"): if(needCastToInt(e)) e = getCastToIntExpr(e); rvalue = EUnop(op, prefix, e); @@ -3322,7 +3322,7 @@ class Writer default: false; } - inline function isBitwiceOp(s:String):Bool return switch(s) { + inline function isBitwiseOp(s:String):Bool return switch(s) { case "<<" | ">>" | ">>>" | "^" | "|" | "&" | "~": true; default: false; } From 52af85278e715d6a5a51e1a2d95e5ce96b5982de Mon Sep 17 00:00:00 2001 From: Xmitre Date: Mon, 11 Dec 2017 02:29:35 +0300 Subject: [PATCH 041/156] handling of field type in general (only some special case fields has type at the moment) and array.length:Int type in Bool expressions in particular --- src/as3hx/Writer.hx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 4c29586..7fa77ab 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1151,6 +1151,9 @@ class Writer } var t2 = getExprType(e2); //write("/* e2 " + e2 + "."+f+" type: "+t2+" */"); + if (t2 != null && (t2.indexOf("Array<") == 0 || t2.indexOf("Vector<") == 0) && f == "length") { + return "Int"; + } switch(t2) { case "FastXML": return switch(f) { @@ -2833,8 +2836,8 @@ class Writer } switch(e) { case EArray(_,_): return EBinop("!=", e, EIdent("null"), false); - case EIdent(id): - if(id == "null") return null; + case EIdent("null"): return null; + case EIdent(_), EField(_, _): var t = getExprType(e); if(t == null || t == "Bool") return null; return switch(t) { @@ -2882,7 +2885,6 @@ class Writer if(r2 == null) return null; return EParent(r2); case ECall(e2, params): //These would require a full typer - case EField(e2, f): null; case ENL(e): var expr = rebuildIfExpr(e); if (expr == null) return null; From d297a6508ae385c2612907831fa4287c080a1070 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Mon, 11 Dec 2017 02:59:10 +0300 Subject: [PATCH 042/156] fixes of uses of rebuildIfExpr( ) without checking of null result --- src/as3hx/Writer.hx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 7fa77ab..30b97ab 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -2680,7 +2680,10 @@ class Writer // fix of such constructions var tail:Signal = s || p; switch(tstring(t)) { case "Bool": - e = rebuildIfExpr(e); + var re:Expr = rebuildIfExpr(e); + if (re != null) { + e = re; + } case "Int": if (getExprType(e) != "Int") { e = getCastToIntExpr(e); @@ -2874,7 +2877,8 @@ class Writer case EParent(e): f(e); default: null; } - return f(r2); + var r3 = f(r2); + return r3 == null ? EUnop(op, prefix, r2) : r3; } var t = getExprType(e2); if(t == null) return null; @@ -3163,6 +3167,7 @@ class Writer case "Bool": lvalue; case "Int" | "UInt" | "Float" | _: rebuildIfExpr(lvalue); } + if (cond == null) cond = lvalue; if(isDynamicType(type)) { cond = switch(cond) { case EBinop(op, e1, e2, false) if(op == "!="): EBinop("==", e1, e2, false); From 33ced8425053abffe363eaceb27b325afe91aa3d Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 13 Dec 2017 05:07:04 +0300 Subject: [PATCH 043/156] config option flashTopLevelPackage (for translation-time replace of flash->openfl\nme). also fix of damaging of case in package naming of flash lib classes (.display3D.*) --- src/as3hx/Config.hx | 8 ++++++-- src/as3hx/Writer.hx | 8 +++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index da6eebe..78a8c87 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -40,6 +40,8 @@ class Config { public var setterMethods : String; /** getter/setter output style **/ public var getterSetterStyle : String; + /** top level package for classes defined in flash.* package in as3. 'flash' is default, but `openfl` or `nme` can be used for example **/ + public var flashTopLevelPackage : String; /** list of paths to exclude from parsing **/ public var excludePaths : List; /** Used only for test cases for compiler to ignore Sprite imports and extends **/ @@ -77,13 +79,13 @@ class Config { * a list of absolute or relative directory paths. * Haxe files are found in this path and added to a map * of imported types used for implicit imports used - * in converted code + * in converted code */ public var importPaths : Array; /** * A map where the key is the name fo a Haxe type - * and the value is its' fully qualified name, + * and the value is its' fully qualified name, * as found in one of the provided importPaths */ public var importTypes : StringMap; @@ -329,6 +331,7 @@ class Config { case "errorContinue": setBoolField(el, true); case "testCase": setBoolField(el, false); case "verifyGeneratedFiles": setBoolField(el, false); + case "flashTopLevelPackage":setCharField(el, "flash"); case "excludeList": setExcludeField(el, new List()); case "conditionalCompilationList": setConditionalVars(el, new List()); case "conditionalCompilationConstantsClass":setCharField(el, ""); @@ -436,6 +439,7 @@ class Config { + diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 30b97ab..45ddc90 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -205,7 +205,13 @@ class Writer function writeImport(i : Array) { - var type = properCaseA(i, true).join("."); + var type; + if (i[0] == "flash") { + i[0] = cfg.flashTopLevelPackage; + type = i.join("."); + } else { + type = properCaseA(i, true).join("."); + } if (!Lambda.has(this.imported, type)) { //prevent duplicate import write("import " + type + ";"); imported.push(type); From 711c0029626c76b475d86e28b0dfb90df71801c4 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Sun, 17 Dec 2017 23:56:59 +0300 Subject: [PATCH 044/156] config variable `useFullTyping`. Allow full typing of available classes. App will firstly parse all classes into memory and then try to apply type info while writing all classes in second phase --- src/Run.hx | 64 +++++++++++++++++++++++++++++++++++---------- src/as3hx/Config.hx | 4 +++ src/as3hx/Typer.hx | 55 +++++++++++++++++++++++++------------- src/as3hx/Writer.hx | 11 +++++--- 4 files changed, 99 insertions(+), 35 deletions(-) diff --git a/src/Run.hx b/src/Run.hx index 36ce09c..2f4d81e 100644 --- a/src/Run.hx +++ b/src/Run.hx @@ -1,5 +1,7 @@ using StringTools; +import as3hx.As3.Program; +import as3hx.Config; import as3hx.ParserUtils; import as3hx.Writer; import as3hx.Error; @@ -8,7 +10,20 @@ import sys.io.File; using haxe.io.Path; class Run { - + + static function writeFile(name:String, program:Program, cfg:Config, f:String, src:String):Void { + Sys.println("target HX file: " + name); + var fw = File.write(name, false); + warnings.set(name, writer.process(program, fw)); + fw.close(); + if(cfg.postProcessor != "") { + postProcessor(cfg.postProcessor, name); + } + if(cfg.verifyGeneratedFiles) { + verifyGeneratedFile(f, src, name); + } + } + static function errorString(e : Error) { return switch(e) { case EInvalidChar(c): "Invalid char '" + String.fromCharCode(c) + "' 0x" + StringTools.hex(c, 2); @@ -18,7 +33,7 @@ class Run { case EUnterminatedXML: "Unterminated XML"; } } - + static function loop(src:String, dst:String, excludes:List) { if (src == null) { Sys.println("source path cannot be null"); @@ -29,7 +44,9 @@ class Run { src = src.normalize(); dst = dst.normalize(); var subDirList = new Array(); - var writer = new Writer(cfg); + if (!cfg.useFullTyping) { + writer = new Writer(cfg); + } for(f in FileSystem.readDirectory(src)) { var srcChildAbsPath = src.addTrailingSlash() + f; var dstChildAbsPath = dst.addTrailingSlash() + f; @@ -59,15 +76,11 @@ class Run { var out = dst; ensureDirectoryExists(out); var name = out.addTrailingSlash() + Writer.properCase(f.substr(0, -3), true) + ".hx"; - Sys.println("target HX file: " + name); - var fw = File.write(name, false); - warnings.set(name, writer.process(program, fw)); - fw.close(); - if(cfg.postProcessor != "") { - postProcessor(cfg.postProcessor, name); - } - if(cfg.verifyGeneratedFiles) { - verifyGeneratedFile(f, src, name); + if (cfg.useFullTyping) { + writer.register(program); + files.push(new FileEntry(program, name, f, src)); + } else { + writeFile(name, program, cfg, f, src); } } } @@ -105,10 +118,20 @@ class Run { static var errors : Array = new Array(); static var warnings : Map> = new Map(); static var cfg : as3hx.Config; - + static var writer:Writer; + static var files:Array = new Array(); + public static function main() { cfg = new as3hx.Config(); + if (cfg.useFullTyping) { + writer = new Writer(cfg); + } loop(cfg.src, cfg.dst, cfg.excludePaths); + if (cfg.useFullTyping) { + for (f in files) { + writeFile(f.name, f.program, cfg, f.f, f.src); + } + } Sys.println(""); Writer.showWarnings(warnings); Sys.println(""); @@ -139,7 +162,7 @@ class Run { } } } - + static var reabs = ~/^([a-z]:|\\\\|\/)/i; public static function directory(dir : String, alt = ".") { if (dir == null) @@ -152,3 +175,16 @@ class Run { return dir; } } + +class FileEntry { + public var program(default, null):Program; + public var name(default, null):String; + public var f(default, null):String; + public var src(default, null):String; + public function new(program:Program, name:String, f:String, src:String):Void { + this.program = program; + this.name = name; + this.f = f; + this.src = src; + } +} \ No newline at end of file diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index 78a8c87..fc17294 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -34,6 +34,8 @@ class Config { public var errorContinue : Bool; /** Write Dynamic for Function **/ public var functionToDynamic : Bool; + /** Allow full typing of available classes. App will firstly parse all classes into memory and then try to apply type info while writing all classes in second phase **/ + public var useFullTyping : Bool; /** getter function template **/ public var getterMethods : String; /** setter function template **/ @@ -322,6 +324,7 @@ class Config { case "vectorToArray": setBoolField(el, true); case "guessCasts": setBoolField(el, true); case "functionToDynamic": setBoolField(el, false); + case "useFullTyping": setBoolField(el, false); case "getterMethods": setCharField(el, "get_%I"); case "setterMethods": setCharField(el, "set_%I"); case "getterSetterStyle": setCharField(el, "haxe", ["haxe","flash","combined"]); @@ -432,6 +435,7 @@ class Config { + diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index 6dfb7fd..8d7a62d 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -10,23 +10,30 @@ import neko.Lib; /** * AS3 typing allows multiple equal variable type declarations in one method and opens new variable context only inside function, not in any {} block */ -class Typer +class Typer { var cfg:Config; var classes : Map> = new Map>(); var context : Map = new Map(); var contextStack : Array> = []; - + public function new(cfg:Config) { this.cfg = cfg; } - + public function getExprType(e:Expr):Null { switch(e) { case ETypedExpr(e2, t): return tstring(t); case EField(e2, f): + switch(e2) { + case EIdent("this"): return contextStack[0].get(f); + default: + } var t2 = getExprType(e2); //write("/* e2 " + e2 + "."+f+" type: "+t2+" */"); + if (t2 != null && (t2.indexOf("Array<") == 0 || t2.indexOf("Vector<") == 0) && f == "length") { + return "Int"; + } switch(t2) { case "FastXML": return switch(f) { @@ -41,6 +48,12 @@ class Typer } default: } + var ts:String = getExprType(e2); + if (ts != null && classes.exists(ts)) { + return classes.get(ts).get(f); + } else { + return null; + } case EIdent(s): s = getModifiedIdent(s); return context.get(s); @@ -61,7 +74,7 @@ class Typer } return null; } - + public function getModifiedIdent(s : String) : String { return switch(s) { case "int": "Int"; @@ -80,7 +93,7 @@ class Typer default: s; }; } - + public function tstring(t:T, isNativeGetSet:Bool = false, fixCase:Bool = true) : String { if(t == null) return null; return switch(t) { @@ -108,17 +121,23 @@ class Typer case TFunction(p): p.map(function(it) return tstring(it)).join("->"); } } - + public function addClass(path:String, c:ClassDef):Void { + Lib.println(path); var classMap:Map = new Map(); parseClassFields(c, classMap); classes[path] = classMap; } - - public function enterClass(c:ClassDef):Void { - parseClassFields(c, context); + + public function enterClass(path, c:ClassDef):Void { + var classMap:Map = classes.get(path); + if (classMap == null) { + classMap = new Map(); + parseClassFields(c, classMap); + } + context = classMap; } - + public function enterFunction(f:Function):Void { openContext(); for (arg in f.args) { @@ -142,11 +161,11 @@ class Typer } RebuildUtils.rebuild(f.expr, lookUpForTyping); } - + public function leaveFunction():Void { closeContext(); } - + function parseClassFields(c:ClassDef, map:Map):Void { for (field in c.fields) { switch(field.kind) { @@ -162,13 +181,13 @@ class Typer } } } - + inline function getRegexpType():String return cfg.useCompat ? "as3hx.Compat.Regex" : "flash.utils.RegExp"; - + inline function isGetter(c:ClassField):Bool return Lambda.has(c.kwds, "get"); - + inline function isSetter(c:ClassField):Bool return Lambda.has(c.kwds, "set"); - + /** * Opens a new context for variable typing @@ -187,7 +206,7 @@ class Typer function closeContext() { context = contextStack.pop(); } - + public static function getFunctionType(f:Function):T { var t = f.args.map(function(it) return it.t); if(f.varArgs != null) t.push(TPath(["Array"])); @@ -195,7 +214,7 @@ class Typer t.push(f.ret.t); return TFunction(t); } - + public static function properCase(pkg:String, hasClassName:Bool):String { return Writer.properCase(pkg, hasClassName); } diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 45ddc90..2ce359a 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -97,7 +97,7 @@ class Writer public function register(p:Program):Void { for (d in p.defs) { switch(d) { - case CDef(c): typer.addClass(p.pack.join(".") + "." + c.name, c); + case CDef(c): typer.addClass((p.pack.length > 0 ? p.pack.join(".") + "." : "") + c.name, c); case FDef(f): case NDef(n): default: @@ -342,6 +342,9 @@ class Writer write(buf.toString()); lvl++; + var path:String = (pack.length > 0 ? pack.join(".") + "." : "") + c.name; + typer.enterClass(path, c); + // process properties writeProperties(c); @@ -529,8 +532,6 @@ class Writer writeMetaData(field.meta); var namespaceMetadata:Array = null; - var typer:Typer = new Typer(cfg); - typer.enterClass(c); if (isFun) { switch(field.kind) { case FFun(f): typer.enterFunction(f); @@ -949,6 +950,7 @@ class Writer } function writeFunction(f : Function, isGetter:Bool, isSetter:Bool, isNative:Bool, ?name : Null, ?ret : FunctionRet) { + typer.enterFunction(f); write("function"); if(name != null) write(" " + name); @@ -996,6 +998,7 @@ class Writer } writeStartStatement(); writeExpr(EBlock(es)); + typer.leaveFunction(); } /** @@ -1147,6 +1150,7 @@ class Writer } function getExprType(e:Expr):Null { + return typer.getExprType(e); /*EField(ECall(EField(EIdent(xml),descendants),[]),user)*/ switch(e) { case ETypedExpr(e2, t): return tstring(t); @@ -1174,6 +1178,7 @@ class Writer } default: } + return typer.getExprType(e); case EIdent(s): s = getModifiedIdent(s); //if(context.get(s) == null) From d981750016a37d8cf4c0482acbdfe03315c5dc05 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Mon, 18 Dec 2017 00:54:14 +0300 Subject: [PATCH 045/156] fix of error on one line comments before colon in ternary like that v = true ? 1 // comment before colon : // comment after colon 2; (colon was placed inside comment previously) --- src/as3hx/Typer.hx | 1 - src/as3hx/Writer.hx | 40 ++++++++++++++++++++++++++++++---------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index 8d7a62d..e8388cf 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -123,7 +123,6 @@ class Typer } public function addClass(path:String, c:ClassDef):Void { - Lib.println(path); var classMap:Map = new Map(); parseClassFields(c, classMap); classes[path] = classMap; diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 2ce359a..71afea6 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -41,6 +41,7 @@ class Writer var rvalue : Expr; var typeImportMap : Map; var lineIsDirty : Bool; // current line contains some non-whitespace/indent characters + var pendingTailComment : String; // one line comment that needs to be written at the end of line var genTypes : Array; //typedef generated while parsing var imported : Array; // store written imports to prevent duplicated var pack : Array; // stores the haxe file package @@ -58,6 +59,7 @@ class Writer this.inE4XFilter = false; this.inLvalAssign = false; this.lineIsDirty = false; + this.pendingTailComment = null; this.typeImportMap = new Map(); this.genTypes = []; @@ -162,7 +164,7 @@ class Writer for(c in comments) { switch(c) { case ECommented(s,b,t,e): - writeComment(indent() + formatComment(s,b)); + writeComment(indent() + formatComment(s,b), !b && t); if (e != null) { switch (e) { case ECommented(_): @@ -891,7 +893,7 @@ class Writer pendingComma = false; write(","); } - writeComment(s); + writeComment(s, !b && t); default: } @@ -1018,7 +1020,7 @@ class Writer for (expr in ret.exprs) { switch (expr) { case ECommented(s,b,t,e): - writeComment(s); + writeComment(s, !b && t); default: } } @@ -2618,7 +2620,7 @@ class Writer result = writeExpr(e); writeDelimiter(); } - writeComment(formatComment(s, isBlock)); + writeComment(formatComment(s, isBlock), !isBlock && isTail); if(!isTail) { writeDelimiter(); result = writeExpr(e); @@ -3613,12 +3615,21 @@ class Writer * comment written on dirty line (not first text on line), * add extra whitespace before and after comment */ - function writeComment(s : String) + function writeComment(s : String, tailOneLineComment : Bool) { - if (lineIsDirty) - s = " " + s + " "; - - write(s); + if (lineIsDirty) { + if (tailOneLineComment) { + if (pendingTailComment == null) { + pendingTailComment = s; + } else { + pendingTailComment += " " + s; + } + } else { + write(" " + s + " "); + } + } else { + write(s); + } } function writeIndent(s = "") @@ -3630,7 +3641,12 @@ class Writer { lineIsDirty = false; - write(indent() + s + cfg.newlineChars); + if (pendingTailComment != null) { + write(indent() + s + pendingTailComment + cfg.newlineChars); + pendingTailComment = null; + } else { + write(indent() + s + cfg.newlineChars); + } } function writeNL(s = "") @@ -3638,6 +3654,10 @@ class Writer lineIsDirty = false; //reset line dirtyness write(s); + if (pendingTailComment != null) { + write(pendingTailComment); + pendingTailComment = null; + } write(cfg.newlineChars); } From aaba37fa6c1266262c4ab5e709b524b88e11d13e Mon Sep 17 00:00:00 2001 From: Xmitre Date: Mon, 18 Dec 2017 04:01:23 +0300 Subject: [PATCH 046/156] fix of error with comments after some expressions s = "s" as String //this comment causes an Writer error --- src/as3hx/parsers/ExprParser.hx | 35 ++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/as3hx/parsers/ExprParser.hx b/src/as3hx/parsers/ExprParser.hx index 1f9aa1f..26421a3 100644 --- a/src/as3hx/parsers/ExprParser.hx +++ b/src/as3hx/parsers/ExprParser.hx @@ -36,9 +36,9 @@ class ExprParser { return parseExprNext(EParent(e), 0); case TBrOpen: tk = tokenizer.token(); - + Debug.dbgln("parseExpr: " + tk, tokenizer.line); - + switch(ParserUtils.removeNewLine(tk)) { case TBrClose: if(funcStart) return EBlock([]); @@ -58,7 +58,7 @@ class ExprParser { var a = new Array(); //check for corner case, block contains only comments and - //newlines. In this case, get all comments and add them to + //newlines. In this case, get all comments and add them to //content of block expression if (ParserUtils.uncomment(ParserUtils.removeNewLine(tk)) == TBrClose) { var ta = ParserUtils.explodeComment(tk); @@ -70,7 +70,7 @@ class ExprParser { } } } - + while(!ParserUtils.opt(tokenizer, TBrClose)) { var e = parseFullExpr(); a.push(e); @@ -146,7 +146,7 @@ class ExprParser { switch(i) { case "public": return parseExprNext(ECommented("/* AS3HX WARNING namespace modifier " + i + ":: */", true, false, null), 0); - default: + default: } tk = tokenizer.token(); switch(tk) { @@ -164,7 +164,7 @@ class ExprParser { //example if(CONFIG::MY_CONFIG) { //code block } //normal "if" statement parsing will take care of it return ECondComp(i + "_" + id, null, null); - default: + default: var e = parseExpr(false); Debug.closeDebug("end conditional compilation: " + i + "::" + id, tokenizer.line); return ECondComp(i + "_" + id, e, null); @@ -205,9 +205,9 @@ class ExprParser { default: ParserUtils.unexpected(tk); } - + var t = parseType(); - + //for Dictionary, expected syntax is "Dictionary." if (parseDictionaryTypes) { tokenizer.ensure(TComma); @@ -290,7 +290,7 @@ class ExprParser { var addToken : Token->Void = function(tk) { if (pendingNewLines != 0) tokenizer.add(TNL(tk)); - else + else tokenizer.add(tk); } @@ -298,9 +298,16 @@ class ExprParser { case TPClose: addToken(tk); return e1; - case TCommented(s,b,t): - addToken(t); - return ECommented(s, b, true, parseExprNext(e1, ++pendingNewLines)); + case TCommented(s,b,t1): + addToken(t1); + var next = parseExprNext(e1, ++pendingNewLines); + if (next != e1) { + return ECommented(s,b,true,next); + } else { + tokenizer.token(); + addToken(t); + return e1; + } default: tokenizer.add(t); return parseExprNext(e1, ++pendingNewLines); @@ -309,7 +316,7 @@ class ExprParser { case TCommented(s,b,t): tokenizer.add(t); return ECommented(s,b,true, parseExprNext(e1, 0)); - + default: Debug.dbgln("parseExprNext stopped at " + tk, tokenizer.line); tokenizer.add(tk); @@ -394,7 +401,7 @@ class ExprParser { } return args.filter(function(e) return !e.match(ENL(null))); } - + public static function parseERegexp(tokenizer:Tokenizer, op:String):Expr { var str = op.substr(1); var prevChar = 0; From d023f46c4a0847be83122092c33f9775b54ca58a Mon Sep 17 00:00:00 2001 From: Xmitre Date: Mon, 18 Dec 2017 05:14:06 +0300 Subject: [PATCH 047/156] fix of handling of `excludeList` config option --- src/Run.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Run.hx b/src/Run.hx index 2f4d81e..953e33f 100644 --- a/src/Run.hx +++ b/src/Run.hx @@ -113,7 +113,7 @@ class Run { } static function isExcludeFile(excludes: List, file: String) - return Lambda.filter(excludes, function (path) return as3hx.Config.toPath(file).indexOf(path.replace(".", "/")) > -1).length > 0; + return Lambda.filter(excludes, function (path) return as3hx.Config.toPath(file).indexOf(path.replace(".", "\\")) > -1).length > 0; static var errors : Array = new Array(); static var warnings : Map> = new Map(); From f4a824b66e48421ed7f5e3bec63f437ac7427f1c Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 20 Dec 2017 23:26:46 +0300 Subject: [PATCH 048/156] whitespaces cleanup --- src/as3hx/parsers/FunctionParser.hx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/as3hx/parsers/FunctionParser.hx b/src/as3hx/parsers/FunctionParser.hx index 5a2f851..6c26774 100644 --- a/src/as3hx/parsers/FunctionParser.hx +++ b/src/as3hx/parsers/FunctionParser.hx @@ -50,7 +50,7 @@ class FunctionParser { var t = null, val = null; expressions.push(EIdent(name)); - if( ParserUtils.opt(tokenizer, TColon) ) { // ":" + if( ParserUtils.opt(tokenizer, TColon) ) { // ":" t = parseType(); //arguments type expressions.push(ETypedExpr(null, t)); } @@ -77,7 +77,7 @@ class FunctionParser { tokenizer.add(t); expressions.push(ENL(null)); - default: + default: } } @@ -88,20 +88,20 @@ class FunctionParser { //newlines var retExpressions:Array = []; - //parse return type + //parse return type if( ParserUtils.opt(tokenizer, TColon) ) { var t = parseType(); retExpressions.push(ETypedExpr(null, t)); f.ret.t = t; } - - //parse until '{' or ';' (for interface method) + + //parse until '{' or ';' (for interface method) while (true) { var tk = tokenizer.token(); switch (tk) { case TNL(t): //parse new line before '{' or ';' tokenizer.add(t); - + //corner case, in AS3 interface method don't //have to end with a ";". So If we encounter a //newline after the return definition, we assume @@ -116,9 +116,9 @@ class FunctionParser { case TCommented(s,b,t): //comment before '{' or ';' tokenizer.add(t); - retExpressions.push(ParserUtils.makeECommented(tk, null)); + retExpressions.push(ParserUtils.makeECommented(tk, null)); - case TBrOpen, TSemicolon: //end of method return + case TBrOpen, TSemicolon: //end of method return tokenizer.add(tk); f.ret.exprs = retExpressions; break; @@ -159,7 +159,7 @@ class FunctionParser { f : f }; } - + inline static function rebuildLocalFunctions(f:Function) { switch(f.expr) { case EBlock(e): From 81d3dac6249b1a2fbc5f3bdc35d0420c1cb5e2b5 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 20 Dec 2017 23:31:43 +0300 Subject: [PATCH 049/156] fixing of one line comments between function return type and opening curly bracket on next line --- src/as3hx/Writer.hx | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 71afea6..1a9be3a 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1019,7 +1019,10 @@ class Writer //write comments after return type for (expr in ret.exprs) { switch (expr) { - case ECommented(s,b,t,e): + case ECommented(s, b, t, e): + // any expression here is just about to be placed before opening bracket `{` so one line comments should + // be moved to the end of line to not to comment it out + if (!b) t = true; writeComment(s, !b && t); default: } @@ -3583,14 +3586,25 @@ class Writer function openb() : String { - if (cfg.bracesOnNewline) - return cfg.newlineChars + indent() + "{"; - else + if (cfg.bracesOnNewline) { + var s:String = cfg.newlineChars + indent() + "{"; + if (pendingTailComment != null) { + s = pendingTailComment + s; + pendingTailComment = null; + } + return s; + } else { return " {"; + } } - inline function closeb() : String { - return cfg.newlineChars + indent() + "}"; + function closeb() : String { + var s:String = cfg.newlineChars + indent() + "}"; + if (pendingTailComment != null) { + s = pendingTailComment + s; + pendingTailComment = null; + } + return s; } function write(s : String) From 10ab807df01ba458e2f72c395a5d3db2ff5a6f5c Mon Sep 17 00:00:00 2001 From: Xmitre Date: Thu, 21 Dec 2017 23:49:09 +0300 Subject: [PATCH 050/156] Better handling of constructor generation. Now constructor is not created if class has now instance fields. Also initialization of variables that uses class instance fields is being moved to the constructor during processing --- src/as3hx/RebuildUtils.hx | 18 +++--- src/as3hx/Writer.hx | 115 ++++++++++++++++++++++++++++---------- 2 files changed, 98 insertions(+), 35 deletions(-) diff --git a/src/as3hx/RebuildUtils.hx b/src/as3hx/RebuildUtils.hx index 2c468ed..cd2ce04 100644 --- a/src/as3hx/RebuildUtils.hx +++ b/src/as3hx/RebuildUtils.hx @@ -16,7 +16,7 @@ enum RebuildResult { /* * RebuildUtils methods can iterate all through provided Expr and it's parameters and somehow process all Exprs by provideed method */ -class RebuildUtils +class RebuildUtils { public static function rebuildArray(es:Array, rebuildMethod:Expr->RebuildResult):Array { var needRebuild:Bool = false; @@ -55,7 +55,7 @@ class RebuildUtils return null; } } - + public static function rebuild(e:Expr, rebuildMethod:Expr->RebuildResult):Expr { if (e == null) return null; var r:RebuildResult = rebuildMethod(e); @@ -67,7 +67,7 @@ class RebuildUtils } return rebuildExprParams(e, rebuildMethod); } - + private static function rebuildExprParams(e:Expr, rebuildMethod:Expr->RebuildResult):Expr { switch(e) { case EFunction(f, name): @@ -216,6 +216,10 @@ class RebuildUtils var re:Expr = rebuild(e, rebuildMethod); if (re == null) return null; return EUnop(op, prefix, re); + case EParent(e): + var re:Expr = rebuild(e, rebuildMethod); + if (re == null) return null; + return EParent(re); case EBinop(op, e1, e2, newLineAfterOp): var re1:Expr = rebuild(e1, rebuildMethod); var re2:Expr = rebuild(e2, rebuildMethod); @@ -226,19 +230,19 @@ class RebuildUtils } else { return null; } - case ENL(e): + case ENL(e): e = rebuild(e, rebuildMethod); if (e == null) return null; return ENL(e); case ECommented(a, b, c, e): - e = rebuild(e, rebuildMethod); + e = rebuild(e, rebuildMethod); if (e == null) return null; return ECommented(a, b, c, e); default: } return null; } - + private static function rebuildSwitchDefault(def:SwitchDefault, rebuildMethod:Expr->RebuildResult):SwitchDefault { var el:Array = rebuildArray(def.el, rebuildMethod); var meta:Array = rebuildArray(def.meta, rebuildMethod); @@ -272,7 +276,7 @@ class RebuildUtils return null; } } - + private static function rebuildSwitchCase(c:SwitchCase, rebuildMethod:Expr->RebuildResult):SwitchCase { var rval:Expr = rebuild(c.val, rebuildMethod); var rel:Array = rebuildArray(c.el, rebuildMethod); diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 1a9be3a..da69a7d 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -483,23 +483,79 @@ class Writer function writeFields(c : ClassDef) { - for (field in c.fields) - writeField(field, c); - if(c.isInterface) + if (c.isInterface) { + for (field in c.fields) { + writeField(field, c); + } return; + } - if(!Lambda.exists(c.fields, - function(field:ClassField) { - switch(field.kind) { - case FFun( f ): - if (field.name == c.name) - return true; - default: - } - return false; + var constructor:Function = null; + var constructorFieldInits:Array = new Array(); + var hasConstructor:Bool = false; + var needConstructor:Bool = false; + + for (field in c.fields) { + switch(field.kind) { + case FFun ( f ): + if (field.name == c.name) { + constructor = f; + hasConstructor = true; + break; + } + case FVar(t, val): + if (val != null) { + var usingInstanceFields:Bool = false; + var rval = RebuildUtils.rebuild(val, function(e) { + switch(e) { + case EIdent(s): + if (s == "this") { + usingInstanceFields = true; + } else { + for (field in c.fields) { + if (s == field.name) { + if (!field.kwds.has("static")) { + usingInstanceFields = true; + return RebuildResult.RReplace(EField(EIdent("this"), s)); + } + break; + } + } + } + default: + } + return RebuildResult.RNull; + }); + if (usingInstanceFields) { + if (rval == null) rval = val; + constructorFieldInits.push(ENL(EBinop("=", EField(EIdent("this"), field.name), rval, false))); + field.kind = FVar(t, null); + } + } + default: } - )) - { + if (!needConstructor && !field.kwds.has("static")) { + needConstructor = true; + if (hasConstructor) break; + } + } + + if (hasConstructor && constructorFieldInits.length > 0) { + switch(constructor.expr) { + case EBlock(e): + constructorFieldInits = constructorFieldInits.concat(e); + default: + constructorFieldInits.push(constructor.expr); + } + constructor.expr = EBlock(constructorFieldInits); + } + + + for (field in c.fields) { + writeField(field, c); + } + + if (needConstructor && !hasConstructor) { addWarning("Required constructor was added for member var initialization"); writeNL(); writeNL(); @@ -511,11 +567,14 @@ class Writer else { write("public "); } + if (c.extend != null) { + constructorFieldInits.push(ENL(ECall(EIdent("super"), []))); + } writeConstructor({ args : [], varArgs : null, ret : null, - expr : EBlock(((null != c.extend) ? [ENL(ECall(EIdent("super"),[]))] : [])) + expr : EBlock(constructorFieldInits) }, c.extend != null); } } @@ -3600,10 +3659,10 @@ class Writer function closeb() : String { var s:String = cfg.newlineChars + indent() + "}"; - if (pendingTailComment != null) { + if (pendingTailComment != null) { s = pendingTailComment + s; - pendingTailComment = null; - } + pendingTailComment = null; + } return s; } @@ -3655,12 +3714,12 @@ class Writer { lineIsDirty = false; - if (pendingTailComment != null) { - write(indent() + s + pendingTailComment + cfg.newlineChars); - pendingTailComment = null; - } else { - write(indent() + s + cfg.newlineChars); - } + if (pendingTailComment != null) { + write(indent() + s + pendingTailComment + cfg.newlineChars); + pendingTailComment = null; + } else { + write(indent() + s + cfg.newlineChars); + } } function writeNL(s = "") @@ -3668,10 +3727,10 @@ class Writer lineIsDirty = false; //reset line dirtyness write(s); - if (pendingTailComment != null) { - write(pendingTailComment); - pendingTailComment = null; - } + if (pendingTailComment != null) { + write(pendingTailComment); + pendingTailComment = null; + } write(cfg.newlineChars); } From 23baac7d65b9237215bd179f4e05a37b78e137bf Mon Sep 17 00:00:00 2001 From: Xmitre Date: Thu, 21 Dec 2017 23:52:55 +0300 Subject: [PATCH 051/156] constructor warning is removed because of no real purpose in it (subjective) --- src/as3hx/Writer.hx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index da69a7d..715cbf0 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -556,7 +556,6 @@ class Writer } if (needConstructor && !hasConstructor) { - addWarning("Required constructor was added for member var initialization"); writeNL(); writeNL(); writeIndent(); From 0620e8d8ec1b6b54048c49fbc0a56c214924c0bd Mon Sep 17 00:00:00 2001 From: Xmitre Date: Sun, 24 Dec 2017 23:51:40 +0300 Subject: [PATCH 052/156] Handling of comments straight after opening brackets. Necessary change of handling of comments before `else if` statements --- src/as3hx/Writer.hx | 106 ++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 64 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 715cbf0..b6e5761 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -144,11 +144,6 @@ class Writer if (i == 0) f(ex[0]); else result.push(ex[i]); } - case ECommented(s,b,t,e): - // catch comments before else blocks - writeNL(); - writeIndent(s); - result.push(ENL(e)); case ENL(ex): f(ex); case EObject(fl) if(fl.empty()): default: result.push(ENL(e)); @@ -164,7 +159,7 @@ class Writer for(c in comments) { switch(c) { case ECommented(s,b,t,e): - writeComment(indent() + formatComment(s,b), !b && t); + writeComment(indent() + formatComment(s,b), b); if (e != null) { switch (e) { case ECommented(_): @@ -951,7 +946,7 @@ class Writer pendingComma = false; write(","); } - writeComment(s, !b && t); + writeComment(s, b); default: } @@ -1078,10 +1073,7 @@ class Writer for (expr in ret.exprs) { switch (expr) { case ECommented(s, b, t, e): - // any expression here is just about to be placed before opening bracket `{` so one line comments should - // be moved to the end of line to not to comment it out - if (!b) t = true; - writeComment(s, !b && t); + writeComment(s, b); default: } } @@ -1865,14 +1857,6 @@ class Writer expr = e2; params = params2; case EArray(_,_): return writeExpr(eCall); - case ECommented(s, b, t, e2): - //This is a hack for the AS3 unit test to - //Haxe unit test conversion. In some cases, - //the first param of the test if converted - //to an end-of-line comment - writeExpr(e2); - write(";"); - write(" // "+ s); return None; default: } @@ -2035,25 +2019,7 @@ class Writer e1 = EBlock(formatBlockBody(e1)); writeExpr(e1); if (e2 != null) { - //corner case : comment located - //before the "else" keyword in the - //source file. - //As to be called recursively, in - //case of multiple one-line comment - //before the "else" - var f:Expr->Expr = null; - f = function(e2) { - return switch (e2) { - case ECommented(s,b,t,e): - writeNL(); - writeIndent(s); - f(e); //skip the comment - default: e2; - } - } - e2 = f(e2); e2 = EBlock(formatBlockBody(e2)); - writeNL(); var elseif:Expr = null; // if we find an EBlock([ENL(EIf(...))]) // after an `else` then we have an @@ -2061,21 +2027,20 @@ class Writer switch(e2) { case EBlock(e3): if (e3 != null && e3.length == 1) { - switch(e3[0]) { - case ENL(e4): - switch(e4) { - case EIf(_, _, _): - // found single if statement after an else - // replace parent `block` + `new line` with - // the `if` statement instead so we stay on - // the same line as the `else` -> `else if` - elseif = e4; - case EBlock(_): - // catch double-nested blocks and replace - // outer block with inner block - e2 = e4; - default: - } + var e4 = ParserUtils.removeNewLineExpr(e3[0]); + var extraExpr:Expr = extractComments(e3[0]); + writeExpr(extraExpr); + switch(e4) { + case EIf(_, _, _): + // found single if statement after an else + // replace parent `block` + `new line` with + // the `if` statement instead so we stay on + // the same line as the `else` -> `else if` + elseif = e4; + case EBlock(_): + // catch double-nested blocks and replace + // outer block with inner block + e2 = e4; default: } } @@ -2083,6 +2048,7 @@ class Writer elseif = e2; default: } + writeNL(); if (elseif != null) { writeIndent("else "); result = writeExpr(elseif); @@ -2681,7 +2647,7 @@ class Writer result = writeExpr(e); writeDelimiter(); } - writeComment(formatComment(s, isBlock), !isBlock && isTail); + writeComment(formatComment(s, isBlock), isBlock); if(!isTail) { writeDelimiter(); result = writeExpr(e); @@ -3687,20 +3653,16 @@ class Writer * comment written on dirty line (not first text on line), * add extra whitespace before and after comment */ - function writeComment(s : String, tailOneLineComment : Bool) + function writeComment(s : String, blockComment : Bool) { - if (lineIsDirty) { - if (tailOneLineComment) { - if (pendingTailComment == null) { - pendingTailComment = s; - } else { - pendingTailComment += " " + s; - } + if (blockComment) { + write(" " + s + " "); + } else { + if (pendingTailComment == null) { + pendingTailComment = s; } else { - write(" " + s + " "); + pendingTailComment += " " + s; } - } else { - write(s); } } @@ -3784,6 +3746,22 @@ class Writer return StringTools.trim(s) == ""; } + function extractComments(expr:Expr) : Expr { + return switch(expr) { + case ENL(e2): + var re:Expr = extractComments(e2); + if (re != null) { + return ENL(re); + } + return null; + case ECommented(s,b,t,e2): + var re:Expr = extractComments(e2); + if (re != null) return ENL(re); + return ECommented(s,b,t,null); + default: null; + } + } + /** * Switches output to a string accumulator * @return contents of buffer after calling f() From 3069c26a0f3274f5972ceba7631977a32aca7720 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Mon, 25 Dec 2017 08:58:21 +0300 Subject: [PATCH 053/156] handling of special symbols in untyped object declaration field names --- src/as3hx/Writer.hx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index b6e5761..da84e60 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -45,6 +45,7 @@ class Writer var genTypes : Array; //typedef generated while parsing var imported : Array; // store written imports to prevent duplicated var pack : Array; // stores the haxe file package + var validVariableNameEReg:EReg; var typer:Typer; public function new(config:Config) @@ -66,6 +67,8 @@ class Writer this.imported = []; this.typer = new Typer(config); + this.validVariableNameEReg = new EReg("^[a-zA-Z_$][0-9a-zA-Z_$]*$", ""); + var doNotImportClasses = [ "Array", "Bool", "Boolean", "Class", "Date", "Dynamic", "EReg", "Enum", "EnumValue", @@ -1364,9 +1367,10 @@ class Writer var length = fl.length; for (i in 0...length) { var field = fl[i]; - writeIndent(field.name + (cfg.spacesOnTypeColon ? " : " : ": ")); + if (i > 0) writeNL(","); + var field = fl[i]; + writeIndent(prepareObjectFieldName(field.name) + (cfg.spacesOnTypeColon ? " : " : ": ")); writeExpr(field.e); - if(i < length - 1) writeNL(i > 0 || fl.length > 1 ? "," : ""); } lvl--; writeNL(); @@ -3329,6 +3333,14 @@ class Writer return false; } + function prepareObjectFieldName(name:String):String { + if (validVariableNameEReg.match(name)) { + return name; + } else { + return '"' + name + '"'; + } + } + /** * Checks if 'e' represents a numerical constant value * @return true if so From b10b50e25bee7a5cc0da4a0973a97851c386cbda Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 26 Dec 2017 11:44:38 +0300 Subject: [PATCH 054/156] config option `useOpenFlTypes` for types openfl.Vector, openfl.utils.Dictionary and openfl.utils.Object --- src/as3hx/Config.hx | 13 +++++++---- src/as3hx/Writer.hx | 56 +++++++++++++++++++++++++++++++++------------ 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index fc17294..b32f090 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -1,3 +1,4 @@ + package as3hx; import haxe.xml.Fast; @@ -48,6 +49,8 @@ class Config { public var excludePaths : List; /** Used only for test cases for compiler to ignore Sprite imports and extends **/ public var testCase : Bool; + /** Try to use openfl.Vector openfl.utils.Dictionary and openfl.utils.Object types **/ + public var useOpenFlTypes : Bool; /** conditional compilation variables **/ public var conditionalVars: List; /** Compile time constants implementation class package path for CONFIG::VAR -> `compile.Time.Constants`.CONFIG_VAR**/ @@ -319,7 +322,7 @@ class Config { case "indentChars": setCharField(el, " "); case "newlineChars": setCharField(el, "\n"); case "bracesOnNewline": setBoolField(el, true); - case "spacesOnTypeColon": setBoolField(el, true); + case "spacesOnTypeColon": setBoolField(el, true); case "uintToInt": setBoolField(el, true); case "vectorToArray": setBoolField(el, true); case "guessCasts": setBoolField(el, true); @@ -333,7 +336,8 @@ class Config { case "forcePrivateSetter": setBoolField(el, true); case "errorContinue": setBoolField(el, true); case "testCase": setBoolField(el, false); - case "verifyGeneratedFiles": setBoolField(el, false); + case "useOpenFlTypes": setBoolField(el, false); + case "verifyGeneratedFiles":setBoolField(el, false); case "flashTopLevelPackage":setCharField(el, "flash"); case "excludeList": setExcludeField(el, new List()); case "conditionalCompilationList": setConditionalVars(el, new List()); @@ -341,8 +345,8 @@ class Config { case "dictionaryToHash": setBoolField(el, false); case "useAngleBracketsNotationForDictionaryTyping": setBoolField(el, true); case "useFastXML": setBoolField(el, true); - case "useCompat": setBoolField(el, true); - case "importPaths": setImportPaths(el, []); + case "useCompat": setBoolField(el, true); + case "importPaths": setImportPaths(el, []); default: Sys.println("Unrecognized config var " + el.name); } @@ -443,6 +447,7 @@ class Config { + diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index da84e60..ea1d910 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -76,12 +76,19 @@ class Writer "Lambda", "List", "Math", "Number", "Reflect", "RegExp", "Std", "String", "StringBuf", "StringTools", "Sys", "Type", "Void", - "Function", "Object", "XML", "XMLList" + "Function", "XML", "XMLList" ]; + if (!cfg.useOpenFlTypes) { + doNotImportClasses.push("Object"); + } for(c in doNotImportClasses) { this.typeImportMap.set(c, null); } - if(!cfg.functionToDynamic) typeImportMap.set("Function", "haxe.Constraints.Function"); + if (!cfg.functionToDynamic) typeImportMap.set("Function", "haxe.Constraints.Function"); + if (cfg.useOpenFlTypes) { + typeImportMap.set("Vector", "openfl.Vector"); + typeImportMap.set("Object", "openfl.utils.Object"); + } var topLevelErrorClasses = [ "ArgumentError", "DefinitionError", "Error", @@ -1122,7 +1129,7 @@ class Writer write(")"); } else { //write("/*!!!" + etype + "!!!*/"); - if(isDynamicType(etype) || ((isArrayType(etype) || e.match(EIdent(_))) && itype != null && itype != "Int" && itype != "UInt")) { + if(isDynamicType(etype) || ((isArrayType(etype) || e.match(EIdent(_))) && itype != null && itype != "Int" && itype != "UInt" && !isOpenFlDictionaryType(etype))) { if(cfg.debugInferredType) { write("/* etype: " + etype + " itype: " + itype + " */"); } @@ -1289,7 +1296,7 @@ class Writer case "Number": "Float"; case "Boolean": "Bool"; case "Function": cfg.functionToDynamic ? "Dynamic" : s; - case "Object": "Dynamic"; + case "Object": cfg.useOpenFlTypes ? "Object" : "Dynamic"; case "undefined": "null"; //case "Error": cfg.mapFlClasses ? "flash.errors.Error" : s; case "XML": "FastXML"; @@ -1490,8 +1497,14 @@ class Writer // Vector. call // _buffers = Vector.([inst1,inst2]); // t is TPath([inst1,inst2]), which should have been handled in ECall - write("Array/*Vector. call?*/"); - addWarning("Vector.", true); + if (cfg.useOpenFlTypes && !cfg.vectorToArray) { + write("Vector<"); + write(tstring(t, false, false)); + write(">"); + } else { + write("Array/*Vector. call?*/"); + addWarning("Vector.", true); + } case EE4XAttr( e1, e2 ): // e1.@e2 writeExpr(e1); @@ -2338,12 +2351,20 @@ class Writer default: writeExpr(e2); } write(")"); - } else if(op == "in") { - write("Lambda.has("); - writeExpr(e2); - write(", "); - writeExpr(e1); - write(")"); + } else if (op == "in") { + var type2:String = getExprType(e2); + if (isOpenFlDictionaryType(type2)) { + writeExpr(e2); + write(".has("); + writeExpr(e1); + write(")"); + } else { + write("Lambda.has("); + writeExpr(e2); + write(", "); + writeExpr(e1); + write(")"); + } } else { // op e1 e2 var eBinop = rebuildBinopExpr(op, e1, e2); if (eBinop != null) return writeExpr(eBinop); @@ -2750,7 +2771,7 @@ class Writer case EArray(a, i): var atype = getExprType(a); if (atype != null) { - if (isMapType(atype)) { + if (isMapType(atype) || isOpenFlDictionaryType(atype)) { writeExpr(a); write(".remove("); writeExpr(i); @@ -3361,10 +3382,14 @@ class Writer static inline function isDynamicType(s:String):Bool return s == "Dynamic"; - static inline function isMapType(s:String):Bool { + inline function isMapType(s:String):Bool { return s != null && (s.startsWith("Map") || s.startsWith("haxe.ds.ObjectMap")); } + inline function isOpenFlDictionaryType(s:String):Bool { + return s != null && s.startsWith("Dictionary") && cfg.useOpenFlTypes; + } + inline function isFunctionExpr(e:Expr):Bool return getExprType(e) == "Function"; inline function isIntExpr(e:Expr):Bool { @@ -3470,6 +3495,7 @@ class Writer case "int" | "uint" | "void": return null; default: return fixCase ? properCase(c, true) : c; } + case TVector(t) if (cfg.useOpenFlTypes): return "Vector"; default: null; } } @@ -3490,7 +3516,7 @@ class Writer case "uint" : cfg.uintToInt ? "Int" : "UInt"; case "void" : "Void"; case "Function" : cfg.functionToDynamic ? "Dynamic" : c; - case "Object" : isNativeGetSet ? "{}" : "Dynamic"; + case "Object" : isNativeGetSet ? "{}" : (cfg.useOpenFlTypes ? "Object" : "Dynamic"); case "XML" : cfg.useFastXML ? "FastXML" : "Xml"; case "XMLList" : cfg.useFastXML ? "FastXMLList" : "Iterator"; case "RegExp" : cfg.useCompat ? "as3hx.Compat.Regex" : "flash.utils.RegExp"; From f03adb86570c77657185f1b0fad0be123a226944 Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 26 Dec 2017 12:15:20 +0300 Subject: [PATCH 055/156] fix of entering and leaving of context in typer --- src/as3hx/Typer.hx | 2 +- src/as3hx/Writer.hx | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index e8388cf..92465be 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -134,7 +134,7 @@ class Typer classMap = new Map(); parseClassFields(c, classMap); } - context = classMap; + contextStack[contextStack.length - 1] = context = classMap; } public function enterFunction(f:Function):Void { diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index ea1d910..537bfb1 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -760,6 +760,10 @@ class Writer null; } + if (isFun) { + typer.leaveFunction(); + } + //if this field is not wrapped in conditional compilation, //do nothing if (field.condVars.length == 0) @@ -790,10 +794,6 @@ class Writer } } - if (isFun) { - typer.leaveFunction(); - } - //close conditional compilation block writeECondCompEnd(condVars); } @@ -1015,7 +1015,6 @@ class Writer } function writeFunction(f : Function, isGetter:Bool, isSetter:Bool, isNative:Bool, ?name : Null, ?ret : FunctionRet) { - typer.enterFunction(f); write("function"); if(name != null) write(" " + name); @@ -1063,7 +1062,6 @@ class Writer } writeStartStatement(); writeExpr(EBlock(es)); - typer.leaveFunction(); } /** @@ -1339,7 +1337,10 @@ class Writer case EForIn(ev, e, block): rv = writeEForIn(ev, e, block); case EBreak(label): write("break"); case EContinue: rv = writeEContinue(); - case EFunction(f, name): writeFunction(f, false, false, false, name); + case EFunction(f, name): + typer.enterFunction(f); + writeFunction(f, false, false, false, name); + typer.leaveFunction(); case EReturn(e): writeEReturn(e); case EArray(e, index): writeEArray(e, index); case EArrayDecl(e): From 493e87304f02221cbb90e029909bda511ab67489 Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 26 Dec 2017 16:56:07 +0300 Subject: [PATCH 056/156] experimental refinement of dictionary key-value types by array access and assignments --- src/Run.hx | 8 +++ src/as3hx/Typer.hx | 152 ++++++++++++++++++++++++++++++++++++++++++++ src/as3hx/Writer.hx | 12 +++- 3 files changed, 170 insertions(+), 2 deletions(-) diff --git a/src/Run.hx b/src/Run.hx index 953e33f..46485e9 100644 --- a/src/Run.hx +++ b/src/Run.hx @@ -128,6 +128,14 @@ class Run { } loop(cfg.src, cfg.dst, cfg.excludePaths); if (cfg.useFullTyping) { + if (cfg.useOpenFlTypes) { + for (f in files) { + writer.refineTypes(f.program); + } + for (f in files) { + writer.applyRefinedTypes(f.program); + } + } for (f in files) { writeFile(f.name, f.program, cfg, f.f, f.src); } diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index 92465be..70dd5fc 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -3,10 +3,16 @@ import as3hx.As3.ClassDef; import as3hx.As3.ClassField; import as3hx.As3.Expr; import as3hx.As3.Function; +import as3hx.As3.Program; import as3hx.As3.T; import as3hx.RebuildUtils.RebuildResult; import neko.Lib; +typedef DictionaryTypes = { + key:Array, + value:Array +} + /** * AS3 typing allows multiple equal variable type declarations in one method and opens new variable context only inside function, not in any {} block */ @@ -14,8 +20,10 @@ class Typer { var cfg:Config; var classes : Map> = new Map>(); + var classFieldDictionaryTypes : Map> = new Map>(); var context : Map = new Map(); var contextStack : Array> = []; + var currentPath:String = null; public function new(cfg:Config) { this.cfg = cfg; @@ -129,6 +137,7 @@ class Typer } public function enterClass(path, c:ClassDef):Void { + currentPath = path; var classMap:Map = classes.get(path); if (classMap == null) { classMap = new Map(); @@ -180,6 +189,149 @@ class Typer } } } + + public function applyRefinedTypes(program:Program):Void { + var pack:String = (program.pack.length > 0 ? program.pack.join(".") + "." : ""); + for (d in program.defs) { + switch (d) { + case CDef(c): + enterClass(pack + c.name, c); + for (f in c.fields) { + var t:T = getDictionaryType(f.name); + var d:String = tstring(t); + if (t != null) { + switch(f.kind) { + case FVar(t1, val): + f.kind = FVar(t, val); + default: + } + context[f.name] = d; + Lib.println(" Refined type in " + pack + c.name + "::" + f.name + ": " + d); + } + } + default: + } + } + } + + public function refineTypes(program:Program):Void { + var currentClass:String = null; + var pack:String = (program.pack.length > 0 ? program.pack.join(".") + "." : ""); + + function refineArrayAccess(e1:Expr, index:Expr, value:Expr):Void { + var type1:String = getExprType(e1); + if (type1 != null && StringTools.startsWith(type1, "Dictionary")) { + var baseType:String = null; + var field:String = null; + switch(e1) { + case EField(e2, f): + baseType = getExprType(e2); + field = f; + case EIdent(s): + baseType = pack + currentClass; + field = s; + default: + } + if (field != null) { + if (classes.exists(baseType)) { + if (!classFieldDictionaryTypes.exists(baseType)) { + classFieldDictionaryTypes.set(baseType, new Map()); + } + var map:Map = classFieldDictionaryTypes.get(baseType); + if (!map.exists(field)) { + map.set(field, { + key:new Array(), + value:new Array() + }); + } + var d:DictionaryTypes = map.get(field); + refineStringType(d.key, getExprType(index)); + if (value != null) { + refineStringType(d.value, getExprType(value)); + } + } + } + } + } + + function rebuild(expr:Expr):RebuildResult { + switch(expr) { + case EFunction(f, name): + enterFunction(f); + var re:Expr = RebuildUtils.rebuild(f.expr, rebuild); + leaveFunction(); + if (re != null) { + return RebuildResult.RReplace(re); + } else { + return RebuildResult.RSkip; + } + case EBinop("=", e1, e2, _): + switch(e1) { + case EArray(e1, index): + refineArrayAccess(e1, index, e2); + default: + } + case EArray(e1, index): + refineArrayAccess(e1, index, null); + default: + } + return null; + } + + for (d in program.defs) { + switch (d) { + case CDef(c): + enterClass(pack + c.name, c); + currentClass = c.name; + for (field in c.fields) { + switch(field.kind) { + case FFun(f): + enterFunction(f); + RebuildUtils.rebuild(f.expr, rebuild); + leaveFunction(); + default: + } + } + case FDef(f): + RebuildUtils.rebuild(f.f.expr, rebuild); + default: + } + } + } + + public function getDictionaryType(field:String):T { + var m:Map = classFieldDictionaryTypes.get(currentPath); + if (m != null) { + var d:DictionaryTypes = m.get(field); + if (d != null) { + var keyT:String = null; + var valueT:String = null; + for (t in d.key) keyT = foldDictionaryType(keyT, t); + for (t in d.value) valueT = foldDictionaryType(valueT, t); + return TDictionary(TPath([keyT]), TPath([valueT])); + //return "Dictionary<" + d.key[0] + "," + d.value[0] + ">"; + } + } + if (contextStack.length < 1) return null; + var t:String = contextStack[0].get(field); + return TPath([t]); + } + + function foldDictionaryType(a:String, b:String):String { + if (a == b) return a; + if (a == "Dynamic" || a == null) return b; + if (b == "Dynamic" || b == null) return a; + if (a == "String") return a; + if (b == "String") return b; + return "Dynamic"; + } + + /** it could be better if we would refine single value on occurance but not to collect all types */ + function refineStringType(types:Array, type:String):Void { + if (type != null) { + types.push(type); + } + } inline function getRegexpType():String return cfg.useCompat ? "as3hx.Compat.Regex" : "flash.utils.RegExp"; diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 537bfb1..de0f61f 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -106,6 +106,14 @@ class Writer } } + public function refineTypes(p:Program):Void { + typer.refineTypes(p); + } + + public function applyRefinedTypes(p:Program):Void { + typer.applyRefinedTypes(p); + } + public function register(p:Program):Void { for (d in p.defs) { switch(d) { @@ -697,7 +705,7 @@ class Writer case FVar(t, val): start(field.name, false); write("var " + getModifiedIdent(field.name)); - if(!isStatic(field.kwds) && isConst(field.kwds)) write("(default, never)"); + if (!isStatic(field.kwds) && isConst(field.kwds)) write("(default, never)"); var type = tstring(t); //check wether a specific type was defined for this array if(isArrayType(type)) { for (genType in this.genTypes) { @@ -2715,7 +2723,7 @@ class Writer case TDictionary(_,_): !cfg.dictionaryToHash; default: true; } - if(out) writeParams(); + if (out) writeParams(); if(!isObject) write(")"); } } From 132a4c67b5a06d4a7df1afb5e4a3323e978258b9 Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 26 Dec 2017 17:00:46 +0300 Subject: [PATCH 057/156] applying typing of init value to class fields and inheritance of typed dictionary constructor from expected type --- src/as3hx/Writer.hx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index de0f61f..1f10590 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -721,7 +721,7 @@ class Writer if(val != null) { write(" = "); lvl++; //extra indenting if init is on multiple lines - writeExpr(val); + writeExpr(ETypedExpr(val, t)); lvl--; } @@ -2749,6 +2749,16 @@ class Writer switch(e) { case ENL(e2): return writeExpr(ENL(ETypedExpr(e2, t))); + case ENew(t2, params): + switch (t2) { + case TDictionary(k, v): + switch (t) { + case TDictionary(k, v): + return writeExpr(ENew(t, params)); + default: + } + default: + } default: } // fix of such constructions var tail:Signal = s || p; From 10592f8f905a00e6be282788c17c42191eabb7f7 Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 9 Jan 2018 10:46:26 +0300 Subject: [PATCH 058/156] option RebuildResult.RReplaceArray( ) wraps arrays of Expr in new line expressions if they are in ENL(EBlock()) --- src/as3hx/RebuildUtils.hx | 344 ++++++++++++++++++++------------------ 1 file changed, 178 insertions(+), 166 deletions(-) diff --git a/src/as3hx/RebuildUtils.hx b/src/as3hx/RebuildUtils.hx index cd2ce04..ab04a7d 100644 --- a/src/as3hx/RebuildUtils.hx +++ b/src/as3hx/RebuildUtils.hx @@ -19,127 +19,143 @@ enum RebuildResult { class RebuildUtils { public static function rebuildArray(es:Array, rebuildMethod:Expr->RebuildResult):Array { - var needRebuild:Bool = false; - var rs:Array = new Array(); - for (i in 0...es.length) { - var e:Expr = es[i]; - var r:RebuildResult = rebuildMethod(e); - switch(r) { - case RReplace(expr): - rs.push(expr); - needRebuild = true; - case RReplaceArray(es): - for (e in es) { - rs.push(e); - } - needRebuild = true; - case REmpty: - needRebuild = true; - case null, RNull: - var expr:Expr = rebuildExprParams(e, rebuildMethod); - if (expr != null) { - rs.push(expr); - needRebuild = true; - } else { - rs.push(e); - } - case RSkip: - rs.push(e); - default: - rs.push(e); + var needRebuild:Bool = false; + var rs:Array = new Array(); + for (i in 0...es.length) { + if (rebuildToArray(es[i], rebuildMethod, rs)) { + needRebuild = true; } - } - if (needRebuild) { - return rs; - } else { - return null; - } - } + } + if (needRebuild) { + return rs; + } else { + return null; + } + } - public static function rebuild(e:Expr, rebuildMethod:Expr->RebuildResult):Expr { - if (e == null) return null; - var r:RebuildResult = rebuildMethod(e); + public static function rebuild(e:Expr, rebuildMethod:Expr->RebuildResult):Expr { + if (e == null) return null; + var r:RebuildResult = rebuildMethod(e); switch(r) { case RReplace(expr): return expr; case RSkip: return null; case null, RNull: default: } - return rebuildExprParams(e, rebuildMethod); - } + switch(e) { + case ENL(e1): + var re = rebuild(e1, rebuildMethod); + if (re == null) { + return e; + } else { + return ENL(re); + } + default: + return rebuildExprParams(e, rebuildMethod); + } + } + + private static function rebuildToArray(e:Expr, rebuildMethod:Expr->RebuildResult, output:Array):Bool { + var r:RebuildResult = rebuildMethod(e); + switch(r) { + case RReplace(expr): + output.push(expr); + return true; + case RReplaceArray(es): + for (expr in es) { + output.push(expr); + } + return true; + case REmpty: + return true; + case null, RNull: + switch(e) { + case ENL(e1) : + if (e1 != null) { + var l:Int = output.length; + var needRebuild = rebuildToArray(e1, rebuildMethod, output); + var i:Int = output.length; + while (i-- > l) { + output[i] = ENL(output[i]); + } + return needRebuild; + } + default: + var expr:Expr = rebuildExprParams(e, rebuildMethod); + if (expr != null) { + output.push(expr); + return true; + } + } + case RSkip: + default: + } + output.push(e); + return false; + } private static function rebuildExprParams(e:Expr, rebuildMethod:Expr->RebuildResult):Expr { - switch(e) { - case EFunction(f, name): - var rexpr = rebuild(f.expr, rebuildMethod); - if (rexpr == null) return null; - return EFunction({args:f.args, varArgs:f.varArgs, ret:f.ret, expr:rexpr}, name); - case EBlock(es): - var needRebuild:Bool = false; - var r:Array = []; - for (e in es) { - var er:Expr = rebuild(e, rebuildMethod); - if (er != null) { - needRebuild = true; - r.push(er); - } else { - r.push(e); - } - } - if (needRebuild) { - return EBlock(r); - } else { - return null; - } - case EForEach(e1, e2, e3): - var re1:Expr = rebuild(e1, rebuildMethod); - var re2:Expr = rebuild(e2, rebuildMethod); - var re3:Expr = rebuild(e3, rebuildMethod); - if (re1 != null || re2 != null || re3 != null) { - if (re1 == null) re1 = e1; - if (re2 == null) re2 = e2; - if (re3 == null) re3 = e3; - return EForEach(re1, re2, re3); - } else { - return null; - } - case EWhile(e1, e2, e3): - var re1:Expr = rebuild(e1, rebuildMethod); - var re2:Expr = rebuild(e2, rebuildMethod); - if (re1 != null || re2 != null) { - if (re1 == null) re1 = e1; - if (re2 == null) re2 = e2; - return EWhile(re1, re2, e3); - } else { - return null; - } - case EIf(e1, e2, e3): - var re1:Expr = rebuild(e1, rebuildMethod); - var re2:Expr = rebuild(e2, rebuildMethod); - var re3:Expr = rebuild(e3, rebuildMethod); - if (re1 != null || re2 != null || re3 != null) { - if (re1 == null) re1 = e1; - if (re2 == null) re2 = e2; - if (re3 == null) re3 = e3; - return EIf(re1, re2, re3); - } else { - return null; - } - case EFor(e1, e2, e3, e4): - var re1:Array = rebuildArray(e1, rebuildMethod); - var re2:Array = rebuildArray(e2, rebuildMethod); - var re3:Array = rebuildArray(e3, rebuildMethod); - var re4:Expr = rebuild(e4, rebuildMethod); - if (re1 != null || re2 != null || re3 != null || re4 != null) { - if (re1 == null) re1 = e1; - if (re2 == null) re2 = e2; - if (re3 == null) re3 = e3; - if (re4 == null) re4 = e4; - return EFor(re1, re2, re3, re4); - } else { - return null; - } - case ETry(e, catches): //ETry( e : Expr, catches : Array<{ name : String, t : Null, e : Expr }> ) + switch(e) { + case EFunction(f, name): + var rexpr = rebuild(f.expr, rebuildMethod); + if (rexpr == null) return null; + return EFunction({args:f.args, varArgs:f.varArgs, ret:f.ret, expr:rexpr}, name); + case EBlock(es): + var r:Array = rebuildArray(es, rebuildMethod); + if (r == null) { + return null; + } else { + return EBlock(r); + } + case EForEach(e1, e2, e3): + var re1:Expr = rebuild(e1, rebuildMethod); + var re2:Expr = rebuild(e2, rebuildMethod); + var re3:Expr = rebuild(e3, rebuildMethod); + if (re1 != null || re2 != null || re3 != null) { + if (re1 == null) re1 = e1; + if (re2 == null) re2 = e2; + if (re3 == null) re3 = e3; + return EForEach(re1, re2, re3); + } else { + return null; + } + case EWhile(e1, e2, e3): + var re1:Expr = rebuild(e1, rebuildMethod); + var re2:Expr = rebuild(e2, rebuildMethod); + if (re1 != null || re2 != null) { + if (re1 == null) re1 = e1; + if (re2 == null) re2 = e2; + return EWhile(re1, re2, e3); + } else { + return null; + } + case EIf(e1, e2, e3): + var re1:Expr = rebuild(e1, rebuildMethod); + var re2:Expr = rebuild(e2, rebuildMethod); + var re3:Expr = rebuild(e3, rebuildMethod); + if (re1 != null || re2 != null || re3 != null) { + if (re1 == null) re1 = e1; + if (re2 == null) re2 = e2; + if (re3 == null) re3 = e3; + return EIf(re1, re2, re3); + } else { + return null; + } + case EFor(e1, e2, e3, e4): + var re1:Array = rebuildArray(e1, rebuildMethod); + var re2:Array = rebuildArray(e2, rebuildMethod); + var re3:Array = rebuildArray(e3, rebuildMethod); + var re4:Expr = rebuild(e4, rebuildMethod); + if (re1 != null || re2 != null || re3 != null || re4 != null) { + if (re1 == null) re1 = e1; + if (re2 == null) re2 = e2; + if (re3 == null) re3 = e3; + if (re4 == null) re4 = e4; + return EFor(re1, re2, re3, re4); + } else { + return null; + } + case ETry(e, catches): //ETry( e : Expr, catches : Array<{ name : String, t : Null, e : Expr }> ) var re:Expr = rebuild(e, rebuildMethod); var needRebuild = false; var rcatches:Array<{ name : String, t : Null, e : Expr }> = []; @@ -186,61 +202,57 @@ class RebuildUtils } else { return null; } - case ENew(t, params): - var rparams:Array = rebuildArray(params, rebuildMethod); - if (rparams != null) { - if (rparams == null) rparams = params; - return ENew(t, rparams); - } else { - return null; - } - case ENamespaceAccess(e, f): - var re:Expr = rebuild(e, rebuildMethod); - if (re == null) return null; - return ENamespaceAccess(re, f); - case EField(e, f): - var re:Expr = rebuild(e, rebuildMethod); - if (re == null) return null; - return EField(re, f); - case ECall(e, params): - var re:Expr = rebuild(e, rebuildMethod); - var rparams:Array = rebuildArray(params, rebuildMethod); - if (re != null || rparams != null) { - if (re == null) re = e; - if (rparams == null) rparams = params; - return ECall(re, rparams); - } else { - return null; - } - case EUnop(op, prefix, e): - var re:Expr = rebuild(e, rebuildMethod); - if (re == null) return null; - return EUnop(op, prefix, re); - case EParent(e): - var re:Expr = rebuild(e, rebuildMethod); - if (re == null) return null; - return EParent(re); - case EBinop(op, e1, e2, newLineAfterOp): - var re1:Expr = rebuild(e1, rebuildMethod); - var re2:Expr = rebuild(e2, rebuildMethod); - if (re1 != null || re2 != null) { - if (re1 == null) re1 = e1; - if (re2 == null) re2 = e2; - return EBinop(op, re1, re2, newLineAfterOp); - } else { - return null; - } - case ENL(e): - e = rebuild(e, rebuildMethod); - if (e == null) return null; - return ENL(e); - case ECommented(a, b, c, e): - e = rebuild(e, rebuildMethod); - if (e == null) return null; - return ECommented(a, b, c, e); - default: - } - return null; + case ENew(t, params): + var rparams:Array = rebuildArray(params, rebuildMethod); + if (rparams != null) { + if (rparams == null) rparams = params; + return ENew(t, rparams); + } else { + return null; + } + case ENamespaceAccess(e, f): + var re:Expr = rebuild(e, rebuildMethod); + if (re == null) return null; + return ENamespaceAccess(re, f); + case EField(e, f): + var re:Expr = rebuild(e, rebuildMethod); + if (re == null) return null; + return EField(re, f); + case ECall(e, params): + var re:Expr = rebuild(e, rebuildMethod); + var rparams:Array = rebuildArray(params, rebuildMethod); + if (re != null || rparams != null) { + if (re == null) re = e; + if (rparams == null) rparams = params; + return ECall(re, rparams); + } else { + return null; + } + case EUnop(op, prefix, e): + var re:Expr = rebuild(e, rebuildMethod); + if (re == null) return null; + return EUnop(op, prefix, re); + case EParent(e): + var re:Expr = rebuild(e, rebuildMethod); + if (re == null) return null; + return EParent(re); + case EBinop(op, e1, e2, newLineAfterOp): + var re1:Expr = rebuild(e1, rebuildMethod); + var re2:Expr = rebuild(e2, rebuildMethod); + if (re1 != null || re2 != null) { + if (re1 == null) re1 = e1; + if (re2 == null) re2 = e2; + return EBinop(op, re1, re2, newLineAfterOp); + } else { + return null; + } + case ECommented(a, b, c, e): + e = rebuild(e, rebuildMethod); + if (e == null) return null; + return ECommented(a, b, c, e); + default: + } + return null; } private static function rebuildSwitchDefault(def:SwitchDefault, rebuildMethod:Expr->RebuildResult):SwitchDefault { From dbc89902dd7ac777df3181a8e1be600afa6e1c86 Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 9 Jan 2018 11:34:16 +0300 Subject: [PATCH 059/156] relocation of local functions to the top of methods. --- src/as3hx/Writer.hx | 4 +++- src/as3hx/WriterUtils.hx | 43 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/as3hx/WriterUtils.hx diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 1f10590..74a8d46 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -987,6 +987,7 @@ class Writer writeArgs(f.args, f.varArgs); writeCloseStatement(); var es = formatBlockBody(f.expr); + es = WriterUtils.moveFunctionDeclarationsToTheTop(es); writeExpr(EBlock(es)); } @@ -1068,6 +1069,7 @@ class Writer formatBlock(es, function(e) return result); es.push(ENL(EReturn(result))); } + es = WriterUtils.moveFunctionDeclarationsToTheTop(es); writeStartStatement(); writeExpr(EBlock(es)); } @@ -3276,7 +3278,7 @@ class Writer default: } } - if(isIntExpr(lvalue)) { + if (isIntExpr(lvalue)) { if(needCastToInt(rvalue)) { switch(rvalue) { case EBinop(op, e1, e2, newLineAfterOp) if(isBitwiseOp(op)): rvalue = getResultForNumerics(op, e1, e2); diff --git a/src/as3hx/WriterUtils.hx b/src/as3hx/WriterUtils.hx new file mode 100644 index 0000000..71443d9 --- /dev/null +++ b/src/as3hx/WriterUtils.hx @@ -0,0 +1,43 @@ +package as3hx; +import as3hx.As3.Expr; +import as3hx.As3.SwitchCase; +import as3hx.As3.SwitchDefault; +import as3hx.As3.T; +import as3hx.RebuildUtils.RebuildResult; +import neko.Lib; + +class WriterUtils +{ + /** + * In AS3 local function declarations are available all throw parent function, but in haxe we need to declare them before usage. + * So we need to relocate local functions that they preceded the usage expressions. + * To keep result code more consistent let's move all function declarations to the begining of parent function. + **/ + public static function moveFunctionDeclarationsToTheTop(expressions:Array):Array { + var localFunctionDeclarations:Array = []; + function lookUpForLocalFunctions(e:Expr):RebuildResult { + switch(e) { + case EBinop(op, e1, e2, newLineAfterOp): + if (op == "=") { + switch(e2) { + case EFunction(f, name): + localFunctionDeclarations.push(ENL(e2)); + return RebuildResult.RReplace(EBinop("=", e1, EIdent(name), newLineAfterOp)); + default: + } + } + return RebuildResult.RSkip; + case EFunction(f, name): + localFunctionDeclarations.push(ENL(e)); + return RebuildResult.REmpty; + default: + } + return null; + } + var expressionsWithoutFunctions:Array = RebuildUtils.rebuildArray(expressions, lookUpForLocalFunctions); + if (expressionsWithoutFunctions == null) { + expressionsWithoutFunctions = expressions; + } + return localFunctionDeclarations.concat(expressionsWithoutFunctions); + } +} \ No newline at end of file From 3e3d03203d8bcecb3debc970c54c9eef7e634058 Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 9 Jan 2018 11:45:47 +0300 Subject: [PATCH 060/156] config option rebuildLocalFunctions (default true). Replacing of local function declarations with variable definitions now is optional --- src/as3hx/Config.hx | 4 ++++ src/as3hx/parsers/FunctionParser.hx | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index b32f090..3fd0382 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -61,6 +61,8 @@ class Config { public var useAngleBracketsNotationForDictionaryTyping : Bool; /** write inferred type information into output **/ public var debugInferredType : Bool; + /** replace local function declarations with variable definitions **/ + public var rebuildLocalFunctions : Bool; /** convert flexunit metadata and calls to munit form */ public var convertFlexunit : Bool; /** make all generated setter private */ @@ -343,6 +345,7 @@ class Config { case "conditionalCompilationList": setConditionalVars(el, new List()); case "conditionalCompilationConstantsClass":setCharField(el, ""); case "dictionaryToHash": setBoolField(el, false); + case "rebuildLocalFunctions": setBoolField(el, true); case "useAngleBracketsNotationForDictionaryTyping": setBoolField(el, true); case "useFastXML": setBoolField(el, true); case "useCompat": setBoolField(el, true); @@ -453,6 +456,7 @@ class Config { + diff --git a/src/as3hx/parsers/FunctionParser.hx b/src/as3hx/parsers/FunctionParser.hx index 6c26774..e127215 100644 --- a/src/as3hx/parsers/FunctionParser.hx +++ b/src/as3hx/parsers/FunctionParser.hx @@ -143,7 +143,9 @@ class FunctionParser { } } Debug.closeDebug("end parseFun()", tokenizer.line); - rebuildLocalFunctions(f); + if (cfg.rebuildLocalFunctions) { + rebuildLocalFunctions(f); + } return f; } From 55d9418fa922897fca80bf26837e188a06b0d2d8 Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 9 Jan 2018 12:33:23 +0300 Subject: [PATCH 061/156] config option `fixLocalVariableDeclarations` (default true). If true, first usage of local variable is forced to be EVar. Subsequent EVar's are replaced by regular assignment. --- src/as3hx/Config.hx | 4 ++ src/as3hx/VarExprFix.hx | 107 ++++++++++++++++++++++++++++++++++++++++ src/as3hx/Writer.hx | 6 +++ 3 files changed, 117 insertions(+) create mode 100644 src/as3hx/VarExprFix.hx diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index 3fd0382..763227b 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -55,6 +55,8 @@ class Config { public var conditionalVars: List; /** Compile time constants implementation class package path for CONFIG::VAR -> `compile.Time.Constants`.CONFIG_VAR**/ public var conditionalCompilationConstantsClass : String; + /** Try fix local variable declarations. In haxe variable should be declared only once and before first usage. **/ + public var fixLocalVariableDeclarations : Bool; /** Transform Dictionary. to Map **/ public var dictionaryToHash : Bool; /** if set to false `Dictionary\/*KeyType,ValueType*\/` notation will be used. By default Dictionary. notation is used **/ @@ -344,6 +346,7 @@ class Config { case "excludeList": setExcludeField(el, new List()); case "conditionalCompilationList": setConditionalVars(el, new List()); case "conditionalCompilationConstantsClass":setCharField(el, ""); + case "fixLocalVariableDeclarations":setBoolField(el, true); case "dictionaryToHash": setBoolField(el, false); case "rebuildLocalFunctions": setBoolField(el, true); case "useAngleBracketsNotationForDictionaryTyping": setBoolField(el, true); @@ -455,6 +458,7 @@ class Config { + diff --git a/src/as3hx/VarExprFix.hx b/src/as3hx/VarExprFix.hx new file mode 100644 index 0000000..b17eda3 --- /dev/null +++ b/src/as3hx/VarExprFix.hx @@ -0,0 +1,107 @@ +package as3hx; +import as3hx.As3.Expr; +import as3hx.RebuildUtils.RebuildResult; +import neko.Lib; + +/** + * ... + * @author xmi + */ +class VarExprFix +{ + private var cfg:Config; + + public function new(cfg:Config){ + this.cfg = cfg; + } + + public function apply(es:Array, typer:Typer):Array { + var map:Map = typer.getContextClone(); + var firstUse:Map = new Map(); + var firstUseLine:Map> = new Map>(); + for (v in map) { + firstUse.set(v, -1); + } + var line:Int = 0; + function rebuildMethodLookForVars(e:Expr):RebuildResult { + switch(e) { + case EIdent(v): + if (!firstUse.exists(v)) { + firstUse.set(v, line); + if (firstUseLine.exists(line)) { + firstUseLine.get(line).push(v); + } else { + firstUseLine.set(line, [v]); + } + } + case EFunction(f, v): + map.set(v, "Function"); + case EVars(vars/*Array<{ name : String, t : Null, val : Null }>*/): + var newVars:Array = []; + var hasChange:Bool = false; + for (vr in vars) { + var v:String = vr.name; + if (!firstUse.exists(v)) { + firstUse.set(v, -1); + newVars.push(EVars([vr])); + } else { + hasChange = true; + if (vr.val != null) { + newVars.push(EBinop("=", EIdent(v), vr.val, false)); + } + } + map.set(v, typer.tstring(vr.t)); + } + if (hasChange) { + return RebuildResult.RReplaceArray(newVars); + } + default: + } + return null; + } + function rebuildMethodPutVars(e:Expr):Array { + if (firstUseLine.exists(line)) { + var res:Array = []; + for (name in firstUseLine.get(line)) { + var type:String = map.get(name); + if (type == null) continue; + var defaultValue:Expr = null; + switch(type) { + case "int", "Int", "UInt": + defaultValue = EConst(CInt("0")); + case "Float": + defaultValue = EConst(CInt("Math.NaN")); + default: + defaultValue = EIdent("null"); + } + res.push(ENL( EVars([ { name:name, t:TPath([type]), val:defaultValue } ]))); + } + if (res.length > 0 ) { + res.push(e); + return res; + } + } + return null; + } + var res:Array = []; + res = RebuildUtils.rebuildArray(es, rebuildMethodLookForVars); + if (res == null) { + res = es; + } + es = res; + res = []; + for (i in 0...es.length) { + line = i; + var e:Expr = es[i]; + var a:Array = rebuildMethodPutVars(e); + if (a != null) { + for (e in a) { + res.push(e); + } + } else { + res.push(e); + } + } + return res; + } +} \ No newline at end of file diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 74a8d46..90f243c 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -988,6 +988,9 @@ class Writer writeCloseStatement(); var es = formatBlockBody(f.expr); es = WriterUtils.moveFunctionDeclarationsToTheTop(es); + if (cfg.fixLocalVariableDeclarations) { + es = new VarExprFix(cfg).apply(es, typer); + } writeExpr(EBlock(es)); } @@ -1070,6 +1073,9 @@ class Writer es.push(ENL(EReturn(result))); } es = WriterUtils.moveFunctionDeclarationsToTheTop(es); + if (cfg.fixLocalVariableDeclarations) { + es = new VarExprFix(cfg).apply(es, typer); + } writeStartStatement(); writeExpr(EBlock(es)); } From b97da1e740f6b6c4f1aa6eebb71acd233ebb5a39 Mon Sep 17 00:00:00 2001 From: xmitre Date: Thu, 11 Jan 2018 16:35:09 +0300 Subject: [PATCH 062/156] fix of RebuildUtils: correct replacing of commented Expr with array of Expr's --- src/as3hx/RebuildUtils.hx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/as3hx/RebuildUtils.hx b/src/as3hx/RebuildUtils.hx index ab04a7d..3d9c2dd 100644 --- a/src/as3hx/RebuildUtils.hx +++ b/src/as3hx/RebuildUtils.hx @@ -43,6 +43,13 @@ class RebuildUtils default: } switch(e) { + case ECommented(s, isBlock, isTail, e1): + var re = rebuild(e1, rebuildMethod); + if (re == null) { + return e; + } else { + return ECommented(s, isBlock, isTail, re); + } case ENL(e1): var re = rebuild(e1, rebuildMethod); if (re == null) { @@ -70,6 +77,17 @@ class RebuildUtils return true; case null, RNull: switch(e) { + case ECommented(s, isBlock, isTail, e1): + if (e1 != null) { + var l:Int = output.length; + var needRebuild = rebuildToArray(e1, rebuildMethod, output); + var i:Int = output.length; + while (i-- > l + 1) { + output[i] = output[i]; + } + output[i] = ECommented(s, isBlock, isTail, output[i]); + return needRebuild; + } case ENL(e1) : if (e1 != null) { var l:Int = output.length; From bdc1086ea63fd831df34b73a4568d7ca6fa88fc1 Mon Sep 17 00:00:00 2001 From: xmitre Date: Thu, 11 Jan 2018 16:40:22 +0300 Subject: [PATCH 063/156] not applying of moveFunctionDeclarationsToTheTop to the anonymous functions --- src/as3hx/ForLoopRebuild.hx | 392 ++++++++++++++++++++++++++++++++++++ src/as3hx/WriterUtils.hx | 11 +- 2 files changed, 399 insertions(+), 4 deletions(-) create mode 100644 src/as3hx/ForLoopRebuild.hx diff --git a/src/as3hx/ForLoopRebuild.hx b/src/as3hx/ForLoopRebuild.hx new file mode 100644 index 0000000..faf1d8f --- /dev/null +++ b/src/as3hx/ForLoopRebuild.hx @@ -0,0 +1,392 @@ +package as3hx; +import as3hx.As3.Expr; +import as3hx.RebuildUtils.RebuildResult; +import neko.Lib; + +/** + * ... + * @author xmi + */ + + +class LoopPosition { + public function new() { } + public var expr:Expr; + public var num:Int; +} + +class ForLoopRebuild +{ + private var loopsListPerLoopVar:Map> = new Map>(); + private var loopsListPerLoopVarStack:Array>> = new Array>>(); + private var loopNumToReplace:Map = new Map(); + private var forLoopNum:Int = 0; + + public function new() { + + } + private function rebuildLookUpPassArray(expressions:Array):Array { + var needUpdate:Bool = false; + var newExpressions:Array = []; + for (e in expressions) { + processLookUpPassExpr(e); + var re:Array = RebuildUtils.rebuildArray([e], rebuildLookUpPass); + if (re != null) { + for (r in re) { + newExpressions.push(r); + } + needUpdate = true; + } else { + newExpressions.push(e); + } + } + if (needUpdate) { + return newExpressions; + } else { + return null; + } + } + + public function replaceForLoopsWithWhile(expressions:Array):Array { + forLoopNum = 0; + + var re:Array = rebuildLookUpPassArray(expressions); + var rexpr:Expr = RebuildUtils.rebuild(EBlock(expressions), rebuildLookUpPass); + switch(rexpr) { + case null: + case EBlock(es): + expressions = es; + default: + } + + forLoopNum = 0; + re = RebuildUtils.rebuildArray(expressions, rebuildReplacePass); + if (re != null) { + expressions = re; + } + return expressions; + } + + + private function openBlockContext():Void { + loopsListPerLoopVarStack.push(loopsListPerLoopVar); + loopsListPerLoopVar = new Map>(); + } + + private function closeBlockContext():Void { + var old:Map> = loopsListPerLoopVar; + loopsListPerLoopVar = loopsListPerLoopVarStack.pop(); + for (key in old.keys()) { + if (loopsListPerLoopVar.exists(key)) { + loopsListPerLoopVar.set(key, loopsListPerLoopVar.get(key).concat(old.get(key))); + } else { + loopsListPerLoopVar.set(key, old.get(key)); + } + } + } + + private function convertEForToEWhile(inits:Array, conds:Array, incrs:Array, expr:Expr):Array { + incrs = incrs.map(function(e) return ENL(e)); + function insertIncrementsBeforeContinue(e:Expr):RebuildResult { + switch(e) { + case EFunction(_, _): + return RebuildResult.RSkip; + case EContinue: + return RebuildResult.RReplace(EBlock( incrs.concat([ENL(e)]))); + default: + } + return null; + } + var r:Expr = RebuildUtils.rebuild(expr, insertIncrementsBeforeContinue); + if (r == null) { + r = expr; + } + + var condition:Expr; + if (conds.length == 0) { + condition = EIdent("true"); + } else { + condition = conds[0]; + for (i in 1...conds.length) { + condition = EBinop("&&", condition, conds[i], false); + } + } + + var whileBody:Array = switch(r) { + case EBlock(e): e; + default: [r]; + } + whileBody = whileBody.concat(incrs); + + var result:Array = []; + for (init in inits) { + result.push(init); + } + result.push(EWhile(condition, EBlock(whileBody), false)); + + return result; + } + + private static function getForLoopVariable(incrementExprs:Array):String { + if (incrementExprs.length < 1) return null; + switch(incrementExprs[0]) { + case null: return null; + case EBinop(_, e, _, _): + switch(e) { + case EIdent(s): return s; + default: + } + case EUnop(_, _, e): + switch(e) { + case EIdent(s): return s; + default: + } + default: + } + return null; + } + + private function rebuildReplacePass(expr:Expr):RebuildResult { + switch(expr) { + case EFor(inits, conds, incrs, e): + if (loopNumToReplace.exists(forLoopNum++)) { + var res:Array = convertEForToEWhile(inits, conds, incrs, e); + + var resRebuild:Array = RebuildUtils.rebuildArray(res, rebuildReplacePass); + if (resRebuild != null) { + res = resRebuild; + } + + return RebuildResult.RReplaceArray(res); + } + default: + } + return null; + } + + private function storeLoop(loopVariable:String, loop:LoopPosition):Void { + if (loopsListPerLoopVar.exists(loopVariable)) { + loopsListPerLoopVar.get(loopVariable).push(loop); + } else { + loopsListPerLoopVar.set(loopVariable, [loop]); + } + } + + private function dropLoops(loopVariable:String):Void { + if (loopsListPerLoopVar.exists(loopVariable)) { + loopsListPerLoopVar.remove(loopVariable); + } + } + + private function replaceLoops(loopVariable:String):Void { + if (loopsListPerLoopVar.exists(loopVariable)) { + for (f in loopsListPerLoopVar.get(loopVariable)) { + loopNumToReplace.set(f.num, true); + + } + loopsListPerLoopVar.remove(loopVariable); + } + } + + private function processLookUpPassExpr(expr:Expr):Void { + var loopVariablesAccess:Map = getOverwrittenIdents(expr, loopsListPerLoopVar); + for (loopVariable in loopVariablesAccess.keys()) { + var wasOverwritten:Bool = loopVariablesAccess.get(loopVariable); + if (wasOverwritten) { + dropLoops(loopVariable); + } else { + replaceLoops(loopVariable); + } + } + } + + private function rebuildLookUpPass(expr:Expr):RebuildResult { + switch(expr) { + case EFor(inits, conds, incrs, e): + if (!canUseForLoop(inits, conds, incrs, e)) { + var r:Expr = RebuildUtils.rebuild(e, rebuildLookUpPass); + if (r != null) e = r; + var res:Array = convertEForToEWhile(inits, conds, incrs, e); + return RebuildResult.RReplaceArray(res); + } else { + var loopVariable:String = getForLoopVariable(incrs); + var loop:LoopPosition = new LoopPosition(); + loop.expr = expr; + loop.num = forLoopNum++; + storeLoop(loopVariable, loop); + + var r:Expr = RebuildUtils.rebuild(e, rebuildLookUpPass); + if (r != null) { + return RebuildResult.RReplace(EFor(inits, conds, incrs, r)); + } else { + return RebuildResult.RSkip; + } + } + case EBlock(expressions): + openBlockContext(); + var newExpressions:Array = rebuildLookUpPassArray(expressions); + closeBlockContext(); + if (newExpressions != null) { + return RebuildResult.RReplace(EBlock(newExpressions)); + } else { + return RebuildResult.RSkip; + } + default: + } + return null; + } + + private static function canUseForLoop(inits:Array, conds:Array, incrs:Array, e:Expr):Bool { + if (inits.length == 0 || conds.length != 1 || incrs.length != 1) return false; + var loopVariable:String = getForLoopVariable(incrs); + var loopIdent:Expr = EIdent(loopVariable); + + // if variable is not set up before loop, no FOR + switch(inits[inits.length - 1]) { + case EBinop("=", e1, e2, _): + if (!e1.equals(loopIdent)) { + return false; + } + case EVars(vars) if(vars.length > 1): return false; + default: return false; + } + + // if comparison is not `variable less then value`, no FOR + switch(conds[0]) { + case EBinop(op, e1, e2, _): + if (op == "<" || op == "<=") { + if (!e1.equals(loopIdent)) { + return false; + } + } else if (op == ">" || op == ">=") { + if (!e2.equals(loopIdent)) { + return false; + } + } else { + return false; + } + default: return false; + } + + // if variable is not incremented by 1, no FOR + switch(incrs[0]) { + case EUnop("++", _, e1): + if (!e1.equals(loopIdent)) { + return false; + } + case EBinop("+=", e1, e2, _): + if ( !e1.equals(loopIdent) || (!e2.equals(EConst(CInt("1"))) && !e2.equals(EConst(CFloat("1.0")))) ) { + return false; + } + case null: return false; + default: return false; + } + + // if variable is modified inside of loop, no FOR + if (checkIfUsesIdentForWriting(loopVariable, e, false)) { + return false; + } + + return true; + } + + private function getOverwrittenIdents(e:Expr, blockContext:Map>):Map { + var result:Map = new Map(); + for (key in loopsListPerLoopVar.keys()) { + if (checkIfUsesIdentValue(key, e)) { + result.set(key, false); + } else if (checkIfUsesIdentForWriting(key, e, true)) { + result.set(key, true); + } + } + return result; + } + + public static function checkIfUsesIdentValue(ident:String, expr:Expr):Bool { + var wasUsed:Bool = false; + function rebuild(e:Expr):RebuildResult { + switch(e) { + case EBlock(es): + for (e in es) { + if (checkIfUsesIdentValue(ident, e)) { + wasUsed = true; + break; + } else if (checkIfUsesIdentForWriting(ident, e, false)) { + break; + } + } + return RebuildResult.RSkip; + case EFor(inits, conds, incrs, e): + var uses:Bool = false; + var overwrites:Bool = false; + for (i in inits) { + if (checkIfUsesIdentValue(ident, i)) { + uses = true; + } else if (checkIfUsesIdentForWriting(ident, i, false)) { + overwrites = true; + } + } + if (overwrites && !uses) { + return RebuildResult.RSkip; + } + case EIdent(v): + if (v == ident) { + wasUsed = true; + return RebuildResult.RSkip; + } + case EBinop(op, e1, e2, _): + if (op == "=" && isIdent(e1, ident)) { + RebuildUtils.rebuild(e2, rebuild); + return RebuildResult.RSkip; + } + case EUnop(op, _, e): + if (isIdent(e, ident)) { + wasUsed = true; + return RebuildResult.RSkip; + } + default: + } + return null; + } + RebuildUtils.rebuild(expr, rebuild); + return wasUsed; + } + + public static function checkIfUsesIdentForWriting(ident:String, expr:Expr, definitelyOverwritten:Bool):Bool { + var result:Bool = false; + function rebuild(e:Expr):RebuildResult { + switch(e) { + case EIf(cond, e1, e2): + if (definitelyOverwritten) { + if (!result && checkIfUsesIdentForWriting(ident, e1, definitelyOverwritten) && checkIfUsesIdentForWriting(ident, e2, definitelyOverwritten)) { + result = true; + } + return RebuildResult.RSkip; + } + case EBinop(op, e1, _, _): + if (op.indexOf("=") != -1 && isIdent(e1, ident)) { + result = true; + return RebuildResult.RSkip; + } + case EUnop(op, _, e): + if (isIdent(e, ident)) { + result = true; + return RebuildResult.RSkip; + } + default: + } + return null; + } + RebuildUtils.rebuild(expr, rebuild); + return result; + } + + public static function isIdent(e:Expr, ident:String):Bool { + switch(e) { + case EParent(e): return isIdent(e, ident); + case EIdent(v): return v == ident; + default: + } + return false; + } +} \ No newline at end of file diff --git a/src/as3hx/WriterUtils.hx b/src/as3hx/WriterUtils.hx index 71443d9..57c930c 100644 --- a/src/as3hx/WriterUtils.hx +++ b/src/as3hx/WriterUtils.hx @@ -21,15 +21,18 @@ class WriterUtils if (op == "=") { switch(e2) { case EFunction(f, name): - localFunctionDeclarations.push(ENL(e2)); - return RebuildResult.RReplace(EBinop("=", e1, EIdent(name), newLineAfterOp)); + return RebuildResult.RSkip; default: } } return RebuildResult.RSkip; case EFunction(f, name): - localFunctionDeclarations.push(ENL(e)); - return RebuildResult.REmpty; + if (name != null) { + localFunctionDeclarations.push(ENL(e)); + return RebuildResult.REmpty; + } else { + return RebuildResult.RSkip; + } default: } return null; From 0ab382b070f136bf843a625b5dea926a6cf07f2c Mon Sep 17 00:00:00 2001 From: xmitre Date: Thu, 11 Jan 2018 16:41:28 +0300 Subject: [PATCH 064/156] fixes of Typer. method getContextClone --- src/as3hx/Typer.hx | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index 70dd5fc..ea6bcec 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -28,13 +28,27 @@ class Typer public function new(cfg:Config) { this.cfg = cfg; } + + public function getContextClone(relativeLevel:Int = 0):Map { + var context:Map; + if (relativeLevel < 0 && -relativeLevel <= contextStack.length) { + context = contextStack[contextStack.length + relativeLevel]; + } else { + context = this.context; + } + var clone:Map = new Map(); + for (v in context.keys()) { + clone.set(v, context.get(v)); + } + return clone; + } public function getExprType(e:Expr):Null { switch(e) { case ETypedExpr(e2, t): return tstring(t); case EField(e2, f): switch(e2) { - case EIdent("this"): return contextStack[0].get(f); + case EIdent("this"): return contextStack.length > 0 ? contextStack[0].get(f) : context.get(f); default: } var t2 = getExprType(e2); @@ -232,7 +246,7 @@ class Typer field = s; default: } - if (field != null) { + if (field != null && baseType != null) { if (classes.exists(baseType)) { if (!classFieldDictionaryTypes.exists(baseType)) { classFieldDictionaryTypes.set(baseType, new Map()); @@ -301,13 +315,17 @@ class Typer public function getDictionaryType(field:String):T { var m:Map = classFieldDictionaryTypes.get(currentPath); - if (m != null) { + if (m != null && field != null) { var d:DictionaryTypes = m.get(field); if (d != null) { var keyT:String = null; var valueT:String = null; for (t in d.key) keyT = foldDictionaryType(keyT, t); for (t in d.value) valueT = foldDictionaryType(valueT, t); + if (cfg.useOpenFlTypes) { + if (keyT == null || keyT == "Dynamic") keyT = "Object"; + if (valueT == null || valueT == "Dynamic") valueT = "Object"; + } return TDictionary(TPath([keyT]), TPath([valueT])); //return "Dictionary<" + d.key[0] + "," + d.value[0] + ">"; } From 8b8cfd684d9e0565afbf03ca47058ba5c215424b Mon Sep 17 00:00:00 2001 From: xmitre Date: Thu, 11 Jan 2018 16:48:52 +0300 Subject: [PATCH 065/156] fix of VarExprFix --- src/as3hx/VarExprFix.hx | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/as3hx/VarExprFix.hx b/src/as3hx/VarExprFix.hx index b17eda3..8e25834 100644 --- a/src/as3hx/VarExprFix.hx +++ b/src/as3hx/VarExprFix.hx @@ -1,5 +1,6 @@ package as3hx; import as3hx.As3.Expr; +import as3hx.As3.Function; import as3hx.RebuildUtils.RebuildResult; import neko.Lib; @@ -15,18 +16,24 @@ class VarExprFix this.cfg = cfg; } - public function apply(es:Array, typer:Typer):Array { - var map:Map = typer.getContextClone(); + public function apply(f:Function, es:Array, typer:Typer):Array { + var map:Map = typer.getContextClone(-1); var firstUse:Map = new Map(); var firstUseLine:Map> = new Map>(); - for (v in map) { + for (v in map.keys()) { firstUse.set(v, -1); } + for (arg in f.args) { + firstUse.set(arg.name, -1); + } + if (f.varArgs != null) { + firstUse.set(f.varArgs, -1); + } var line:Int = 0; function rebuildMethodLookForVars(e:Expr):RebuildResult { switch(e) { case EIdent(v): - if (!firstUse.exists(v)) { + if (v != null && !firstUse.exists(v)) { firstUse.set(v, line); if (firstUseLine.exists(line)) { firstUseLine.get(line).push(v); @@ -35,7 +42,9 @@ class VarExprFix } } case EFunction(f, v): - map.set(v, "Function"); + if (v != null) { + map.set(v, "Function"); + } case EVars(vars/*Array<{ name : String, t : Null, val : Null }>*/): var newVars:Array = []; var hasChange:Bool = false; From 99baa572f3a69fc7e5ebcbe9a376d4c4fec4fbec Mon Sep 17 00:00:00 2001 From: xmitre Date: Thu, 11 Jan 2018 16:51:17 +0300 Subject: [PATCH 066/156] revert of accidental commit --- src/as3hx/ForLoopRebuild.hx | 392 ------------------------------------ 1 file changed, 392 deletions(-) delete mode 100644 src/as3hx/ForLoopRebuild.hx diff --git a/src/as3hx/ForLoopRebuild.hx b/src/as3hx/ForLoopRebuild.hx deleted file mode 100644 index faf1d8f..0000000 --- a/src/as3hx/ForLoopRebuild.hx +++ /dev/null @@ -1,392 +0,0 @@ -package as3hx; -import as3hx.As3.Expr; -import as3hx.RebuildUtils.RebuildResult; -import neko.Lib; - -/** - * ... - * @author xmi - */ - - -class LoopPosition { - public function new() { } - public var expr:Expr; - public var num:Int; -} - -class ForLoopRebuild -{ - private var loopsListPerLoopVar:Map> = new Map>(); - private var loopsListPerLoopVarStack:Array>> = new Array>>(); - private var loopNumToReplace:Map = new Map(); - private var forLoopNum:Int = 0; - - public function new() { - - } - private function rebuildLookUpPassArray(expressions:Array):Array { - var needUpdate:Bool = false; - var newExpressions:Array = []; - for (e in expressions) { - processLookUpPassExpr(e); - var re:Array = RebuildUtils.rebuildArray([e], rebuildLookUpPass); - if (re != null) { - for (r in re) { - newExpressions.push(r); - } - needUpdate = true; - } else { - newExpressions.push(e); - } - } - if (needUpdate) { - return newExpressions; - } else { - return null; - } - } - - public function replaceForLoopsWithWhile(expressions:Array):Array { - forLoopNum = 0; - - var re:Array = rebuildLookUpPassArray(expressions); - var rexpr:Expr = RebuildUtils.rebuild(EBlock(expressions), rebuildLookUpPass); - switch(rexpr) { - case null: - case EBlock(es): - expressions = es; - default: - } - - forLoopNum = 0; - re = RebuildUtils.rebuildArray(expressions, rebuildReplacePass); - if (re != null) { - expressions = re; - } - return expressions; - } - - - private function openBlockContext():Void { - loopsListPerLoopVarStack.push(loopsListPerLoopVar); - loopsListPerLoopVar = new Map>(); - } - - private function closeBlockContext():Void { - var old:Map> = loopsListPerLoopVar; - loopsListPerLoopVar = loopsListPerLoopVarStack.pop(); - for (key in old.keys()) { - if (loopsListPerLoopVar.exists(key)) { - loopsListPerLoopVar.set(key, loopsListPerLoopVar.get(key).concat(old.get(key))); - } else { - loopsListPerLoopVar.set(key, old.get(key)); - } - } - } - - private function convertEForToEWhile(inits:Array, conds:Array, incrs:Array, expr:Expr):Array { - incrs = incrs.map(function(e) return ENL(e)); - function insertIncrementsBeforeContinue(e:Expr):RebuildResult { - switch(e) { - case EFunction(_, _): - return RebuildResult.RSkip; - case EContinue: - return RebuildResult.RReplace(EBlock( incrs.concat([ENL(e)]))); - default: - } - return null; - } - var r:Expr = RebuildUtils.rebuild(expr, insertIncrementsBeforeContinue); - if (r == null) { - r = expr; - } - - var condition:Expr; - if (conds.length == 0) { - condition = EIdent("true"); - } else { - condition = conds[0]; - for (i in 1...conds.length) { - condition = EBinop("&&", condition, conds[i], false); - } - } - - var whileBody:Array = switch(r) { - case EBlock(e): e; - default: [r]; - } - whileBody = whileBody.concat(incrs); - - var result:Array = []; - for (init in inits) { - result.push(init); - } - result.push(EWhile(condition, EBlock(whileBody), false)); - - return result; - } - - private static function getForLoopVariable(incrementExprs:Array):String { - if (incrementExprs.length < 1) return null; - switch(incrementExprs[0]) { - case null: return null; - case EBinop(_, e, _, _): - switch(e) { - case EIdent(s): return s; - default: - } - case EUnop(_, _, e): - switch(e) { - case EIdent(s): return s; - default: - } - default: - } - return null; - } - - private function rebuildReplacePass(expr:Expr):RebuildResult { - switch(expr) { - case EFor(inits, conds, incrs, e): - if (loopNumToReplace.exists(forLoopNum++)) { - var res:Array = convertEForToEWhile(inits, conds, incrs, e); - - var resRebuild:Array = RebuildUtils.rebuildArray(res, rebuildReplacePass); - if (resRebuild != null) { - res = resRebuild; - } - - return RebuildResult.RReplaceArray(res); - } - default: - } - return null; - } - - private function storeLoop(loopVariable:String, loop:LoopPosition):Void { - if (loopsListPerLoopVar.exists(loopVariable)) { - loopsListPerLoopVar.get(loopVariable).push(loop); - } else { - loopsListPerLoopVar.set(loopVariable, [loop]); - } - } - - private function dropLoops(loopVariable:String):Void { - if (loopsListPerLoopVar.exists(loopVariable)) { - loopsListPerLoopVar.remove(loopVariable); - } - } - - private function replaceLoops(loopVariable:String):Void { - if (loopsListPerLoopVar.exists(loopVariable)) { - for (f in loopsListPerLoopVar.get(loopVariable)) { - loopNumToReplace.set(f.num, true); - - } - loopsListPerLoopVar.remove(loopVariable); - } - } - - private function processLookUpPassExpr(expr:Expr):Void { - var loopVariablesAccess:Map = getOverwrittenIdents(expr, loopsListPerLoopVar); - for (loopVariable in loopVariablesAccess.keys()) { - var wasOverwritten:Bool = loopVariablesAccess.get(loopVariable); - if (wasOverwritten) { - dropLoops(loopVariable); - } else { - replaceLoops(loopVariable); - } - } - } - - private function rebuildLookUpPass(expr:Expr):RebuildResult { - switch(expr) { - case EFor(inits, conds, incrs, e): - if (!canUseForLoop(inits, conds, incrs, e)) { - var r:Expr = RebuildUtils.rebuild(e, rebuildLookUpPass); - if (r != null) e = r; - var res:Array = convertEForToEWhile(inits, conds, incrs, e); - return RebuildResult.RReplaceArray(res); - } else { - var loopVariable:String = getForLoopVariable(incrs); - var loop:LoopPosition = new LoopPosition(); - loop.expr = expr; - loop.num = forLoopNum++; - storeLoop(loopVariable, loop); - - var r:Expr = RebuildUtils.rebuild(e, rebuildLookUpPass); - if (r != null) { - return RebuildResult.RReplace(EFor(inits, conds, incrs, r)); - } else { - return RebuildResult.RSkip; - } - } - case EBlock(expressions): - openBlockContext(); - var newExpressions:Array = rebuildLookUpPassArray(expressions); - closeBlockContext(); - if (newExpressions != null) { - return RebuildResult.RReplace(EBlock(newExpressions)); - } else { - return RebuildResult.RSkip; - } - default: - } - return null; - } - - private static function canUseForLoop(inits:Array, conds:Array, incrs:Array, e:Expr):Bool { - if (inits.length == 0 || conds.length != 1 || incrs.length != 1) return false; - var loopVariable:String = getForLoopVariable(incrs); - var loopIdent:Expr = EIdent(loopVariable); - - // if variable is not set up before loop, no FOR - switch(inits[inits.length - 1]) { - case EBinop("=", e1, e2, _): - if (!e1.equals(loopIdent)) { - return false; - } - case EVars(vars) if(vars.length > 1): return false; - default: return false; - } - - // if comparison is not `variable less then value`, no FOR - switch(conds[0]) { - case EBinop(op, e1, e2, _): - if (op == "<" || op == "<=") { - if (!e1.equals(loopIdent)) { - return false; - } - } else if (op == ">" || op == ">=") { - if (!e2.equals(loopIdent)) { - return false; - } - } else { - return false; - } - default: return false; - } - - // if variable is not incremented by 1, no FOR - switch(incrs[0]) { - case EUnop("++", _, e1): - if (!e1.equals(loopIdent)) { - return false; - } - case EBinop("+=", e1, e2, _): - if ( !e1.equals(loopIdent) || (!e2.equals(EConst(CInt("1"))) && !e2.equals(EConst(CFloat("1.0")))) ) { - return false; - } - case null: return false; - default: return false; - } - - // if variable is modified inside of loop, no FOR - if (checkIfUsesIdentForWriting(loopVariable, e, false)) { - return false; - } - - return true; - } - - private function getOverwrittenIdents(e:Expr, blockContext:Map>):Map { - var result:Map = new Map(); - for (key in loopsListPerLoopVar.keys()) { - if (checkIfUsesIdentValue(key, e)) { - result.set(key, false); - } else if (checkIfUsesIdentForWriting(key, e, true)) { - result.set(key, true); - } - } - return result; - } - - public static function checkIfUsesIdentValue(ident:String, expr:Expr):Bool { - var wasUsed:Bool = false; - function rebuild(e:Expr):RebuildResult { - switch(e) { - case EBlock(es): - for (e in es) { - if (checkIfUsesIdentValue(ident, e)) { - wasUsed = true; - break; - } else if (checkIfUsesIdentForWriting(ident, e, false)) { - break; - } - } - return RebuildResult.RSkip; - case EFor(inits, conds, incrs, e): - var uses:Bool = false; - var overwrites:Bool = false; - for (i in inits) { - if (checkIfUsesIdentValue(ident, i)) { - uses = true; - } else if (checkIfUsesIdentForWriting(ident, i, false)) { - overwrites = true; - } - } - if (overwrites && !uses) { - return RebuildResult.RSkip; - } - case EIdent(v): - if (v == ident) { - wasUsed = true; - return RebuildResult.RSkip; - } - case EBinop(op, e1, e2, _): - if (op == "=" && isIdent(e1, ident)) { - RebuildUtils.rebuild(e2, rebuild); - return RebuildResult.RSkip; - } - case EUnop(op, _, e): - if (isIdent(e, ident)) { - wasUsed = true; - return RebuildResult.RSkip; - } - default: - } - return null; - } - RebuildUtils.rebuild(expr, rebuild); - return wasUsed; - } - - public static function checkIfUsesIdentForWriting(ident:String, expr:Expr, definitelyOverwritten:Bool):Bool { - var result:Bool = false; - function rebuild(e:Expr):RebuildResult { - switch(e) { - case EIf(cond, e1, e2): - if (definitelyOverwritten) { - if (!result && checkIfUsesIdentForWriting(ident, e1, definitelyOverwritten) && checkIfUsesIdentForWriting(ident, e2, definitelyOverwritten)) { - result = true; - } - return RebuildResult.RSkip; - } - case EBinop(op, e1, _, _): - if (op.indexOf("=") != -1 && isIdent(e1, ident)) { - result = true; - return RebuildResult.RSkip; - } - case EUnop(op, _, e): - if (isIdent(e, ident)) { - result = true; - return RebuildResult.RSkip; - } - default: - } - return null; - } - RebuildUtils.rebuild(expr, rebuild); - return result; - } - - public static function isIdent(e:Expr, ident:String):Bool { - switch(e) { - case EParent(e): return isIdent(e, ident); - case EIdent(v): return v == ident; - default: - } - return false; - } -} \ No newline at end of file From 7078d7b83df12b0302e3403261223f95aff077b1 Mon Sep 17 00:00:00 2001 From: xmitre Date: Thu, 11 Jan 2018 16:53:07 +0300 Subject: [PATCH 067/156] refactoring of replaceForLoopsWithWhile. Checking of usage of loop variable in current function context. If variable value will be used after loop, while is applied. --- src/as3hx/ForLoopRebuild.hx | 392 ++++++++++++++++++++++++++++++++++++ src/as3hx/Writer.hx | 142 ++++++------- src/as3hx/WriterUtils.hx | 4 + 3 files changed, 452 insertions(+), 86 deletions(-) create mode 100644 src/as3hx/ForLoopRebuild.hx diff --git a/src/as3hx/ForLoopRebuild.hx b/src/as3hx/ForLoopRebuild.hx new file mode 100644 index 0000000..faf1d8f --- /dev/null +++ b/src/as3hx/ForLoopRebuild.hx @@ -0,0 +1,392 @@ +package as3hx; +import as3hx.As3.Expr; +import as3hx.RebuildUtils.RebuildResult; +import neko.Lib; + +/** + * ... + * @author xmi + */ + + +class LoopPosition { + public function new() { } + public var expr:Expr; + public var num:Int; +} + +class ForLoopRebuild +{ + private var loopsListPerLoopVar:Map> = new Map>(); + private var loopsListPerLoopVarStack:Array>> = new Array>>(); + private var loopNumToReplace:Map = new Map(); + private var forLoopNum:Int = 0; + + public function new() { + + } + private function rebuildLookUpPassArray(expressions:Array):Array { + var needUpdate:Bool = false; + var newExpressions:Array = []; + for (e in expressions) { + processLookUpPassExpr(e); + var re:Array = RebuildUtils.rebuildArray([e], rebuildLookUpPass); + if (re != null) { + for (r in re) { + newExpressions.push(r); + } + needUpdate = true; + } else { + newExpressions.push(e); + } + } + if (needUpdate) { + return newExpressions; + } else { + return null; + } + } + + public function replaceForLoopsWithWhile(expressions:Array):Array { + forLoopNum = 0; + + var re:Array = rebuildLookUpPassArray(expressions); + var rexpr:Expr = RebuildUtils.rebuild(EBlock(expressions), rebuildLookUpPass); + switch(rexpr) { + case null: + case EBlock(es): + expressions = es; + default: + } + + forLoopNum = 0; + re = RebuildUtils.rebuildArray(expressions, rebuildReplacePass); + if (re != null) { + expressions = re; + } + return expressions; + } + + + private function openBlockContext():Void { + loopsListPerLoopVarStack.push(loopsListPerLoopVar); + loopsListPerLoopVar = new Map>(); + } + + private function closeBlockContext():Void { + var old:Map> = loopsListPerLoopVar; + loopsListPerLoopVar = loopsListPerLoopVarStack.pop(); + for (key in old.keys()) { + if (loopsListPerLoopVar.exists(key)) { + loopsListPerLoopVar.set(key, loopsListPerLoopVar.get(key).concat(old.get(key))); + } else { + loopsListPerLoopVar.set(key, old.get(key)); + } + } + } + + private function convertEForToEWhile(inits:Array, conds:Array, incrs:Array, expr:Expr):Array { + incrs = incrs.map(function(e) return ENL(e)); + function insertIncrementsBeforeContinue(e:Expr):RebuildResult { + switch(e) { + case EFunction(_, _): + return RebuildResult.RSkip; + case EContinue: + return RebuildResult.RReplace(EBlock( incrs.concat([ENL(e)]))); + default: + } + return null; + } + var r:Expr = RebuildUtils.rebuild(expr, insertIncrementsBeforeContinue); + if (r == null) { + r = expr; + } + + var condition:Expr; + if (conds.length == 0) { + condition = EIdent("true"); + } else { + condition = conds[0]; + for (i in 1...conds.length) { + condition = EBinop("&&", condition, conds[i], false); + } + } + + var whileBody:Array = switch(r) { + case EBlock(e): e; + default: [r]; + } + whileBody = whileBody.concat(incrs); + + var result:Array = []; + for (init in inits) { + result.push(init); + } + result.push(EWhile(condition, EBlock(whileBody), false)); + + return result; + } + + private static function getForLoopVariable(incrementExprs:Array):String { + if (incrementExprs.length < 1) return null; + switch(incrementExprs[0]) { + case null: return null; + case EBinop(_, e, _, _): + switch(e) { + case EIdent(s): return s; + default: + } + case EUnop(_, _, e): + switch(e) { + case EIdent(s): return s; + default: + } + default: + } + return null; + } + + private function rebuildReplacePass(expr:Expr):RebuildResult { + switch(expr) { + case EFor(inits, conds, incrs, e): + if (loopNumToReplace.exists(forLoopNum++)) { + var res:Array = convertEForToEWhile(inits, conds, incrs, e); + + var resRebuild:Array = RebuildUtils.rebuildArray(res, rebuildReplacePass); + if (resRebuild != null) { + res = resRebuild; + } + + return RebuildResult.RReplaceArray(res); + } + default: + } + return null; + } + + private function storeLoop(loopVariable:String, loop:LoopPosition):Void { + if (loopsListPerLoopVar.exists(loopVariable)) { + loopsListPerLoopVar.get(loopVariable).push(loop); + } else { + loopsListPerLoopVar.set(loopVariable, [loop]); + } + } + + private function dropLoops(loopVariable:String):Void { + if (loopsListPerLoopVar.exists(loopVariable)) { + loopsListPerLoopVar.remove(loopVariable); + } + } + + private function replaceLoops(loopVariable:String):Void { + if (loopsListPerLoopVar.exists(loopVariable)) { + for (f in loopsListPerLoopVar.get(loopVariable)) { + loopNumToReplace.set(f.num, true); + + } + loopsListPerLoopVar.remove(loopVariable); + } + } + + private function processLookUpPassExpr(expr:Expr):Void { + var loopVariablesAccess:Map = getOverwrittenIdents(expr, loopsListPerLoopVar); + for (loopVariable in loopVariablesAccess.keys()) { + var wasOverwritten:Bool = loopVariablesAccess.get(loopVariable); + if (wasOverwritten) { + dropLoops(loopVariable); + } else { + replaceLoops(loopVariable); + } + } + } + + private function rebuildLookUpPass(expr:Expr):RebuildResult { + switch(expr) { + case EFor(inits, conds, incrs, e): + if (!canUseForLoop(inits, conds, incrs, e)) { + var r:Expr = RebuildUtils.rebuild(e, rebuildLookUpPass); + if (r != null) e = r; + var res:Array = convertEForToEWhile(inits, conds, incrs, e); + return RebuildResult.RReplaceArray(res); + } else { + var loopVariable:String = getForLoopVariable(incrs); + var loop:LoopPosition = new LoopPosition(); + loop.expr = expr; + loop.num = forLoopNum++; + storeLoop(loopVariable, loop); + + var r:Expr = RebuildUtils.rebuild(e, rebuildLookUpPass); + if (r != null) { + return RebuildResult.RReplace(EFor(inits, conds, incrs, r)); + } else { + return RebuildResult.RSkip; + } + } + case EBlock(expressions): + openBlockContext(); + var newExpressions:Array = rebuildLookUpPassArray(expressions); + closeBlockContext(); + if (newExpressions != null) { + return RebuildResult.RReplace(EBlock(newExpressions)); + } else { + return RebuildResult.RSkip; + } + default: + } + return null; + } + + private static function canUseForLoop(inits:Array, conds:Array, incrs:Array, e:Expr):Bool { + if (inits.length == 0 || conds.length != 1 || incrs.length != 1) return false; + var loopVariable:String = getForLoopVariable(incrs); + var loopIdent:Expr = EIdent(loopVariable); + + // if variable is not set up before loop, no FOR + switch(inits[inits.length - 1]) { + case EBinop("=", e1, e2, _): + if (!e1.equals(loopIdent)) { + return false; + } + case EVars(vars) if(vars.length > 1): return false; + default: return false; + } + + // if comparison is not `variable less then value`, no FOR + switch(conds[0]) { + case EBinop(op, e1, e2, _): + if (op == "<" || op == "<=") { + if (!e1.equals(loopIdent)) { + return false; + } + } else if (op == ">" || op == ">=") { + if (!e2.equals(loopIdent)) { + return false; + } + } else { + return false; + } + default: return false; + } + + // if variable is not incremented by 1, no FOR + switch(incrs[0]) { + case EUnop("++", _, e1): + if (!e1.equals(loopIdent)) { + return false; + } + case EBinop("+=", e1, e2, _): + if ( !e1.equals(loopIdent) || (!e2.equals(EConst(CInt("1"))) && !e2.equals(EConst(CFloat("1.0")))) ) { + return false; + } + case null: return false; + default: return false; + } + + // if variable is modified inside of loop, no FOR + if (checkIfUsesIdentForWriting(loopVariable, e, false)) { + return false; + } + + return true; + } + + private function getOverwrittenIdents(e:Expr, blockContext:Map>):Map { + var result:Map = new Map(); + for (key in loopsListPerLoopVar.keys()) { + if (checkIfUsesIdentValue(key, e)) { + result.set(key, false); + } else if (checkIfUsesIdentForWriting(key, e, true)) { + result.set(key, true); + } + } + return result; + } + + public static function checkIfUsesIdentValue(ident:String, expr:Expr):Bool { + var wasUsed:Bool = false; + function rebuild(e:Expr):RebuildResult { + switch(e) { + case EBlock(es): + for (e in es) { + if (checkIfUsesIdentValue(ident, e)) { + wasUsed = true; + break; + } else if (checkIfUsesIdentForWriting(ident, e, false)) { + break; + } + } + return RebuildResult.RSkip; + case EFor(inits, conds, incrs, e): + var uses:Bool = false; + var overwrites:Bool = false; + for (i in inits) { + if (checkIfUsesIdentValue(ident, i)) { + uses = true; + } else if (checkIfUsesIdentForWriting(ident, i, false)) { + overwrites = true; + } + } + if (overwrites && !uses) { + return RebuildResult.RSkip; + } + case EIdent(v): + if (v == ident) { + wasUsed = true; + return RebuildResult.RSkip; + } + case EBinop(op, e1, e2, _): + if (op == "=" && isIdent(e1, ident)) { + RebuildUtils.rebuild(e2, rebuild); + return RebuildResult.RSkip; + } + case EUnop(op, _, e): + if (isIdent(e, ident)) { + wasUsed = true; + return RebuildResult.RSkip; + } + default: + } + return null; + } + RebuildUtils.rebuild(expr, rebuild); + return wasUsed; + } + + public static function checkIfUsesIdentForWriting(ident:String, expr:Expr, definitelyOverwritten:Bool):Bool { + var result:Bool = false; + function rebuild(e:Expr):RebuildResult { + switch(e) { + case EIf(cond, e1, e2): + if (definitelyOverwritten) { + if (!result && checkIfUsesIdentForWriting(ident, e1, definitelyOverwritten) && checkIfUsesIdentForWriting(ident, e2, definitelyOverwritten)) { + result = true; + } + return RebuildResult.RSkip; + } + case EBinop(op, e1, _, _): + if (op.indexOf("=") != -1 && isIdent(e1, ident)) { + result = true; + return RebuildResult.RSkip; + } + case EUnop(op, _, e): + if (isIdent(e, ident)) { + result = true; + return RebuildResult.RSkip; + } + default: + } + return null; + } + RebuildUtils.rebuild(expr, rebuild); + return result; + } + + public static function isIdent(e:Expr, ident:String):Bool { + switch(e) { + case EParent(e): return isIdent(e, ident); + case EIdent(v): return v == ident; + default: + } + return false; + } +} \ No newline at end of file diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 90f243c..772da00 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -989,7 +989,7 @@ class Writer var es = formatBlockBody(f.expr); es = WriterUtils.moveFunctionDeclarationsToTheTop(es); if (cfg.fixLocalVariableDeclarations) { - es = new VarExprFix(cfg).apply(es, typer); + es = new VarExprFix(cfg).apply(f, es, typer); } writeExpr(EBlock(es)); } @@ -1073,8 +1073,9 @@ class Writer es.push(ENL(EReturn(result))); } es = WriterUtils.moveFunctionDeclarationsToTheTop(es); + es = WriterUtils.replaceForLoopsWithWhile(es); if (cfg.fixLocalVariableDeclarations) { - es = new VarExprFix(cfg).apply(es, typer); + es = new VarExprFix(cfg).apply(f, es, typer); } writeStartStatement(); writeExpr(EBlock(es)); @@ -1323,8 +1324,8 @@ class Writer } function writeModifiedIdent(s : String) { - write(getModifiedIdent(s)); - } + write(getModifiedIdent(s)); + } /** * Write an expression @@ -2130,95 +2131,64 @@ class Writer inline function writeEFor(inits:Array, conds:Array, incrs:Array, e:Expr):BlockEnd { //Sys.println('inits: ${inits}; conds: ${conds}; incrs: ${incrs}'); openContext(); - var useWhileLoop:Void->Bool = function() { - if (inits.empty() || conds.empty()) return true; - switch(inits[0]) { - case EVars(vars) if(vars.length > 1): return true; - case EIdent(v): return true; - default: - } - if (conds[0].match(EBinop("&&" | "||", _, _, _))) return true; - //index must be incremented by 1 - if (incrs.length == 1) { - return switch(incrs[0]) { - case EUnop(op, _, _): op != "++"; - case EBinop(openb,_,_,_): true; - default: false; - } - } - return true; + for (i in 0...inits.length - 1) { + var e:Expr = inits[i]; + writeExpr(ENL(e)); } - var isWhileLoop = useWhileLoop(); - if (!isWhileLoop) { - write("for ("); - switch(inits[0]) { - case EVars(v): - write(v[0].name); + write("for ("); + if (inits.length == 0) { + neko.Lib.println(inits + ";" + conds + ";" + incrs + " : " + e); + } + switch(inits[inits.length - 1]) { + case EVars(v): + write(v[0].name); + write(" in "); + writeExpr(v[0].val); + write("..."); + // var i:int = 0; + // for (i = 0; i < size; i++) + case EBinop(op, e1, e2, newLineAfterOp): + if (op == "=") { + switch (e1) { + case EIdent(v): write(v); + default: + } write(" in "); - writeExpr(v[0].val); + writeExpr(e2); write("..."); - // var i:int = 0; - // for (i = 0; i < size; i++) - case EBinop(op, e1, e2, newLineAfterOp): - if (op == "=") { - switch (e1) { - case EIdent(v): write(v); - default: + } + default: + } + switch(conds[0]) { + case EBinop(op, e1, e2, nl): + switch(op) { + case ">", ">=": + var t:Expr = e1; + e1 = e2; + e2 = t; + default: + } + switch(op) { + //corner case, for "<=" binop, limit value should be incremented + case "<=", ">=": + switch(e2) { + case EConst(CInt(v)): + //increment int constants + var e = EConst(CInt(Std.string(Std.parseInt(v) + 1))); + writeExpr(e2); + case _: + //when var used (like <= array.length), no choice but + //to append "+1" + writeExpr(e2); + write(" + 1"); } - write(" in "); - writeExpr(e2); - write("..."); - } - default: - } - switch(conds[0]) { - case EBinop(op, e1, e2, nl): - switch(op) { - //corne case, for "<=" binop, limit value should be incremented - case "<=": - switch(e2) { - case EConst(CInt(v)): - //increment int constants - var e = EConst(CInt(Std.string(Std.parseInt(v) + 1))); - writeExpr(e2); - case _: - //when var used (like <= array.length), no choice but - //to append "+1" - writeExpr(e2); - write(" + 1"); - } - case _: writeExpr(e2); - } - writeCloseStatement(); - default: - } - } else { - inits = inits.filter(function(it) return !it.match(EIdent(_))); - for(init in inits) { - writeExpr(init); - writeNL(";"); - } - if(!inits.empty()) writeIndent(); - write("while ("); - if (conds.empty()) { - write("true"); - } else { - for (i in 0...conds.length) { - if (i > 0) - write(" && "); - writeExpr(conds[i]); + case _: writeExpr(e2); } - } - writeCloseStatement(); + writeCloseStatement(); + default: } var es = formatBlockBody(e); - //don't write increments for a "for" loop - if (isWhileLoop) { - for (incr in incrs) { - es.push(ENL(incr)); - } - } - writeLoop(isWhileLoop ? incrs : [], function() { writeExpr(EBlock(es)); }); + writeLoop([], function() { writeExpr(EBlock(es)); }); closeContext(); return None; } diff --git a/src/as3hx/WriterUtils.hx b/src/as3hx/WriterUtils.hx index 57c930c..d444ce8 100644 --- a/src/as3hx/WriterUtils.hx +++ b/src/as3hx/WriterUtils.hx @@ -43,4 +43,8 @@ class WriterUtils } return localFunctionDeclarations.concat(expressionsWithoutFunctions); } + + public static function replaceForLoopsWithWhile(expressions:Array):Array { + return new ForLoopRebuild().replaceForLoopsWithWhile(expressions); + } } \ No newline at end of file From 4f936123f1a51329fd093c72b0bb4421183b5a08 Mon Sep 17 00:00:00 2001 From: xmitre Date: Thu, 11 Jan 2018 18:03:00 +0300 Subject: [PATCH 068/156] resolving of constructions booleanCondition || method(); and booleanCondition && method(); in blocks of code and comments in typed expressions --- src/as3hx/Writer.hx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 772da00..82f459c 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -721,7 +721,7 @@ class Writer if(val != null) { write(" = "); lvl++; //extra indenting if init is on multiple lines - writeExpr(ETypedExpr(val, t)); + writeETypedExpr(val, t); lvl--; } @@ -1705,7 +1705,8 @@ class Writer write("{"); lvl++; for (ex in e) { - writeFinish(writeExpr(ex)); + + writeFinish(writeETypedExpr(ex, TPath([null]))); } lvl--; write(closeb()); @@ -2727,6 +2728,8 @@ class Writer switch(e) { case ENL(e2): return writeExpr(ENL(ETypedExpr(e2, t))); + case ECommented(s, isBlock, isTail, e2): + return writeECommented(s, isBlock, isTail, ETypedExpr(e2, t)); case ENew(t2, params): switch (t2) { case TDictionary(k, v): @@ -2746,8 +2749,9 @@ class Writer if (re != null) { e = re; } - case "Int": - if (getExprType(e) != "Int") { + case "Int", "Uint": + var et:String = getExprType(e); + if (et != "Int" && et != "UInt") { e = getCastToIntExpr(e); //e = ECall(EField(EIdent("Std"), "int"), [ETypedExpr(e, null)]); } From 779f37bd2dc6967ac698f7b9405d8365804ba17f Mon Sep 17 00:00:00 2001 From: xmitre Date: Thu, 11 Jan 2018 18:15:41 +0300 Subject: [PATCH 069/156] now guessing of dictionary types can extract types from reversed typedValue=dict[key]; --- src/as3hx/Typer.hx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index ea6bcec..72e6c77 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -285,6 +285,11 @@ class Typer refineArrayAccess(e1, index, e2); default: } + switch(e2) { + case EArray(e2, index): + refineArrayAccess(e2, index, e1); + default: + } case EArray(e1, index): refineArrayAccess(e1, index, null); default: From af63e56900c5e60beedd5b1f4ba99bd105f50a0b Mon Sep 17 00:00:00 2001 From: xmitre Date: Thu, 11 Jan 2018 18:47:05 +0300 Subject: [PATCH 070/156] usage of stringified types while recovering types for dictionary constructor from variable type --- src/as3hx/Writer.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 82f459c..edcf113 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -2734,6 +2734,8 @@ class Writer switch (t2) { case TDictionary(k, v): switch (t) { + case TPath(p) if (p.length == 1) : + return writeExpr(ENew(t, params)); case TDictionary(k, v): return writeExpr(ENew(t, params)); default: From 74d6af6a735782d9c6b7eb0f2b862e5bc880d393 Mon Sep 17 00:00:00 2001 From: xmitre Date: Thu, 11 Jan 2018 19:25:53 +0300 Subject: [PATCH 071/156] handling of imports and self type in class typization --- src/as3hx/Typer.hx | 28 +++++++++++++++++++++------- src/as3hx/Writer.hx | 3 ++- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index 72e6c77..4398158 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -24,6 +24,7 @@ class Typer var context : Map = new Map(); var contextStack : Array> = []; var currentPath:String = null; + var importsMap : Map; public function new(cfg:Config) { this.cfg = cfg; @@ -71,11 +72,19 @@ class Typer default: } var ts:String = getExprType(e2); - if (ts != null && classes.exists(ts)) { - return classes.get(ts).get(f); - } else { - return null; + if (ts != null) { + if (context.exists(ts)) { + ts = context.get(ts); + } + if (classes.exists(ts)) { + return classes.get(ts).get(f); + } else if (importsMap != null && importsMap.exists(ts)) { + if (classes.exists(ts)) { + return classes.get(importsMap.get(ts)).get(f); + } + } } + return null; case EIdent(s): s = getModifiedIdent(s); return context.get(s); @@ -146,7 +155,7 @@ class Typer public function addClass(path:String, c:ClassDef):Void { var classMap:Map = new Map(); - parseClassFields(c, classMap); + parseClassFields(path, c, classMap); classes[path] = classMap; } @@ -155,10 +164,14 @@ class Typer var classMap:Map = classes.get(path); if (classMap == null) { classMap = new Map(); - parseClassFields(c, classMap); + parseClassFields(path, c, classMap); } contextStack[contextStack.length - 1] = context = classMap; } + + public function setImports(importsMap:Map):Void { + this.importsMap = importsMap; + } public function enterFunction(f:Function):Void { openContext(); @@ -188,7 +201,7 @@ class Typer closeContext(); } - function parseClassFields(c:ClassDef, map:Map):Void { + function parseClassFields(path:String, c:ClassDef, map:Map):Void { for (field in c.fields) { switch(field.kind) { case FVar(t, val): @@ -202,6 +215,7 @@ class Typer default: } } + map.set(c.name, path); } public function applyRefinedTypes(program:Program):Void { diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index edcf113..058d2b6 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -359,6 +359,7 @@ class Writer var path:String = (pack.length > 0 ? pack.join(".") + "." : "") + c.name; typer.enterClass(path, c); + typer.setImports(typeImportMap); // process properties writeProperties(c); @@ -2920,7 +2921,7 @@ class Writer default: EBinop("!=", e, EIdent("null"), false); } case EBinop(op, e2, e3, n): - if(isBitwiseOp(op)) return EBinop("!=", EParent(e), EConst(CInt("0")), false); + if(isBitwiseOp(op) || isNumericOp(op)) return EBinop("!=", EParent(e), EConst(CInt("0")), false); if(isNumericConst(e2) || isNumericConst(e3)) return null; if(op == "==" || op == "!=" || op == "!==" || op == "===") return null; if(op == "is" || op == "in" || op == "as") return null; From b9f6b3d8ba8cde63b695b544edec0c0251bf85ba Mon Sep 17 00:00:00 2001 From: xmitre Date: Thu, 11 Jan 2018 19:30:08 +0300 Subject: [PATCH 072/156] type fixing of return value in functions --- src/as3hx/Writer.hx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 058d2b6..2ee2737 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -39,6 +39,7 @@ class Writer var inE4XFilter : Bool; var inLvalAssign : Bool; // current expr is lvalue in assignment (expr = valOfSomeSort) var rvalue : Expr; + var functionReturnType : T; var typeImportMap : Map; var lineIsDirty : Bool; // current line contains some non-whitespace/indent characters var pendingTailComment : String; // one line comment that needs to be written at the end of line @@ -1028,6 +1029,9 @@ class Writer } function writeFunction(f : Function, isGetter:Bool, isSetter:Bool, isNative:Bool, ?name : Null, ?ret : FunctionRet) { + var oldFunctionReturnType:T = functionReturnType; + functionReturnType = f.ret.t; + write("function"); if(name != null) write(" " + name); @@ -1080,6 +1084,7 @@ class Writer } writeStartStatement(); writeExpr(EBlock(es)); + functionReturnType = oldFunctionReturnType; } /** @@ -1109,7 +1114,7 @@ class Writer write("return"); if(e == null) return; write(" "); - writeExpr(e); + writeETypedExpr(e, functionReturnType); } function writeEArray(e:Expr, index:Expr) { From e6057dca263344313ac2fbc21a1ce18795e98680 Mon Sep 17 00:00:00 2001 From: xmitre Date: Fri, 12 Jan 2018 11:31:52 +0300 Subject: [PATCH 073/156] boolean type check of while loop condition --- src/as3hx/Writer.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 2ee2737..6419e7e 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -2124,7 +2124,7 @@ class Writer writeExpr(EBlock(formatBlockBody(e))); writeStartStatement(); write("while ("); - result = writeExpr(cond); + result = writeExpr(rebuildIfExpr(cond)); write(")"); } else { write("while ("); From e9b8f8cbe7ec002edcbaa92d31bad3fa07c5aa3a Mon Sep 17 00:00:00 2001 From: xmitre Date: Mon, 15 Jan 2018 11:27:47 +0300 Subject: [PATCH 074/156] add imports of refined types of dictionary --- src/as3hx/Typer.hx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index 4398158..1795b09 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -226,6 +226,13 @@ class Typer enterClass(pack + c.name, c); for (f in c.fields) { var t:T = getDictionaryType(f.name); + switch (t) { + case TDictionary(k, v): + addImport(program, k); + addImport(program, v); + case null: + default: + } var d:String = tstring(t); if (t != null) { switch(f.kind) { @@ -394,6 +401,10 @@ class Typer function closeContext() { context = contextStack.pop(); } + + function addImport(program:Program, t:T):Void { + program.typesSeen.push(t); + } public static function getFunctionType(f:Function):T { var t = f.args.map(function(it) return it.t); From dcbc952130431b74f94807fa4c5ab514c865aba0 Mon Sep 17 00:00:00 2001 From: xmitre Date: Mon, 15 Jan 2018 11:35:13 +0300 Subject: [PATCH 075/156] converting delete with dot field access to Reflect.deleteField for anonymous objects --- src/as3hx/Writer.hx | 66 ++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 6419e7e..1995e58 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -2748,8 +2748,8 @@ class Writer } default: } - default: - } + default: + } // fix of such constructions var tail:Signal = s || p; switch(tstring(t)) { case "Bool": @@ -2775,37 +2775,43 @@ class Writer return writeExpr(e); } - inline function writeEDelete(e:Expr) { - switch(e) { - case EArray(a, i): - var atype = getExprType(a); - if (atype != null) { - if (isMapType(atype) || isOpenFlDictionaryType(atype)) { - writeExpr(a); - write(".remove("); - writeExpr(i); - write(")"); - } else if (atype == "Dynamic") { - switch(i) { - case EConst(c): - switch(c) { - case CInt(v) | CFloat(v): i = EConst(CString(v)); - default: - } - case EIdent(_): - var type = getExprType(i); - if (type == null || type != "String") { - i = getToStringExpr(i); - } + private function writeDelete(object:Expr, index:Expr):Void { + var atype = getExprType(object); + if (atype != null) { + if (isMapType(atype) || isOpenFlDictionaryType(atype)) { + writeExpr(object); + write(".remove("); + writeExpr(index); + write(")"); + } else if (atype == "Dynamic") { + switch(index) { + case EConst(c): + switch(c) { + case CInt(v) | CFloat(v): index = EConst(CString(v)); default: } - writeExpr(ECall(EField(EIdent("Reflect"), "deleteField"), [a, i])); - } else if(atype == "Dictionary") { - addWarning("EDelete"); - writeNL("This is an intentional compilation error. See the README for handling the delete keyword"); - writeIndent('delete ${getIdentString(a)}[${getIdentString(i)}]'); - } + case EIdent(_): + var type = getExprType(index); + if (type == null || type != "String") { + index = getToStringExpr(index); + } + default: } + writeExpr(ECall(EField(EIdent("Reflect"), "deleteField"), [object, index])); + } else if(atype == "Dictionary") { + addWarning("EDelete"); + writeNL("This is an intentional compilation error. See the README for handling the delete keyword"); + writeIndent('delete ${getIdentString(object)}[${getIdentString(index)}]'); + } + } + } + + inline function writeEDelete(e:Expr) { + switch(e) { + case EField(e, f): + writeDelete(e, EConst(CString(f))); + case EArray(a, i): + writeDelete(a, i); default: addWarning("EDelete"); writeNL("This is an intentional compilation error. See the README for handling the delete keyword"); From 7de9de2456a44a342e9c765968cff28c076daf4b Mon Sep 17 00:00:00 2001 From: xmitre Date: Mon, 15 Jan 2018 11:40:15 +0300 Subject: [PATCH 076/156] experimental removing of Array code stub because of consistent as3 `Array` to haxe `Array` conversion --- src/as3hx/Writer.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 1995e58..9389b77 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -2302,7 +2302,7 @@ class Writer case "Array": write("try cast("); writeExpr(e1); - write(", Array) catch(e:Dynamic) null"); + write(", Array) catch(e:Dynamic) null"); addWarning("as array", true); case "Class": addWarning("as Class",true); From 9d0ed5b54968b92d9ee4a29762a2c1ab41343b82 Mon Sep 17 00:00:00 2001 From: xmitre Date: Mon, 15 Jan 2018 11:56:48 +0300 Subject: [PATCH 077/156] handling of "".search( ) method with "".indexOf and as3hx.Compat.search( ) --- src/as3hx/Compat.hx | 10 +++++++++- src/as3hx/Writer.hx | 13 +++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/as3hx/Compat.hx b/src/as3hx/Compat.hx index 579647c..26156fd 100644 --- a/src/as3hx/Compat.hx +++ b/src/as3hx/Compat.hx @@ -70,7 +70,15 @@ class Compat { } return result; } - + + public static function search(s:String, ereg:EReg):Int { + if (ereg.match(s)) { + return ereg.matchedPos().pos; + } else { + return -1; + } + } + macro public static function getFunctionLength(f) { switch(Context.follow(Context.typeof(f))) { case TFun(args, _): return @:pos(Context.currentPos()) macro $v{args.length}; diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 9389b77..c0ea4d2 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -3056,6 +3056,19 @@ class Writer } } } + else if(f == "search") { + var type = getExprType(e); + if(type != null) { + if (type == "String") { + var param0Type:String = getExprType(params[0]); + if (param0Type == "as3hx.Compat.Regex" || param0Type == "EReg") { + result = ECall(EField(EIdent("as3hx.Compat"), "search"), [e, params[0]]); + } else { + result = ECall(EField(e, "indexOf"), [params[0]]); + } + } + } + } else if(f == "indexOf") { //in AS3, indexOf is a method in Array while it is not in Haxe //Replace it by the Labda.indexOf method From d3a05e725e34681d6541efd1cab01f76bab37e48 Mon Sep 17 00:00:00 2001 From: xmitre Date: Mon, 15 Jan 2018 11:59:36 +0300 Subject: [PATCH 078/156] whitespaces formatting fix --- src/as3hx/Writer.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index c0ea4d2..b81ac92 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -2748,8 +2748,8 @@ class Writer } default: } - default: - } + default: + } // fix of such constructions var tail:Signal = s || p; switch(tstring(t)) { case "Bool": From 097541a0fdad07e39f3df61dcc855cf844ac6de4 Mon Sep 17 00:00:00 2001 From: xmitre Date: Mon, 15 Jan 2018 12:41:32 +0300 Subject: [PATCH 079/156] config option `replaceVarArgsWithOptionalArguments` to almost consistently deal with existing (...varArgs:Array) code --- src/as3hx/Compat.hx | 28 ++++++++++++++++++++++++++++ src/as3hx/Config.hx | 4 ++++ src/as3hx/Writer.hx | 42 +++++++++++++++++++++++++++++++++++------- 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/as3hx/Compat.hx b/src/as3hx/Compat.hx index 26156fd..925d5df 100644 --- a/src/as3hx/Compat.hx +++ b/src/as3hx/Compat.hx @@ -79,6 +79,34 @@ class Compat { } } + public static function makeArgs(a1:Dynamic, a2:Dynamic, a3:Dynamic, a4:Dynamic, a5:Dynamic = null, a6:Dynamic = null):Array { + if (a6 == null) { + if (a5 == null) { + if (a4 == null) { + if (a3 == null) { + if (a2 == null) { + if (a1 == null) { + return []; + } else { + return [a1]; + } + } else { + return [a1, a2]; + } + } else { + return [a1, a2, a3]; + } + } else { + return [a1, a2, a3, a4]; + } + } else { + return [a1, a2, a3, a4, a5]; + } + } else { + return [a1, a2, a3, a4, a5, a6]; + } + } + macro public static function getFunctionLength(f) { switch(Context.follow(Context.typeof(f))) { case TFun(args, _): return @:pos(Context.currentPos()) macro $v{args.length}; diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index 763227b..212316c 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -51,6 +51,8 @@ class Config { public var testCase : Bool; /** Try to use openfl.Vector openfl.utils.Dictionary and openfl.utils.Object types **/ public var useOpenFlTypes : Bool; + /** Replace varArgs with set of optional arguments converted to an Array **/ + public var replaceVarArgsWithOptionalArguments : Bool; /** conditional compilation variables **/ public var conditionalVars: List; /** Compile time constants implementation class package path for CONFIG::VAR -> `compile.Time.Constants`.CONFIG_VAR**/ @@ -341,6 +343,7 @@ class Config { case "errorContinue": setBoolField(el, true); case "testCase": setBoolField(el, false); case "useOpenFlTypes": setBoolField(el, false); + case "replaceVarArgsWithOptionalArguments": setBoolField(el, false); case "verifyGeneratedFiles":setBoolField(el, false); case "flashTopLevelPackage":setCharField(el, "flash"); case "excludeList": setExcludeField(el, new List()); @@ -454,6 +457,7 @@ class Config { + diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index b81ac92..3ce38d0 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -881,9 +881,9 @@ class Writer } } - function writeArgs(args : Array<{ name : String, t : Null, val : Null, exprs : Array }>, ?varArgs:String) + function writeArgs(args : Array<{ name : String, t : Null, val : Null, exprs : Array }>, varArgs:String = null, functionExpressions:Array) { - if(varArgs != null) { + if(varArgs != null && !cfg.replaceVarArgsWithOptionalArguments) { var varArg = { name:varArgs, t:TPath(["Array"]), @@ -972,6 +972,33 @@ class Writer } } } + + if (cfg.replaceVarArgsWithOptionalArguments) { + // Adding workaround for (...params:Array) + var varArgsNum:Int = 4; + var argNum:Int = args.length; + if (varArgs != null) { + for (i in 1...varArgsNum + 1) { + if (argNum++ > 0) write(", "); + write('$varArgs$i:Dynamic = null'); + } + + if (functionExpressions.length > 0) { + functionExpressions[0] = ENL(functionExpressions[0]); + } + + var callArgs:Array = []; + for (i in 1...varArgsNum + 1) { + callArgs.push(EIdent(varArgs + i)); + } + functionExpressions.unshift(ENL(EVars([{ + name:varArgs, + t:TPath(["Array"]), + val:ECall(EIdent("as3hx.Compat.makeArgs"), callArgs) + }]))); + } + } + lvl -= 2; return fst; } @@ -986,9 +1013,9 @@ class Writer } } write("function new("); - writeArgs(f.args, f.varArgs); - writeCloseStatement(); var es = formatBlockBody(f.expr); + writeArgs(f.args, f.varArgs, es); + writeCloseStatement(); es = WriterUtils.moveFunctionDeclarationsToTheTop(es); if (cfg.fixLocalVariableDeclarations) { es = new VarExprFix(cfg).apply(f, es, typer); @@ -1032,18 +1059,19 @@ class Writer var oldFunctionReturnType:T = functionReturnType; functionReturnType = f.ret.t; + // ensure the function body is in a block + var es = f.expr != null ? formatBlockBody(f.expr) : []; + write("function"); if(name != null) write(" " + name); write("("); - writeArgs(f.args, f.varArgs); + writeArgs(f.args, f.varArgs, es); write(")"); // return type if (ret == null) ret = f.ret; writeFunctionReturn(ret, isGetter, isSetter, isNative); - // ensure the function body is in a block - var es = f.expr != null ? formatBlockBody(f.expr) : []; var formatExpr:Expr->(Expr->Expr)->Expr = null; var formatBlock:Array->(Expr->Expr)->Array = function(exprs, getResult) { for(i in 0...exprs.length) { From 4b2b760f7e3888b5c1ce7b13c72c1f6f6fe99e6d Mon Sep 17 00:00:00 2001 From: xmitre Date: Mon, 15 Jan 2018 19:16:01 +0300 Subject: [PATCH 080/156] minor fixes, redundant code, missed call of `WriterUtils.replaceForLoopsWithWhile` --- src/as3hx/Writer.hx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 3ce38d0..b0df4de 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -210,7 +210,6 @@ class Writer { if (imports.length > 0) { - var imported = []; //holds already written types to prevent duplicates for(i in imports) { writeImport(i); writeNL(); @@ -975,9 +974,9 @@ class Writer if (cfg.replaceVarArgsWithOptionalArguments) { // Adding workaround for (...params:Array) - var varArgsNum:Int = 4; - var argNum:Int = args.length; if (varArgs != null) { + var varArgsNum:Int = 4; + var argNum:Int = args.length; for (i in 1...varArgsNum + 1) { if (argNum++ > 0) write(", "); write('$varArgs$i:Dynamic = null'); @@ -1017,6 +1016,7 @@ class Writer writeArgs(f.args, f.varArgs, es); writeCloseStatement(); es = WriterUtils.moveFunctionDeclarationsToTheTop(es); + es = WriterUtils.replaceForLoopsWithWhile(es); if (cfg.fixLocalVariableDeclarations) { es = new VarExprFix(cfg).apply(f, es, typer); } @@ -2171,9 +2171,6 @@ class Writer writeExpr(ENL(e)); } write("for ("); - if (inits.length == 0) { - neko.Lib.println(inits + ";" + conds + ";" + incrs + " : " + e); - } switch(inits[inits.length - 1]) { case EVars(v): write(v[0].name); From e801461511d74164aecbc400fa071c953b883bce Mon Sep 17 00:00:00 2001 From: xmitre Date: Mon, 15 Jan 2018 19:17:18 +0300 Subject: [PATCH 081/156] possible fix of vector.length++ and vector.length-- operators --- src/as3hx/Writer.hx | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index b0df4de..89eb62a 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -2445,9 +2445,22 @@ class Writer return Semi; } - inline function writeEUnop(op:String, prefix:Bool, e:Expr):BlockEnd { + function writeEUnop(op:String, prefix:Bool, e:Expr):BlockEnd { var result = Semi; var type = getExprType(e); + switch(e) { + case EField(a, "length") if (op == "++" || op == "--"): + var type = getExprType(a); + if (type != null && type.startsWith("Vector<")) { + if (op == "++") { + writeExpr(EBinop("+=", e, EConst(CInt("1")), false)); + } else { + writeExpr(EBinop("-=", e, EConst(CInt("1")), false)); + } + return result; + } + default: + } if((isIntType(type) || type == "UInt") && op == "!") { writeExpr(EBinop("!=", e, EConst(CInt("0")), false)); result = None; From 4e1fe4d45c8dca3f9a4497cc7c610da0945ce82b Mon Sep 17 00:00:00 2001 From: xmitre Date: Mon, 15 Jan 2018 19:19:54 +0300 Subject: [PATCH 082/156] config param `importExclude` lets setup as3 import paths that should not be included in haxe files but should be looked up through existing codebase --- src/as3hx/Config.hx | 16 ++++++++++++++++ src/as3hx/Writer.hx | 3 +++ 2 files changed, 19 insertions(+) diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index 212316c..20f8a2e 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -94,6 +94,11 @@ class Config { */ public var importPaths : Array; + /** + * list of as3 import paths that should not be included in haxe files but should be looked up through existing codebase + */ + public var importExclude : Array; + /** * A map where the key is the name fo a Haxe type * and the value is its' fully qualified name, @@ -356,6 +361,7 @@ class Config { case "useFastXML": setBoolField(el, true); case "useCompat": setBoolField(el, true); case "importPaths": setImportPaths(el, []); + case "importExclude": setImportExclude(el, []); default: Sys.println("Unrecognized config var " + el.name); } @@ -409,6 +415,15 @@ class Config { } } } + + function setImportExclude(f:Fast, defaultVars:Array) { + importExclude = defaultVars; + for (importPath in f.nodes.variable) { + if (importPath.has.value) { + importExclude.push(importPath.att.value); + } + } + } public static function toPath(inPath:String):String { if (!isWindows()) @@ -471,6 +486,7 @@ class Config { + '; } } diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 89eb62a..0e837bc 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -227,6 +227,9 @@ class Writer } else { type = properCaseA(i, true).join("."); } + if (cfg.importExclude != null && cfg.importExclude.indexOf(type) != -1) { + return; + } if (!Lambda.has(this.imported, type)) { //prevent duplicate import write("import " + type + ";"); imported.push(type); From 217413679c16042d55084a5feb8d23fe19033899 Mon Sep 17 00:00:00 2001 From: xmitre Date: Mon, 15 Jan 2018 19:21:42 +0300 Subject: [PATCH 083/156] fix of working of ForLoopRebuild with var expressions in surrounding code --- src/as3hx/ForLoopRebuild.hx | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/as3hx/ForLoopRebuild.hx b/src/as3hx/ForLoopRebuild.hx index faf1d8f..a6ba5fd 100644 --- a/src/as3hx/ForLoopRebuild.hx +++ b/src/as3hx/ForLoopRebuild.hx @@ -240,17 +240,18 @@ class ForLoopRebuild if (inits.length == 0 || conds.length != 1 || incrs.length != 1) return false; var loopVariable:String = getForLoopVariable(incrs); var loopIdent:Expr = EIdent(loopVariable); - // if variable is not set up before loop, no FOR switch(inits[inits.length - 1]) { case EBinop("=", e1, e2, _): if (!e1.equals(loopIdent)) { return false; } - case EVars(vars) if(vars.length > 1): return false; + case EVars(vars): + if (vars.length > 1) { + return false; + } default: return false; } - // if comparison is not `variable less then value`, no FOR switch(conds[0]) { case EBinop(op, e1, e2, _): @@ -334,6 +335,15 @@ class ForLoopRebuild wasUsed = true; return RebuildResult.RSkip; } + case EVars(vars): + for (v in vars) { + if (v.name == ident) { + if (v.val != null) { + RebuildUtils.rebuild(v.val, rebuild); + } + return RebuildResult.RSkip; + } + } case EBinop(op, e1, e2, _): if (op == "=" && isIdent(e1, ident)) { RebuildUtils.rebuild(e2, rebuild); @@ -363,6 +373,13 @@ class ForLoopRebuild } return RebuildResult.RSkip; } + case EVars(vars): + for (v in vars) { + if (v.name == ident) { + result = true; + return RebuildResult.RSkip; + } + } case EBinop(op, e1, _, _): if (op.indexOf("=") != -1 && isIdent(e1, ident)) { result = true; From b821f32839ef849a1a58371f1c0c146db9922adb Mon Sep 17 00:00:00 2001 From: xmitre Date: Mon, 15 Jan 2018 19:23:29 +0300 Subject: [PATCH 084/156] fix of coworking of config.replaceVarArgsWithOptionalArguments and config.fixLocalVariableDeclarations options --- src/as3hx/VarExprFix.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/as3hx/VarExprFix.hx b/src/as3hx/VarExprFix.hx index 8e25834..dca0ae9 100644 --- a/src/as3hx/VarExprFix.hx +++ b/src/as3hx/VarExprFix.hx @@ -26,7 +26,7 @@ class VarExprFix for (arg in f.args) { firstUse.set(arg.name, -1); } - if (f.varArgs != null) { + if (f.varArgs != null && !cfg.replaceVarArgsWithOptionalArguments) { firstUse.set(f.varArgs, -1); } var line:Int = 0; From 331e08da7871c9d717f97edfadbf34329dab54de Mon Sep 17 00:00:00 2001 From: xmitre Date: Mon, 15 Jan 2018 19:48:22 +0300 Subject: [PATCH 085/156] fix of typing of varArgs variable --- src/as3hx/Typer.hx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index 1795b09..d9edeae 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -53,7 +53,6 @@ class Typer default: } var t2 = getExprType(e2); - //write("/* e2 " + e2 + "."+f+" type: "+t2+" */"); if (t2 != null && (t2.indexOf("Array<") == 0 || t2.indexOf("Vector<") == 0) && f == "length") { return "Int"; } @@ -178,6 +177,9 @@ class Typer for (arg in f.args) { context.set(arg.name, tstring(arg.t)); } + if (f.varArgs != null) { + context.set(f.varArgs, "Array"); + } function lookUpForTyping(expr:Expr):RebuildResult { switch(expr) { case EVars(vars): From d80dff209974b4423d9968a31273800a3f04fbe5 Mon Sep 17 00:00:00 2001 From: xmitre Date: Mon, 15 Jan 2018 20:06:34 +0300 Subject: [PATCH 086/156] handling of "string".match method --- src/as3hx/Compat.hx | 9 +++++++++ src/as3hx/Writer.hx | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/src/as3hx/Compat.hx b/src/as3hx/Compat.hx index 925d5df..a934357 100644 --- a/src/as3hx/Compat.hx +++ b/src/as3hx/Compat.hx @@ -79,6 +79,15 @@ class Compat { } } + public static function match(s:String, ereg:EReg, parenthesesBlockIndex:Int = 0):Array { + var matches:Array = []; + while (ereg.match(s)) { + matches.push(ereg.matched(parenthesesBlockIndex)); + s = ereg.matchedRight(); + } + return matches; + } + public static function makeArgs(a1:Dynamic, a2:Dynamic, a3:Dynamic, a4:Dynamic, a5:Dynamic = null, a6:Dynamic = null):Array { if (a6 == null) { if (a5 == null) { diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 0e837bc..a061f67 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -3097,6 +3097,14 @@ class Writer } } } + else if(f == "match") { + var type = getExprType(e); + if(type != null) { + if (type == "String") { + result = ECall(EField(EIdent("as3hx.Compat"), "match"), [e, params[0]]); + } + } + } else if(f == "search") { var type = getExprType(e); if(type != null) { From a8578a060c83743b6c094bc115218e2bef35ee96 Mon Sep 17 00:00:00 2001 From: xmitre Date: Mon, 15 Jan 2018 20:07:16 +0300 Subject: [PATCH 087/156] correct Bool type of `true` and `false` idents --- src/as3hx/Typer.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index d9edeae..800f76d 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -85,6 +85,7 @@ class Typer } return null; case EIdent(s): + if (s == "true" || s == "false") return "Bool"; s = getModifiedIdent(s); return context.get(s); case EVars(vars) if(vars.length == 1): return tstring(vars[0].t); From 66c2a3858d293659e75877f0cfdbfeb4cee3ca22 Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 16 Jan 2018 11:36:20 +0300 Subject: [PATCH 088/156] dealing with decodeURI, encodeURI, escape, unescape --- src/as3hx/Typer.hx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index 800f76d..dcad868 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -85,7 +85,11 @@ class Typer } return null; case EIdent(s): - if (s == "true" || s == "false") return "Bool"; + switch(s) { + case "true", "false": return "Bool"; + case "encodeURI", "decodeURI", "escape", "unescape": return "String->String"; + default: + } s = getModifiedIdent(s); return context.get(s); case EVars(vars) if(vars.length == 1): return tstring(vars[0].t); @@ -113,13 +117,17 @@ class Typer case "Number": "Float"; case "Boolean": "Bool"; case "Function": cfg.functionToDynamic ? "Dynamic" : s; - case "Object": "Dynamic"; + case "Object": cfg.useOpenFlTypes ? "Object" : "Dynamic"; case "undefined": "null"; //case "Error": cfg.mapFlClasses ? "flash.errors.Error" : s; case "XML": "FastXML"; case "XMLList": "FastXMLList"; case "NaN":"Math.NaN"; case "Dictionary": cfg.dictionaryToHash ? "haxe.ds.ObjectMap" : s; + case "decodeURI": "StringTools.decodeURI"; + case "encodeURI": "StringTools.encodeURI"; + case "escape": "StringTools.htmlEscape"; + case "unescape": "StringTools.htmlUnescape"; //case "QName": cfg.mapFlClasses ? "flash.utils.QName" : s; default: s; }; From e33df92a84dabf0df1f36af883fcd86c4bfe3cee Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 16 Jan 2018 11:37:08 +0300 Subject: [PATCH 089/156] extracting type of ECall return type --- src/as3hx/Typer.hx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index dcad868..785f745 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -84,6 +84,14 @@ class Typer } } return null; + case ECall(e, params): + var t:String = getExprType(e); + if (t != null) { + var li:Int = t.lastIndexOf("->"); + if (li != -1) { + return t.substr(li + 2); + } + } case EIdent(s): switch(s) { case "true", "false": return "Bool"; From f13298c970f5dbe1151933480497020f878f0c17 Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 16 Jan 2018 11:38:46 +0300 Subject: [PATCH 090/156] fix of error in refactoring of multiple local var exprs if class var with same name exists --- src/as3hx/VarExprFix.hx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/as3hx/VarExprFix.hx b/src/as3hx/VarExprFix.hx index dca0ae9..a590861 100644 --- a/src/as3hx/VarExprFix.hx +++ b/src/as3hx/VarExprFix.hx @@ -18,16 +18,20 @@ class VarExprFix public function apply(f:Function, es:Array, typer:Typer):Array { var map:Map = typer.getContextClone(-1); + var localVar:Map = new Map(); var firstUse:Map = new Map(); var firstUseLine:Map> = new Map>(); for (v in map.keys()) { firstUse.set(v, -1); + localVar.set(v, false); } for (arg in f.args) { firstUse.set(arg.name, -1); + localVar.set(arg.name, true); } if (f.varArgs != null && !cfg.replaceVarArgsWithOptionalArguments) { firstUse.set(f.varArgs, -1); + localVar.set(f.varArgs, true); } var line:Int = 0; function rebuildMethodLookForVars(e:Expr):RebuildResult { @@ -50,15 +54,16 @@ class VarExprFix var hasChange:Bool = false; for (vr in vars) { var v:String = vr.name; - if (!firstUse.exists(v)) { - firstUse.set(v, -1); - newVars.push(EVars([vr])); - } else { + if (firstUse.exists(v) && localVar.get(v) == true) { hasChange = true; if (vr.val != null) { newVars.push(EBinop("=", EIdent(v), vr.val, false)); } + } else { + firstUse.set(v, -2); + newVars.push(EVars([vr])); } + localVar.set(v, true); map.set(v, typer.tstring(vr.t)); } if (hasChange) { From d21a2efdc0bda5db7a5372d229277ce0bc0f3f5e Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 16 Jan 2018 11:40:07 +0300 Subject: [PATCH 091/156] removed duplication of `getModifiedIdent` method (previously moved to Typer class) --- src/as3hx/Writer.hx | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index a061f67..53f3997 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -708,7 +708,7 @@ class Writer switch(field.kind) { case FVar(t, val): start(field.name, false); - write("var " + getModifiedIdent(field.name)); + write("var " + typer.getModifiedIdent(field.name)); if (!isStatic(field.kwds) && isConst(field.kwds)) write("(default, never)"); var type = tstring(t); //check wether a specific type was defined for this array if(isArrayType(type)) { @@ -744,7 +744,7 @@ class Writer ret.t = f.args[0].t; cfg.makeSetterName(field.name); //"set" + ucfirst(field.name); } else { - getModifiedIdent(field.name); + typer.getModifiedIdent(field.name); } if(isGetter(field.kwds) || isSetter(field.kwds)) { // write flash native @@ -1297,7 +1297,7 @@ class Writer } return typer.getExprType(e); case EIdent(s): - s = getModifiedIdent(s); + s = typer.getModifiedIdent(s); //if(context.get(s) == null) // write("/* AS3HX WARNING var " + s + " is not in scope */"); return context.get(s); @@ -1341,27 +1341,8 @@ class Writer } } - function getModifiedIdent(s : String) : String { - return switch(s) { - case "int": "Int"; - case "uint": cfg.uintToInt ? "Int" : "UInt"; - case "Number": "Float"; - case "Boolean": "Bool"; - case "Function": cfg.functionToDynamic ? "Dynamic" : s; - case "Object": cfg.useOpenFlTypes ? "Object" : "Dynamic"; - case "undefined": "null"; - //case "Error": cfg.mapFlClasses ? "flash.errors.Error" : s; - case "XML": "FastXML"; - case "XMLList": "FastXMLList"; - case "NaN":"Math.NaN"; - case "Dictionary": cfg.dictionaryToHash ? "haxe.ds.ObjectMap" : s; - //case "QName": cfg.mapFlClasses ? "flash.utils.QName" : s; - default: s; - }; - } - function writeModifiedIdent(s : String) { - write(getModifiedIdent(s)); + write(typer.getModifiedIdent(s)); } /** @@ -1794,7 +1775,7 @@ class Writer if(getExprType(e2) == "FastXML") inArrayAccess = true; case EIdent(v): - switch(getModifiedIdent(v)) { + switch(typer.getModifiedIdent(v)) { case "Int": if(f == "MAX_VALUE") { writeExpr(getCompatFieldExpr("INT_MAX")); @@ -1866,7 +1847,7 @@ class Writer } var type = tstring(v.t); context.set(v.name, type); - write("var " + getModifiedIdent(v.name)); + write("var " + typer.getModifiedIdent(v.name)); writeVarType(v.t); if(rvalue != null) { write(" = "); From 330be99da827d1177ba454b0ff229eea4a80d849 Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 16 Jan 2018 14:23:11 +0300 Subject: [PATCH 092/156] handling of type of (a as B) and new B() expressions --- src/as3hx/Typer.hx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index 785f745..3245313 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -104,8 +104,10 @@ class Typer case EArray(n, _): return getExprType(n); case EArrayDecl(_): return "Array"; case EUnop(_, _, e2): return getExprType(e2); + case EBinop(_ => "as", _, type, _): return getExprType(type); case EBinop(_ => "/", _, _, _): return "Float"; - case EBinop(_, e1, e2, _) if(getExprType(e1) != "Float" && getExprType(e2) != "Float"): return "Int"; + case EBinop(_, e1, e2, _) if (getExprType(e1) != "Float" && getExprType(e2) != "Float"): return "Int"; + case ENew(t, params): return tstring(t); case EConst(c): return switch(c) { case CInt(_): "Int"; From 304d6225c09784749f8a4b88a54ef008e452daa2 Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 16 Jan 2018 14:24:30 +0300 Subject: [PATCH 093/156] method replace on string now unconditionaly resolved to StringTools.replace, if param is not regexp --- src/as3hx/Writer.hx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 53f3997..e06c95a 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -3038,14 +3038,8 @@ class Writer params[0] = e; result = ECall(EField(param0, f), params); } else { - var isString = switch(param0) { - case ECall(e,_): getIdentString(e) == "String"; - default: param0Type == "String"; - } - if(isString) { - params.insert(0, e); - result = ECall(EField(EIdent("StringTools"), f), params); - } + params.insert(0, e); + result = ECall(EField(EIdent("StringTools"), f), params); } } } From 9274a7a716755f6d71361a0833d2b8541c8adf03 Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 16 Jan 2018 19:06:13 +0300 Subject: [PATCH 094/156] handling variables with name "static" --- src/as3hx/ParserUtils.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/as3hx/ParserUtils.hx b/src/as3hx/ParserUtils.hx index 24dc38b..ef15ad1 100644 --- a/src/as3hx/ParserUtils.hx +++ b/src/as3hx/ParserUtils.hx @@ -13,6 +13,8 @@ class ParserUtils { case "enum": "_enum"; case "_enum": "__enum"; case "__enum": "___enum"; + case "static": "_static"; + case "_static": "__static"; default: StringTools.replace(name, "$", "__DOLLAR__"); } } From 9d1a1afc5b792f7c83bec18724734fa80b05c372 Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 16 Jan 2018 19:07:18 +0300 Subject: [PATCH 095/156] fix of handling of imports in Type system --- src/as3hx/Typer.hx | 30 +++++++++++------ src/as3hx/Writer.hx | 81 ++++++++++++--------------------------------- 2 files changed, 40 insertions(+), 71 deletions(-) diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index 3245313..0cee1b0 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -70,16 +70,15 @@ class Typer } default: } - var ts:String = getExprType(e2); - if (ts != null) { - if (context.exists(ts)) { - ts = context.get(ts); + if (t2 != null) { + if (context.exists(t2)) { + t2 = context.get(t2); } - if (classes.exists(ts)) { - return classes.get(ts).get(f); - } else if (importsMap != null && importsMap.exists(ts)) { - if (classes.exists(ts)) { - return classes.get(importsMap.get(ts)).get(f); + if (classes.exists(t2)) { + return classes.get(t2).get(f); + } else if (importsMap != null && importsMap.exists(t2)) { + if (classes.exists(importsMap.get(t2))) { + return classes.get(importsMap.get(t2)).get(f); } } } @@ -187,8 +186,17 @@ class Typer contextStack[contextStack.length - 1] = context = classMap; } - public function setImports(importsMap:Map):Void { - this.importsMap = importsMap; + public function setImports(importsMap:Map, imported:Array):Void { + this.importsMap = new Map(); + for (key in importsMap.keys()) { + if (importsMap.get(key) != null) { + this.importsMap.set(key, importsMap.get(key)); + } + } + for (key in imported) { + var i:Int = key.lastIndexOf("."); + this.importsMap.set(key.substr(i + 1), key); + } } public function enterFunction(f:Function):Void { diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index e06c95a..ec9d138 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -118,7 +118,7 @@ class Writer public function register(p:Program):Void { for (d in p.defs) { switch(d) { - case CDef(c): typer.addClass((p.pack.length > 0 ? p.pack.join(".") + "." : "") + c.name, c); + case CDef(c): typer.addClass((p.pack.length > 0 ? getImportString(p.pack) + "." : "") + c.name, c); case FDef(f): case NDef(n): default: @@ -220,13 +220,7 @@ class Writer function writeImport(i : Array) { - var type; - if (i[0] == "flash") { - i[0] = cfg.flashTopLevelPackage; - type = i.join("."); - } else { - type = properCaseA(i, true).join("."); - } + var type = getImportString(i); if (cfg.importExclude != null && cfg.importExclude.indexOf(type) != -1) { return; } @@ -238,6 +232,15 @@ class Writer typeImportMap.set(i[i.length - 1], null); } } + + function getImportString(i : Array) { + if (i[0] == "flash") { + i[0] = cfg.flashTopLevelPackage; + return i.join("."); + } else { + return properCaseA(i, true).join("."); + } + } function writeAdditionalImports(defPackage : Array, allTypes : Array, definedTypes : Array) { @@ -362,7 +365,7 @@ class Writer var path:String = (pack.length > 0 ? pack.join(".") + "." : "") + c.name; typer.enterClass(path, c); - typer.setImports(typeImportMap); + typer.setImports(typeImportMap, imported); // process properties writeProperties(c); @@ -1268,55 +1271,6 @@ class Writer function getExprType(e:Expr):Null { return typer.getExprType(e); - /*EField(ECall(EField(EIdent(xml),descendants),[]),user)*/ - switch(e) { - case ETypedExpr(e2, t): return tstring(t); - case EField(e2, f): - switch(e2) { - case EIdent("this"): return contextStack[0].get(f); - default: - } - var t2 = getExprType(e2); - //write("/* e2 " + e2 + "."+f+" type: "+t2+" */"); - if (t2 != null && (t2.indexOf("Array<") == 0 || t2.indexOf("Vector<") == 0) && f == "length") { - return "Int"; - } - switch(t2) { - case "FastXML": - return switch(f) { - case "descendants", "nodes": "FastXMLList"; - case "node": "FastXML"; - case "length": "Int"; - case _: "FastXMLList"; - } - case "FastXMLList": - switch(f) { - case "length": return "Int"; - } - default: - } - return typer.getExprType(e); - case EIdent(s): - s = typer.getModifiedIdent(s); - //if(context.get(s) == null) - // write("/* AS3HX WARNING var " + s + " is not in scope */"); - return context.get(s); - case EVars(vars) if(vars.length == 1): return tstring(vars[0].t); - case EArray(n, _): return getExprType(n); - case EArrayDecl(_): return "Array"; - case EUnop(_, _, e2): return getExprType(e2); - case EBinop(_ => "/", _, _, _): return "Float"; - case EBinop(_, e1, e2, _) if(getExprType(e1) != "Float" && getExprType(e2) != "Float"): return "Int"; - case EConst(c): - return switch(c) { - case CInt(_): "Int"; - case CFloat(_): "Float"; - case CString(_): "String"; - } - case ERegexp(_, _): return getRegexpType(); - default: - } - return null; } inline function getRegexpType():String return cfg.useCompat ? "as3hx.Compat.Regex" : "flash.utils.RegExp"; @@ -2130,13 +2084,17 @@ class Writer inline function writeEWhile(cond:Expr, e:Expr, doWhile:Bool):BlockEnd { var result:BlockEnd; + var rcond:Expr = rebuildIfExpr(cond); + if (rcond != null) { + cond = rcond; + } if (doWhile) { write("do"); writeStartStatement(); writeExpr(EBlock(formatBlockBody(e))); writeStartStatement(); write("while ("); - result = writeExpr(rebuildIfExpr(cond)); + result = writeExpr(cond); write(")"); } else { write("while ("); @@ -2824,6 +2782,8 @@ class Writer addWarning("EDelete"); writeNL("This is an intentional compilation error. See the README for handling the delete keyword"); writeIndent('delete ${getIdentString(object)}[${getIdentString(index)}]'); + } else if (atype.startsWith("Array")) { + writeExpr(EBinop("=", EArray(object, index), EIdent("null"), false)); } } } @@ -2946,7 +2906,8 @@ class Writer var t = getExprType(e); if(t == null || t == "Bool") return null; return switch(t) { - case "Int" | "UInt": EBinop("!=", e, EConst(CInt("0")), false); + case "Int" | "UInt": + EBinop("!=", e, EConst(CInt("0")), false); case "Float": var lvalue = EBinop("!=", e, EConst(CInt("0")), false); var rvalue = EUnop("!", true, ECall(EField(EIdent("Math"), "isNaN"), [e])); From c0c7931edde0f085b19f92ba0f6d0f472a5867f8 Mon Sep 17 00:00:00 2001 From: xmitre Date: Wed, 17 Jan 2018 15:15:28 +0300 Subject: [PATCH 096/156] fix for "config param `importExclude` lets setup as3 import paths that should not be included in haxe files but should be looked up through existing codebase" --- src/as3hx/Writer.hx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index ec9d138..fe5ffe4 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -3850,7 +3850,11 @@ class Writer case CDef(c): for (meta in c.meta) { switch (meta) { - case EImport(v): defined.push(v[v.length - 1]); + case EImport(v): + if (cfg.importExclude != null && cfg.importExclude.indexOf(v.join(".")) != -1) { + continue; + } + defined.push(v[v.length - 1]); default: } } From bebda02b0bdc7f6d6bd6c26041ec1cf6826a77e0 Mon Sep 17 00:00:00 2001 From: xmitre Date: Wed, 17 Jan 2018 15:23:01 +0300 Subject: [PATCH 097/156] fix of getImportString --- src/as3hx/Writer.hx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index fe5ffe4..19484b6 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -118,7 +118,7 @@ class Writer public function register(p:Program):Void { for (d in p.defs) { switch(d) { - case CDef(c): typer.addClass((p.pack.length > 0 ? getImportString(p.pack) + "." : "") + c.name, c); + case CDef(c): typer.addClass((p.pack.length > 0 ? getImportString(p.pack, false) + "." : "") + c.name, c); case FDef(f): case NDef(n): default: @@ -220,7 +220,7 @@ class Writer function writeImport(i : Array) { - var type = getImportString(i); + var type = getImportString(i, true); if (cfg.importExclude != null && cfg.importExclude.indexOf(type) != -1) { return; } @@ -233,12 +233,12 @@ class Writer } } - function getImportString(i : Array) { + function getImportString(i : Array, hasClassName:Bool) { if (i[0] == "flash") { i[0] = cfg.flashTopLevelPackage; return i.join("."); } else { - return properCaseA(i, true).join("."); + return properCaseA(i, hasClassName).join("."); } } @@ -247,7 +247,7 @@ class Writer // We don't want to import any type that is defined within // this file, so add each of those to the type import map // first. - for(d in definedTypes) { + for (d in definedTypes) { typeImportMap.set(d, null); } From 3ac5574ad3976fa3f3e33938a557c448f02f38fa Mon Sep 17 00:00:00 2001 From: xmitre Date: Wed, 17 Jan 2018 15:26:39 +0300 Subject: [PATCH 098/156] self class reference in variable initialization is not threated as reference to local variable any more --- src/as3hx/Writer.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 19484b6..64c701e 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -533,7 +533,7 @@ class Writer usingInstanceFields = true; } else { for (field in c.fields) { - if (s == field.name) { + if (s == field.name && s != c.name) { if (!field.kwds.has("static")) { usingInstanceFields = true; return RebuildResult.RReplace(EField(EIdent("this"), s)); From aaa1232b01fd6ca6e4900ce48aeeeda26dbb308d Mon Sep 17 00:00:00 2001 From: xmitre Date: Wed, 17 Jan 2018 15:33:46 +0300 Subject: [PATCH 099/156] fix of for( in ) iteration throw keys in dictionary (now threating dictionary as map) --- src/as3hx/Writer.hx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 64c701e..9898571 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -2220,7 +2220,12 @@ class Writer inline function writeEForIn(ev:Expr, e:Expr, block:Expr):BlockEnd { openContext(); var etype = getExprType(e); - var regexp:EReg = ~/^Map<([^,]*)?,?.*>$/; + var regexp:EReg; + if (isOpenFlDictionaryType(etype)) { + regexp = ~/^Dictionary<([^,]*)?,?.*>$/; + } else { + regexp = ~/^Map<([^,]*)?,?.*>$/; + } var isMap:Bool = etype != null && regexp.match(etype); write("for ("); switch(ev) { From c40b49206aa353cb28d23c074d92128c2981bd17 Mon Sep 17 00:00:00 2001 From: xmitre Date: Wed, 17 Jan 2018 15:35:57 +0300 Subject: [PATCH 100/156] enhancement of isFunctionExpr (handling of ArgType->RetType Function type notation) --- src/as3hx/Writer.hx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 9898571..d05f001 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -3408,7 +3408,10 @@ class Writer return s != null && s.startsWith("Dictionary") && cfg.useOpenFlTypes; } - inline function isFunctionExpr(e:Expr):Bool return getExprType(e) == "Function"; + inline function isFunctionExpr(e:Expr):Bool { + var type:String = getExprType(e); + return type == "Function" || type.indexOf("->") != -1; + } inline function isIntExpr(e:Expr):Bool { var type = getExprType(e); From e1d09679e07c6a5159a3c07b8d9957735e6cc312 Mon Sep 17 00:00:00 2001 From: xmitre Date: Wed, 17 Jan 2018 15:38:03 +0300 Subject: [PATCH 101/156] handling of classes in the same package in Type system --- src/as3hx/Typer.hx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index 0cee1b0..16d7913 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -23,6 +23,7 @@ class Typer var classFieldDictionaryTypes : Map> = new Map>(); var context : Map = new Map(); var contextStack : Array> = []; + var pack:String = null; var currentPath:String = null; var importsMap : Map; @@ -80,6 +81,8 @@ class Typer if (classes.exists(importsMap.get(t2))) { return classes.get(importsMap.get(t2)).get(f); } + } else if (currentPath.length > 0 && classes.exists(pack + "." + t2)) { + return classes.get(pack + "." + t2).get(f); } } return null; @@ -178,6 +181,7 @@ class Typer public function enterClass(path, c:ClassDef):Void { currentPath = path; + pack = currentPath.substr(0, currentPath.lastIndexOf(".")); var classMap:Map = classes.get(path); if (classMap == null) { classMap = new Map(); From 487c9d10249fa5be9e6d657dad893cadd62f3b37 Mon Sep 17 00:00:00 2001 From: xmitre Date: Wed, 17 Jan 2018 15:38:53 +0300 Subject: [PATCH 102/156] fix of match and search in Compat for RegExp. handling of lastIndex parameter in RegExp --- src/as3hx/Compat.hx | 52 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/as3hx/Compat.hx b/src/as3hx/Compat.hx index a934357..3ff36f4 100644 --- a/src/as3hx/Compat.hx +++ b/src/as3hx/Compat.hx @@ -71,7 +71,7 @@ class Compat { return result; } - public static function search(s:String, ereg:EReg):Int { + public static function search(s:String, ereg:FlashRegExpAdapter):Int { if (ereg.match(s)) { return ereg.matchedPos().pos; } else { @@ -79,7 +79,24 @@ class Compat { } } - public static function match(s:String, ereg:EReg, parenthesesBlockIndex:Int = 0):Array { + public static function searchEReg(s:String, ereg:EReg):Int { + if (ereg.match(s)) { + return ereg.matchedPos().pos; + } else { + return -1; + } + } + + public static function match(s:String, ereg:FlashRegExpAdapter, parenthesesBlockIndex:Int = 0):Array { + var matches:Array = []; + while (ereg.match(s)) { + matches.push(ereg.matched(parenthesesBlockIndex)); + s = ereg.matchedRight(); + } + return matches; + } + + public static function matchEReg(s:String, ereg:EReg, parenthesesBlockIndex:Int = 0):Array { var matches:Array = []; while (ereg.match(s)) { matches.push(ereg.matched(parenthesesBlockIndex)); @@ -477,11 +494,28 @@ class FlashRegExpAdapter { _global = opt.indexOf("g") != -1; } + public var lastIndex(get, set):Int; + var _ereg:EReg; var _global:Bool; var _lastTestedString : String; var _restOfLastTestedString : String; - var _lastTestedStringProcessedSize = 0; + var _lastIndex:Int = 0; + + private function get_lastIndex():Int { + return _lastIndex; + } + + private function set_lastIndex(value:Int):Int { + if (_lastIndex != value) { + if (_lastTestedString != null) { + _restOfLastTestedString = _lastTestedString.substr(value); + } + return _lastIndex = value; + } else { + return value; + } + } /** * Performs a search for the regular expression on the given string str. @@ -503,7 +537,13 @@ class FlashRegExpAdapter { * the stringinput — The string (str) */ public function exec(str:String):Null> { - var testStr = _lastTestedString == str ? _restOfLastTestedString : str; + var testStr; + if (_lastTestedString == str) { + if (lastIndex + testStr = _restOfLastTestedString; + } else { + testStr = str; + } var matched = _ereg.match(testStr); var index = 0; if (_global) { @@ -512,10 +552,10 @@ class FlashRegExpAdapter { var matchedLeftLength = _ereg.matchedLeft().length; index = _lastTestedStringProcessedSize + matchedLeftLength; _restOfLastTestedString = _ereg.matchedRight(); - _lastTestedStringProcessedSize += matchedLeftLength + _ereg.matched(0).length; + _lastIndex += matchedLeftLength + _ereg.matched(0).length; } else { _restOfLastTestedString = null; - _lastTestedStringProcessedSize = 0; + _lastIndex = lastIndex; } } return matched ? new FlashRegExpExecResult(str, _ereg, index).matches : null; From bb2735533ecb97006242fdf23f6b81d9e04c8f84 Mon Sep 17 00:00:00 2001 From: xmitre Date: Wed, 17 Jan 2018 15:46:42 +0300 Subject: [PATCH 103/156] fix for "enhancement of isFunctionExpr (handling of ArgType->RetType Function type notation)" --- src/as3hx/Writer.hx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index d05f001..a7a4700 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -3410,7 +3410,7 @@ class Writer inline function isFunctionExpr(e:Expr):Bool { var type:String = getExprType(e); - return type == "Function" || type.indexOf("->") != -1; + return type == "Function" || type != null && type.indexOf("->") != -1; } inline function isIntExpr(e:Expr):Bool { @@ -3958,5 +3958,4 @@ class Writer function (v:String) return v.length > 0 ? v.charAt(0).toUpperCase() + v.substr(1) : "" ).array().join(""); } - } \ No newline at end of file From f1563dd20b5be29bac067a8414aa35981a188fd4 Mon Sep 17 00:00:00 2001 From: xmitre Date: Thu, 18 Jan 2018 19:37:45 +0300 Subject: [PATCH 104/156] fix (handling) of recursion on EForIn expression --- src/as3hx/RebuildUtils.hx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/as3hx/RebuildUtils.hx b/src/as3hx/RebuildUtils.hx index 3d9c2dd..4437241 100644 --- a/src/as3hx/RebuildUtils.hx +++ b/src/as3hx/RebuildUtils.hx @@ -125,6 +125,18 @@ class RebuildUtils } else { return EBlock(r); } + case EForIn(e1, e2, e3): + var re1:Expr = rebuild(e1, rebuildMethod); + var re2:Expr = rebuild(e2, rebuildMethod); + var re3:Expr = rebuild(e3, rebuildMethod); + if (re1 != null || re2 != null || re3 != null) { + if (re1 == null) re1 = e1; + if (re2 == null) re2 = e2; + if (re3 == null) re3 = e3; + return EForIn(re1, re2, re3); + } else { + return null; + } case EForEach(e1, e2, e3): var re1:Expr = rebuild(e1, rebuildMethod); var re2:Expr = rebuild(e2, rebuildMethod); @@ -264,6 +276,7 @@ class RebuildUtils } else { return null; } + //case EVars(vars): not implemented case ECommented(a, b, c, e): e = rebuild(e, rebuildMethod); if (e == null) return null; From 17c556130133abed6c7be8b63579eb0fa86957b6 Mon Sep 17 00:00:00 2001 From: xmitre Date: Thu, 18 Jan 2018 19:38:23 +0300 Subject: [PATCH 105/156] fix of match and search in Compat for RegExp. handling of lastIndex parameter in RegExp --- src/as3hx/Compat.hx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/as3hx/Compat.hx b/src/as3hx/Compat.hx index 3ff36f4..23c36be 100644 --- a/src/as3hx/Compat.hx +++ b/src/as3hx/Compat.hx @@ -539,7 +539,6 @@ class FlashRegExpAdapter { public function exec(str:String):Null> { var testStr; if (_lastTestedString == str) { - if (lastIndex testStr = _restOfLastTestedString; } else { testStr = str; @@ -550,7 +549,7 @@ class FlashRegExpAdapter { _lastTestedString = str; if (matched) { var matchedLeftLength = _ereg.matchedLeft().length; - index = _lastTestedStringProcessedSize + matchedLeftLength; + index = _lastIndex + matchedLeftLength; _restOfLastTestedString = _ereg.matchedRight(); _lastIndex += matchedLeftLength + _ereg.matched(0).length; } else { From 2b8bda0ebcbd23d26ab3af6bd69ca3ee9d16c6ac Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 27 Jun 2018 15:37:17 +0300 Subject: [PATCH 106/156] as3-compatible behavior of xml for non-existent @Attributes --- src/FastXML.hx | 20 +++++++++++++++++--- src/FastXMLList.hx | 2 +- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/FastXML.hx b/src/FastXML.hx index d14dd28..9eedad3 100644 --- a/src/FastXML.hx +++ b/src/FastXML.hx @@ -1,3 +1,4 @@ +import haxe.xml.Fast; private class NodeAccess implements Dynamic { var __x : Xml; @@ -30,7 +31,7 @@ private class AttribAccess implements Dynamic { throw "Cannot access document attribute "+name; var v = __x.get(name); if( v == null ) - throw __x.nodeName+" is missing attribute "+name; + return ""; return v; } @@ -76,7 +77,7 @@ private class NodeListAccess implements Dynamic { public function resolve( name : String ) : FastXMLList { var l = new Array(); - for( x in __x.elementsNamed(name) ) + for( x in __x.elementsNamed(name) ) l.push(new FastXML(x)); return new FastXMLList(l); } @@ -191,7 +192,7 @@ class FastXML { throw "Cannot access document attribute "+name; x.set(name,value); } - + public function toString() : String { return x.toString(); } @@ -201,6 +202,19 @@ class FastXML { return new FastXML(x.firstChild()); } + #if openfl + public static function parseByteArray(s:openfl.utils.ByteArray) : FastXML { + s.position = 0; + var ss:String = s.readMultiByte(s.length, null); + var x = Xml.parse(ss); + var lastNode:Xml = null; + for (e in x) { + lastNode = e; + } + return new FastXML(lastNode); + } + #end + public static function filterNodes(a : FastXMLList, f : FastXML -> Bool) : FastXMLList { var rv = new Array(); for(i in a) diff --git a/src/FastXMLList.hx b/src/FastXMLList.hx index e42fedc..ccb7b29 100644 --- a/src/FastXMLList.hx +++ b/src/FastXMLList.hx @@ -38,7 +38,7 @@ class FastXMLList { public function iterator() : Iterator { return l.iterator(); } - + public function length() : Int { return l.length; } From 57e28f0e3ae77c67d792ffe7eca8a1abf39d4c0a Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 27 Jun 2018 18:16:32 +0300 Subject: [PATCH 107/156] fix of ternary with unop: (!true ? true : false) --- src/as3hx/ParserUtils.hx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/as3hx/ParserUtils.hx b/src/as3hx/ParserUtils.hx index ef15ad1..67607b1 100644 --- a/src/as3hx/ParserUtils.hx +++ b/src/as3hx/ParserUtils.hx @@ -18,7 +18,7 @@ class ParserUtils { default: StringTools.replace(name, "$", "__DOLLAR__"); } } - + /** * Takes a token that may be a comment and returns * an array of tokens that will have the comments @@ -137,7 +137,7 @@ class ParserUtils { return t; } default: - return t; + return t; } } @@ -163,7 +163,7 @@ class ParserUtils { } /** - * In certain cases, a typedef will be generated + * In certain cases, a typedef will be generated * for a class attribute, for better type safety */ public static function generateTypeIfNeeded(classVar : ClassField) @@ -204,12 +204,12 @@ class ParserUtils { default: return null; } - + //if the array is empty, type can't be defined if (arrayDecl.length == 0) { return null; } - + //return the type of an object field var getType:Expr->String = function(e) { switch (e) { @@ -220,12 +220,12 @@ class ParserUtils { case CFloat(v): return "Float"; case CString(v): - return "String"; + return "String"; } case EIdent(id): if (id == "true" || id == "false") { return "Bool"; - } + } return "Dynamic"; default: return "Dynamic"; @@ -233,7 +233,7 @@ class ParserUtils { } //Type declaration is only created for array of objects,. - //Type is retrieved from the first object fields, then + //Type is retrieved from the first object fields, then //all remaining objects in the array are check against this //type. If the type is different, then it is a mixed type //array and no type declaration should be created @@ -338,6 +338,7 @@ class ParserUtils { public static function makeUnop(op:String, e:Expr):Expr { return switch(e) { + case ETernary(cond, e1, e2): ETernary(EUnop(op, true, cond), e1, e2); case EBinop(bop, e1, e2, n): EBinop(bop, makeUnop(op, e1), e2, n); default: EUnop(op, true, e); } From cd5b519f70025f7e1b02f8780b347cba9e4384ae Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 27 Jun 2018 18:19:31 +0300 Subject: [PATCH 108/156] fix of missparsing of /*/ as closed comment --- src/as3hx/Tokenizer.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/as3hx/Tokenizer.hx b/src/as3hx/Tokenizer.hx index acf9f78..149ba86 100644 --- a/src/as3hx/Tokenizer.hx +++ b/src/as3hx/Tokenizer.hx @@ -251,6 +251,7 @@ class Tokenizer { var old = line; var contents : String = "/*"; try { + char = null; while( true ) { while( char != "*".code ) { if( char == "\n".code ) { From 33b539dc42da4ddad6f5ac4af1a4a47b48f2abe5 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 27 Jun 2018 18:29:17 +0300 Subject: [PATCH 109/156] deeper rebuild options --- src/as3hx/RebuildUtils.hx | 127 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 123 insertions(+), 4 deletions(-) diff --git a/src/as3hx/RebuildUtils.hx b/src/as3hx/RebuildUtils.hx index 4437241..65d4a54 100644 --- a/src/as3hx/RebuildUtils.hx +++ b/src/as3hx/RebuildUtils.hx @@ -1,9 +1,10 @@ package as3hx; import as3hx.As3.Expr; +import as3hx.As3.Function; +import as3hx.As3.Program; import as3hx.As3.SwitchCase; import as3hx.As3.SwitchDefault; import as3hx.As3.T; -import neko.Lib; enum RebuildResult { RReplace( expr : Expr ); // replace current expression with provided expr @@ -18,6 +19,50 @@ enum RebuildResult { */ class RebuildUtils { + public static function rebuildProgram(program:Program, cfg:Config, typer:Typer, rebuild:Expr->RebuildResult):Void { + for (d in program.defs) { + switch (d) { + case CDef(c): + var path:String = typer.getPackageString(program.pack) + c.name; + typer.setPackage(typer.getImportString(program.pack, false)); + typer.setImports(WriterImports.getImports(program, cfg, c), null); + typer.enterClass(path, c); + for (field in c.fields) { + switch(field.kind) { + case FFun(f): + typer.enterFunction(f, field.name, c); + var expr:Expr = RebuildUtils.rebuild(f.expr, rebuild); + if (expr != null) { + f.expr = expr; + } + rebuildArgs(f, rebuild); + typer.leaveFunction(); + case FVar(t, val): + var expr:Expr = RebuildUtils.rebuild(EBinop("=", EIdent(field.name), val, false), rebuild); + if (expr != null) { + // type could be changed while rebuilding + t = field.kind.getParameters()[0]; + switch(expr) { + case EBinop(_, _, val, _): + field.kind = FVar(t, val); + typer.overrideFieldType(path, field.name, typer.expandType(t)); + default: + } + } + default: + } + } + case FDef(f): + var expr:Expr = RebuildUtils.rebuild(f.f.expr, rebuild); + if (expr != null) { + f.f.expr = expr; + } + rebuildArgs(f.f, rebuild); + default: + } + } + } + public static function rebuildArray(es:Array, rebuildMethod:Expr->RebuildResult):Array { var needRebuild:Bool = false; var rs:Array = new Array(); @@ -61,8 +106,8 @@ class RebuildUtils return rebuildExprParams(e, rebuildMethod); } } - - private static function rebuildToArray(e:Expr, rebuildMethod:Expr->RebuildResult, output:Array):Bool { + + public static function rebuildToArray(e:Expr, rebuildMethod:Expr->RebuildResult, output:Array):Bool { var r:RebuildResult = rebuildMethod(e); switch(r) { case RReplace(expr): @@ -117,6 +162,7 @@ class RebuildUtils case EFunction(f, name): var rexpr = rebuild(f.expr, rebuildMethod); if (rexpr == null) return null; + rebuildArgs(f, rebuildMethod); return EFunction({args:f.args, varArgs:f.varArgs, ret:f.ret, expr:rexpr}, name); case EBlock(es): var r:Array = rebuildArray(es, rebuildMethod); @@ -125,6 +171,13 @@ class RebuildUtils } else { return EBlock(r); } + case EArrayDecl(es): + var r:Array = rebuildArray(es, rebuildMethod); + if (r == null) { + return null; + } else { + return EArrayDecl(r); + } case EForIn(e1, e2, e3): var re1:Expr = rebuild(e1, rebuildMethod); var re2:Expr = rebuild(e2, rebuildMethod); @@ -244,6 +297,13 @@ class RebuildUtils var re:Expr = rebuild(e, rebuildMethod); if (re == null) return null; return ENamespaceAccess(re, f); + case EArray(e, index): + var re:Expr = rebuild(e, rebuildMethod); + var rindex:Expr = rebuild(index, rebuildMethod); + if (re == null && index == null) return null; + if (re == null) re = e; + if (rindex == null) rindex = index; + return EArray(re, rindex); case EField(e, f): var re:Expr = rebuild(e, rebuildMethod); if (re == null) return null; @@ -262,10 +322,26 @@ class RebuildUtils var re:Expr = rebuild(e, rebuildMethod); if (re == null) return null; return EUnop(op, prefix, re); + case EReturn(e): + var re:Expr = rebuild(e, rebuildMethod); + if (re == null) return null; + return EReturn(re); case EParent(e): var re:Expr = rebuild(e, rebuildMethod); if (re == null) return null; return EParent(re); + case ETernary(cond, e1, e2): + var rcond:Expr = rebuild(cond, rebuildMethod); + var re1:Expr = rebuild(e1, rebuildMethod); + var re2:Expr = rebuild(e2, rebuildMethod); + if (rcond != null || re1 != null || re2 != null) { + if (rcond == null) rcond = cond; + if (re1 == null) re1 = e1; + if (re2 == null) re2 = e2; + return ETernary(rcond, re1, re2); + } else { + return null; + } case EBinop(op, e1, e2, newLineAfterOp): var re1:Expr = rebuild(e1, rebuildMethod); var re2:Expr = rebuild(e2, rebuildMethod); @@ -276,7 +352,34 @@ class RebuildUtils } else { return null; } - //case EVars(vars): not implemented + case ETypedExpr(e, t): + var re:Expr = rebuild(e, rebuildMethod); + if (re == null) return null; + return ETypedExpr(re, t); + case EVars(vars): + if (vars.length == 1) { + var v = vars[0]; + if (v.val != null) { + var rval:Expr = rebuild(v.val, rebuildMethod); + if (rval == null) return null; + return EVars([{name:v.name, t:v.t, val:rval}]); + } + } + case EObject(fields): + var needRebuild:Bool = false; + var resultFields:Array<{ name : String, e : Expr }> = []; + for (i in 0...fields.length) { + var re:Expr = rebuild(fields[i].e, rebuildMethod); + if (re != null) { + resultFields.push({name:fields[i].name, e:re}); + needRebuild = true; + } else { + resultFields.push(fields[i]); + } + } + if (needRebuild) { + return EObject(resultFields); + } case ECommented(a, b, c, e): e = rebuild(e, rebuildMethod); if (e == null) return null; @@ -337,4 +440,20 @@ class RebuildUtils return null; } } + + private static function rebuildArgs(f:Function, rebuildMethod:Expr->RebuildResult):Void { + //Array<{ name : String, t : Null, val : Null, exprs:Array }> + for (v in f.args) { + switch(v.val) { + case null: + case EConst(_): + case EIdent("null"): + default: + var rv:Expr = rebuild(v.val, rebuildMethod); + if (rv != null) { + v.val = rv; + } + } + } + } } \ No newline at end of file From 904d0b5ab5f06deebbd6fedbea3620bb588c765d Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 27 Jun 2018 18:31:09 +0300 Subject: [PATCH 110/156] improvement of VarExprFix. Still not ideal but covers a lot of cases --- src/as3hx/VarExprFix.hx | 210 ++++++++++++++++++++++++++++++++-------- 1 file changed, 171 insertions(+), 39 deletions(-) diff --git a/src/as3hx/VarExprFix.hx b/src/as3hx/VarExprFix.hx index a590861..412f199 100644 --- a/src/as3hx/VarExprFix.hx +++ b/src/as3hx/VarExprFix.hx @@ -11,16 +11,23 @@ import neko.Lib; class VarExprFix { private var cfg:Config; - + public function new(cfg:Config){ this.cfg = cfg; } - + public function apply(f:Function, es:Array, typer:Typer):Array { - var map:Map = typer.getContextClone(-1); + var map:Map = typer.getContextClone(0); var localVar:Map = new Map(); var firstUse:Map = new Map(); var firstUseLine:Map> = new Map>(); + var blockVars:Array = new Array(); + var restrictedVars:Array = new Array(); + var varsToIgnore:Array = new Array(); + var hasVarsToInsert:Bool = false; + var inLocalFunction:Bool = false; + var line:Int = 0; + var depth:Int = 0; for (v in map.keys()) { firstUse.set(v, -1); localVar.set(v, false); @@ -33,36 +40,142 @@ class VarExprFix firstUse.set(f.varArgs, -1); localVar.set(f.varArgs, true); } - var line:Int = 0; - function rebuildMethodLookForVars(e:Expr):RebuildResult { + function rebuildMethodCleanUp(e:Expr):RebuildResult { switch(e) { - case EIdent(v): - if (v != null && !firstUse.exists(v)) { - firstUse.set(v, line); - if (firstUseLine.exists(line)) { - firstUseLine.get(line).push(v); + case EVars(vars/*Array<{ name : String, t : Null, val : Null }>*/): + var newVars:Array = []; + var hasChange:Bool = false; + for (vr in vars) { + var v:String = vr.name; + if (varsToIgnore.indexOf(v) != -1 && (!firstUseLine.exists(line) || firstUseLine.get(line).indexOf(v) == -1)) { + hasChange = true; + if (firstUseLine.exists(line)) { + firstUseLine.get(line).push(v); + } else { + firstUseLine.set(line, [v]); + hasVarsToInsert = true; + } + if (vr.val != null) { + newVars.push(EBinop("=", EIdent(v), vr.val, false)); + } } else { - firstUseLine.set(line, [v]); + newVars.push(EVars([vr])); } } - case EFunction(f, v): + if (hasChange) { + return RebuildResult.RReplaceArray(newVars); + } + default: + } + return null; + } + function rebuildMethodLookForVars(e:Expr):RebuildResult { + switch(e) { + case EFor(inits, conds, incrs, e): + if (inLocalFunction) return null; + depth++; + var oldBlockVars:Array = blockVars; + blockVars = new Array(); + + var rinits:Array = RebuildUtils.rebuildArray(inits, rebuildMethodLookForVars); + var rconds:Array = RebuildUtils.rebuildArray(conds, rebuildMethodLookForVars); + var rincrs:Array = RebuildUtils.rebuildArray(incrs, rebuildMethodLookForVars); + var re:Expr = null; + switch(e) { + case EBlock(es): + var res:Array = RebuildUtils.rebuildArray(es, rebuildMethodLookForVars); + if (res != null) re = EBlock(res); + default: + re = RebuildUtils.rebuild(e, rebuildMethodLookForVars); + } + for (v in blockVars) { + restrictedVars.push(v); + } + blockVars = oldBlockVars; + depth--; + if (rinits == null && rconds == null && rincrs == null && re == null) { + return RebuildResult.RSkip; + } else { + if (rinits == null) rinits = inits; + if (rconds == null) rconds = conds; + if (rincrs == null) rincrs = incrs; + if (re == null) re = e; + return RebuildResult.RReplace(EFor(rinits, rconds, rincrs, re)); + } + case EBlock(es): + if (inLocalFunction) return null; + depth++; + var oldBlockVars:Array = blockVars; + blockVars = new Array(); + var r:Array = RebuildUtils.rebuildArray(es, rebuildMethodLookForVars); + for (v in blockVars) { + restrictedVars.push(v); + } + blockVars = oldBlockVars; + depth--; + if (r == null) { + return RebuildResult.RSkip; + } else { + return RebuildResult.RReplace(EBlock(r)); + } + case EIdent(v): if (v != null) { - map.set(v, "Function"); + if (!localVar.exists(v)) { + if (!inLocalFunction && v == "arguments") { + var arguments:Array = []; + for (arg in f.args) { + arguments.push(EIdent(arg.name)); + } + return RebuildResult.RReplace(ECommented("/*arguments*/", true, true, EArrayDecl(arguments))); + } + return null; + } + if (!firstUse.exists(v) || firstUse.get(v) == -1) { + firstUse.set(v, line); + if (firstUseLine.exists(line)) { + firstUseLine.get(line).push(v); + } else { + firstUseLine.set(line, [v]); + hasVarsToInsert = true; + } + } else if (restrictedVars.indexOf(v) != -1) { + varsToIgnore.push(v); + restrictedVars.remove(v); + } + } + case EFunction(f, name): + if (name != null) { + map.set(name, "Function"); } + var oldInLocalFunction = inLocalFunction; + inLocalFunction = true; + var rexpr = RebuildUtils.rebuild(f.expr, rebuildMethodLookForVars); + inLocalFunction = oldInLocalFunction; + if (rexpr == null) return null; + return RebuildResult.RReplace(EFunction({args:f.args, varArgs:f.varArgs, ret:f.ret, expr:rexpr}, name)); case EVars(vars/*Array<{ name : String, t : Null, val : Null }>*/): + if (inLocalFunction) return null; var newVars:Array = []; var hasChange:Bool = false; for (vr in vars) { var v:String = vr.name; - if (firstUse.exists(v) && localVar.get(v) == true) { + if (!localVar.exists(v)) continue; + if (firstUse.exists(v) && firstUse.get(v) != -1) { hasChange = true; if (vr.val != null) { newVars.push(EBinop("=", EIdent(v), vr.val, false)); } + if (restrictedVars.indexOf(v) != -1) { + varsToIgnore.push(v); + restrictedVars.remove(v); + } } else { - firstUse.set(v, -2); + if (depth > 0) { + blockVars.push(v); + } newVars.push(EVars([vr])); } + firstUse.set(v, -2); localVar.set(v, true); map.set(v, typer.tstring(vr.t)); } @@ -73,12 +186,13 @@ class VarExprFix } return null; } - function rebuildMethodPutVars(e:Expr):Array { + function rebuildMethodInsertVars(e:Expr):RebuildResult { if (firstUseLine.exists(line)) { - var res:Array = []; + var res:Array = null; for (name in firstUseLine.get(line)) { + if (firstUse.get(name) != -2) continue; var type:String = map.get(name); - if (type == null) continue; + if (type == null || type == "Function") continue; var defaultValue:Expr = null; switch(type) { case "int", "Int", "UInt": @@ -88,34 +202,52 @@ class VarExprFix default: defaultValue = EIdent("null"); } - res.push(ENL( EVars([ { name:name, t:TPath([type]), val:defaultValue } ]))); + if (res == null) res = []; + res.push(ENL(EVars([ { name:name, t:TPath([type]), val:defaultValue } ]))); } - if (res.length > 0 ) { - res.push(e); - return res; + if (res != null && res.length > 0) { + var te:Expr = e; + var newLines:Int = 0; + while (true) { + switch(te) { + case ENL(e): + te = e; + newLines++; + default: + break; + } + } + while (newLines-- > 1) { + res[0] = ENL(res[0]); + } + res.push(ENL(te)); + return RebuildResult.RReplaceArray(res); } } - return null; - } - var res:Array = []; - res = RebuildUtils.rebuildArray(es, rebuildMethodLookForVars); - if (res == null) { - res = es; + return RebuildResult.RSkip; } - es = res; - res = []; - for (i in 0...es.length) { - line = i; - var e:Expr = es[i]; - var a:Array = rebuildMethodPutVars(e); - if (a != null) { - for (e in a) { - res.push(e); + function rebuildByLine(es:Array, rebuildMethod:Expr->RebuildResult):Array { + var needRebuild:Bool = false; + var rs:Array = new Array(); + for (i in 0...es.length) { + line = i; + if (RebuildUtils.rebuildToArray(es[i], rebuildMethod, rs)) { + needRebuild = true; } + } + if (needRebuild) { + return rs; } else { - res.push(e); + return es; } } - return res; + es = rebuildByLine(es, rebuildMethodLookForVars); + if (varsToIgnore.length > 0) { + es = rebuildByLine(es, rebuildMethodCleanUp); + } + if (hasVarsToInsert) { + es = rebuildByLine(es, rebuildMethodInsertVars); + } + return es; } } \ No newline at end of file From 43390eeddd5adef494bc0bf48907aed8f66f0cfc Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 27 Jun 2018 18:43:11 +0300 Subject: [PATCH 111/156] attempt to import classes from is , as expressions --- src/as3hx/parsers/ExprParser.hx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/as3hx/parsers/ExprParser.hx b/src/as3hx/parsers/ExprParser.hx index 26421a3..90e258f 100644 --- a/src/as3hx/parsers/ExprParser.hx +++ b/src/as3hx/parsers/ExprParser.hx @@ -269,7 +269,11 @@ class ExprParser { return switch(e2) { case ETernary(cond, te1, te2): ETernary(ParserUtils.makeBinop(tokenizer, s, e1, cond, pendingNewLines != 0), te1, te2); - default: ParserUtils.makeBinop(tokenizer, s, e1, e2, pendingNewLines != 0); + case EIdent(v) if (s != "in"): + types.seen.push(TPath([v])); + ParserUtils.makeBinop(tokenizer, s, e1, e2, pendingNewLines != 0); + default: + ParserUtils.makeBinop(tokenizer, s, e1, e2, pendingNewLines != 0); } default: if (pendingNewLines != 0) { From 91b1c1f1d2c14cd833a950f7cd46ca30b206e51d Mon Sep 17 00:00:00 2001 From: Xmitre Date: Thu, 28 Jun 2018 00:08:25 +0300 Subject: [PATCH 112/156] typing of everything parsing of type params and type hints from comments /*HintType*/ /**/. libPaths Config option for paths that are used for typing but not for conversion getQualifiedClassName and getQualifiedSuperClassName are now processed in Writer. ClassDef now is a class. Generated types are written before class. Number.toPrecision() refining of type params for Dictionaries and Signals typing of EForEach params handling of multi fromCharCode, multi shift handling of toLocaleLowerCase, toLocaleUpperCase handling of Vector.filter, Array.filter handling of Int a /= b --- src/AS3.hx | 102 ++ src/Run.hx | 48 +- src/as3hx/As3.hx | 24 +- src/as3hx/CallbackRebuild.hx | 48 + src/as3hx/CommonImports.hx | 79 + src/as3hx/Compat.hx | 302 +++- src/as3hx/Config.hx | 21 +- src/as3hx/DictionaryRebuild.hx | 266 +++ src/as3hx/InheritanceTypeParser.hx | 27 + src/as3hx/RebuildParentStaticFieldAccess.hx | 42 + src/as3hx/SignalRebuild.hx | 273 ++++ src/as3hx/Typer.hx | 1628 ++++++++++++++++--- src/as3hx/Writer.hx | 1121 +++++++++---- src/as3hx/WriterImports.hx | 115 ++ src/as3hx/parsers/ClassParser.hx | 68 +- src/as3hx/parsers/OverrideTypeComment.hx | 40 + src/as3hx/parsers/ProgramParser.hx | 2 +- src/as3hx/parsers/StructureParser.hx | 136 +- src/as3hx/parsers/TypeParser.hx | 51 +- 19 files changed, 3717 insertions(+), 676 deletions(-) create mode 100644 src/AS3.hx create mode 100644 src/as3hx/CallbackRebuild.hx create mode 100644 src/as3hx/CommonImports.hx create mode 100644 src/as3hx/DictionaryRebuild.hx create mode 100644 src/as3hx/InheritanceTypeParser.hx create mode 100644 src/as3hx/RebuildParentStaticFieldAccess.hx create mode 100644 src/as3hx/SignalRebuild.hx create mode 100644 src/as3hx/WriterImports.hx create mode 100644 src/as3hx/parsers/OverrideTypeComment.hx diff --git a/src/AS3.hx b/src/AS3.hx new file mode 100644 index 0000000..5b221c7 --- /dev/null +++ b/src/AS3.hx @@ -0,0 +1,102 @@ +package; +import haxe.macro.Context; +import haxe.macro.Expr.ExprOf; +import haxe.macro.Expr; + +/** + * ... + * @author + */ +class AS3 { + + public static function str(e:Dynamic):String { + var t:Class = Type.getClass(e); + return t == null ? Std.string(e) : "[object " + Type.getClassName(t) + "]"; + } + + public static inline function asDynamic(e:Dynamic):Dynamic { + return Std.is(e, haxe.Constraints.IMap) ? e : null; + } + + public static inline function asDictionary(e:Dynamic):Dynamic { + return Std.is(e, haxe.Constraints.IMap) ? untyped e : null; + } + + public static inline function asObject(e:Dynamic):openfl.utils.Object { + return untyped e; + } + + public static inline function asClass(e:Dynamic, t:Class):T { + return Std.is(e, t) ? untyped e : null; + } + + public static inline function asFloat(e:Dynamic):Float { + //return cast(e, Float); + return as3hx.Compat.parseFloat(e); + } + + public static inline function asBool(e:Dynamic):Bool { + return e != false && e != null && e != 0 && !(Std.is(e, String) && e.length == 0); + } + + public static function AS(e:Dynamic, type:Dynamic):Dynamic { + return Std.is(e, type) ? e : null; + } + + public static macro function as(e:Expr, type:Expr):Expr { + //switch(Context.typeof(e)) { + switch(type.expr) { + //case EConst(CIdent("Dictionary")): return macro Std.is($e, haxe.Constraints.IMap) ? $e : null; + case EConst(CIdent("Dictionary")): return macro AS3.asDictionary($e); + case EConst(CIdent("Object")): return macro AS3.asObject($e); + case EConst(CIdent("Float")): return macro AS3.asFloat($e); + case EConst(CIdent("Bool")): return macro AS3.asBool($e); + + //write("(try cast("); + //writeExpr(e1); + //write(", "); + //switch(e2) { + //case EIdent(s): writeModifiedIdent(s); + //default: writeExpr(e2); + //} + //case TAbstract(t, _) if(t.get().name == "Dictionary"): return macro Std.is($e, haxe.Constraints.IMap) ? $e : null; + //case TInst(t, _) if(t.get().pack.length == 0): t.get().name; + case _: + } + //throw Context.typeExpr(type); + //throw Context.typeof(type); + return macro AS3.asClass($e, $type); + //return macro { + //cast AS3.AS(${e}, ${type}); + //cast(AS3.AS(${e}, ${type}), ); + //} + //return switch(type) { + //case "Int": macro ${e}; + //case "Float": macro Std.int(${e}); + //case "String": macro @:privateAccess as3hx.Compat._parseInt(${e}, ${base}); + //case "Bool": macro ${e} ? 1 : 0; + //case _: macro Std.parseInt(Std.string(${e})); + //} + } + + public static inline function hasOwnProperty(o:Dynamic, field:String):Bool { + #if js + var tmp; + if(o == null) { + return false; + } else { + var tmp1; + if(untyped o.__properties__ && o.__properties__["get_" + field]) { + return true; + } else if (untyped o.prototype) { + return untyped o.prototype.hasOwnProperty(field); + } else { + return Reflect.hasField(o, field); + } + } + #else + return false; + #end + } + +} \ No newline at end of file diff --git a/src/Run.hx b/src/Run.hx index 46485e9..86806d8 100644 --- a/src/Run.hx +++ b/src/Run.hx @@ -2,9 +2,9 @@ using StringTools; import as3hx.As3.Program; import as3hx.Config; +import as3hx.Error; import as3hx.ParserUtils; import as3hx.Writer; -import as3hx.Error; import sys.FileSystem; import sys.io.File; using haxe.io.Path; @@ -34,6 +34,45 @@ class Run { } } + static function loopImports(src:String, excludes:List) { + if (src == null) { + Sys.println("source path cannot be null"); + } + src = src.normalize(); + var subDirList = new Array(); + for(f in FileSystem.readDirectory(src)) { + var srcChildAbsPath = src.addTrailingSlash() + f; + if (FileSystem.isDirectory(srcChildAbsPath)) { + subDirList.push(f); + } else if(f.endsWith(".as") && !isExcludeFile(excludes, srcChildAbsPath)) { + var file = srcChildAbsPath; + Sys.println("import AS3 file: " + file); + var p = new as3hx.Parser(cfg); + var content = File.getContent(file); + var program = try p.parseString(content, src, f) catch(e : Error) { + #if macro + File.stderr().writeString(file + ":" + p.tokenizer.line + ": " + errorString(e) + "\n"); + #end + if(cfg.errorContinue) { + errors.push("In " + file + "(" + p.tokenizer.line + ") : " + errorString(e)); + continue; + } else { + #if neko + neko.Lib.rethrow("In " + file + "(" + p.tokenizer.line + ") : " + errorString(e)); + #elseif cpp + cpp.Lib.rethrow("In " + file + "(" + p.tokenizer.line + ") : " + errorString(e)); + null; + #end + } + } + writer.register(program); + } + } + for (name in subDirList) { + loopImports((src.addTrailingSlash() + name), excludes); + } + } + static function loop(src:String, dst:String, excludes:List) { if (src == null) { Sys.println("source path cannot be null"); @@ -126,8 +165,14 @@ class Run { if (cfg.useFullTyping) { writer = new Writer(cfg); } + for (libPath in cfg.libPaths) { + loopImports(libPath, cfg.excludePaths); + } + + loop(cfg.src, cfg.dst, cfg.excludePaths); if (cfg.useFullTyping) { + writer.prepareTyping(); if (cfg.useOpenFlTypes) { for (f in files) { writer.refineTypes(f.program); @@ -136,6 +181,7 @@ class Run { writer.applyRefinedTypes(f.program); } } + writer.finishTyping(); for (f in files) { writeFile(f.name, f.program, cfg, f.f, f.src); } diff --git a/src/as3hx/As3.hx b/src/as3hx/As3.hx index e0ea40d..fbb5cf9 100644 --- a/src/as3hx/As3.hx +++ b/src/as3hx/As3.hx @@ -83,16 +83,20 @@ typedef ClassField = { var condVars : Array; } -typedef ClassDef = { - var meta : Array; - var kwds : Array; - var imports : Array>; - var isInterface : Bool; - var name : String; - var fields : Array; - var implement : Array; - var extend : Null; - var inits : Array; +class ClassDef { + public function new():Void { + + } + public var meta : Array; + public var kwds : Array; + public var imports : Array>; + public var isInterface : Bool; + public var name : String; + public var typeParams : String; + public var fields : Array; + public var implement : Array; + public var extend : Null; + public var inits : Array; } typedef FunctionDef = { diff --git a/src/as3hx/CallbackRebuild.hx b/src/as3hx/CallbackRebuild.hx new file mode 100644 index 0000000..149450e --- /dev/null +++ b/src/as3hx/CallbackRebuild.hx @@ -0,0 +1,48 @@ +package as3hx; +import as3hx.As3.Expr; +import as3hx.As3.Function; +import as3hx.As3.Program; +import as3hx.As3.T; +import as3hx.RebuildUtils.RebuildResult; + +/** + * ... + * @author + */ +class CallbackRebuild { + private var cfg:Config; + private var typer:Typer; + + public function new(cfg:Config, typer:Typer) { + this.cfg = cfg; + this.typer = typer; + } + + + public function apply(program:Program):Void { + RebuildUtils.rebuildProgram(program, cfg, typer, rebuild); + } + + private function rebuild(expr:Expr):RebuildResult { + switch (expr) { + case ECall(e, params) : + var args:Array = typer.getFunctionArgTypes(e); + if (args != null) { + for (i in 0...args.length) { + var a = args[i]; + if (a != null && params[i] != null) { + var t:String = typer.tstring(a); + if (t != null && t.indexOf("->") != -1) { + var ps:Array = t.split("->"); + var pt:Array = ps.map(function(s:String):T { return TPath([typer.expandStringType(s)]); }); + typer.overrideExprType(params[i], TFunction(pt)); + } + } + } + } + default: + } + return null; + } + +} \ No newline at end of file diff --git a/src/as3hx/CommonImports.hx b/src/as3hx/CommonImports.hx new file mode 100644 index 0000000..9f91867 --- /dev/null +++ b/src/as3hx/CommonImports.hx @@ -0,0 +1,79 @@ +package as3hx; + +/** + * ... + * @author xmi + */ +class CommonImports +{ + private static var imports:Map> = new Map>(); + public static function getImports(cfg:Config):Map { + if (imports.exists(cfg)) { + return imports.get(cfg); + } else { + var newImports:Map = createImports(cfg); + imports.set(cfg, newImports); + return newImports; + } + } + + private static function createImports(cfg:Config):Map { + var map:Map = new Map(); + var doNotImportClasses = [ + "Array", "Bool", "Boolean", "Class", "Date", + "Dynamic", "EReg", "Enum", "EnumValue", + "Float", "Map", "Int", "UInt", "IntIter", + "Lambda", "List", "Math", "Number", "Reflect", + "RegExp", "Std", "String", "StringBuf", + "StringTools", "Sys", "Type", "Void", + "Function", "XML", "XMLList" + ]; + + if (!cfg.useOpenFlTypes) { + doNotImportClasses.push("Object"); + } + + for(c in doNotImportClasses) { + //map.set(c, null); + map.set(c, c); + } + + if (!cfg.functionToDynamic) { + map.set("Function", "haxe.Constraints.Function"); + } + + if (cfg.useOpenFlTypes) { + map.set("Vector", "openfl.Vector"); + map.set("Object", "openfl.utils.Object"); + } + + var topLevelErrorClasses = [ + "ArgumentError", "DefinitionError", "Error", + "EvalError", "RangeError", "ReferenceError", + "SecurityError", "SyntaxError", "TypeError", + "URIError", "VerifyError" + ]; + + for(c in topLevelErrorClasses) { + if (cfg.useOpenFlTypes) { + map.set(c, "openfl.errors." + c); + } else { + map.set(c, "flash.errors." + c); + } + } + + for(c in cfg.importTypes.keys()) { + map.set(c, cfg.importTypes.get(c)); + } + map.set("MD5", "MD5"); + map.set("Signal", "signals.Signal"); + map.set("ISignal", "signals.Signal"); + map.set("NativeSignal", "signals.NativeSignal"); + map.set("AGALMiniAssembler", "openfl.utils.AGALMiniAssembler"); + map.set("Base64", "haxe.crypto.Base64"); + + //import avm2.intrinsics.memory.Sf32; + //import avm2.intrinsics.memory.Si32; + return map; + } +} \ No newline at end of file diff --git a/src/as3hx/Compat.hx b/src/as3hx/Compat.hx index 23c36be..083f273 100644 --- a/src/as3hx/Compat.hx +++ b/src/as3hx/Compat.hx @@ -1,13 +1,14 @@ package as3hx; import Type; +import haxe.ds.Vector; import haxe.macro.Expr; import haxe.macro.Context; using StringTools; /** - * Collection of functions that just have no real way to be compatible in Haxe + * Collection of functions that just have no real way to be compatible in Haxe */ class Compat { @@ -44,7 +45,7 @@ class Compat { if (a.length > length) a.splice(length, a.length - length); else a[length - 1] = null; } - + /** * Adds elements to and removes elements from an array. This method modifies the array without making a copy. * @param startIndex An integer that specifies the index of the element in the array where the insertion or @@ -64,7 +65,7 @@ class Compat { public static inline function arraySplice(a:Array, startIndex:Int, deleteCount:Int, ?values:Array):Array { var result = a.splice(startIndex, deleteCount); if(values != null) { - for(i in 0...values.length) { + for (i in 0...values.length) { a.insert(startIndex + i, values[i]); } } @@ -90,7 +91,7 @@ class Compat { public static function match(s:String, ereg:FlashRegExpAdapter, parenthesesBlockIndex:Int = 0):Array { var matches:Array = []; while (ereg.match(s)) { - matches.push(ereg.matched(parenthesesBlockIndex)); + matches.push(ereg.matched(parenthesesBlockIndex)); s = ereg.matchedRight(); } return matches; @@ -99,38 +100,59 @@ class Compat { public static function matchEReg(s:String, ereg:EReg, parenthesesBlockIndex:Int = 0):Array { var matches:Array = []; while (ereg.match(s)) { - matches.push(ereg.matched(parenthesesBlockIndex)); + matches.push(ereg.matched(parenthesesBlockIndex)); s = ereg.matchedRight(); } return matches; } - public static function makeArgs(a1:Dynamic, a2:Dynamic, a3:Dynamic, a4:Dynamic, a5:Dynamic = null, a6:Dynamic = null):Array { - if (a6 == null) { - if (a5 == null) { - if (a4 == null) { - if (a3 == null) { - if (a2 == null) { - if (a1 == null) { - return []; + public static function makeArgs(a1:Dynamic, a2:Dynamic, a3:Dynamic, a4:Dynamic, a5:Dynamic = null, a6:Dynamic = null, a7:Dynamic = null):Array { + if (a7 == null) { + if (a6 == null) { + if (a5 == null) { + if (a4 == null) { + if (a3 == null) { + if (a2 == null) { + if (a1 == null) { + return []; + } else { + return [a1]; + } } else { - return [a1]; + return [a1, a2]; } } else { - return [a1, a2]; + return [a1, a2, a3]; } } else { - return [a1, a2, a3]; + return [a1, a2, a3, a4]; } } else { - return [a1, a2, a3, a4]; + return [a1, a2, a3, a4, a5]; } } else { - return [a1, a2, a3, a4, a5]; + return [a1, a2, a3, a4, a5, a6]; } } else { - return [a1, a2, a3, a4, a5, a6]; + return [a1, a2, a3, a4, a5, a6, a7]; + } + } + + private static var _weights:Array; + public static function sortIndexedArray(weights:Array):Array { + var indices:Array = new Array(); + for (i in 0...weights.length) { + indices[i] = i; } + _weights = weights; + indices.sort(sortWeights); + _weights = null; + return indices; + } + + private static function sortWeights(a:Int, b:Int):Int { + var d:Float = _weights[b] - _weights[a]; + return d > 0 ? 1 : (d < 0 ? -1 : 0); } macro public static function getFunctionLength(f) { @@ -139,7 +161,105 @@ class Compat { default: throw new Error("not a function", f.pos); } } - + + #if openfl + public static inline function newByteArray():openfl.utils.ByteArray { + var ba:openfl.utils.ByteArray = new openfl.utils.ByteArray(); + ba.endian = openfl.utils.Endian.BIG_ENDIAN; + return ba; + } + + public static function castVector(p:Dynamic):openfl.Vector { + if (p == null) return null; + var c:Class = Type.getClass(p); + if (c == null) return null; + if (Type.getClassName(c) != "openfl._Vector.AbstractVector") return null; + //var type:String = Type.getClassName(Type.getClass(p.data)); + //} else if (TType == Function && type == "openfl._Vector.FunctionVector") { + return cast p; + } + + /** T==null is Vector.<*>, otherwise T could be Abstract of Class */ + public static function isVector(p:Dynamic, T:Dynamic = null):Bool { + if (p == null) return null; + var c:Class = Type.getClass(p); + if (c == null) return null; + if (Type.getClassName(c) != "openfl._Vector.AbstractVector") return null; + var v:openfl.Vector = cast p; + if (v.length > 0 && T != null && v[0] != null && !Std.is(v[0], T)) { + return false; + } + return true; + } + + public static inline function each(obj:openfl.utils.Object):Iterator { + return new ObjectIterator(obj); + } + + public static function filter(v:openfl.Vector, filterMethod:T->Int->openfl.Vector->Bool):openfl.Vector { + var r:openfl.Vector = new openfl.Vector(); + for (i in 0...v.length) { + if (filterMethod(v[i], i, v)) { + r.push(v[i]); + } + } + return r; + } + + public static inline function vectorSplice(a:openfl.Vector, startIndex:Int, deleteCount:Int, ?values:Array):openfl.Vector { + var result = a.splice(startIndex, deleteCount); + if(values != null) { + for (i in 0...values.length) { + a.insertAt(startIndex + i, values[i]); + } + } + return result; + } + #end + + public static inline function castClass(c:Dynamic):Class { + return switch(Type.typeof(c)) { + case TClass(c): c; + default: null; + } + } + + public static inline function getQualifiedClassName(o:Dynamic):String { + if (o == null) { + return null; + } else if (untyped o.__name__) { + return o.__name__; + } else { + var c:Class = Type.getClass(o); + if (c != null) { + return Type.getClassName(c); + } else { + return null; + } + } + //var c:Class = Type.getClass(o); + //if (c == null) { + //c = castClass(o); + //} + //if (c != null) { + //return Type.getClassName(c); + //} else { + //return null; + //} + } + + public static inline function getQualifiedSuperclassName(o:Dynamic):String { + var c:Class = Type.getClass(o); + if (c == null) { + c = castClass(o); + } + if (c != null) { + return Type.getClassName(Type.getSuperClass(c)); + } else { + return null; + } + } + /** * Converts a typed expression into a Float. */ @@ -169,10 +289,11 @@ class Compat { case "Int": macro ${e}; case "Float": macro Std.int(${e}); case "String": macro @:privateAccess as3hx.Compat._parseInt(${e}, ${base}); + case "Bool": macro ${e} ? 1 : 0; case _: macro Std.parseInt(Std.string(${e})); } } - + static function _parseInt(s:String, ?base:Int):Null { #if js if(base == null) base = s.indexOf("0x") == 0 ? 16 : 10; @@ -216,7 +337,7 @@ class Compat { /** * Runs a function at a specified interval (in milliseconds). - * + * * Instead of using the setInterval() method, consider * creating a Timer object, with the specified interval, using 0 as the repeatCount * parameter (which sets the timer to repeat indefinitely).If you intend to use the clearInterval() method to cancel the @@ -246,7 +367,7 @@ class Compat { return -1; #end } - + /** * Cancels a specified setInterval() call. * @param id The ID of the setInterval() call, which you set to a variable, as in the following: @@ -263,10 +384,10 @@ class Compat { throw "Supported by version 3.3 or higher"; #end } - + /** * Runs a specified function after a specified delay (in milliseconds). - * + * * Instead of using this method, consider * creating a Timer object, with the specified interval, using 1 as the repeatCount * parameter (which sets the timer to run only once).If you intend to use the clearTimeout() method to cancel the @@ -296,7 +417,7 @@ class Compat { return -1; #end } - + /** * Cancels a specified setTimeout() call. * @param id The ID of the setTimeout() call, which you set to a variable, as in the following: @@ -313,7 +434,7 @@ class Compat { throw "Supported by version 3.3 or higher"; #end } - + /** * Runtime value of FLOAT_MAX depends on target platform */ @@ -335,7 +456,7 @@ class Compat { return 1.79e+308; #end } - + /** * Runtime value of FLOAT_MIN depends on target platform */ @@ -357,7 +478,7 @@ class Compat { return -1.79E+308; #end } - + /** * Runtime value of INT_MAX depends on target platform */ @@ -381,7 +502,7 @@ class Compat { return 2^31-1; #end } - + /** * Runtime value of INT_MIN depends on target platform */ @@ -405,7 +526,7 @@ class Compat { return -2^31; #end } - + /** * Returns a string representation of the number in fixed-point notation. * Fixed-point notation means that the string will contain a specific number of digits @@ -437,13 +558,51 @@ class Compat { return s; #end } + + public static function toPrecision(n:Float, prec:Int):String { + n = Math.round(n * Math.pow(10, prec)); + var str = '' + n; + var len = str.length; + if(len <= prec){ + while(len < prec){ + str = '0' + str; + len++; + } + return '0.' + str; + } else{ + return str.substr(0, len - prec) + '.' + str.substr(len - prec); + } + } + + /** returns timezone offset in minutes */ + public static function getTimezoneOffset():Int { + #if flash + return untyped new flash.Date().getTimezoneOffset(); + #elseif js + return untyped __js__("new Date().getTimezoneOffset()"); + #else + var now = Date.now(); + now = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0); + return 24 * 60 * Math.round(now.getTime() / 24 / 3600 / 1000) - Std.int(now.getTime() / 1000 / 60); + /* + //https://github.com/HaxeFoundation/haxe/issues/3268 + var a = DateTools.format(Date.fromTime(0), '%H:%M').split(':'); + var offset = -Std.parseInt(a[0]) * 60 + Std.parseInt(a[1]); // will care about DST (daylight saving time), but can fail with < UTC-1200 and > UTC+1200 + trace(offset); + + //https://github.com/waneck/geotools/issues/2 + trace ( (new Date(1970, 0, 1, 0, 0, 0).getTime() / 1000 / 60)) ); // may not work in Neko, do not care about DST (daylight saving time) + trace ( ((new Date(1970, 1, 1, 0, 0, 0).getTime() - 31 * 24 * 60 * 60 * 1000) / 1000 / 60) ); //should work in Neko too + */ + #end + } } #if (!flash && !js && (haxe_ver >= "3.3")) private class FlashTimerAdapter { - + public static var timers:Array = []; - + public static function setInterval(callback:Dynamic, milliseconds:Int, rest:Array):Int { var timer = new haxe.Timer(milliseconds); timers.push(timer); @@ -451,9 +610,9 @@ private class FlashTimerAdapter { timer.run = function() Reflect.callMethod(null, callback, rest); return id; } - + public static function clearInterval(id:Int) stopTimer(id); - + public static function setTimeout(callback:Dynamic, milliseconds:Int, rest:Array):Int { var timer = new haxe.Timer(milliseconds); timers.push(timer); @@ -464,15 +623,15 @@ private class FlashTimerAdapter { } return id; } - + public static function clearTimeout(id:Int) stopTimer(id); - + static function stopTimer(id:Int) { timers[id].stop(); timers[id] = null; } -} -#end + } + #end #if python @:pythonImport("sys") @@ -488,24 +647,24 @@ typedef Regex = flash.utils.RegExp; typedef Regex = FlashRegExpAdapter; class FlashRegExpAdapter { - - public function new(r:String, opt:String) { + + public function new(r:String, opt:String = '') { _ereg = new EReg(r, opt); _global = opt.indexOf("g") != -1; } - + public var lastIndex(get, set):Int; - + var _ereg:EReg; var _global:Bool; var _lastTestedString : String; var _restOfLastTestedString : String; var _lastIndex:Int = 0; - + private function get_lastIndex():Int { return _lastIndex; } - + private function set_lastIndex(value:Int):Int { if (_lastIndex != value) { if (_lastTestedString != null) { @@ -516,10 +675,10 @@ class FlashRegExpAdapter { return value; } } - + /** * Performs a search for the regular expression on the given string str. - * + * * If the g (global) flag is not set for the regular * expression, then the search starts * at the beginning of the string (at index position 0); the search ignores @@ -530,7 +689,7 @@ class FlashRegExpAdapter { * of the end of the match. * @param str The string to search. * @return If there is no match, null; otherwise, an object with the following properties: - * + * * An array, in which element 0 contains the complete matching substring, and * other elements of the array (1 through n) contain substrings that match parenthetical groups * in the regular expression index — The character position of the matched substring within @@ -559,10 +718,10 @@ class FlashRegExpAdapter { } return matched ? new FlashRegExpExecResult(str, _ereg, index).matches : null; } - + /** * Tests for the match of the regular expression in the given string str. - * + * * If the g (global) flag is not set for the regular expression, * then the search starts at the beginning of the string (at index position 0); the search ignores * the lastIndex property of the regular expression.If the g (global) flag is set for the regular expression, then the search starts @@ -573,23 +732,23 @@ class FlashRegExpAdapter { * @return If there is a match, true; otherwise, false. */ public function test(str:String):Bool return match(str); - + public function map(s:String, f:EReg-> String):String return _ereg.map(s, f); - + public function match(s:String):Bool return _ereg.match(s); - + public function matched(n:Int):String return _ereg.matched(n); - + public function matchedLeft():String return _ereg.matchedLeft(); - + public function matchedPos():{pos:Int, len:Int} return _ereg.matchedPos(); - + public function matchedRight():String return _ereg.matchedRight(); - + public function matchSub(s:String, pos:Int, len:Int = -1):Bool return _ereg.matchSub(s, pos, len); - + public function replace(s:String, by:String):String return _ereg.replace(s, by); - + public function split(s:String):Array return _ereg.split(s); } @@ -599,11 +758,11 @@ private class FlashRegExpExecResult { this.index = index; populateMatches(ereg); } - + public var index(default,null) : Int = 0; public var input(default,null) : String; public var matches(default,null) : Array; - + function populateMatches(ereg:EReg) { matches = []; try { @@ -616,4 +775,25 @@ private class FlashRegExpExecResult { } } } +#end + +#if openfl +class ObjectIterator { + private var object:openfl.utils.Object; + private var fields:Array; + private var i:Int; + private var l:Int; + public inline function new(object:openfl.utils.Object) { + this.fields = Reflect.fields(object); + this.object = object; + this.i = 0; + this.l = fields.length; + } + public inline function next():Dynamic { + return object[fields[i++]]; + } + public inline function hasNext():Bool { + return i < l; + } +} #end \ No newline at end of file diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index 20f8a2e..bdf33e5 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -86,6 +86,12 @@ class Config { */ public var postProcessor : String = ""; + /** + * a list of absolute or relative directory paths. + * as3 files from this paths are parsed as a source for type info + */ + public var libPaths : Array; + /** * a list of absolute or relative directory paths. * Haxe files are found in this path and added to a map @@ -293,6 +299,8 @@ class Config { convertFlexunit = true; case "-dict2hash": dictionaryToHash = true; + case "-libPath", "--libPath": + libPaths.push(args.shift()); default: break; } @@ -352,6 +360,7 @@ class Config { case "verifyGeneratedFiles":setBoolField(el, false); case "flashTopLevelPackage":setCharField(el, "flash"); case "excludeList": setExcludeField(el, new List()); + case "libPaths": setLibPaths(el, new Array()); case "conditionalCompilationList": setConditionalVars(el, new List()); case "conditionalCompilationConstantsClass":setCharField(el, ""); case "fixLocalVariableDeclarations":setBoolField(el, true); @@ -398,6 +407,15 @@ class Config { } } + function setLibPaths(f:Fast, defaultLibPaths:Array) { + libPaths = defaultLibPaths; + for (dir in f.nodes.path) { + if (dir.has.value) { + libPaths.push(dir.att.value); + } + } + } + function setConditionalVars(f:Fast, defaultVars:List) { conditionalVars = defaultVars; for (conditionalVar in f.nodes.variable) { @@ -415,7 +433,7 @@ class Config { } } } - + function setImportExclude(f:Fast, defaultVars:Array) { importExclude = defaultVars; for (importPath in f.nodes.variable) { @@ -485,6 +503,7 @@ class Config { + '; diff --git a/src/as3hx/DictionaryRebuild.hx b/src/as3hx/DictionaryRebuild.hx new file mode 100644 index 0000000..2a92378 --- /dev/null +++ b/src/as3hx/DictionaryRebuild.hx @@ -0,0 +1,266 @@ +package as3hx; +import as3hx.As3.ClassDef; +import as3hx.As3.Expr; +import as3hx.As3.Function; +import as3hx.As3.Program; +import as3hx.As3.T; +import as3hx.DictionaryRebuild.ComplexType; +import as3hx.RebuildUtils.RebuildResult; +import neko.Lib; + +class ComplexType { + public var types:Array; + public var name:String; + public function new(name:String, types:Array):Void { + this.name = name; + this.types = types; + } +} + +typedef DictionaryTypes = { + key:Array, + value:Array +} + +/** + * ... + * @author ... + */ +class DictionaryRebuild +{ + var classFieldDictionaryTypes : Map> = new Map>(); + var typer:Typer; + var cfg:Config; + + public function new(typer:Typer, cfg:Config) { + this.typer = typer; + this.cfg = cfg; + } + + function getUnderlyingIdent(expr:Expr):Expr { + switch(expr) { + case EArray(e, index): + return getUnderlyingIdent(e); + case EField(e, f): + return e; + case EIdent(v): + return expr; + default: + return null; + } + } + + + private function isOpenFlDictionaryType(s:String):Bool { + return s != null && (StringTools.startsWith(s, "Dictionary") || StringTools.startsWith(s, "openfl.utils.Dictionary")) && cfg.useOpenFlTypes; + } + + public function applyRefinedTypes(program:Program):Void { + for (i in 0...4) { + refineTypes(program); + } + } + + public function refineTypes(program:Program):Void { + var currentClass:String = null; + var pack:String = typer.getPackageString(program.pack); + + function refineArrayAccess(e1:Expr, index:Expr, valueType:String):Void { + var type1:String = typer.getExprType(e1); + var identExpr:Expr = getUnderlyingIdent(e1); + var identType:String = typer.getExprType(identExpr); + switch(e1) { + case EArray(e, i): + var newStringType:String = "Dictionary<" + typer.getExprType(index) + "," + valueType + ">"; + refineArrayAccess(e, i, newStringType); + return; + default: + } + if (type1 != null && (StringTools.startsWith(type1, "Dictionary") || StringTools.startsWith(type1, "openfl.utils.Dictionary"))) { + var baseType:String = null; + var field:String = null; + switch(e1) { + case EField(e2, f): + baseType = typer.getExprType(e2); + field = f; + case EIdent(s): + baseType = pack + currentClass; + field = s; + default: + } + if (field != null && baseType != null) { + if (typer.classes.exists(baseType)) { + var indexType:String = typer.getExprType(index); + var newStringType:String = foldStringType(field, typer.expandStringType(type1), typer.expandStringType(indexType), typer.expandStringType(valueType)); + if (newStringType != type1) { + typer.overrideIdentType(field, typer.expandType(TPath([newStringType]))); + } + } + } + } + } + var returnType:T = null; + function rebuild(expr:Expr):RebuildResult { + switch(expr) { + case EFunction(f, name): + typer.enterFunction(f, name); + var oldReturnType:T = returnType; + returnType = f.ret.t; + var re:Expr = RebuildUtils.rebuild(f.expr, rebuild); + f.ret.t = returnType; + returnType = oldReturnType; + typer.leaveFunction(); + if (re != null) { + return RebuildResult.RReplace(EFunction({args: f.args, varArgs: f.varArgs, ret:f.ret, expr:re}, name)); + } else { + return RebuildResult.RSkip; + } + case EReturn(e): + switch(e) { + case EArray(e, index): + refineArrayAccess(e, index, typer.tstring(returnType)); + RebuildUtils.rebuild(e, rebuild); + RebuildUtils.rebuild(index, rebuild); + return RebuildResult.RSkip; + case null: + default: + var newType:String = typer.getExprType(e); + if (isOpenFlDictionaryType(newType)) { + var oldType:String = typer.tstring(returnType); + newType = foldDictionaryType2(oldType, newType); + newType = typer.shortenStringType(newType); + if (oldType != newType) { + returnType = TPath([newType]); + } + } + } + case EVars(vars): + for (v in vars) { + switch(v.val) { + case ETypedExpr(e, t): + switch(e) { + case EArray(e1, index): + refineArrayAccess(e1, index, typer.tstring(v.t)); + RebuildUtils.rebuild(e1, rebuild); + RebuildUtils.rebuild(index, rebuild); + return RebuildResult.RSkip; + case null: + default: + } + case null: + default: + } + } + case EBinop("=", e1, e2, _): + switch(e1) { + case EArray(e1, index): + refineArrayAccess(e1, index, typer.getExprType(e2)); + RebuildUtils.rebuild(e1, rebuild); + RebuildUtils.rebuild(index, rebuild); + return RebuildResult.RSkip; + default: + } + switch(e2) { + case EArray(e2, index): + refineArrayAccess(e2, index, typer.getExprType(e1)); + RebuildUtils.rebuild(e2, rebuild); + RebuildUtils.rebuild(index, rebuild); + return RebuildResult.RSkip; + default: + } + case EArray(e1, index): + refineArrayAccess(e1, index, "Dynamic"); + default: + } + return null; + } + + typer.enterProgram(program); + for (d in program.defs) { + switch (d) { + case CDef(c): + typer.setImports(WriterImports.getImports(program, cfg, c), null); + typer.enterClass(pack + c.name, c); + currentClass = c.name; + for (field in c.fields) { + switch(field.kind) { + case FFun(f): + typer.enterFunction(f, field.name, c); + returnType = f.ret.t; + RebuildUtils.rebuild(f.expr, rebuild); + f.ret.t = returnType; + typer.leaveFunction(); + default: + } + } + case FDef(f): + returnType = f.f.ret.t; + RebuildUtils.rebuild(f.f.expr, rebuild); + default: + } + } + } + + function foldStringType(field:String, old:String, newKey:String, newValue:String):String { + var openIndex:Int = old.indexOf("<"); + if (openIndex == -1) { + return "Dictionary<" + newKey + "," + newValue + ">"; + } + var name:String = old.substr(0, openIndex); + var depth:Int = 0; + var splitIndex:Int = -1; + for (i in openIndex + 1...old.length) { + switch (old.charCodeAt(i)) { + case '<'.code: depth++; + case '>'.code: depth--; + case ','.code: + if (depth == 0) { + splitIndex = i; + break; + } + } + } + if (splitIndex != -1) { + var oldKey:String = old.substring(openIndex + 1, splitIndex); + var oldValue:String = old.substring(splitIndex + 1, old.length - 1); + newKey = foldDictionaryType2(oldKey, newKey); + newValue = foldDictionaryType2(oldValue, newValue); + } + return name + "<" + newKey + "," + newValue + ">"; + } + + function foldDictionaryType2(a:String, b:String):String { + if (a == b) return a; + //use as type param + if (a == "T") return a; + if (b == "T") return b; + + var aIsAny:Bool = a == "Dynamic" || a == "Object" || a == "openfl.utils.Object" || a == null || a == "null"; + var bIsAny:Bool = b == "Dynamic" || b == "Object" || b == "openfl.utils.Object" || b == null || b == "null"; + if (aIsAny && bIsAny) return "Dynamic"; + if (aIsAny) return b; + if (bIsAny) return a; + + if (a == "String") return a; + if (b == "String") return b; + + if ((a.indexOf("openfl.utils.Dictionary") == 0 || a.indexOf("Dictionary") == 0) && (b.indexOf("openfl.utils.Dictionary") == 0 || b.indexOf("Dictionary") == 0)) { + var newKey:String = foldDictionaryType2(Typer.getMapParam(a, 0), Typer.getMapParam(b, 0)); + var newValue:String = foldDictionaryType2(Typer.getMapParam(a, 1), Typer.getMapParam(b, 1)); + if (newKey == "null") newKey = "Dynamic"; + if (newValue == "null") newValue = "Dynamic"; + return "openfl.utils.Dictionary<" + newKey + "," + newValue + ">"; + } + if (typer.doImplements(a, b)) return b; + if (typer.doImplements(b, a)) return a; + return "Dynamic"; + } + + + /** it could be better if we would refine single value on occurance but not to collect all types */ + function refineStringType(types:Array, type:String):Void { + if (type != null) { + types.push(type); + } + } +} \ No newline at end of file diff --git a/src/as3hx/InheritanceTypeParser.hx b/src/as3hx/InheritanceTypeParser.hx new file mode 100644 index 0000000..0a3a90a --- /dev/null +++ b/src/as3hx/InheritanceTypeParser.hx @@ -0,0 +1,27 @@ +package as3hx; +import as3hx.As3.ClassDef; + +/** + * ... + * @author d.skvortsov + */ +class InheritanceTypeParser +{ + public static function getParent(typer:Typer, child:ClassDef):ClassDef { + switch (child.extend) { + case null: + case TPath(p): + var parentClassString:String = typer.getImportString(p, true); + var path:String = typer.resolveClassIdent(parentClassString); + if (path == null) { + path = WriterImports.getImport(parentClassString, cfg, classes, child, null, parentPath.substring(0, parentPath.lastIndexOf("."))); + } + if (path != null) { + parentPath = path; + return classDefs.get(path); + } + default: + } + return null; + } +} \ No newline at end of file diff --git a/src/as3hx/RebuildParentStaticFieldAccess.hx b/src/as3hx/RebuildParentStaticFieldAccess.hx new file mode 100644 index 0000000..c43a391 --- /dev/null +++ b/src/as3hx/RebuildParentStaticFieldAccess.hx @@ -0,0 +1,42 @@ +package as3hx; +import as3hx.As3.Expr; +import as3hx.As3.Program; +import as3hx.RebuildUtils.RebuildResult; + +/** + * ... + * @author + */ +class RebuildParentStaticFieldAccess { + private var cfg:Config; + private var typer:Typer; + private var program:Program; + + public function new(cfg:Config, typer:Typer) { + this.cfg = cfg; + this.typer = typer; + } + + public function apply(program:Program):Void { + this.program = program; + RebuildUtils.rebuildProgram(program, cfg, typer, rebuild); + } + + private function rebuild(expr:Expr):RebuildResult { + switch(expr) { + case EIdent(v): + var staticFieldHost:String = typer.getIsStaticField(v); + if (staticFieldHost != null) { + var a:Array = staticFieldHost.split("."); + typer.addImport(program, TPath(a)); + var staticFieldHostName:String = a[a.length - 1]; + return RebuildResult.RReplace(EField(EIdent(staticFieldHostName), v)); + } + default: + //if (staticFieldHost != null) { + //write(staticFieldHost + "."); + //} + } + return null; + } +} \ No newline at end of file diff --git a/src/as3hx/SignalRebuild.hx b/src/as3hx/SignalRebuild.hx new file mode 100644 index 0000000..c31d708 --- /dev/null +++ b/src/as3hx/SignalRebuild.hx @@ -0,0 +1,273 @@ +package as3hx; +import as3hx.As3.Definition; +import as3hx.As3.Program; +import as3hx.As3.T; +import as3hx.As3.Expr; +import as3hx.RebuildUtils.RebuildResult; + +/** + * ... + * @author ... + */ +class SignalRebuild +{ + private var cfg:Config; + private var typer:Typer; + + private var currentField:String = null; + private var currentFieldType:T; + + private var succededReplace:Bool = false; + + private static var toCleanUp:Array = []; + + public function new(cfg:Config, typer:Typer) { + this.cfg = cfg; + this.typer = typer; + } + + public function apply(program:Program):Void { + var t1:Float = haxe.Timer.stamp(); + RebuildUtils.rebuildProgram(program, cfg, typer, rebuildSignals); + var t2:Float = haxe.Timer.stamp(); + rebuildParameters(program); + var t3:Float = haxe.Timer.stamp(); + refineVariableTypes(program); + var t4:Float = haxe.Timer.stamp(); + var name:String = "null"; + switch(program.defs[0]) { + case CDef(c):name = c.name; + default: + } + //trace(name + " " + (t2 - t1) + " " + (t3 - t2) + " " + (t4 - t3)); + } + + public function refineVariableTypes(program:Program):Void { + RebuildUtils.rebuildProgram(program, cfg, typer, rebuildVariableTypes); + } + + private function isSignalType(s:String):Bool { + return s != null && (s.indexOf("Signal<") == 0 || s.indexOf("signals.Signal<") == 0); + } + + private function isNativeSignalType(s:String):Bool { + return s != null && (s.indexOf("NativeSignal") == 0 || s.indexOf("signals.NativeSignal") == 0); + } + + private function rebuildVariableTypes(expr:Expr):RebuildResult { + switch (expr) { + case ECall(e, params) : + switch(e) { + case EField(e, field): + var s:String = typer.getExprType(e); + if (field == "add" || field == "addOnce" || field == "remove") { + if (isSignalType(s)) { + var p:Array = []; + var types:String = s.substring(s.indexOf("<") + 1, s.length - 1); + if (types == "T" || types == "Type" || types == "T->Void" || types == "Type->Void") return null; + if (types == "Void") types = "Void->Void"; + for (s in types.split("->")) { + p.push(typer.expandType(TPath([s]))); + } + typer.overrideExprType(params[0], TFunction(p)); + } else if (isNativeSignalType(s)) { + var p:Array = [TPath(["Dynamic"]), TPath(["Void"])]; + typer.overrideExprType(params[0], TFunction(p)); + } + } else if (field == "dispatch") { + if (isSignalType(s)) { + var p:Array = []; + var types:String = s.substring(s.indexOf("<") + 1, s.length - 1); + if (types == "T" || types == "Type" || types == "T->Void" || types == "Type->Void") return null; + if (types == "Void") types = "Void->Void"; + for (s in types.split("->")) { + //p.push(TPath([s])); + p.push(typer.expandType(TPath([s]))); + } + var rparams:Array = []; + for (i in 0...params.length) { + rparams.push(ETypedExpr(params[i], p[i])); + } + return RebuildResult.RReplace(ECall(EField(e, field), rparams)); + } + } + default: + } + default: + } + return null; + } + + private function tryOverrideType(name:String, t:T):Void { + typer.overrideIdentType(name, typer.expandType(t)); + } + + public static function cleanup(cfg:Config, typer:Typer):Void { + var s:SignalRebuild = new SignalRebuild(cfg, typer); + for (i in 0...5) { + var prevToCleanUp:Array = toCleanUp.copy(); + toCleanUp = []; + var list:Array = []; + for (p in prevToCleanUp) { + s.apply(p); + if (p.defs.length > 0) { + switch(p.defs[0]) { + case CDef(c): + list.push(p.pack + "." + c.name); + default: + } + } + } + neko.Lib.println("SignalRebuild cleanUp " + prevToCleanUp.length + " left: " + list); + if (toCleanUp.length == 0) { + neko.Lib.println("SignalRebuild cleanUp complete"); + break; + } + } + } + + private function rebuildParameters(program:Program):Void { + for (d in program.defs) { + switch (d) { + case CDef(c): + var path:String = (program.pack.length > 0 ? program.pack.join(".") + "." : "") + c.name; + typer.enterClass(path, c); + for (field in c.fields) { + currentField = field.name; + switch(field.kind) { + case FVar(t, val): + case FFun(f): + typer.enterFunction(f, field.name, c); + currentFieldType = f.ret.t; + switch (currentFieldType) { + case null: + case TPath(pathArray): + var p:String = pathArray.join("."); + if (p == "Signal" || p == "org.osflash.signals.Signal" || p == "idv.cjcat.signals.Signal" || p == "signals.Signal") { + succededReplace = false; + var expr:Expr = RebuildUtils.rebuild(f.expr, rebuildParams); + if (!succededReplace) { + if (toCleanUp.indexOf(program) == -1) { + toCleanUp.push(program); + } + } + } + if (p == "ISignal" || p == "org.osflash.signals.ISignal" || p == "idv.cjcat.signals.ISignal" || p == "signals.ISignal") { + succededReplace = false; + var expr:Expr = RebuildUtils.rebuild(f.expr, rebuildParamsInterface); + if (!succededReplace) { + if (toCleanUp.indexOf(program) == -1) { + toCleanUp.push(program); + } + } + } + default: + } + typer.leaveFunction(); + default: + } + } + case FDef(f): + //var expr:Expr = RebuildUtils.rebuild(f.f.expr, rebuildParams); + //if (expr != null) { + //f.f.expr = expr; + //} + default: + } + } + } + + private function rebuildParams(expr:Expr):RebuildResult { + switch(expr) { + case EReturn(e): + if (e != null) { + var t:String = typer.getExprType(e); + if (t != null && t != "null" && t != "Signal") { + succededReplace = true; + tryOverrideType(currentField, TPath([t])); + } + } + default: + } + return null; + } + + private function rebuildParamsInterface(expr:Expr):RebuildResult { + switch(expr) { + case EReturn(e): + if (e != null) { + var t:String = typer.getExprType(e); + if (t != null && t != "null" && t != "Signal") { + succededReplace = true; + t = StringTools.replace(t, "", "Void>"); + tryOverrideType(currentField, TPath([StringTools.replace(t, "Signal", "ISignal")])); + } + } + default: + } + return null; + } + + private function rebuildSignals(expr:Expr):RebuildResult { + switch(expr) { + case EBinop("=", e1, e2, newLineAfterOp): + var types = getNewSignalType(typer.getExprType(e1), typer.getExprType(e2)); + if (types != null) { + var t:T = TPath([types]); + switch(e1) { + case EIdent(v): + var variableType:T = typer.expandType(t); + if (typer.getExprType(e1) == "ISignal") { + types = StringTools.replace(types, "", "Void>"); + variableType = TPath([StringTools.replace(typer.expandStringType(types), "Signal", "ISignal")]); + } + tryOverrideType(v, variableType); + default: + } + return RebuildResult.RReplace(EBinop("=", e1, ENew(TPath([typer.shortenStringType(types)]), []), newLineAfterOp)); + } + case EVars(vars): + for (v in vars) { + if (v.val == null) continue; + + var ts:String = typer.tstring(v.t); + var types = getNewSignalType(ts, typer.getExprType(v.val)); + if (types != null) { + var a:Array = [types]; + //var a:Array = ["Signal<" + types + ">"]; + var t:T = TPath(a); + if (ts == "ISignal") { + a[0] = StringTools.replace(a[0], "", "Void>"); + a[0] = "I" + a[0]; + } + tryOverrideType(v.name, t); + v.t = truncateFullPath(types); + } + } + default: + } + return null; + } + + private function truncateFullPath(complexType:String):T { + var delimiters:Array = []; + var types:Array> = Typer.getTypeParams(complexType, delimiters); + var shortTypes:Array = []; + for (p in types) { + shortTypes.push(p[p.length - 1]); + } + var s:String = shortTypes[0] + "<" + shortTypes[1]; + for (i in 2...shortTypes.length) { + s += "->" + shortTypes[i]; + } + return TPath([s + ">"]); + } + + private function getNewSignalType(oldType:String, newType:String):String { + if (newType != null && newType.indexOf("Signal<") == 0 && typer.shortenStringType(oldType) != newType) { + return newType; + } else { + return null; + } + } +} \ No newline at end of file diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index 16d7913..b3be476 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -3,34 +3,39 @@ import as3hx.As3.ClassDef; import as3hx.As3.ClassField; import as3hx.As3.Expr; import as3hx.As3.Function; +import as3hx.As3.FunctionDef; import as3hx.As3.Program; import as3hx.As3.T; import as3hx.RebuildUtils.RebuildResult; -import neko.Lib; - -typedef DictionaryTypes = { - key:Array, - value:Array -} /** * AS3 typing allows multiple equal variable type declarations in one method and opens new variable context only inside function, not in any {} block */ class Typer { + public var classes(default,null) : Map> = new Map>(); + public var classDefs(default,null) : Map = new Map(); + public var classChildren(default,null):Map> = new Map>(); + public var currentPath(default, null):String = null; var cfg:Config; - var classes : Map> = new Map>(); - var classFieldDictionaryTypes : Map> = new Map>(); + var classesByPackages:Map> = new Map>(); + var parentStaticFields : Map = new Map(); + var funDefs : Map = new Map(); + var classPrograms : Map = new Map(); + var staticContext : Map = new Map(); var context : Map = new Map(); var contextStack : Array> = []; + var functionStack : Array = []; + var functionStackName : Array = []; var pack:String = null; - var currentPath:String = null; var importsMap : Map; + var classPacks:Map = new Map(); + var _hostClassRef:Reference = new Reference(); public function new(cfg:Config) { this.cfg = cfg; } - + public function getContextClone(relativeLevel:Int = 0):Map { var context:Map; if (relativeLevel < 0 && -relativeLevel <= contextStack.length) { @@ -42,51 +47,282 @@ class Typer for (v in context.keys()) { clone.set(v, context.get(v)); } + for (v in staticContext.keys()) { + clone.set(v, context.get(v)); + } return clone; } - public function getExprType(e:Expr):Null { + public function isExistingIdent(ident:String):Bool { + switch(ident) { + case "as3hx.Compat", "Std", "true", "false", "encodeURI", "decodeURI", "escape", "unescape", "encodeURIComponent", "decodeURIComponent": return true; + default: + } + ident = getModifiedIdent(ident); + if (context.exists(ident)) { + return true; + } else if (staticContext.exists(ident)) { + return true; + } else if (importsMap != null && importsMap.exists(ident)) { + return true; + } + return false; + } + + private function getQualifiedClassName(shortName:String):String { + if (classes.exists(shortName)) return shortName; + if (importsMap != null && importsMap.exists(shortName)) return importsMap.get(shortName); + return ''; + } + + public function getThisIdentType(ident:String):String { + return contextStack.length > 0 ? contextStack[0].get(ident) : null; + } + + public function getIsInterface(e:Expr):Bool { + var type:String = getExprType(e, true); + if (type != null && classDefs.exists(type)) { + return classDefs[type].isInterface; + } else { + return false; + } + } + + public function doImplements(a:String, b:String):Bool { + var ca:ClassDef = classDefs[a]; + var cb:ClassDef = classDefs[b]; + if (cb == null) return false; + while (ca != null) { + if (ca == cb) return true; + if (cb.isInterface) { + for (t in ca.implement) { + switch(t) { + case TPath(t): + if (t[t.length - 1] == cb.name) return true; + if (t[t.length - 1].indexOf("." + cb.name) != -1) return true; + default: + } + } + } + var classPackage:String = classPacks.get(ca); + var parentPath:String = getPathByType(ca.extend, ca, null, classPackage); + if (parentPath == null) break; + ca = classDefs[parentPath]; + } + return false; + } + + public function getField(v:String, hostClass:Reference, c:ClassDef = null):ClassField { + if (c == null) { + c = classDefs[currentPath]; + } + while (c != null) { + for (f in c.fields) { + hostClass.value = c; + if (f.name == v) return f; + } + if (c.extend == null) break; + var classPackage:String = classPacks.get(c); + var parentPath:String = getPathByType(c.extend, c, null, classPackage); + if (parentPath != null) { + c = classDefs[parentPath]; + } else { + break; + } + } + return null; + } + + public function getFunctionArgTypes(e:Expr):Array { + var c:ClassDef = null; + var f:ClassField = null; + switch (e) { + case EIdent(v): + c = classDefs[currentPath]; + f = getField(v, _hostClassRef, c); + case EField(e, field): + var t:String = getExprType(e); + if (t != null) { + c = classDefs[t]; + f = getField(field, _hostClassRef, c); + } + default: + } + if (f != null) { + c = _hostClassRef.value; + switch(f.kind) { + case FFun(f): + var r:Array = []; + for (i in 0...f.args.length) { + var a = f.args[i]; + if (a != null && a.t != null) { + r.push(expandType(a.t, c)); + } else { + r.push(null); + } + } + return r; + default: + } + } + return null; + } + + public function isVariable(ident:String):Bool { + return context.exists(ident) || staticContext.exists(ident); + } + + public function getExprType(e:Expr, isFieldAccess:Bool = false):Null { switch(e) { + case null: return null; case ETypedExpr(e2, t): return tstring(t); case EField(e2, f): switch(e2) { - case EIdent("this"): return contextStack.length > 0 ? contextStack[0].get(f) : context.get(f); + case EIdent("this"): + return contextStack.length > 0 ? contextStack[0].get(f) : context.get(f); default: } - var t2 = getExprType(e2); - if (t2 != null && (t2.indexOf("Array<") == 0 || t2.indexOf("Vector<") == 0) && f == "length") { - return "Int"; + var t2 = getExprType(e2, true); + if (t2 != null && (t2.indexOf("Array<") == 0 || t2.indexOf("Vector<") == 0)) { + switch(f) { + case "length": return "Int"; + case "sort" : return "Function->Void"; + } } switch(t2) { + case "Reflect": + switch(f) { + case "hasField": return "Dynamic->String->Bool"; + case "field": return "Dynamic->String->Dynamic"; + case "setField": return "Dynamic->String->Dynamic->Void"; + } + case "Signal","signals.Signal": + switch(f) { + case "add": return "Function->Void"; + case "addOnce": return "Function->Void"; + case "remove": return "Function->Void"; + } + case "as3hx.Compat": + switch(f) { + case "parseInt": return "Float->Int"; + case "setTimeout": return "Dynamic->Int->Int"; + case "getQualifiedClassName": return "Dynamic->String"; + } + case "Date": + switch(f) { + case "getTime": return "Void->Float"; + case "now": return "Void->Date"; + case "time": return "Float"; + } + case "Math": + switch(f) { + case "ceil", "floor", "round": return "Float->Int"; + case "max", "min": return "Float->Float->Float"; + case "random": return "Void->Float"; + default: return "Float->Float"; + } + case "Std": + switch(f) { + case "int": return "Float->Int"; + case "is": return "Dynamic->Dynamic->Bool"; + case "parseFloat": return "String->Float"; + case "parseInt": return "String->Int"; + case "random": return "Int->Int"; + case "string": return "Dynamic->String"; + default: + } + case "StringTools": + return switch(f) { + case "replace": return "String->String->String->String"; + default: return "String"; + } + case "String": + return switch(f) { + case "length": return "Int"; + case "charCodeAt": return "Int->Int"; + case "indexOf": return "String->Int"; + case "lastIndexOf": return "String->Int"; + case "split": return "String->Array"; + case "substr", "substring": return "Int->Int->String"; + case "replace": return "String->String->String"; + case "toLowerCase", "toUpperCase", "toString", "toLocaleLowerCase", "toLocaleUpperCase": return "Void->String"; + case "fromCharCode": return "Int->String"; + default: return "String"; + } + case "FastXMLNodeAccess": return "FastXML"; + case "FastXMLNodeListAccess": return "FastXMLList"; + case "FastXMLAttribAccess": return "String"; + case "FastXMLHasAttribAccess": return "Bool"; + case "FastXMLHasNodeAccess": return "Bool"; case "FastXML": return switch(f) { - case "descendants", "nodes": "FastXMLList"; - case "node": "FastXML"; - case "length": "Int"; + case "copy": return "Void->FastXML"; + case "node":"FastXMLNodeAccess"; + case "nodes":"FastXMLNodeListAccess"; + case "att":"FastXMLAttribAccess"; + case "has":"FastXMLHasAttribAccess"; + case "hasNode":"FastXMLHasNodeAccess"; + case "name":"String"; + case "innerData":"String"; + case "innerHTML":"String"; + case "descendants": "String->FastXMLList"; + //case "descendants", "nodes": "FastXMLList"; + //case "node": "FastXML"; + //case "length": "Int"; case _: "FastXMLList"; } case "FastXMLList": switch(f) { + case "copy": return "Void->FastXMLList"; case "length": return "Int"; + case "descendants": return "String->FastXMLList"; + case "get": return "Int->FastXML"; + default: return "FastXMLList"; // will be transformed to .descendants() } default: + if (t2 != null && t2.indexOf("Dictionary<") == 0) { + switch(f) { + case "exists": return "Dynamic->Bool"; + } + } } if (t2 != null) { + var cl:String = resolveClassIdent(t2); if (context.exists(t2)) { t2 = context.get(t2); + } else if (staticContext.exists(t2)) { + t2 = staticContext.get(t2); + } + if (importsMap != null && importsMap.exists(t2)) { + var t:String = importsMap.get(t2); + if (t != null) t2 = t; + } + if (t2.indexOf(".") != -1) { + var t2Array:Array = t2.split("."); + t2 = getImportString(t2Array, true); } if (classes.exists(t2)) { - return classes.get(t2).get(f); - } else if (importsMap != null && importsMap.exists(t2)) { - if (classes.exists(importsMap.get(t2))) { - return classes.get(importsMap.get(t2)).get(f); - } - } else if (currentPath.length > 0 && classes.exists(pack + "." + t2)) { - return classes.get(pack + "." + t2).get(f); + t2 = classes.get(t2).get(f); + return t2; } } return null; case ECall(e, params): + /* handling of as3 typing calls */ + switch(e) { + case EIdent("Number"): return "Float"; + case EIdent("String"): return "String"; + case EIdent("int"): return "Int"; + case EIdent("uint"): return "Int"; + case EIdent("getQualifiedClassName"): return "String"; + case EField(e, "instance"): + switch(e) { + case EIdent("Std"): + return getExprType(params[1]); + default: + } + default: + } var t:String = getExprType(e); if (t != null) { var li:Int = t.lastIndexOf("->"); @@ -96,20 +332,143 @@ class Typer } case EIdent(s): switch(s) { + case "as3hx.Compat": return "as3hx.Compat"; + case "Std": return "Std"; case "true", "false": return "Bool"; - case "encodeURI", "decodeURI", "escape", "unescape": return "String->String"; + case "encodeURI", "decodeURI", "escape", "unescape", "encodeURIComponent", "decodeURIComponent": return "String->String"; + case "this": return currentPath; + case "trace": return "Dynamic->Void"; + case "super": + var c:ClassDef = classDefs[currentPath]; + if (c != null && c.extend != null) { + var classPackage:String = classPacks.get(c); + var parentPath:String = getPathByType(c.extend, c, null, classPackage); + if (parentPath != null && classDefs[parentPath] != null) { + c = classDefs[parentPath]; + for (f in c.fields) { + if (f.name == c.name) { + switch(f.kind) { + case FFun(f): + var pack:Array = classPrograms[c].pack; + var constructorReturnType:T = TPath([pack.length > 0 ? pack + "." + c.name : c.name]); + return "Dynamic->" + tstring(getFunctionType(f, constructorReturnType)); + default: + } + } + } + } + } + return "Void->Dynamic"; default: } + //var ss:String = s; + var ident:Bool = false; s = getModifiedIdent(s); - return context.get(s); + if (context.exists(s)) { + s = context.get(s); + ident = true; + } else if (staticContext.exists(s)) { + s = staticContext.get(s); + ident = true; + } + if (s != null && importsMap != null && importsMap.exists(s)) { + var t:String = importsMap.get(s); + s = t == null ? s : t; + if (!ident && !isFieldAccess) return "Class"; + } + return s; case EVars(vars) if(vars.length == 1): return tstring(vars[0].t); - case EArray(n, _): return getExprType(n); + case EArray(n, _): + var tn:String = getExprType(n); + if (tn != null) { + if (StringTools.startsWith(tn, "Array")) { + return tn.substring(6, tn.lastIndexOf(">")); + } else if (StringTools.startsWith(tn, "Vector")) { + return expandStringType(tn.substring(7, tn.lastIndexOf(">"))); + } else if (StringTools.startsWith(tn, "Dictionary") || StringTools.startsWith(tn, "openfl.utils.Dictionary")) { + var bothTypes:String = tn.substring(tn.indexOf("<") + 1, tn.lastIndexOf(">")); + var commaPosition:Int = -1; + var level:Int = 0; + for (i in 0...bothTypes.length) { + var char:Int = bothTypes.charCodeAt(i); + if (char == "<".code) { + level++; + } else if (char == ">".code) { + level--; + } else if (char == ",".code) { + if (level == 0) { + commaPosition = i; + break; + } + } + } + if (commaPosition != -1) { + return bothTypes.substr(commaPosition + 1); + } + } + } + return tn; case EArrayDecl(_): return "Array"; case EUnop(_, _, e2): return getExprType(e2); - case EBinop(_ => "as", _, type, _): return getExprType(type); - case EBinop(_ => "/", _, _, _): return "Float"; - case EBinop(_, e1, e2, _) if (getExprType(e1) != "Float" && getExprType(e2) != "Float"): return "Int"; - case ENew(t, params): return tstring(t); + case EParent(e): return getExprType(e); + case ETernary(cond, e1, e2): return getExprType(e1); + case EVector(t): return "Vector<" + tstring(t) + ">"; + case EBinop(op, e1, e2, _) : + switch(op) { + case "=" : return getExprType(e1); + case "as": return getExprType(e2, true); + case "/" : return "Float"; + case "is" | "in" | "||" | "&&" | "!=" | "!==" | "==" | "===" | ">" | ">=" | "<" | "<=": return "Bool"; + default: + var t1:String = getExprType(e1); + var t2:String = getExprType(e2); + if (op == "+" && t1 == "String" || t2 == "String") return "String"; + if (t1 != "Float" && t2 != "Float") return "Int"; + return "Float"; + } + case ENew(t, params): + switch(t) { + case TComplex(e): + var pack:Array = getPackString(e); + if (pack != null) { + t = TPath(pack); + } + default: + } + switch(t) { + case TPath(p): + if (p[p.length - 1] == "Signal") { + var types:Array = []; + for (param in params) { + switch(param) { + case EVector(t): + types.push(tstring(TVector(t))); + case EIdent(v): + var fullPath:String = resolveClassIdent(v); + types.push(tstring(TPath([fullPath == null ? v : fullPath]))); + //types.push(tstring(TPath([fullPath]))); + //types.push(tstring(TPath([v]))); + default: + } + } + types.push("Void"); + return "Signal<" +types.join("->") + ">"; + } else if (p[p.length - 1] == "Dictionary" && cfg.useOpenFlTypes) { + return "Dictionary"; + } + default: + } + return tstring(t); + case ECondComp(_, e, e2): + return getExprType(e); + case ENL(e): + return getExprType(e); + case EBlock(es): + if (es.length == 1) { + return getExprType(es[0]); + } + //case EFunction(f, _): + //return tstring(getFunctionType(f, null)); case EConst(c): return switch(c) { case CInt(_): "Int"; @@ -122,6 +481,11 @@ class Typer return null; } + inline function isBooleanOp(s:String):Bool return switch(s) { + case "||" | "&&" | "!=" | "!==" | "==" | "===": true; + case _: false; + } + public function getModifiedIdent(s : String) : String { return switch(s) { case "int": "Int"; @@ -136,8 +500,10 @@ class Typer case "XMLList": "FastXMLList"; case "NaN":"Math.NaN"; case "Dictionary": cfg.dictionaryToHash ? "haxe.ds.ObjectMap" : s; - case "decodeURI": "StringTools.decodeURI"; - case "encodeURI": "StringTools.encodeURI"; + case "decodeURI": "StringTools.urlDecode"; + case "encodeURI": "StringTools.urlEncode"; + case "decodeURIComponent": "StringTools.urlDecode"; + case "encodeURIComponent": "StringTools.urlEncode"; case "escape": "StringTools.htmlEscape"; case "unescape": "StringTools.htmlUnescape"; //case "QName": cfg.mapFlClasses ? "flash.utils.QName" : s; @@ -145,6 +511,18 @@ class Typer }; } + public static function tstringStatic(t:T) : String { + if(t == null) return null; + return switch(t) { + case TStar: "Dynamic"; + case TVector(t): "Vector<" + tstringStatic(t) + ">"; + case TPath(p): + var c = p.join("."); + return c; + default: t + ""; + } + } + public function tstring(t:T, isNativeGetSet:Bool = false, fixCase:Bool = true) : String { if(t == null) return null; return switch(t) { @@ -161,253 +539,944 @@ class Typer case "uint" : cfg.uintToInt ? "Int" : "UInt"; case "void" : "Void"; case "Function" : cfg.functionToDynamic ? "Dynamic" : c; - case "Object" : isNativeGetSet ? "{}" : "Dynamic"; + case "Object" : isNativeGetSet ? "{}" : (cfg.useOpenFlTypes ? "Object" : "Dynamic"); case "XML" : cfg.useFastXML ? "FastXML" : "Xml"; case "XMLList" : cfg.useFastXML ? "FastXMLList" : "Iterator"; case "RegExp" : cfg.useCompat ? "as3hx.Compat.Regex" : "flash.utils.RegExp"; - default : fixCase ? properCase(c, true) : c; + //default : fixCase ? properCase(c, true) : c; + default : cfg.importExclude.indexOf(c) != -1 ? p[p.length - 1] : fixCase ? properCase(c, true) : c; } case TComplex(e): return getExprType(e); // not confirmed case TDictionary(k, v): (cfg.dictionaryToHash ? "haxe.ds.ObjectMap" : "Dictionary") + "<" + tstring(k) + "," + tstring(v) + ">"; - case TFunction(p): p.map(function(it) return tstring(it)).join("->"); + case TFunction(p): p.map(function(it) { + var s:String = tstring(it); + if (s != null && s.indexOf("->") != -1) { + return "(" + s + ")"; + } else { + return s; + } + }).join("->"); + } + } + + public function addGlobalFunction(path:String, f:FunctionDef):Void { + var contextRoot = contextStack.length > 0 ? contextStack[0] : context; + funDefs[f.name] = path; + //contextRoot.set(f.name, getFunctionType(f.f)); + } + + public function hasGlobalFunction(name:String):String { + return funDefs.get(name); + } + + public function addProgram(p:Program):Void { + var pack:String = getImportString(p.pack, false); + var path:String = p.pack.length > 0 ? pack + "." : ""; + var packMap:Map; + if (classesByPackages.exists(pack)) { + packMap = classesByPackages.get(pack); + } else { + packMap = new Map(); + classesByPackages.set(pack, packMap); + } + for (d in p.defs) { + switch(d) { + case CDef(c): addClass(p, pack, path + c.name, c); + packMap.set(c.name, path + c.name); + classPrograms.set(c, p); + case FDef(f): addGlobalFunction(path + f.name, f); + case NDef(n): + default: + } } } - public function addClass(path:String, c:ClassDef):Void { + public function addClass(p:Program, pack:String, path:String, c:ClassDef):Void { var classMap:Map = new Map(); - parseClassFields(path, c, classMap); + if (!cfg.useFullTyping) { + parseClassFields(p, pack, c, classMap); + } classes[path] = classMap; + classDefs[path] = c; + classPacks.set(c, pack); } - public function enterClass(path, c:ClassDef):Void { - currentPath = path; - pack = currentPath.substr(0, currentPath.lastIndexOf(".")); + public function parseParentClasses():Void { + for (path in classes.keys()) { + var c:ClassDef = classDefs[path]; + parseClassFields(classPrograms[c], classPacks[c], c, classes[path]); + } + for (path in classes.keys()) { + parseParentClass(path); + } + } + + private function parseParentClass(path:String):Map { var classMap:Map = classes.get(path); - if (classMap == null) { - classMap = new Map(); - parseClassFields(path, c, classMap); + if (!classMap.exists("%childrenComplete")) { + var c:ClassDef = classDefs.get(path); + if (c.isInterface) { + for (t in c.implement) { + parseOneParentClass(t, path, c, classMap); + } + } else if (c.extend != null) { + parseOneParentClass(c.extend, path, c, classMap); + } + classMap.set("%childrenComplete", ""); } - contextStack[contextStack.length - 1] = context = classMap; + return classMap; } - - public function setImports(importsMap:Map, imported:Array):Void { - this.importsMap = new Map(); - for (key in importsMap.keys()) { - if (importsMap.get(key) != null) { - this.importsMap.set(key, importsMap.get(key)); + + private function parseOneParentClass(parentT:T, path:String, c:ClassDef, classMap:Map):Void { + var classPackage:String = classPacks.get(c); + var parentPath:String = getPathByType(parentT, c, null, classPackage); + if (parentPath != null) { + if (!classChildren.exists(parentPath)) { + classChildren.set(parentPath, [path]); + } else { + classChildren.get(parentPath).push(path); + } + var parentClassMap:Map = parseParentClass(parentPath); + for (field in parentClassMap.keys()) { + classMap.set(field, parentClassMap.get(field)); } } - for (key in imported) { - var i:Int = key.lastIndexOf("."); - this.importsMap.set(key.substr(i + 1), key); + } + + public function getPathByType(t:T, hostClass:ClassDef, packageArray:Array = null, packageString:String = null):String { + switch (t) { + case null: + case TPath(p): + if (p.length == 1 && p[0].indexOf(".") != -1) { + p = p[0].split("."); + } + var parentClassString:String = getImportString(p, true); + if (parentClassString.indexOf("<") != -1) { + parentClassString = parentClassString.substr(0, parentClassString.indexOf("<")); + } + var path:String; + if (parentClassString.indexOf(".") == -1) { + path = resolveClassIdent(parentClassString); + if (path == null) { + if (packageString == null && packageArray != null) { + packageString = getImportString(packageArray, false); + } + path = WriterImports.getImport(parentClassString, cfg, classes, hostClass, null, packageString); + } + } else { + path = parentClassString; + } + if (path != null && classes.exists(path)) { + return path; + } + default: } + return null; } - public function enterFunction(f:Function):Void { - openContext(); - for (arg in f.args) { - context.set(arg.name, tstring(arg.t)); + public function getClassConstructorTypes(path:String):Array { + var c:String = path; + if (context.exists(path)) { + c = context.get(path); + } else if (staticContext.exists(path)) { + c = staticContext.get(path); + } else if (importsMap != null && importsMap.exists(path)) { + var t:String = importsMap.get(path); + c = t == null ? path : t; } - if (f.varArgs != null) { - context.set(f.varArgs, "Array"); + var def:ClassDef = classDefs.get(c); + if (def != null) return getConstructorType(def); + return null; + } + + public function getIsStaticField(ident:String):String { + if (!parentStaticFields.exists(ident) || context.exists(ident)) { + return null; } + return parentStaticFields.get(ident); + } + + private function isLocalIdent(v:String):Bool { + if (contextStack.length > 0 && context.exists(v) && !contextStack[0].exists(v)) { + return true; + } + for (i in 1...contextStack.length) { + if (contextStack[i].exists(v)) { + return true; + } + } + return false; + } + + public function overrideExprType(expr:Expr, t:T):Void { + switch (expr) { + case null: + case EIdent(v): + if (isLocalIdent(v)) { + overrideLocalType(v, t); + } else { + overrideIdentType(v, t); + } + case EField(e, f): + var cName:String = getExprType(e); + if (cName != null) { + overrideIdentType(f, t, classDefs[cName]); + } else { + trace("null expr type for " + e + "." + f); + } + default: + } + } + + public function overrideLocalType(v:String, t:T):Void { + var index:Int = functionStack.length - 1; + while (index >= 0) { + var f:Function = functionStack[index]; + + var found:Bool = false; + + var short:T = shortenType(t); + for (arg in f.args) { + if (arg.name == v) { + arg.t = short; + if (functionStackName[index] != null) { + overrideExprType(EIdent(functionStackName[index]), getFunctionType(f, null)); + } + found = true; + } + } + if (!found) { + found = overrideFunctionLocalType(f, v, short); + } + if (found) { + for (i in index...contextStack.length) { + contextStack[i].set(v, tstring(t)); + } + context.set(v, tstring(t)); + } + index--; + } + } + + public function overrideFunctionLocalType(f:Function, v:String, t:T):Bool { + //trace("override local type " + currentPath + "." + v + " : " + t + " (UNIMPLEMENTED"); + //t = shortenType(t); + //for (arg in f.args) { + //if (arg.name == v) { + //arg.t = t; + //return true; + //} + //} + var replaced:Bool = false; function lookUpForTyping(expr:Expr):RebuildResult { switch(expr) { case EVars(vars): - for (v in vars) { - context.set(v.name, tstring(v.t)); + for (variable in vars) { + if (variable.name == v) { + variable.t = t; + replaced = true; + } } - case EFunction(f, name): - if (name != null) { - context.set(name, tstring(getFunctionType(f))); + case EFunction(fun, name): + if (name == v) { + replaced = true; + switch(t) { + case TFunction(p): + overrideFunctionParams(fun, p); + default: + trace("UNCOMPATEABLE TYPE : " + t + " with function " + name); + } } // Stop parsing this branch. We are not interested in variables in another scope - return RSkip; + return RebuildResult.RSkip; default: } return null; } RebuildUtils.rebuild(f.expr, lookUpForTyping); + return replaced; } - public function leaveFunction():Void { - closeContext(); + public function overrideFieldType(path:String, name:String, t:T, overrideInParents:Bool = true):Void { + if (currentPath == path) { + context.set(name, tstring(t)); + } + var c:ClassDef = classDefs[path]; + var classMap:Map = classes[path]; + if (classMap == null) return; + classMap.set(name, tstring(t)); + if (overrideInParents && c.extend != null) { + var classPackage:String = classPacks.get(c); + var parentPath:String = getPathByType(c.extend, c, null, classPackage); + if (parentPath != null) { + var parentClassMap:Map = classes.get(parentPath); + if (parentClassMap.exists(name)) { + overrideFieldType(parentPath, name, t); + return; + } + } + } + var children:Array = classChildren[path]; + if (children != null) { + for (childPath in children) { + overrideFieldType(childPath, name, t, false); + } + } } - function parseClassFields(path:String, c:ClassDef, map:Map):Void { - for (field in c.fields) { - switch(field.kind) { - case FVar(t, val): - map.set(field.name, tstring(t)); - case FFun(f): - if (isSetter(field) || isGetter(field)) { - map.set(field.name, tstring(f.ret.t)); + public static function getTypeParams(type:String, delimiters:Array = null):Array> { + var result:Array> = new Array>(); + var name:String = ""; + var inDelimiter:Bool = false; + for (i in 0...type.length) { + var c:Int = type.charCodeAt(i); + var newInDelimiter:Bool; + switch(c) { + case "<".code, ">".code, "-".code, ",".code, " ".code, "(".code, ")".code: + newInDelimiter = true; + default: + newInDelimiter = false; + } + if (newInDelimiter != inDelimiter) { + inDelimiter = newInDelimiter; + if (name.length > 0) { + if (inDelimiter) { + result.push(name.split(".")); } else { - map.set(field.name, tstring(getFunctionType(f))); + if (delimiters != null) { + delimiters.push(name); + } } - default: + name = ""; + } } + name += String.fromCharCode(c); } - map.set(c.name, path); - } - - public function applyRefinedTypes(program:Program):Void { - var pack:String = (program.pack.length > 0 ? program.pack.join(".") + "." : ""); - for (d in program.defs) { - switch (d) { - case CDef(c): - enterClass(pack + c.name, c); - for (f in c.fields) { - var t:T = getDictionaryType(f.name); - switch (t) { - case TDictionary(k, v): - addImport(program, k); - addImport(program, v); - case null: - default: + if (inDelimiter) { + if (delimiters != null) { + delimiters.push(name); + } + } else { + result.push(name.split(".")); + } + return result; + } + + public function expandStringType(stringType:String, c:ClassDef = null):String { + if (stringType == null) return null; + return expandStringTypeToArray(stringType, c).join("."); + } + + public function expandType(t:T, c:ClassDef = null):T { + switch (t) { + case null: + if (c != null) trace("null T for class ", c.name); + return null; + case TFunction(p): + var pr:Array = []; + for (pi in p) { + pr.push(expandType(pi, c)); + } + return TFunction(pr); + case TPath(p): + var lastWord:String = p[p.length - 1]; + return TPath(expandStringTypeToArray(lastWord, c)); + default: return t; + } + } + + private function expandStringTypeToArray(stringType:String, c:ClassDef = null):Array { + var delimiters:Array = new Array(); + var t:Array> = getTypeParams(stringType, delimiters); + var s:String; + var r:Array; + var l:Int = 1; + if (t[0].length == 1) { + if (l == 1) { + r = getFullTypeName(t[0][0], c).split("."); + s = r.pop(); + } else { + s = getFullTypeName(t[0][0], c); + r = []; + } + } else { + if (l == 1) { + r = t[0]; + s = r.pop(); + } else { + s = t[0].join("."); + r = []; + } + } + for (i in 1...t.length) { + var fullType:String = ''; + if (t[i].length == 1) { + fullType = getFullTypeName(t[i][0], c); + } else { + fullType = t[i].join("."); + } + s += delimiters[i - 1] + fullType; + } + if (delimiters.length == t.length) { + s += delimiters[delimiters.length - 1]; + } + r.push(s); + return r; + } + + public function shortenTypeAndImport(c:ClassDef, t:T):T { + if (c != null) { + addTypeImports(classPrograms[c], t); + } + return shortenType(t); + } + + public function shortenType(t:T):T { + switch (t) { + case TFunction(p): + var pr = []; + for (i in 0...p.length) { + pr.push( shortenType(p[i]) ); + } + return TFunction(pr); + case TDictionary(k, v): + return TDictionary(shortenType(k), shortenType(v)); + case TPath(p): + var s:String = p[p.length - 1]; + var delimiters:Array = new Array(); + var t:Array> = getTypeParams(s, delimiters); + var s:String = t[0][t[0].length - 1]; + for (i in 1...t.length) { + s += delimiters[i - 1] + t[i][t[i].length - 1]; + } + if (delimiters.length == t.length) { + s += delimiters[delimiters.length - 1]; + } + return TPath([s]); + default: return t; + } + } + + public function shortenStringType(type:String):String { + var delimiters:Array = []; + var t:Array> = getTypeParams(type, delimiters); + var s:String = t[0][t[0].length - 1]; + for (i in 1...t.length) { + s += delimiters[i - 1] + t[i][t[i].length - 1]; + } + if (delimiters.length == t.length) { + s += delimiters[delimiters.length - 1]; + } + return s; + } + + private function addTypeImports(program:Program, t:T):Void { + switch(t) { + case TDictionary(k, v): + addTypeImports(program, k); + addTypeImports(program, v); + case TPath(p): + var i:String; + if (p.length == 1) { + p = p[0].split("."); + t = TPath(p); + } + i = getImportString(p, true); + if (i.indexOf(">") != -1) { + for (t in getTypeParams(i)) { + if (t.length != 1 || t[0] != "Void" || t[0] != "Dynamic") { + addImport(program, TPath(t)); } - var d:String = tstring(t); - if (t != null) { - switch(f.kind) { - case FVar(t1, val): - f.kind = FVar(t, val); - default: - } - context[f.name] = d; - Lib.println(" Refined type in " + pack + c.name + "::" + f.name + ": " + d); + } + } else { + addImport(program, t); + } + default: + addImport(program, t); + } + } + + public function overrideIdentType(name:String, t:T, c:ClassDef = null):Void { + if (c == null) { + if (classDefs.exists(currentPath)) { + c = classDefs.get(currentPath); + overrideFieldType(currentPath, name, t); + } + } else { + overrideFieldType(getClassPath(c), name, t); + } + if (c != null) { + var f:ClassField = getField(name, _hostClassRef, c); + c = _hostClassRef.value; + if (f == null) return; + switch(f.kind) { + case FVar(oldT, val): + t = shortenTypeAndImport(c, t); + f.kind = FVar(t, val); + case FFun(fun): + if (f.kwds.indexOf("get") == -1 && f.kwds.indexOf("set") == -1) { + switch(t) { + case TFunction(p): + overrideFunctionParams(fun, p, c); + default: + t = shortenTypeAndImport(c, t); + fun.ret.t = t; } + } else if (fun.ret.t != null) { + t = shortenTypeAndImport(c, t); + fun.ret.t = t; + } else if (fun.args.length != 0) { + t = shortenTypeAndImport(c, t); + fun.args[0].t = t; } default: } } } - - public function refineTypes(program:Program):Void { - var currentClass:String = null; - var pack:String = (program.pack.length > 0 ? program.pack.join(".") + "." : ""); - - function refineArrayAccess(e1:Expr, index:Expr, value:Expr):Void { - var type1:String = getExprType(e1); - if (type1 != null && StringTools.startsWith(type1, "Dictionary")) { - var baseType:String = null; - var field:String = null; - switch(e1) { - case EField(e2, f): - baseType = getExprType(e2); - field = f; - case EIdent(s): - baseType = pack + currentClass; - field = s; - default: + + private function overrideFunctionParams(fun:Function, types:Array, c:ClassDef = null):Void { + fun.ret.t = types[types.length - 1]; + var expressionsToInsert:Array = []; + for (i in 0...types.length - 1) { + var arg = fun.args[i]; + if (arg == null) continue; + var t:T = types[i]; + if (!typesAreEqual(shortenType(t), arg.t)) { + t = shortenTypeAndImport(c, t); + var oldT:T = arg.t; + var oldName:String = arg.name; + arg.t = t; + arg.name = "__" + oldName; + var e:Expr = EIdent(arg.name); + var ts:String = tstring(oldT); + if (ts != "Dynamic") { + e = EBinop("as", e, EIdent(ts), false); } - if (field != null && baseType != null) { - if (classes.exists(baseType)) { - if (!classFieldDictionaryTypes.exists(baseType)) { - classFieldDictionaryTypes.set(baseType, new Map()); - } - var map:Map = classFieldDictionaryTypes.get(baseType); - if (!map.exists(field)) { - map.set(field, { - key:new Array(), - value:new Array() - }); - } - var d:DictionaryTypes = map.get(field); - refineStringType(d.key, getExprType(index)); - if (value != null) { - refineStringType(d.value, getExprType(value)); - } + expressionsToInsert.push(ENL(EVars([{name:oldName, t:oldT, val:e}]))); + for (j in 0...arg.exprs.length) { + var e:Expr = arg.exprs[j]; + switch(e) { + case EIdent(v): + arg.exprs[j] = EIdent(arg.name); + case ETypedExpr(e, oldT): + arg.exprs[j] = ETypedExpr(e, types[i]); + default: } } } } - - function rebuild(expr:Expr):RebuildResult { - switch(expr) { - case EFunction(f, name): - enterFunction(f); - var re:Expr = RebuildUtils.rebuild(f.expr, rebuild); - leaveFunction(); - if (re != null) { - return RebuildResult.RReplace(re); - } else { - return RebuildResult.RSkip; + if (expressionsToInsert.length > 0) { + unshiftIntoFunction(fun, expressionsToInsert); + } + } + + private function unshiftIntoFunction(f:Function, toInsert:Array):Void { + var doInsert:Expr->Expr = null; + doInsert = function(e) { + if(e == null) return null; + switch(e) { + case EBlock(ex): + if (ex.length == 0) return doInsert(ex[0]); + if (ex.length > 0) { + ex[0] = ENL(ex[0]); } - case EBinop("=", e1, e2, _): - switch(e1) { - case EArray(e1, index): - refineArrayAccess(e1, index, e2); + ex = toInsert.concat(ex); + return EBlock(ex); + case ENL(ex): return doInsert(ex); + case EObject(fl) if (fl.length == 0): return EBlock(toInsert); + default: + toInsert.push(ENL(e)); + return EBlock(toInsert); + } + } + f.expr = doInsert(f.expr); + } + + private function typesAreEqual(a:T, b:T):Bool { + return tstring(a) == tstring(b); + } + + + private function getClassPath(c:ClassDef):String { + var pack:String = classPacks[c]; + if (pack != null && pack.length > 0) { + return pack + "." + c.name; + } else { + return c.name; + } + } + + public function getPackageString(i : Array):String { + if (i.length == 0) { + return ""; + } else if (i[0] == "flash") { + i[0] = cfg.flashTopLevelPackage; + return i.join(".") + "."; + } else { + return Writer.properCaseA(i, false).join(".") + "."; + } + } + + public function getImportString(i : Array, hasClassName:Bool) { + if (i[0] == "flash") { + i[0] = cfg.flashTopLevelPackage; + return i.join("."); + } else { + return Writer.properCaseA(i, hasClassName).join("."); + } + } + + function resolveClassIdent(ident:String):String { + if (classes.exists(ident)) { + return ident; + } else if (importsMap != null && importsMap.exists(ident)) { + var t:String = importsMap.get(ident); + if (t != null && classes.exists(t)) { + return t; + } + } + return null; + } + + public function setPackage(pack:String):Void { + this.pack = pack; + } + + public function enterProgram(program:Program):Void { + setPackage(getImportString(program.pack, false)); + } + + public function enterClass(path:String, c:ClassDef):Void { + currentPath = path; + //parentStaticFields = new Map(); + staticContext = new Map(); + var classMap:Map; + classMap = classes.get(path); + var ic:ClassDef = c; + var parentPath:String = path; + if (ic.extend != null) { + //classMap = new Map(); + while (ic != null && ic.extend != null) { + var packageString:String = parentPath.substring(0, parentPath.lastIndexOf(".")); + var path:String = getPathByType(ic.extend, ic, classPrograms[ic].pack, packageString); + if (path != null) { + parentPath = path; + ic = classDefs.get(path); + if (ic == null) break; + parseStaticFields(parentPath, ic); + } else { + ic = null; + break; + } + //switch (ic.extend) { + //case null: + //case TPath(p): + //var parentClassString:String = getImportString(p, true); + //var path:String = resolveClassIdent(parentClassString); + //if (path == null) { + //path = WriterImports.getImport(parentClassString, cfg, classes, ic, null, parentPath.substring(0, parentPath.lastIndexOf("."))); + //} + //if (path != null) { + //parentPath = path; + //ic = classDefs.get(path); + //if (ic == null) break; + //parseStaticFields(parentPath, ic); + ////var childClassMap:Map = classes.get(path); + ////if (childClassMap != null) { + ////for (key in childClassMap.keys()) { + ////classMap.set(key, childClassMap.get(key)); + ////} + ////} + //} else { + //ic = null; + //break; + //} + //default: + //} + } + } else { + //classMap = classes.get(path); + } + parseStaticFields(path, c, true); + var classMapCopy:Map = new Map(); + if (classMap != null) { + for (key in classMap.keys()) { + if (!staticContext.exists(key)) { + classMapCopy.set(key, classMap.get(key)); + } + } + } + classMap = classMapCopy; + //if (classMap == null) { + //classMap = new Map(); + //} + //for (key in staticContext.keys()) { + //if (classMap.exists(key)) { + //classMap.remove(key); + //} + //} + //parseClassFields(path, c, classMap); + context = classMap; + if (contextStack.length > 0) { + contextStack[contextStack.length - 1] = context; + } + } + + public function getFullTypeName(ident:String, c:ClassDef = null):String { + //switch(s) { + //case "as3hx.Compat": return "as3hx.Compat"; + //case "Std": return "Std"; + //case "true", "false": return "Bool"; + //case "encodeURI", "decodeURI", "escape", "unescape": return "String->String"; + //default: + //} + //s = getModifiedIdent(s); + if (ident == "null") return ident; + if (context.exists(ident)) { + return context.get(ident); + } else if (staticContext.exists(ident)) { + return staticContext.get(ident); + } else if (importsMap != null && importsMap.exists(ident)) { + var t:String = importsMap.get(ident); + return t == null ? ident : t; + } else if (classes.exists(ident)) { + return ident; + } else if (cfg.useOpenFlTypes && ident == "Dictionary") { + return "openfl.utils.Dictionary"; + } + var parentPath:String; + if (c == null) { + c = classDefs[currentPath]; + parentPath = currentPath; + } else { + parentPath = getClassPath(c); + var fullTypeName:String = WriterImports.getImport(ident, cfg, classes, c, classPrograms[c], parentPath); + if (fullTypeName != null) return fullTypeName; + } + while (c.extend != null) { + parentPath = getPathByType(c.extend, c, null, parentPath.substr(0, parentPath.lastIndexOf("."))); + if (parentPath != null && classes.exists(parentPath)) { + c = classDefs.get(parentPath); + var fullTypeName:String = WriterImports.getImport(ident, cfg, classes, c, classPrograms[c], parentPath); + if (fullTypeName != null) return fullTypeName; + } else break; + } + if (ident == "null" || ident == "this") return ident; + //trace("UNKNOWN IDENT " + ident); + return ident; + } + + public function getFullTypeNameDescription(ident:String):String { + //switch(s) { + //case "as3hx.Compat": return "as3hx.Compat"; + //case "Std": return "Std"; + //case "true", "false": return "Bool"; + //case "encodeURI", "decodeURI", "escape", "unescape": return "String->String"; + //default: + //} + //s = getModifiedIdent(s); + if (context.exists(ident)) { + trace(1, context.get(ident)); + return context.get(ident); + } else if (staticContext.exists(ident)) { + trace(2, staticContext.get(ident)); + return staticContext.get(ident); + } else if (importsMap != null && importsMap.exists(ident)) { + var t:String = importsMap.get(ident); + trace(3, t); + return t == null ? ident : t; + } else if (classes.exists(ident)) { + trace(4, ident); + return ident; + } else if (cfg.useOpenFlTypes && ident == "Dictionary") { + return "openfl.utils.Dictionary"; + } + var c:ClassDef = classDefs[currentPath]; + var parentPath:String = currentPath; + while (c.extend != null) { + parentPath = getPathByType(c.extend, c, null, parentPath.substr(0, parentPath.lastIndexOf("."))); + if (parentPath != null && classes.exists(parentPath)) { + c = classDefs.get(parentPath); + var fullTypeName:String = WriterImports.getImport(ident, cfg, classes, c, classPrograms[c], parentPath); + trace(5, fullTypeName); + if (fullTypeName != null) return fullTypeName; + } else break; + } + trace(6, ident); + if (ident == "null" || ident == "this") return ident; + //trace("UNKNOWN IDENT " + ident); + return ident; + } + + public function setImports(importsMap:Map, imported:Array):Void { + this.importsMap = new Map(); + for (key in importsMap.keys()) { + var fullPath:String = importsMap.get(key); + if (fullPath != null) { + this.importsMap.set(key, fullPath); + } + } + var packMap:Map = this.classesByPackages.get(pack); + if (packMap != null) { + for (key in packMap.keys()) { + this.importsMap.set(key, packMap.get(key)); + } + } + + if (imported != null) { + for (key in imported) { + var i:Int = key.lastIndexOf("."); + this.importsMap.set(key.substr(i + 1), key); + } + } + } + + public function enterFunction(f:Function, name:String, c:ClassDef = null):Void { + openContext(f, name, c); + for (arg in f.args) { + context.set(arg.name, tstring(arg.t)); + } + if (f.varArgs != null) { + context.set(f.varArgs, "Array"); + } + function lookUpForTyping(expr:Expr):RebuildResult { + switch(expr) { + case EForEach(ev, e, block): + var etype:String = getExprType(e); + var isMap:Bool = etype != null && (etype.indexOf("Map") == 0 || etype.indexOf("Dictionary") == 0 || etype.indexOf("openfl.utils.Dictionary") == 0); + var isVector:Bool = etype != null && (etype.indexOf("Array") == 0 || etype.indexOf("Vector") == 0 || etype.indexOf("openfl.Vector") == 0); + switch(ev) { + case EVars(vars): + if(vars.length == 1 && vars[0].val == null) { + var type:String; + if (isMap) { + type = Typer.getMapParam(etype, 1); + if (type == null) { + type = "Dynamic"; + } + } else if (isVector) { + type = getVectorParam(etype); + } else { + type = "String"; + } + context.set(vars[0].name, type); + var re2:Expr = RebuildUtils.rebuild(e, lookUpForTyping); + var re3:Expr = RebuildUtils.rebuild(block, lookUpForTyping); + if (re2 != null || re3 != null) { + if (re2 == null) re2 = e; + if (re3 == null) re3 = block; + return RebuildResult.RReplace(EForEach(ev, re2, re3)); + } else { + return RebuildResult.RSkip; + } + } default: } - switch(e2) { - case EArray(e2, index): - refineArrayAccess(e2, index, e1); + case EForIn(ev, e, block): + var etype:String = getExprType(e); + var isMap:Bool = etype != null && (etype.indexOf("Map") == 0 || etype.indexOf("Dictionary") == 0 || etype.indexOf("openfl.utils.Dictionary") == 0); + switch(ev) { + case EVars(vars): + if(vars.length == 1 && vars[0].val == null) { + var type:String; + if (isMap) { + type = getMapIndexType(etype); + if (type == null) { + type = "Dynamic"; + } + } else { + type = "String"; + } + context.set(vars[0].name, type); + var re2:Expr = RebuildUtils.rebuild(e, lookUpForTyping); + var re3:Expr = RebuildUtils.rebuild(block, lookUpForTyping); + if (re2 != null || re3 != null) { + if (re2 == null) re2 = e; + if (re3 == null) re3 = block; + return RebuildResult.RReplace(EForIn(ev, re2, re3)); + } else { + return RebuildResult.RSkip; + } + } default: } - case EArray(e1, index): - refineArrayAccess(e1, index, null); + case EVars(vars): + for (v in vars) { + context.set(v.name, tstring(v.t)); + } + case EFunction(f, name): + if (name != null) { + context.set(name, tstring(getFunctionType(f))); + } + // Stop parsing this branch. We are not interested in variables in another scope + return RebuildResult.RSkip; default: } return null; } - - for (d in program.defs) { - switch (d) { - case CDef(c): - enterClass(pack + c.name, c); - currentClass = c.name; - for (field in c.fields) { - switch(field.kind) { - case FFun(f): - enterFunction(f); - RebuildUtils.rebuild(f.expr, rebuild); - leaveFunction(); - default: - } + RebuildUtils.rebuild(f.expr, lookUpForTyping); + } + + public function leaveFunction():Void { + closeContext(); + } + + function parseStaticFields(path:String, c:ClassDef, remove:Bool = false):Void { + for (field in c.fields) { + if (!isStatic(field)) continue; + + var type:String = null; + switch(field.kind) { + case FVar(t, val): + type = tstring(t); + case FFun(f): + if (isSetter(field)) { + type = tstring(f.args[0].t); + } else if (isGetter(field)) { + type = tstring(f.ret.t); + } else { + var constructorReturnType:T = field.name == c.name ? TPath([c.name]) : null; + type = tstring(getFunctionType(f, constructorReturnType)); } - case FDef(f): - RebuildUtils.rebuild(f.f.expr, rebuild); default: } + if (remove) { + parentStaticFields.remove(field.name); + staticContext.remove(field.name); + } else { + parentStaticFields.set(field.name, path); + staticContext.set(field.name, type); + } } } - - public function getDictionaryType(field:String):T { - var m:Map = classFieldDictionaryTypes.get(currentPath); - if (m != null && field != null) { - var d:DictionaryTypes = m.get(field); - if (d != null) { - var keyT:String = null; - var valueT:String = null; - for (t in d.key) keyT = foldDictionaryType(keyT, t); - for (t in d.value) valueT = foldDictionaryType(valueT, t); - if (cfg.useOpenFlTypes) { - if (keyT == null || keyT == "Dynamic") keyT = "Object"; - if (valueT == null || valueT == "Dynamic") valueT = "Object"; + + function parseClassFields(p:Program, pack:String, c:ClassDef, map:Map):Void { + var imports:Map = WriterImports.getImports(p, cfg, c); + for (field in c.fields) { + var type:String = null; + switch(field.kind) { + case FVar(t, val): + type = tstring(t); + case FFun(f): + if (isSetter(field)) { + type = tstring(f.args[0].t); + } else if (isGetter(field)) { + type = tstring(f.ret.t); + } else { + var constructorReturnType:T = field.name == c.name ? TPath([pack.length > 0 ? pack + "." + c.name : c.name]) : null; + type = tstring(getFunctionType(f, constructorReturnType)); + } + default: + } + if (type != null) { + var t:String = WriterImports.getImportWithMap(type, cfg, classes, imports, pack); + if (t != null) { + type = t; } - return TDictionary(TPath([keyT]), TPath([valueT])); - //return "Dictionary<" + d.key[0] + "," + d.value[0] + ">"; + map.set(field.name, type); } } - if (contextStack.length < 1) return null; - var t:String = contextStack[0].get(field); - return TPath([t]); - } - - function foldDictionaryType(a:String, b:String):String { - if (a == b) return a; - if (a == "Dynamic" || a == null) return b; - if (b == "Dynamic" || b == null) return a; - if (a == "String") return a; - if (b == "String") return b; - return "Dynamic"; - } - - /** it could be better if we would refine single value on occurance but not to collect all types */ - function refineStringType(types:Array, type:String):Void { - if (type != null) { - types.push(type); - } + //map.set(c.name, path); } inline function getRegexpType():String return cfg.useCompat ? "as3hx.Compat.Regex" : "flash.utils.RegExp"; @@ -416,15 +1485,21 @@ class Typer inline function isSetter(c:ClassField):Bool return Lambda.has(c.kwds, "set"); + inline function isStatic(c:ClassField):Bool return Lambda.has(c.kwds, "static"); + /** * Opens a new context for variable typing */ - function openContext() { + function openContext(f:Function = null, name:String = null, cl:ClassDef = null) { var c = new Map(); for(k in context.keys()) c.set(k, context.get(k)); contextStack.push(context); + if (f != null) { + functionStack.push(f); + functionStackName.push(name); + } context = c; } @@ -433,21 +1508,140 @@ class Typer */ function closeContext() { context = contextStack.pop(); + if (functionStack.length > 0) { + functionStack.pop(); + functionStackName.pop(); + } + } + + function hasImport(program:Program, path:Array):Bool { + for (p in program.imports) { + if (p.length == path.length) { + var samePath:Bool = true; + for (i in 0...p.length) { + if (p[i] != path[i]) { + samePath = false; + break; + } + } + if (samePath) { + return true; + } + } + } + return false; } - - function addImport(program:Program, t:T):Void { + + public function addImport(program:Program, t:T):Void { + if (program.typesSeen.indexOf(t) != -1) return; program.typesSeen.push(t); + switch(t) { + case TPath(path): + if (path.length == 1 && (CommonImports.getImports(cfg).exists(path[0]) || path[0].indexOf(".") == -1)) return; + if (!hasImport(program, path)) { + program.imports.push(path); + } + default: + } } - public static function getFunctionType(f:Function):T { + function getConstructorType(c:ClassDef):Array { + var args:Array = []; + for (f in c.fields) { + if (f.name == c.name) { + switch(f.kind) { + case FFun(f): + for (arg in f.args) { + args.push(arg.t); + } + default: + } + } + } + return args; + } + + public function getMapIndexType(s:String):String { + var startIndex:Int = s.indexOf("<"); + if (startIndex == -1) return null; + var commaIndex:Int = s.indexOf(","); + if (commaIndex == -1) return null; + return s.substring(startIndex + 1, commaIndex); + } + + public function getPackString(expr:Expr):Array { + switch(expr) { + case EIdent(s): + return isExistingIdent(s) ? null : [s]; + case EField(e, f): + var s:Array = getPackString(e); + if (s != null) { + s.push(f); + } + return s; + default: return null; + } + } + + public static function getFunctionType(f:Function, constructorReturnType:T = null):T { var t = f.args.map(function(it) return it.t); if(f.varArgs != null) t.push(TPath(["Array"])); - if(t.length == 0) t.push(TPath(["Void"])); - t.push(f.ret.t); + if (t.length == 0) t.push(TPath(["Void"])); + if (constructorReturnType != null) { + t = [constructorReturnType]; + } else { + t.push(f.ret.t); + } return TFunction(t); } public static function properCase(pkg:String, hasClassName:Bool):String { - return Writer.properCase(pkg, hasClassName); + var openIndex:Int = pkg.indexOf("<"); + if (openIndex == -1) { + return Writer.properCase(pkg, hasClassName); + } else { + return Writer.properCase(pkg.substr(0, openIndex), hasClassName) + pkg.substr(openIndex); + } + } + + public static function getVectorParam(s:String):String { + var openIndex:Int = s.indexOf("<"); + if (openIndex == -1) return "Dynamic"; + var closeIndex:Int = s.lastIndexOf(">"); + if (closeIndex == -1) return "Dynamic"; + return s.substring(openIndex + 1, closeIndex); + } + public static function getMapParam(s:String, index:Int):String { + var openIndex:Int = s.indexOf("<"); + if (openIndex == -1) return "Dynamic"; + var splitIndex:Int = -1; + var depth:Int = 0; + for (i in openIndex + 1...s.length) { + switch (s.charCodeAt(i)) { + case '<'.code: depth++; + case '>'.code: depth--; + case ','.code: + if (depth == 0) { + splitIndex = i; + break; + } + } + } + if (splitIndex != -1) { + if (index == 0) { + return s.substring(openIndex + 1, splitIndex); + } else if (index == 1) { + return s.substring(splitIndex + 1, s.length - 1); + } else { + return "Dynamic"; + } + } else { + return "Dynamic"; + } } +} + +class Reference { + public var value:T; + public function new() { } } \ No newline at end of file diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index a7a4700..dac5cdb 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -46,8 +46,10 @@ class Writer var genTypes : Array; //typedef generated while parsing var imported : Array; // store written imports to prevent duplicated var pack : Array; // stores the haxe file package - var validVariableNameEReg:EReg; + var generatedTypesWritten:Bool; + var validVariableNameEReg:EReg; var typer:Typer; + var dictionaries:DictionaryRebuild; public function new(config:Config) { @@ -63,67 +65,76 @@ class Writer this.lineIsDirty = false; this.pendingTailComment = null; - this.typeImportMap = new Map(); + //this.typeImportMap = new Map(); this.genTypes = []; this.imported = []; this.typer = new Typer(config); + this.dictionaries = new DictionaryRebuild(typer, config); this.validVariableNameEReg = new EReg("^[a-zA-Z_$][0-9a-zA-Z_$]*$", ""); - var doNotImportClasses = [ - "Array", "Bool", "Boolean", "Class", "Date", - "Dynamic", "EReg", "Enum", "EnumValue", - "Float", "Map", "Int", "IntIter", - "Lambda", "List", "Math", "Number", "Reflect", - "RegExp", "Std", "String", "StringBuf", - "StringTools", "Sys", "Type", "Void", - "Function", "XML", "XMLList" - ]; - if (!cfg.useOpenFlTypes) { - doNotImportClasses.push("Object"); - } - for(c in doNotImportClasses) { - this.typeImportMap.set(c, null); - } - if (!cfg.functionToDynamic) typeImportMap.set("Function", "haxe.Constraints.Function"); - if (cfg.useOpenFlTypes) { - typeImportMap.set("Vector", "openfl.Vector"); - typeImportMap.set("Object", "openfl.utils.Object"); - } - - var topLevelErrorClasses = [ - "ArgumentError", "DefinitionError", "Error", - "EvalError", "RangeError", "ReferenceError", - "SecurityError", "SyntaxError", "TypeError", - "URIError", "VerifyError" - ]; - - for(c in topLevelErrorClasses) { - this.typeImportMap.set(c, "flash.errors." + c); - } - - for(c in cfg.importTypes.keys()) { - this.typeImportMap.set(c, cfg.importTypes.get(c)); - } + //var doNotImportClasses = [ + //"Array", "Bool", "Boolean", "Class", "Date", + //"Dynamic", "EReg", "Enum", "EnumValue", + //"Float", "Map", "Int", "IntIter", + //"Lambda", "List", "Math", "Number", "Reflect", + //"RegExp", "Std", "String", "StringBuf", + //"StringTools", "Sys", "Type", "Void", + //"Function", "XML", "XMLList" + //]; + //if (!cfg.useOpenFlTypes) { + //doNotImportClasses.push("Object"); + //} + //for(c in doNotImportClasses) { + //this.typeImportMap.set(c, c); + //} + //if (!cfg.functionToDynamic) typeImportMap.set("Function", "haxe.Constraints.Function"); + //if (cfg.useOpenFlTypes) { + //typeImportMap.set("Vector", "openfl.Vector"); + //typeImportMap.set("Object", "openfl.utils.Object"); + //} +// + //var topLevelErrorClasses = [ + //"ArgumentError", "DefinitionError", "Error", + //"EvalError", "RangeError", "ReferenceError", + //"SecurityError", "SyntaxError", "TypeError", + //"URIError", "VerifyError" + //]; +// + //for(c in topLevelErrorClasses) { + //this.typeImportMap.set(c, "flash.errors." + c); + //} +// + //for(c in cfg.importTypes.keys()) { + //this.typeImportMap.set(c, cfg.importTypes.get(c)); + //} + //typeImportMap.set("MD5", "MD5"); + //typeImportMap.set("Signal", "org.osflash.signals.Signal"); + //typeImportMap.set("AGALMiniAssembler", "openfl.utils.AGALMiniAssembler"); + } + + public function prepareTyping():Void { + typer.parseParentClasses(); } public function refineTypes(p:Program):Void { - typer.refineTypes(p); + dictionaries.refineTypes(p); + new SignalRebuild(cfg, typer).apply(p); + new RebuildParentStaticFieldAccess(cfg, typer).apply(p); } - + public function applyRefinedTypes(p:Program):Void { - typer.applyRefinedTypes(p); + dictionaries.applyRefinedTypes(p); + new SignalRebuild(cfg, typer).apply(p); + new CallbackRebuild(cfg, typer).apply(p); } - + + public function finishTyping():Void { + SignalRebuild.cleanup(cfg, typer); + } + public function register(p:Program):Void { - for (d in p.defs) { - switch(d) { - case CDef(c): typer.addClass((p.pack.length > 0 ? getImportString(p.pack, false) + "." : "") + c.name, c); - case FDef(f): - case NDef(n): - default: - } - } + typer.addProgram(p); } /** @@ -210,7 +221,7 @@ class Writer { if (imports.length > 0) { - for(i in imports) { + for (i in imports) { writeImport(i); writeNL(); } @@ -220,9 +231,15 @@ class Writer function writeImport(i : Array) { - var type = getImportString(i, true); + var type = typer.getImportString(i, true); if (cfg.importExclude != null && cfg.importExclude.indexOf(type) != -1) { - return; + var short:String = type.substr(type.lastIndexOf(".") + 1); + var full:String = typeImportMap[short]; + if (full != null) { + type = full; + } else { + return; + } } if (!Lambda.has(this.imported, type)) { //prevent duplicate import write("import " + type + ";"); @@ -232,15 +249,6 @@ class Writer typeImportMap.set(i[i.length - 1], null); } } - - function getImportString(i : Array, hasClassName:Bool) { - if (i[0] == "flash") { - i[0] = cfg.flashTopLevelPackage; - return i.join("."); - } else { - return properCaseA(i, hasClassName).join("."); - } - } function writeAdditionalImports(defPackage : Array, allTypes : Array, definedTypes : Array) { @@ -254,14 +262,26 @@ class Writer // Now convert each seen type enum into the corresponding // type import string. var uniqueTypes = new Map(); - for(t in allTypes) { + for (t in allTypes) { var importType = istring(t); if(importType != null) { if(!typeImportMap.exists(importType)) { typeImportMap.set(importType, null); } else { + //var type = typer.getImportString(i, true); + //if (cfg.importExclude != null && cfg.importExclude.indexOf(type) != -1) { + uniqueTypes.set(importType, true); } + } else { + var full:String = tstring(t); + var short:String = typer.shortenStringType(full); + if (!typeImportMap.exists(short)) { + if (short != full) { + typeImportMap.set(short, full); + uniqueTypes.set(short, true); + } + } } } @@ -269,8 +289,9 @@ class Writer // map. var addnImports = new Array(); for(u in uniqueTypes.keys()) { - if(typeImportMap.exists(u)) { - u = typeImportMap.get(u); + if (typeImportMap.exists(u)) { + var nu:String = typeImportMap.get(u); + u = u == nu ? null : nu; } else { u = properCaseA(defPackage, false).concat([u]).join("."); } @@ -314,8 +335,10 @@ class Writer switch(d) { case EMeta(_): writeExpr(d); - case ECommented(s,b,t,e): - writeExpr(d); + case ECommented(s, b, t, e): + if (!t) { + writeExpr(d); + } case ENL(e): writeNL(); writeIndent(); @@ -340,6 +363,11 @@ class Writer { writeMetaData(c.meta); + if (!generatedTypesWritten) { + writeGeneratedTypes(genTypes); + generatedTypesWritten = true; + } + var buf = new StringBuf(); this.isInterface = c.isInterface; @@ -349,7 +377,10 @@ class Writer buf.add(c.isInterface ? "interface " : "class "); - buf.add(properCase(c.name,true)); + buf.add(properCase(c.name, true)); + if (c.typeParams != null) { + buf.add(c.typeParams); + } var parents = []; if (null != c.extend) { @@ -364,8 +395,9 @@ class Writer lvl++; var path:String = (pack.length > 0 ? pack.join(".") + "." : "") + c.name; - typer.enterClass(path, c); + typer.setPackage(path.substr(0, path.lastIndexOf("."))); typer.setImports(typeImportMap, imported); + typer.enterClass(path, c); // process properties writeProperties(c); @@ -388,7 +420,7 @@ class Writer { var p = []; var h = new Map(); - var getOrCreateProperty = function(name, t, stat) + var getOrCreateProperty = function(name, t, stat, internal) { var property = h.get(name); if (property == null) @@ -399,6 +431,7 @@ class Writer set : "never", ret : t, sta : stat, + internal : internal, pub : false, getMeta : null, setMeta : null @@ -423,7 +456,7 @@ class Writer var getterDirective : String = "get"; // haxe 3 // haxe 2: cfg.makeGetterName(field.name); - var property = getOrCreateProperty(field.name, f.ret.t, isStatic(field.kwds)); + var property = getOrCreateProperty(field.name, f.ret.t, isStatic(field.kwds), isInternal(field.kwds)); property.getMeta = field.meta; if (isPublic(field.kwds)) { @@ -438,7 +471,7 @@ class Writer var setterDirective : String = "set"; // haxe 3 // haxe 2: cfg.makeSetterName(field.name); - var property = getOrCreateProperty(field.name, f.args[0].t, isStatic(field.kwds)); + var property = getOrCreateProperty(field.name, f.args[0].t, isStatic(field.kwds), isInternal(field.kwds)); property.setMeta = field.meta; if (isPublic(field.kwds)) { @@ -468,6 +501,8 @@ class Writer writeMetaData(property.getMeta); } + if (property.internal) + writeAllow(); if(cfg.getterSetterStyle == "combined") write("#if !flash "); if (property.pub) { @@ -518,10 +553,9 @@ class Writer for (field in c.fields) { switch(field.kind) { case FFun ( f ): - if (field.name == c.name) { + if (!hasConstructor && field.name == c.name) { constructor = f; hasConstructor = true; - break; } case FVar(t, val): if (val != null) { @@ -556,7 +590,6 @@ class Writer } if (!needConstructor && !field.kwds.has("static")) { needConstructor = true; - if (hasConstructor) break; } } @@ -589,12 +622,15 @@ class Writer if (c.extend != null) { constructorFieldInits.push(ENL(ECall(EIdent("super"), []))); } - writeConstructor({ + var f:Function = { args : [], varArgs : null, ret : null, expr : EBlock(constructorFieldInits) - }, c.extend != null); + } + typer.enterFunction(f, c.name, c); + writeConstructor(f, c.extend != null); + typer.leaveFunction(); } } @@ -614,19 +650,19 @@ class Writer var namespaceMetadata:Array = null; if (isFun) { switch(field.kind) { - case FFun(f): typer.enterFunction(f); + case FFun(f): typer.enterFunction(f, field.name, c); default: }; } var lookUpForNamespaces = function(e:Expr):RebuildResult { switch(e) { case ENamespaceAccess(e, f): - var type:String = typer.getExprType(e); + var type:String = typer.getExprType(e, true); if (type == null) return null; if (typeImportMap.exists(type)) { - var typePath:String = typeImportMap.get(type); - if (typePath != null) { - type = typePath; + var fullType:String = typer.getFullTypeName(type); + if (fullType != null) { + type = fullType; } } if (namespaceMetadata == null) { @@ -639,7 +675,7 @@ class Writer return null; } - var start = function(name:String, isFlashNative:Bool=false, isConstructor=false) { + var start = function(name:String, isFlashNative:Bool=false, isConstructor=false):Bool { if((isGet || isSet) && cfg.getterSetterStyle == "combined") { writeNL(isFlashNative ? "#if flash" : "#else"); //writeNL(""); @@ -701,29 +737,42 @@ class Writer //static non-inlined field would prevent Haxe compilation switch(val) { case EConst(c): write("inline "); + return true; default: } default: } } } + return false; } switch(field.kind) { case FVar(t, val): - start(field.name, false); + var isInlined:Bool = start(field.name, false); write("var " + typer.getModifiedIdent(field.name)); - if (!isStatic(field.kwds) && isConst(field.kwds)) write("(default, never)"); + if (!isInlined && isConst(field.kwds)) { + if (val != null) { + write("(default, never)"); + } else { + write("(default, null)"); // constants that depends on class fields will be initialized in constructor, so they are not actually constants + } + } var type = tstring(t); //check wether a specific type was defined for this array if(isArrayType(type)) { for (genType in this.genTypes) { if (field.name == genType.fieldName) { - t = TVector(TPath([genType.name])); + t = (TPath(["Array<" + genType.name + ">"])); } } } writeVarType(t); context.set(field.name, tstring(t)); + if (val == null) { + if (type == "Int") val = EConst(CInt("0")); + else if (type == "Bool") val = EIdent("false"); + } + //initialise class property if(val != null) { write(" = "); @@ -738,7 +787,9 @@ class Writer if (field.name == c.name) { start("new", false, true); + typer.enterFunction(f, c.name, c); writeConstructor(f, c.extend != null); + typer.leaveFunction(); } else { var ret = f.ret; var name = if (isGetter(field.kwds)) { @@ -766,7 +817,7 @@ class Writer } } else { start(name, false); - writeFunction(f, isGetter(field.kwds), isSetter(field.kwds), false, name, ret); + writeFunction(f, isGetter(field.kwds), isSetter(field.kwds), false, name, ret, field.meta); } } @@ -910,6 +961,19 @@ class Writer for (arg in args) //for each method argument { + if (arg.val != null) { + switch (arg.val) { + case EField(_, _), EIdent("NaN"): + arg.t = TPath(["Null<" + tstring(arg.t) + ">"]); + functionExpressions.unshift(ENL( + EIf(EBinop("==", EIdent(arg.name), EIdent("null"), false), + EBinop("=", EIdent(arg.name), arg.val, false) + ) + )); + arg.val = EIdent("null"); + default: + } + } for (expr in arg.exprs) //for each expression within that argument { switch (expr) { @@ -933,7 +997,7 @@ class Writer write(s); } case ETypedExpr(_, t): - writeVarType(t); + writeVarType(arg.t); context.set(arg.name, tstring(arg.t)); if(arg.val != null) { write(" = "); @@ -967,10 +1031,6 @@ class Writer writeIndent(); case ECommented(s,b,t,e): // comment among arguments - if (pendingComma) { - pendingComma = false; - write(","); - } writeComment(s, b); default: @@ -981,7 +1041,7 @@ class Writer if (cfg.replaceVarArgsWithOptionalArguments) { // Adding workaround for (...params:Array) if (varArgs != null) { - var varArgsNum:Int = 4; + var varArgsNum:Int = 7; var argNum:Int = args.length; for (i in 1...varArgsNum + 1) { if (argNum++ > 0) write(", "); @@ -1035,18 +1095,17 @@ class Writer function constructorHasSuper(?expr : Expr) : Bool { if (expr == null) return false; - return switch(expr) { - case ECall(EIdent("super"), _): true; - case EBlock(exprs): - for (expr in exprs) { - if (constructorHasSuper(expr)) { - return true; - } - } - false; - case ENL(expr): constructorHasSuper(expr); - default: false; + var hasSuper:Bool = false; + function rebuildHasSuper(e:Expr):RebuildResult { + switch(e) { + case EIdent("super"): + hasSuper = true; + default: + } + return null; } + RebuildUtils.rebuild(expr, rebuildHasSuper); + return hasSuper; } inline function writeEContinue():BlockEnd { @@ -1061,16 +1120,27 @@ class Writer return result; } - function writeFunction(f : Function, isGetter:Bool, isSetter:Bool, isNative:Bool, ?name : Null, ?ret : FunctionRet) { + function writeFunction(f : Function, isGetter:Bool, isSetter:Bool, isNative:Bool, ?name : Null, ?ret : FunctionRet, ?meta:Array) { var oldFunctionReturnType:T = functionReturnType; functionReturnType = f.ret.t; - + // ensure the function body is in a block var es = f.expr != null ? formatBlockBody(f.expr) : []; - + write("function"); if(name != null) write(" " + name); + if (meta != null) { + for (e in meta) { + switch(e) { + case ECommented(s, b, t, e): + if (t) { + writeComment(s, b); + } + default: + } + } + } write("("); writeArgs(f.args, f.varArgs, es); write(")"); @@ -1144,6 +1214,10 @@ class Writer } } + inline function writeInComment(p:Dynamic):Void { + write("/* " + p + " */"); + } + inline function writeEReturn(?e:Expr) { write("return"); if(e == null) return; @@ -1183,18 +1257,31 @@ class Writer inLvalAssign = oldInLVA; write(")"); } else { - //write("/*!!!" + etype + "!!!*/"); - if(isDynamicType(etype) || ((isArrayType(etype) || e.match(EIdent(_))) && itype != null && itype != "Int" && itype != "UInt" && !isOpenFlDictionaryType(etype))) { + //write("/*!!!" + e + ":" + etype + "!!!*/"); + var oldInLVA = inLvalAssign; + inLvalAssign = false; + if (isArrayType(etype) || isVectorType(etype) || isOpenFlDictionaryType(etype) || isMapType(etype) || isByteArrayType(etype)/* || etype == "PropertyProxy"*/) { + writeExpr(e); + inArrayAccess = old; + write("["); + if (isOpenFlDictionaryType(etype) || isMapType(etype)) { + writeETypedExpr(index, TPath([typer.getMapIndexType(etype)])); + } else { + writeETypedExpr(index, TPath(["Int"])); + } + write("]"); + } else { + var isAnonymouse:Bool = isDynamicType(etype); + + //if(isObject || ((isArray || e.match(EIdent(_))) && itype != null && itype != "Int" && itype != "UInt" && !isOpenFlDictionaryType(etype))) { if(cfg.debugInferredType) { write("/* etype: " + etype + " itype: " + itype + " */"); } var isString = (itype == "String"); - var oldInLVA = inLvalAssign; - inLvalAssign = false; if(oldInLVA && !inEField) - write("Reflect.setField("); + write(isAnonymouse ? "Reflect.setField(" : "Reflect.setProperty("); else - write("Reflect.field("); + write(isAnonymouse ? "Reflect.field(" : "Reflect.getProperty("); writeExpr(e); inArrayAccess = old; write(", "); @@ -1206,15 +1293,9 @@ class Writer writeExpr(rvalue); rvalue = null; } - inLvalAssign = oldInLVA; write(")"); - } else { - writeExpr(e); - inArrayAccess = old; - write("["); - writeExpr(index); - write("]"); } + inLvalAssign = oldInLVA; } } @@ -1269,8 +1350,8 @@ class Writer } } - function getExprType(e:Expr):Null { - return typer.getExprType(e); + function getExprType(e:Expr, isFieldAccess:Bool = false):Null { + return typer.getExprType(e, isFieldAccess); } inline function getRegexpType():String return cfg.useCompat ? "as3hx.Compat.Regex" : "flash.utils.RegExp"; @@ -1288,16 +1369,9 @@ class Writer } } - function typeExpr(e:Expr) : String { - return switch(e) { - case EIdent(s): context.get(s); - default: null; - } - } - function writeModifiedIdent(s : String) { - write(typer.getModifiedIdent(s)); - } + write(typer.getModifiedIdent(s)); + } /** * Write an expression @@ -1326,8 +1400,8 @@ class Writer case EForIn(ev, e, block): rv = writeEForIn(ev, e, block); case EBreak(label): write("break"); case EContinue: rv = writeEContinue(); - case EFunction(f, name): - typer.enterFunction(f); + case EFunction(f, name): + typer.enterFunction(f, name); writeFunction(f, false, false, false, name); typer.leaveFunction(); case EReturn(e): writeEReturn(e); @@ -1353,7 +1427,33 @@ class Writer case ENew(t, params): writeENew(t, params); case EThrow( e ): write("throw "); - writeExpr(e); + function joinToString(params:Array):Expr { + var r = params[0]; + for (i in 1...params.length) { + r = EBinop("+", r, params[i], false); + if (i < params.length - 1) { + r = EBinop("+", r, EConst(CString(" ")), false); + } + } + return r; + } + switch (e) { + case ENew(t, params): + var c = params.copy(); + c.unshift(EConst(CString(tstring(t) + ": "))); + writeExpr(joinToString(c)); + case ECall(e1, params): + switch(e1) { + case EIdent(s): + var c = params.copy(); + c.unshift(EConst(CString(s + ": "))); + writeExpr(joinToString(c)); + default: + writeExpr(e); + } + default: + writeExpr(e); + } case ETry(e, catches): rv = writeETry(e, catches); case EObject(fl): if (fl.empty()) { @@ -1366,7 +1466,7 @@ class Writer var field = fl[i]; if (i > 0) writeNL(","); var field = fl[i]; - writeIndent(prepareObjectFieldName(field.name) + (cfg.spacesOnTypeColon ? " : " : ": ")); + writeIndent(prepareObjectFieldName(field.name) + (cfg.spacesOnTypeColon ? " : " : ": ")); writeExpr(field.e); } lvl--; @@ -1677,7 +1777,7 @@ class Writer write("{"); lvl++; for (ex in e) { - + writeFinish(writeETypedExpr(ex, TPath([null]))); } lvl--; @@ -1698,27 +1798,31 @@ class Writer var t2 = getExprType(e); //write("/* EField ("+Std.string(e)+","+Std.string(f)+") " +t1 + ":"+t2+ " */\n"); var old = inArrayAccess; - if(t1 == "FastXMLList" || (t1 == null && t2 == "FastXML")) { + if (t2 == "FastXMLList" && t1 == "FastXMLList") { + writeExpr(ECall(EField(e, "descendants"), [EConst(CString(f))])); + } else if(t1 == "FastXMLList" || (t1 == null && t2 == "FastXML")) { //write("/* t1 : " + t1 + " */"); writeExpr(e); if(inArrayAccess) write(".nodes." + f); else - write(".node." + f + ".innerData"); - } else if(t1 == "FastXML" || (t1 == null && t2 == "FastXMLList")) { - writeExpr(e); - write(".node"); - write("." + f + ".innerData"); + //write(".node." + f + ".innerData"); + write(".node." + f); } else { if (t2 == "Date") { switch(f) { + case "time" : return writeExpr(ECall(EField(e, "getTime"), [])); case "fullYear" : return writeExpr(ECall(EField(e, "getFullYear"), [])); case "month" : return writeExpr(ECall(EField(e, "getMonth"), [])); case "day" : return writeExpr(ECall(EField(e, "getDay"), [])); + case "date" : return writeExpr(ECall(EField(e, "getDate"), [])); case "hours" : return writeExpr(ECall(EField(e, "getHours"), [])); + case "hoursUTC" : return writeExpr(ECall(EField(e, "getHours/*UTC*/"), [])); case "minutes" : return writeExpr(ECall(EField(e, "getMinutes"), [])); case "seconds" : return writeExpr(ECall(EField(e, "getSeconds"), [])); case "milliseconds": return writeExpr(EParent(EBinop("%", ECall(EField(e, "getTime"), []), EConst(CInt("1000")), false))); + case "timezoneOffset": return writeExpr(getCompatCallExpr("getTimezoneOffset", [])); + case "getTimezoneOffset": return writeExpr(getCompatFieldExpr("getTimezoneOffset")); default: } } @@ -1753,9 +1857,15 @@ class Writer return None; } default: - if(f == "length" && isFunctionExpr(e)) { - writeExpr(getCompatCallExpr("getFunctionLength", [e])); - return None; + if (f == "length") { + var type:String = getExprType(e); + if (type == "Function" || type == "haxe.Constraints.Function") { + write("1 /*# of arguments of " + v + "*/"); + return None; + } else if (type != null && type.indexOf("->") != -1) { + writeExpr(getCompatCallExpr("getFunctionLength", [e])); + return None; + } } } case ECall(e, p): @@ -1840,13 +1950,18 @@ class Writer write("("); writeExpr(e); write(")"); + //write("/*TYPE " + getExprType(e) + " " + e + "*/"); } } function writeECall(fullExpr:Expr, expr:Expr, params:Array):BlockEnd { switch(expr) { case EField(expr, f): - if (f == "push" && params.length > 1 && isArrayExpr(expr)) { + if ((f == "push" || f == "unshift") && params.length > 1 && (isArrayExpr(expr) || isVectorExpr(expr))) { + if (f == "unshift") { + params = params.copy(); + params.reverse(); + } for(it in params) { writeExpr(ECall(EField(expr, f), [it])); write(";"); @@ -1864,9 +1979,8 @@ class Writer case ECall(e2, params2): expr = e2; params = params2; - case EArray(_,_): return writeExpr(eCall); - return None; default: + return writeExpr(eCall); } } var f:Expr->Expr = null; @@ -1885,26 +1999,53 @@ class Writer switch(expr) { case EIdent(n): var c = n.charCodeAt(0); - if(n.indexOf(".") == -1 && (c>=65 && c<=90)) { + if(n.indexOf(".") == -1 && (c>=65 && c<=90) || c == 103) { handled = true; switch(n) { case "Number": writeCastToFloat(params[0]); case "String": writeToString(params[0]); case "Boolean": - write("cast("); + write("AS3.as("); writeExpr(params[0]); write(", "); write("Bool)"); case "XML": var type = tstring(TPath(["XML"])); - write('$type.parse('); + var ts:String = getExprType(params[0]); + if (ts != null && ts.indexOf("ByteArray") != -1) { + write('$type.parseByteArray('); + } else { + write('$type.parse('); + } writeExpr(params[0]); write(")"); + case "getQualifiedClassName": + var t:String = getExprType(params[0]); + if (t == "Class" || t == "Class") { + writeExpr(ECall(EField(EIdent("Type"), "getClassName"), params)); + } else if (t == "Dynamic" || t == null) { + writeExpr(ECall(EField(EIdent("as3hx.Compat"), "getQualifiedClassName"), params)); + } else { // regular type + writeExpr(ECall(EField(EIdent("Type"), "getClassName"), [ECall(EField(EIdent("Type"), "getClass"), params)])); + } + //ECall(EField(EIdent("Type"), "getClassName"), [ECall(EField(EIdent("Type"), "getSuperClass"), [e])]); + + case "getQualifiedSuperclassName": + var t:String = getExprType(params[0]); + if (t == "Class" || t == "Class") { + writeExpr(ECall(EField(EIdent("Type"), "getClassName"), [ECall(EField(EIdent("Type"), "getSuperClass"), params)])); + } else if (t == "Dynamic" || t == null) { + writeExpr(ECall(EField(EIdent("as3hx.Compat"), "getQualifiedSuperclassName"), params)); + } else { // regular type + writeExpr(ECall(EField(EIdent("Type"), "getClassName"), [ECall(EField(EIdent("Type"), "getSuperClass"), [ECall(EField(EIdent("Type"), "getClass"), params)])])); + } + //case "": // Classes that needs to be converted to casts + //write("cast(("); + //writeExpr(params[0]); + //write("), "); + //write(n + ")"); default: - write("cast(("); - writeExpr(params[0]); - write("), "); - write(n + ")"); + handled = false; } } // other cases that come up as ECall @@ -1920,60 +2061,75 @@ class Writer write(")"); handled = true; case "int" | "uint": - writeCastToInt(params[0]); + writeExpr(getCastToIntExpr(params[0])); + //writeCastToInt(params[0]); handled = true; } case EVector(t): handled = true; if(cfg.vectorToArray) { writeExpr(params[0]); - } else { - write("Vector.ofArray(cast "); + } else if (cfg.useOpenFlTypes) { + write("openfl.Vector.ofArray(cast "); writeExpr(params[0]); write(")"); } default: } } - if(!handled) { - //return wether the param at the index is the last - //method call argument - var isLastArgument:Array->Int->Bool = function(params, index) { - //return wether the expression is a method call - //argument, which excludes comments and newlines - var isArgument : Expr->Bool = null; - isArgument = function(fullExpr) { - return switch(fullExpr) { - case ECommented(s,b,t,expr): isArgument(expr); - case ENL(expr): isArgument(expr); - default: true; + if (!handled) { + switch(expr) { + case EIdent(n): + var globalFunction:String = typer.isExistingIdent(n) ? null : typer.hasGlobalFunction(n); + if (globalFunction != null) { + //write(properCase(globalFunction, true) + "."); + write(n.charAt(0).toUpperCase() + n.substr(1) + "."); + } else { + var type:String = typer.getExprType(expr); + var className:String = type.substring(type.lastIndexOf(".") + 1); + if (type != "Function" && type != "haxe.Constraints.Function" && type.indexOf("->") == -1 && (className.charAt(0) == className.charAt(0).toUpperCase())) { + writeEBinop("as", params[0], expr, false); + handled = true; + } } + default: + } + } + if (!handled) { + var isArgument : Expr->Bool = null; + isArgument = function(fullExpr) { + return switch(fullExpr) { + case ECommented(s,b,t,expr): isArgument(expr); + case ENL(expr): isArgument(expr); + default: true; } - - //check all remaining parameters - var i = index; - while(i < params.length - 1) { - if(isArgument(params[i])) - return false; - i++; - } - return true; } + var tstring:String = typer.getExprType(expr); + var types:Array = tstring == null ? [] : tstring.split("->"); writeExpr(expr); write("("); var enl = false; + var hadArguments:Bool = false; for(i in 0...params.length) { - var isNotLastArgument = !isLastArgument(params, i); var param = params[i]; - switch(param) { - case ECommented(s, b, t, expr): - var delimiter = t && isNotLastArgument ? ", " : null; - writeECommented(s, b, t, expr, delimiter); - default: + var hasType:Bool = i < types.length - 1; + if (isArgument(params[i])) { + if (hadArguments) { + write(", "); + } + hadArguments = true; + } + switch(param) { + case EVector(t): + param = EIdent("Vector"); + default: + } + if (hasType && param != null) { + writeETypedExpr(param, TPath([types[i]])); + } else { writeExpr(param); - if(isNotLastArgument) write(", "); - } + } if(!enl && (param.match(ECommented(_,false,true,_)) || param.match(ENL(_)))) enl = true; } if(enl) { @@ -2071,7 +2227,7 @@ class Writer return result; } - inline function writeETernarny(cond:Expr, e1:Expr, ?e2:Expr) { + inline function writeETernarny(cond:Expr, e1:Expr, ?e2:Expr):BlockEnd { write("("); var rb = rebuildIfExpr(cond); if(rb != null) writeExpr(rb); @@ -2079,7 +2235,10 @@ class Writer write(") ? "); writeExpr(e1); write(getColon()); - writeExpr(e2); + if (e2 != null && getExprType(e1) == "String" && getExprType(e2) != "String") { + e2 = getToStringExpr(e2); + } + return writeExpr(e2); } inline function writeEWhile(cond:Expr, e:Expr, doWhile:Bool):BlockEnd { @@ -2115,6 +2274,7 @@ class Writer write("for ("); switch(inits[inits.length - 1]) { case EVars(v): + context.set(v[0].name, "Int"); write(v[0].name); write(" in "); writeExpr(v[0].val); @@ -2124,7 +2284,9 @@ class Writer case EBinop(op, e1, e2, newLineAfterOp): if (op == "=") { switch (e1) { - case EIdent(v): write(v); + case EIdent(v): + write(v); + context.set(v, "Int"); default: } write(" in "); @@ -2189,6 +2351,11 @@ class Writer var t = getExprType(e); var regexpMap:EReg = ~/^Map<([^,]*, *)?(.*)>$/; var regexpArray:EReg = ~/^Array<(.*)>$/; + var regexpVector:EReg = ~/^Vector<(.*)>$/; + var regexpDictionary:EReg = ~/^Dictionary<([^,]*, *)?(.*)>$/; + var regexpDictionaryOpenfl:EReg = ~/^openfl.utils.Dictionary<([^,]*, *)?(.*)>$/; + var isDictionary:Bool = false; + var isObject:Bool = false; if(varName == null) { write("/* AS3HX ERROR varName is null in expression " + e); } else if(t == "FastXML" || t == "FastXMLList") { @@ -2203,13 +2370,41 @@ class Writer write("/* inferred type: " + regexpArray.matched(1) + " */" ); } context.set(varName, regexpArray.matched(1)); + } else if (t != null && regexpVector.match(t)) { + if (cfg.debugInferredType) { + write("/* inferred type: " + regexpVector.matched(1) + " */" ); + } + context.set(varName, regexpVector.matched(1)); + } else if (t != null && regexpDictionary.match(t)) { + if (cfg.debugInferredType) { + write("/* inferred type: " + regexpDictionary.matched(1) + " */" ); + } + isDictionary = true; + context.set(varName, regexpDictionary.matched(1)); + } else if (t != null && regexpDictionaryOpenfl.match(t)) { + if (cfg.debugInferredType) { + write("/* inferred type: " + regexpDictionaryOpenfl.matched(1) + " */" ); + } + isDictionary = true; + context.set(varName, regexpDictionaryOpenfl.matched(1)); + } else if (t == "Object" || t == "openfl.utils.Object") { + isObject = true; } else { write("/* AS3HX WARNING could not determine type for var: " + varName + " exp: " + e + " type: " + t + " */"); + isObject = true; } write(" in "); var old = inArrayAccess; inArrayAccess = true; - writeExpr(e); + if (isDictionary) { + writeExpr(ECall(EField(e, "each"), [])); + } else if (isObject) { + write("as3hx.Compat.each("); + writeExpr(e); + write(")"); + } else { + writeExpr(e); + } inArrayAccess = old; writeCloseStatement(); var result = writeExpr(EBlock(formatBlockBody(block))); @@ -2217,12 +2412,14 @@ class Writer return result; } - inline function writeEForIn(ev:Expr, e:Expr, block:Expr):BlockEnd { + function writeEForIn(ev:Expr, e:Expr, block:Expr):BlockEnd { openContext(); var etype = getExprType(e); var regexp:EReg; + var canBeDictionary:Bool = false; if (isOpenFlDictionaryType(etype)) { - regexp = ~/^Dictionary<([^,]*)?,?.*>$/; + regexp = ~/^openfl.utils.Dictionary<([^,]*)?,?.*>$/; + canBeDictionary = true; } else { regexp = ~/^Map<([^,]*)?,?.*>$/; } @@ -2232,15 +2429,17 @@ class Writer case EVars(vars): if(vars.length == 1 && vars[0].val == null) { write(vars[0].name); + var type:String; if (!isMap || regexp.matched(1) == null) { - context.set(vars[0].name, "String"); + type = "String"; } else if (isIntType(regexp.matched(1))) { - context.set(vars[0].name, "Int"); + type = "Int"; } else { - context.set(vars[0].name, regexp.matched(1)); + type = regexp.matched(1); } + context.set(vars[0].name, type); if (cfg.debugInferredType) { - write("/* inferred type: " + context.get(vars[0].name) + " */" ); + write("/* inferred type: " + type + " */" ); } } else { writeExpr(ev); @@ -2251,7 +2450,13 @@ class Writer write(" in "); if (isMap) { writeExpr(e); - write(".keys()"); + if (!canBeDictionary) { + write(".keys()"); + } + } else if (isArrayExpr(e)) { + write("0..."); + writeExpr(e); + write(".length"); } else { write("Reflect.fields("); writeExpr(e); @@ -2264,77 +2469,121 @@ class Writer } function writeEBinop(op:String, e1:Expr, e2:Expr, newLineAfterOp:Bool):BlockEnd { - if(op == "as") { + if (op == "as") { + var defaultCast:Bool = false; switch(e2) { case EIdent(s): switch(s) { case "String": writeToString(e1); - case "int": writeCastToInt(e1); + case "int", "Int", "uint", "UInt": writeCastToInt(e1); case "Number": writeCastToFloat(e1); case "Array": - write("try cast("); + write("(try cast("); writeExpr(e1); - write(", Array) catch(e:Dynamic) null"); + write(", Array) catch(e:Dynamic) null)"); addWarning("as array", true); case "Class": - addWarning("as Class",true); - write("Type.getClass("); + //addWarning("as Class", true); + write("as3hx.Compat.castClass("); writeExpr(e1); write(")"); - default: - write("try cast("); + case "Function": + addWarning("as Function", false); + write("cast "); writeExpr(e1); - write(", "); - switch(e2) { - case EIdent(s): writeModifiedIdent(s); - default: writeExpr(e2); + default: + if (s == "Dictionary" || s == "PropertyProxy" || s == "Object") { + write("AS3.as("); + writeExpr(e1); + write(", " + s + ")"); + } else if (s == "ByteArray" || s == "Bitmap" || s.indexOf("Vector") == 0 || s == "Dictionary") { + write("(try cast("); + writeExpr(e1); + write(", "); + switch(e2) { + case EIdent(s): writeModifiedIdent(s); + default: writeExpr(e2); + } + write(") catch(e:Dynamic) null)"); + } else { + defaultCast = true; } - write(") catch(e:Dynamic) null"); } case EField(_): - write("try cast("); + defaultCast = true; + case EVector(_): + if (cfg.useOpenFlTypes) { + write("as3hx.Compat.castVector("); + writeExpr(e1); + write(")"); + } else { + write("try cast("); + writeExpr(e1); + write(", "); + write("Vector"); + write(") catch(e:Dynamic) null"); + } + default: throw "Unexpected " + Std.string(e2); + } + if (defaultCast) { + var e1t:String = typer.getExprType(e1); + var e2t:String = typer.getExprType(e2, true); + if (e2t == "Object" || e2t == "openfl.utils.Object" || e2t == "Dynamic") { + write("(cast "); + writeExpr(e1); + write(")"); + } else if (typer.getIsInterface(e1) || typer.getIsInterface(e2) || e1t == "Object" || e1t == "openfl.utils.Object") { + write("AS3.as("); writeExpr(e1); write(", "); - switch(e2) { - case EIdent(s): writeModifiedIdent(s); - default: writeExpr(e2); - } - write(") catch(e:Dynamic) null"); - case EVector(_): - write("try cast("); + writeExpr(e2); + write(")"); + } else { + write("AS3.as("); writeExpr(e1); write(", "); writeExpr(e2); - write(") catch(e:Dynamic) null"); - default: throw "Unexpected " + Std.string(e2); + write(")"); + } } - } else if(op == "is") { - write("Std.is("); - writeExpr(e1); - write(", "); + } else if (op == "is") { switch(e2) { - case EIdent(s): writeModifiedIdent(s); - default: writeExpr(e2); + case EVector(t) if (cfg.useOpenFlTypes): + write("as3hx.Compat.isVector("); + writeExpr(e1); + var ts:String = tstring(t); + if (ts != "Dynamic") { + write(", "); + write(ts); + } + write(")"); + default: + write("Std.is("); + writeExpr(e1); + write(", "); + writeExpr(e2); + write(")"); } - write(")"); + } else if (op == "in") { var type2:String = getExprType(e2); - if (isOpenFlDictionaryType(type2)) { - writeExpr(e2); - write(".has("); - writeExpr(e1); - write(")"); + var result:Expr; + if (isMapType(type2) || isOpenFlDictionaryType(type2)) { + var rebuiltExpr = EField(e2, "exists"); + result = ECall(rebuiltExpr, [ETypedExpr(e1, TPath([typer.getMapIndexType(type2)]))]); + } else if (isDynamicType(type2)) { + //Reflect.hasField(e, f); + result = ECall(EField(EIdent("Reflect"), "hasField"), [e2, e1]); } else { - write("Lambda.has("); - writeExpr(e2); - write(", "); - writeExpr(e1); - write(")"); + //(Type.getInstanceFields(Type.getClass(e)).indexOf(params[0]) != -1) + result = EParent(EBinop("!=", ECall(EField(ECall(EField(EIdent("Type"), "getInstanceFields"), [ECall(EField(EIdent("Type"), "getClass"), [e2])]), "indexOf"), [e1]), EConst(CInt("-1")), false)); } + writeExpr(result); } else { // op e1 e2 var eBinop = rebuildBinopExpr(op, e1, e2); if (eBinop != null) return writeExpr(eBinop); + var lookForRValue:Bool = true; var oldInLVA = inLvalAssign; if (op.indexOf("=") != -1) { if (op == "=") inLvalAssign = true; @@ -2347,7 +2596,7 @@ class Writer switch(e1) { case EArrayDecl(_): rvalue = e2; case ECall(_, _): rvalue = e1; - case _: + case _:lookForRValue = false; } } @@ -2362,7 +2611,7 @@ class Writer lvl += 2; inLvalAssign = oldInLVA; - if(rvalue != null) { + if(!lookForRValue || rvalue != null) { //check wether newline was found just before //op while parsing if (newLineAfterOp) { @@ -2398,7 +2647,7 @@ class Writer switch(e) { case EField(a, "length") if (op == "++" || op == "--"): var type = getExprType(a); - if (type != null && type.startsWith("Vector<")) { + if (isVectorType(type)) { if (op == "++") { writeExpr(EBinop("+=", e, EConst(CInt("1")), false)); } else { @@ -2660,41 +2909,119 @@ class Writer return result; } + private inline function writeDictionaryTypeConstructor(k:String, v:String):Void { + //write("new "); + //if (k == "Dynamic" || k == "Object" || k == "openfl.utils.Object") { + //if (k == "Object" || k == "openfl.utils.Object") k = "Dynamic"; + //write("haxe.ds.ObjectMap<" + k + ", "); + //} else if (k == "Float" || k == "Class" || k == "Class") { + //write("Dictionary<" + k + ","); + //} else { + //write("Map<" + k + ","); + //} + //write(v + ">("); + if (k == "Dynamic") k = "Object"; + write("new Dictionary<" + k + "," + v + ">("); + } + inline function writeENew(t : T, params : Array):Void { var writeParams = function() { + var argTypes:Array = typer.getClassConstructorTypes(tstring(t)); for(i in 0...params.length) { if(i > 0) write(", "); - writeExpr(params[i]); + var param:Expr = params[i]; + switch(param) { + case EVector(t): + param = EIdent("Vector"); + default: + } + if (argTypes != null && i < argTypes.length) { + writeETypedExpr(param, argTypes[i]); + } else { + writeExpr(param); + } } } - //write("/* " +context.get(tstring(t,false,false))+ " */"); - var origType = context.get(tstring(t, false, false)); - if(origType == "Class") { + switch(t) { + case TComplex(e): + var pack:Array = typer.getPackString(e); + if (pack != null) { + t = TPath(pack); + } + default: + } + var isVariable:Bool = false; + var handled = false; + switch(t) { + case TPath(p) if (p.length == 1 && typer.isVariable(p[0])): isVariable = true; + default: + } + if(isVariable) { write("Type.createInstance("); write(tstring(t, false, false)); write(", ["); writeParams(); write("])"); + handled = true; } //in AS3, if Date constructed without argument, uses current time - else if (tstring(t) == "Date" && params.empty()) { - write("Date.now()"); //use Haxe constructor for current time - } else { - var isObject = switch(t) { - case TPath(p) if(p[0] == "Object"): true; - default: false; + else if (tstring(t) == "Date") { + if (params.length == 0) { + write("Date.now()"); //use Haxe constructor for current time + handled = true; + } else if (params.length == 1) { + write("Date.fromTime("); + writeParams(); + write(")"); + handled = true; + } else { + while (params.length < 6) { + params.push(EConst(CInt("0"))); + } + } + } + var isObject = false; + var isDictionary = false; + if (!handled) { + switch(t) { + case TDictionary(k, v): + if (cfg.useOpenFlTypes && !cfg.dictionaryToHash) { + var ks:String = tstring(k); + var kv:String = tstring(v); + writeDictionaryTypeConstructor(ks, kv); + isDictionary = true; + } + case TPath(p) if (p[0] == "Object" || p[0] == "openfl.utils.Object"): isObject = true; + case TPath(p) if (p[0] == "ByteArray" || p[0] == "openfl.utils.ByteArray"): + writeExpr(getCompatCallExpr("newByteArray", params)); + handled = true; + case TPath(p): + if (isOpenFlDictionaryType(p[0])) { + var ks:String = Typer.getMapParam(p[0], 0); + var kv:String = Typer.getMapParam(p[0], 1); + writeDictionaryTypeConstructor(ks, kv); + isDictionary = true; + } + default: + } + } + if (!handled) { + if (isObject) write("{}"); + else if (isDictionary) { } - if(isObject) write("{}"); else write("new " + tstring(t) + "("); // prevent params when converting vector to array var out = switch(t) { case TVector(_): !cfg.vectorToArray; - case TDictionary(_,_): !cfg.dictionaryToHash; + case TDictionary(_, _): !cfg.dictionaryToHash; + case TPath(p): !(p[0] == "Array"); default: true; } + if (isDictionary && params.length > 0) write("/*"); if (out) writeParams(); - if(!isObject) write(")"); + if (isDictionary && params.length > 0) write("*/"); + if (!isObject) write(")"); } } @@ -2715,34 +3042,69 @@ class Writer return result; } + function isOpenFlDictionaryTypeT(t:T):Bool { + switch (t) { + case TDictionary(_, _): return true; + case TPath(p): + if (p.length == 1) { + if (p[0].indexOf("Dictionary") == 0 || p[0].indexOf("openfl.utils.Dictionary") == 0) { + return true; + } + } else if (p.length == 3) { + if (p[0] == "openfl" && p[1] == "utils" && p[2].indexOf("Dictionary") == 0) { + return true; + } + } + default: + } + return false; + } + function writeETypedExpr(e:Expr, t:T):BlockEnd { switch(e) { + case null: + write("(null as " + tstring(t) + ")"); + return None; case ENL(e2): return writeExpr(ENL(ETypedExpr(e2, t))); case ECommented(s, isBlock, isTail, e2): return writeECommented(s, isBlock, isTail, ETypedExpr(e2, t)); + case ETernary(cond, e1, e2): + return writeETernarny(cond, ETypedExpr(e1, t), ETypedExpr(e2, t)); case ENew(t2, params): - switch (t2) { - case TDictionary(k, v): - switch (t) { - case TPath(p) if (p.length == 1) : - return writeExpr(ENew(t, params)); - case TDictionary(k, v): - return writeExpr(ENew(t, params)); - default: - } - default: + if (isOpenFlDictionaryTypeT(t2) && isOpenFlDictionaryTypeT(t)) { + return writeExpr(ENew(typer.shortenType(t), params)); + } + case EIdent("null"): + switch(tstring(t)) { + case "String": + return writeExpr(e); + case "Bool": + return writeExpr(EIdent("false")); + case "Int","UInt": + return writeExpr(EConst(CInt("0"))); } default: } // fix of such constructions var tail:Signal = s || p; switch(tstring(t)) { + case "Function", "haxe.Constraints.Function": + var et:String = getExprType(e); + if (et == "Function" || et == "haxe.Constraints.Function") { + write("cast "); + } + case "Signal": + write("cast "); + case "String": + if (getExprType(e) != "String") { + e = getToStringExpr(e); + } case "Bool": var re:Expr = rebuildIfExpr(e); if (re != null) { e = re; } - case "Int", "Uint": + case "Int", "UInt": var et:String = getExprType(e); if (et != "Int" && et != "UInt") { e = getCastToIntExpr(e); @@ -2768,7 +3130,7 @@ class Writer write(".remove("); writeExpr(index); write(")"); - } else if (atype == "Dynamic") { + } else if (atype == "Dynamic" || atype == "Object" || atype == "openfl.utils.Object") { switch(index) { case EConst(c): switch(c) { @@ -2787,8 +3149,13 @@ class Writer addWarning("EDelete"); writeNL("This is an intentional compilation error. See the README for handling the delete keyword"); writeIndent('delete ${getIdentString(object)}[${getIdentString(index)}]'); - } else if (atype.startsWith("Array")) { + } else if (isArrayType(atype)) { writeExpr(EBinop("=", EArray(object, index), EIdent("null"), false)); + } else { + addWarning("EDelete"); + writeNL("This is an intentional compilation error. See the README for handling the delete keyword"); + writeIndent('delete ${getIdentString(object)}[${getIdentString(index)}]'); + writeInComment(atype); } } } @@ -2828,7 +3195,8 @@ class Writer case EIdent(id): if(id.charAt(0) == "@") return EIdent("x.att."+id.substr(1)); - return EIdent("x.node."+id+".innerData"); + //return EIdent("x.node."+id+".innerData"); + return EIdent("x.node."+id); case ECall(e2, params): //ECall(EField(EIdent(name),charAt),[EConst(CInt(0))]) var f = function(e) : String { @@ -2907,11 +3275,11 @@ class Writer switch(e) { case EArray(_,_): return EBinop("!=", e, EIdent("null"), false); case EIdent("null"): return null; - case EIdent(_), EField(_, _): + case EIdent(_), EField(_, _), ECall(_, _): var t = getExprType(e); if(t == null || t == "Bool") return null; return switch(t) { - case "Int" | "UInt": + case "Int" | "UInt": EBinop("!=", e, EConst(CInt("0")), false); case "Float": var lvalue = EBinop("!=", e, EConst(CInt("0")), false); @@ -2956,7 +3324,6 @@ class Writer var r2 = rebuildIfExpr(e2); if(r2 == null) return null; return EParent(r2); - case ECall(e2, params): //These would require a full typer case ENL(e): var expr = rebuildIfExpr(e); if (expr == null) return null; @@ -2987,9 +3354,22 @@ class Writer var result = null; switch (expr) { case EField(e, f): - if(f == "hasOwnProperty") { - var rebuiltExpr = EField(e, "exists"); - result = ECall(rebuiltExpr, params); + if (f == "hasOwnProperty") { + var type = getExprType(e); + if (isMapType(type) || isOpenFlDictionaryType(type)) { + var rebuiltExpr = EField(e, "exists"); + result = ECall(rebuiltExpr, params); + } else if (isDynamicType(type)) { + //Reflect.hasField(e, f); + var e1:Expr = params[0]; + if (getExprType(e1) != "String") { + e1 = getToStringExpr(e1); + } + result = ECall(EField(EIdent("Reflect"), "hasField"), [e, e1]); + } else { + //(Type.getInstanceFields(Type.getClass(e)).indexOf(params[0]) != -1) + result = EParent(EBinop("!=", ECall(EField(ECall(EField(EIdent("Type"), "getInstanceFields"), [ECall(EField(EIdent("Type"), "getClass"), [e])]), "indexOf"), params), EConst(CInt("-1")), false)); + } } else if(f == "replace") { var type = getExprType(e); @@ -3009,6 +3389,17 @@ class Writer } } } + else if(f == "fromCharCode" && params.length > 1) { + var type = getIdentString(e); + if (type == "String") { + //replace AS3 slice by Haxe substr + var rebuiltExpr = ECall(EField(e, f), [params[0]]); + for (i in 1...params.length) { + rebuiltExpr = EBinop("+", rebuiltExpr, ECall(EField(e, f), [params[i]]), false); + } + result = rebuiltExpr; + } + } else if(f == "slice") { var type = getExprType(e); if(type != null) { @@ -3022,7 +3413,7 @@ class Writer } } } - else if(f == "splice") { + else if (f == "splice") { if(isArrayExpr(e)) { switch(params.length) { case 0 | 2: @@ -3037,6 +3428,20 @@ class Writer } } } + if(isVectorExpr(e)) { + switch(params.length) { + case 0 | 2: + case 1: + params.push(EField(e, "length")); + result = ECall(EField(e, f), params); + default: + if(cfg.useCompat) { + var p = [e].concat(params.slice(0, 2)); + p.push(EArrayDecl(params.slice(2, params.length))); + result = getCompatCallExpr("vectorSplice", p); + } + } + } } else if(f == "match") { var type = getExprType(e); @@ -3046,6 +3451,22 @@ class Writer } } } + else if(f == "toLocaleLowerCase") { + var type = getExprType(e); + if(type != null) { + if (type == "String") { + result = ECall(EField(e, "toLowerCase"), params); + } + } + } + else if(f == "toLocaleUpperCase") { + var type = getExprType(e); + if(type != null) { + if (type == "String") { + result = ECall(EField(e, "toUpperCase"), params); + } + } + } else if(f == "search") { var type = getExprType(e); if(type != null) { @@ -3078,6 +3499,11 @@ class Writer result = ECall(EField(e, "insert"), params); } } + else if (f == "filter") { + if(isArrayExpr(e) || isVectorExpr(e)) { + result = ECall(EField(EIdent("as3hx.Compat"), "filter"), [e, params[0]]); + } + } else if((f == "min" || f == "max") && params.length > 2) { if(getIdentString(e) == "Math") { result = ECall(EField(e, f), params.slice(0, 2)); @@ -3086,7 +3512,7 @@ class Writer } } } - else if(f == "toFixed") { + else if (f == "toFixed" || f == "toPrecision") { if(getExprType(e) == "Float") { result = getCompatCallExpr(f, [e].concat(params)); } @@ -3111,7 +3537,7 @@ class Writer result = ECall(EField(e, f), [EConst(CInt("0"))]); } } - else if(f == "apply") { + else if (f == "apply") { if(isFunctionExpr(e)) { params = [EIdent("null"), e].concat(params.slice(1)); result = ECall(EField(EIdent("Reflect"), "callMethod"), params); @@ -3276,7 +3702,9 @@ class Writer } } if (isIntExpr(lvalue)) { - if(needCastToInt(rvalue)) { + if (op == "/=") { + return EBinop("=", lvalue, EBinop("/", lvalue, rvalue, false), false); + } else if(needCastToInt(rvalue)) { switch(rvalue) { case EBinop(op, e1, e2, newLineAfterOp) if(isBitwiseOp(op)): rvalue = getResultForNumerics(op, e1, e2); case EUnop(op, prefix, e) if(op == "~"): @@ -3372,13 +3800,13 @@ class Writer return false; } - function prepareObjectFieldName(name:String):String { - if (validVariableNameEReg.match(name)) { - return name; - } else { - return '"' + name + '"'; - } - } + function prepareObjectFieldName(name:String):String { + if (validVariableNameEReg.match(name)) { + return name; + } else { + return '"' + name + '"'; + } + } /** * Checks if 'e' represents a numerical constant value @@ -3394,23 +3822,36 @@ class Writer return isArrayType(type); } + inline function isVectorExpr(e:Expr):Bool { + var type = getExprType(e); + return isVectorType(type); + } + static inline function isArrayType(s:String):Bool { - return s != null && StringTools.startsWith(s, "Array<"); + return s != null && ((s.indexOf("Array<") == 0) || s == "Array"); } - static inline function isDynamicType(s:String):Bool return s == "Dynamic"; + static inline function isVectorType(s:String):Bool { + return s != null && s.indexOf("Vector<") == 0; + } + + static inline function isDynamicType(s:String):Bool return s == "Dynamic" || s == "Object" || s == "openfl.utils.Object"; inline function isMapType(s:String):Bool { - return s != null && (s.startsWith("Map") || s.startsWith("haxe.ds.ObjectMap")); + return s != null && (s.indexOf("Map") == 0 || s.indexOf("haxe.ds.ObjectMap") == 0); + } + + inline function isByteArrayType(s:String):Bool { + return s == "ByteArray"; } inline function isOpenFlDictionaryType(s:String):Bool { - return s != null && s.startsWith("Dictionary") && cfg.useOpenFlTypes; + return s != null && (s.indexOf("Dictionary") == 0 || s.indexOf("openfl.utils.Dictionary") == 0) && cfg.useOpenFlTypes; } inline function isFunctionExpr(e:Expr):Bool { var type:String = getExprType(e); - return type == "Function" || type != null && type.indexOf("->") != -1; + return type == "Function" || type == "haxe.Constraints.Function" || (type != null && type.indexOf("->") != -1); } inline function isIntExpr(e:Expr):Bool { @@ -3453,7 +3894,7 @@ class Writer static function eregQuote(s : String) : String { - return "'" + StringTools.replace(s, "\\", "\\\\") + "'"; + return '"' + StringTools.replace(StringTools.replace(s, '\\', '\\\\'), '"', '\\"') + '"'; } function isOverride(kwds : Array) : Bool @@ -3522,30 +3963,10 @@ class Writer } function tstring(t : T, isNativeGetSet:Bool = false, fixCase:Bool = true) : String { - if(t == null) return null; return switch(t) { - case TStar: "Dynamic"; - case TVector(t): cfg.vectorToArray ? "Array<" + tstring(t) + ">" : "Vector<" + tstring(t) + ">"; - case TPath(p): - var c = p.join("."); - return switch(c) { - case "Array" : "Array"; - case "Boolean" : "Bool"; - case "Class" : "Class"; - case "int" : "Int"; - case "Number" : "Float"; - case "uint" : cfg.uintToInt ? "Int" : "UInt"; - case "void" : "Void"; - case "Function" : cfg.functionToDynamic ? "Dynamic" : c; - case "Object" : isNativeGetSet ? "{}" : (cfg.useOpenFlTypes ? "Object" : "Dynamic"); - case "XML" : cfg.useFastXML ? "FastXML" : "Xml"; - case "XMLList" : cfg.useFastXML ? "FastXMLList" : "Iterator"; - case "RegExp" : cfg.useCompat ? "as3hx.Compat.Regex" : "flash.utils.RegExp"; - default : fixCase ? properCase(c, true) : c; - } + case null: null; case TComplex(e): buffer(function() { writeExpr(e); }); - case TDictionary(k, v): (cfg.dictionaryToHash ? "haxe.ds.ObjectMap" : "Dictionary") + "<" + tstring(k) + "," + tstring(v) + ">"; - case TFunction(p): p.map(function(it) return tstring(it)).join("->"); + default: typer.tstring(t, isNativeGetSet, fixCase); } } @@ -3566,11 +3987,13 @@ class Writer { //first func need to be converted to the field //type for classes + var kwds:Array = fDef.kwds.copy(); + kwds.push("static"); var funcAsClassField : ClassField = { name : fDef.name, - meta : fDef.meta, + meta : [ENL(null)], condVars : [], - kwds : fDef.kwds, + kwds : kwds, kind : FFun(fDef.f) }; @@ -3578,24 +4001,24 @@ class Writer var name = fDef.name.charAt(0).toUpperCase() + fDef.name.substr(1); //generate class doc - var meta = []; + var meta = fDef.meta.copy(); meta.push(ENL(null)); meta.push(ECommented("/**\n * Class for " + fDef.name + "\n */",false,false,null)); meta.push(ENL(null)); - //builds the class definition - return { - name : "ClassFor" + name, - meta:meta, - kwds:["final"], //always final as generated class - imports:[], - isInterface : false, - extend : null, - implement : [], - fields:[funcAsClassField], - inits : [] - }; + var result:ClassDef = new ClassDef(); + result.meta = meta; + result.kwds = ["final"]; + result.imports = []; + result.isInterface = false; + result.name = name; + result.typeParams = null; + result.fields = [funcAsClassField]; + result.implement = []; + result.extend = null; + result.inits = []; + return result; } function writeNamespaceDef(n : NamespaceDef) @@ -3715,7 +4138,13 @@ class Writer function writeComment(s : String, blockComment : Bool) { if (blockComment) { - write(" " + s + " "); + if (s.indexOf("haxe:") == 2) { + write(s.substring(7, s.length - 2)); + } else if (lineIsDirty) { + write(" " + s + " "); + } else { + write(s); + } } else { if (pendingTailComment == null) { pendingTailComment = s; @@ -3842,17 +4271,28 @@ class Writer return b.join(""); } - public function process(program : Program, writer : Output):Map { + public function process(program : Program, output : Output):Map { warnings = new Map(); + var commons:Map = CommonImports.getImports(cfg); + typeImportMap = new Map(); + for (key in commons.keys()) { + typeImportMap.set(key, commons.get(key)); + } + //list of imported types must be reseted for each file, //as only one instance of Writer write all the files imported = []; var defined:Array = []; - for (type in program.typesDefd) + pack = program.pack; + var packWithDot:String = properCaseA(pack, false).join(".") + (program.pack.length > 0 ? "." : ""); + + for (type in program.typesDefd) { defined.push(type.name); + imported.push(packWithDot + type.name); + } switch(program.defs[0]) { case CDef(c): @@ -3869,14 +4309,22 @@ class Writer default: } - o = writer; + for (def in program.defs) { + switch(def) { + case CDef(c): + defined.push(c.name); + imported.push(packWithDot + c.name); + default: + } + } + + o = output; genTypes = program.genTypes; - pack = program.pack; writeComments(program.header); writePackage(program.pack); writeImports(program.imports); writeAdditionalImports(program.pack, program.typesSeen, defined); - writeGeneratedTypes(program.genTypes); + generatedTypesWritten = false; writeDefinitions(program.defs); writeComments(program.footer); return warnings; @@ -3915,6 +4363,7 @@ class Writer case "as Class": println("WARNING: These files casted using 'obj as Class', which may produce incorrect code"); case "as number", "as int": println("WARNING: "+warn+" casts in these files"); case "as array": println("ERROR: type must be determined for 'as array' cast for:"); + case "as Function": println("WARNING: These files had a cast to Function which was ommited due to haxe type system"); case "EDelete": println("FATAL: Files will not compile due to 'delete' keyword. See README"); default: println("WARNING: " + warn); } @@ -3930,9 +4379,13 @@ class Writer public static function properCaseA(path:Array, hasClassName:Bool):Array { var result = []; + if (path.length == 3 && path[0] == "haxe" && path[1] == "Constraints" && path[2] == "Function") { + return path; + } for(i in 0...path.length) { if(hasClassName && i == path.length - 1) - result[i] = removeUnderscores(path[i]); + //result[i] = removeUnderscores(path[i]); removed by no reason + result[i] = path[i]; else { var p = path[i]; result[i] = p.charAt(0).toLowerCase() + p.substr(1); diff --git a/src/as3hx/WriterImports.hx b/src/as3hx/WriterImports.hx new file mode 100644 index 0000000..8c2c6a2 --- /dev/null +++ b/src/as3hx/WriterImports.hx @@ -0,0 +1,115 @@ +package as3hx; +import as3hx.As3.ClassDef; +import as3hx.As3.Program; + +/** + * ... + * @author xmi + */ +class WriterImports +{ + public static function getImportWithMap(ident:String, cfg:Config, allClasses:Map, imports:Map, currentPackage:String = null):String { + if (imports.exists(ident)) return imports.get(ident); + if (currentPackage != null) { + var currentPackageIdent:String = currentPackage + "." + ident; + if (allClasses.exists(currentPackageIdent)) { + return currentPackageIdent; + } + } + return null; + } + + public static function getImport(ident:String, cfg:Config, allClasses:Map, c:ClassDef, program:Program, currentPackage:String = null):String { + for (e in c.meta) { + switch(e) { + case EImport(i): + var name:String = getImportString(cfg, i); + if (cfg.importExclude != null && cfg.importExclude.indexOf(name) != -1) { + continue; + } + if (i[i.length - 1] == ident && allClasses.exists(name)) return name; + default: + } + } + if (program != null) { + for (i in program.imports) { + var name:String = getImportString(cfg, i); + if (cfg.importExclude != null && cfg.importExclude.indexOf(name) != -1) { + continue; + } + if (i[i.length - 1] == ident && allClasses.exists(name)) return name; + } + for (e in program.header) { + switch(e) { + case EImport(i): + var name:String = getImportString(cfg, i); + if (cfg.importExclude != null && cfg.importExclude.indexOf(name) != -1) { + continue; + } + if (i[i.length - 1] == ident && allClasses.exists(name)) return name; + default: + } + } + } + var commons:Map = CommonImports.getImports(cfg); + if (commons.exists(ident)) return commons.get(ident); + + if (currentPackage == null && program != null) { + currentPackage = program.pack.join("."); + } + if (currentPackage != null) { + var currentPackageIdent:String = currentPackage + "." + ident; + if (allClasses.exists(currentPackageIdent)) { + return currentPackageIdent; + } + } + return null; + } + + public static function getImports(p:Program, cfg:Config, c:ClassDef):Map { + var map:Map = new Map(); + var common:Map = CommonImports.getImports(cfg); + for (key in common.keys()) { + map.set(key, common.get(key)); + } + if (p != null) { + for (i in p.imports) { + addImport(cfg, map, i); + } + for (e in p.header) { + switch(e) { + case EImport(i): + addImport(cfg, map, i); + default: + } + } + } + + for (e in c.meta) { + switch(e) { + case EImport(i): + addImport(cfg, map, i); + default: + } + } + return map; + } + + static function addImport(cfg:Config, map:Map, i:Array):Void { + var type:String = getImportString(cfg, i); + if (cfg.importExclude != null && cfg.importExclude.indexOf(type) != -1) { + return; + } + map.set(i[i.length - 1], type); + } + + static function getImportString(cfg:Config, i : Array) { + if (i[0] == "flash") { + i[0] = cfg.flashTopLevelPackage; + return i.join("."); + } else { + return Writer.properCaseA(i, true).join("."); + } + } + +} \ No newline at end of file diff --git a/src/as3hx/parsers/ClassParser.hx b/src/as3hx/parsers/ClassParser.hx index d686332..03eaf29 100644 --- a/src/as3hx/parsers/ClassParser.hx +++ b/src/as3hx/parsers/ClassParser.hx @@ -18,6 +18,32 @@ class ClassParser { var parseImport = ImportParser.parse.bind(tokenizer, cfg); var cname = tokenizer.id(); + var typeParams = null; + + var next = tokenizer.token(); + switch (next) { + case TCommented(s, isBlock, t): + var type:T = OverrideTypeComment.extractType(cname, s, types); + if (type == null) { + tokenizer.add(next); + } else { + switch(type) { + case TPath(p): + cname = p.join("."); + var i:Int = cname.indexOf("<"); + if (i != -1) { + typeParams = cname.substr(i); + cname = cname.substr(0, i); + } + tokenizer.add(t); + default: + tokenizer.add(next); + } + } + default: + tokenizer.add(next); + } + var classMeta = meta; var imports = []; meta = []; @@ -182,19 +208,19 @@ class ClassParser { pf(false, true); case TCommented(s,b,t): - f(t); + f(t); case TNL(t): meta.push(ENL(null)); - f(t); + f(t); default: tokenizer.add(t); pf(false, false); - } + } } f(t); - + condVars.pop(); Debug.closeDebug("end conditional compilation: " + ns + "::" + id, tokenizer.line); break; @@ -243,17 +269,18 @@ class ClassParser { } } Debug.closeDebug("parseClass(" + cname+") finished", tokenizer.line); - return { - meta : classMeta, - kwds : kwds, - imports : imports, - isInterface : isInterface, - name : cname, - fields : fields, - implement : impl, - extend : extend, - inits : inits - }; + var result:ClassDef = new ClassDef(); + result.meta = classMeta; + result.kwds = kwds; + result.imports = imports; + result.isInterface = isInterface; + result.name = cname; + result.typeParams = typeParams; + result.fields = fields; + result.implement = impl; + result.extend = extend; + result.inits = inits; + return result; } public static function parseVar(tokenizer, types:Types, cfg:Config, kwds, meta, condVars:Array) : ClassField { @@ -276,7 +303,7 @@ class ClassParser { kind : FVar(t, val), condVars : condVars }; - + var genType = ParserUtils.generateTypeIfNeeded(rv); if (genType != null) types.gen.push(genType); @@ -285,7 +312,7 @@ class ClassParser { return rv; } - public static function parseFun(tokenizer, types:Types, cfg, kwds:Array,meta,condVars:Array, isInterface:Bool) : ClassField { + public static function parseFun(tokenizer, types:Types, cfg, kwds:Array, meta:Array, condVars:Array, isInterface:Bool) : ClassField { var parseFunction = FunctionParser.parse.bind(tokenizer, types, cfg); Debug.openDebug("parseClassFun(", tokenizer.line); @@ -301,6 +328,13 @@ class ClassParser { name = tokenizer.id(); } } + var t = tokenizer.token(); + switch (t) { + case TCommented(s, isBlock, t): + meta.push(ECommented(s, isBlock, true, null)); + default: + } + tokenizer.add(t); Debug.dbgln(Std.string(kwds) + " " + name + ")", tokenizer.line, false); var f = parseFunction(isInterface); tokenizer.end(); diff --git a/src/as3hx/parsers/OverrideTypeComment.hx b/src/as3hx/parsers/OverrideTypeComment.hx new file mode 100644 index 0000000..e2a49e0 --- /dev/null +++ b/src/as3hx/parsers/OverrideTypeComment.hx @@ -0,0 +1,40 @@ +package as3hx.parsers; +import as3hx.As3.T; +import as3hx.Parser.Types; + +/** + * ... + * @author + */ +class OverrideTypeComment { + public static function extractType(baseString:String, s:String, types:Types):T { + if (s.indexOf("haxe:") == 2) { // /*haxe: + var arg = s.substring(7, s.length - 2); + var typeArray:Array = null; + for (a in Typer.getTypeParams(arg)) { + types.seen.push(TPath(a)); + if (typeArray == null) { + typeArray = a; + } + } + var l:Int = typeArray.join(".").length; + if (l < arg.length) { + typeArray = typeArray.copy(); + } + typeArray[typeArray.length - 1] += arg.substring(typeArray.join(".").length); + return TPath(typeArray); + } else if (baseString != null && s.indexOf("<") == 2 && s.lastIndexOf(">") == s.length - 3) { + var arg = s.substring(2, s.length - 2); + var typeArray:Array = null; + for (a in Typer.getTypeParams(arg)) { + types.seen.push(TPath(a)); + if (typeArray == null) { + typeArray = a; + } + } + return TPath([baseString + arg]); + } else { + return null; + } + } +} \ No newline at end of file diff --git a/src/as3hx/parsers/ProgramParser.hx b/src/as3hx/parsers/ProgramParser.hx index 1548501..2ff9234 100644 --- a/src/as3hx/parsers/ProgramParser.hx +++ b/src/as3hx/parsers/ProgramParser.hx @@ -134,7 +134,7 @@ class ProgramParser { c.meta.pop(); c.meta.pop(); } - + //put the import in the first class meta c.meta.push(EImport(impt)); diff --git a/src/as3hx/parsers/StructureParser.hx b/src/as3hx/parsers/StructureParser.hx index 469648b..436afc7 100644 --- a/src/as3hx/parsers/StructureParser.hx +++ b/src/as3hx/parsers/StructureParser.hx @@ -34,8 +34,8 @@ class StructureParser { if(elseExpr != null) elseExpr = f(elseExpr); switch(cond) { case ECondComp(v, e, e2): - //corner case, the condition is an AS3 preprocessor - //directive, it must contain the block to wrap it + //corner case, the condition is an AS3 preprocessor + //directive, it must contain the block to wrap it //in Haxe #if #end preprocessor directive ECondComp(v, e1, elseExpr); default: @@ -132,17 +132,121 @@ class StructureParser { tokenizer.ensure(TOp(">")); if(tokenizer.peek() != TBkOpen) ParserUtils.unexpected(tokenizer.peek()); + types.seen.push(TVector(t)); ECall(EVector(t), [parseExpr(false)]); } else { + var peek:Token = tokenizer.peek(); + var call:Expr = parseExpr(false); + var firstCall:Expr; + function extractFirstCall(e:Expr):Expr { + switch(e) { + case ECall(e, params): + var re:Expr = extractFirstCall(e); + if (re == null) { + var type; + switch(e) { + case EIdent(v): + type = TPath([v]); + types.seen.push(type); + case EVector(t): + type = TVector(t); + types.seen.push(type); + default: + type = TComplex(e); + } + return firstCall = ENew(type, params); + } else { + return ECall(re, params); + } + case EIdent(v): return null; + case EVector(t): return null; + case ECommented(s, isBlock, isTail, e): + var re:Expr = extractFirstCall(e); + if (re == null) { + return null; + } else if (isBlock && isTail) { + switch(re) { + case ENew(t, params): + var base:T = OverrideTypeComment.extractType(Typer.tstringStatic(t), s, types); + if (base != null) { + return ENew(base, params); + } + + var k:T = null; + var v:T = null; + if (s.indexOf(",") != -1) { + s = s.substring(2, s.length - 2); + var commaIndex:Int = s.indexOf(","); + if (commaIndex != -1) { + k = TPath([Typer.getMapParam(s, 0)]); + v = TPath([Typer.getMapParam(s, 1)]); + } + } + if (k != null && v != null) { + switch(t) { + case TPath(p) if (p.length == 1 && p[0] == "Dictionary"): + types.seen.push(TDictionary(k, v)); + return ENew(TDictionary(k, v), params); + case TDictionary(k,v): + types.seen.push(TDictionary(k, v)); + return ENew(TDictionary(k, v), params); + default: + } + } + default: + } + } + return ECommented(s, isBlock, isTail, re); + case EArray(e, index): + var re:Expr = extractFirstCall(e); + if (re == null) { + return null; + } else { + return EArray(re, index); + } + case EBinop(op, e1, e2, newLineAfterOp): + var re1:Expr = extractFirstCall(e1); + if (re1 == null) { + return null; + } else { + return EBinop(op, re1, e2, newLineAfterOp); + } + case EField(e, f): + var re:Expr = extractFirstCall(e); + if (re == null) { + return null; + } else { + return EField(re, f); + } + default: return null; + } + } + switch(call) { + case EIdent(v): + var type = TPath([v]); + types.seen.push(type); + return ENew(type, []); + case EVector(t): + var type = TVector(t); + types.seen.push(type); + return ENew(type, []); + default: + var result:Expr = extractFirstCall(call); + if (firstCall != null) { + return result; + } else { + ParserUtils.unexpected(peek); + } + } var t = parseType(); // o = new (iconOrLabel as Class)() as DisplayObject var cc = switch(t) { case TComplex(e1) : switch (e1) { - case EBinop(op, e2, e3, n): + case EBinop(op, e2, e3, n): if (op == "as") { switch (e2) { - case ECall(e4, a): + case ECall(e4, a): EBinop(op, ECall(EField(EIdent("Type"), "createInstance"), [e4, EArrayDecl(a)]), e3, n); default: null; } @@ -163,7 +267,7 @@ class StructureParser { tokenizer.ensure(TPOpen); var name = tokenizer.id(); var t:T = null; - + var next = tokenizer.token(); switch (ParserUtils.uncomment(ParserUtils.removeNewLine(next))) { case TColon: @@ -174,7 +278,7 @@ class StructureParser { default: ParserUtils.unexpected(next); } - + var e = parseExpr(false); catches.push( { name : name, t : t, e : e } ); } @@ -230,7 +334,7 @@ class StructureParser { } cl.push(caseObj); } - + //reset for next case or default meta = []; } @@ -248,7 +352,7 @@ class StructureParser { ParserUtils.unexpected(tk); } } - + ESwitch(e, cl, def); case "do": var e = parseExpr(false); @@ -271,20 +375,6 @@ class StructureParser { var e = parseExpr(false); tokenizer.end(); EDelete(e); - case "getQualifiedClassName": - tokenizer.ensure(TPOpen); - var e = parseExpr(false); - e = switch(e) { - case EIdent(v) if(v == "this"): ECall(EField(EIdent("Type"), "getClass"), [e]); - default: e; - } - tokenizer.ensure(TPClose); - ECall(EField(EIdent("Type"), "getClassName"), [e]); - case "getQualifiedSuperclassName": - tokenizer.ensure(TPOpen); - var e = parseExpr(false); - tokenizer.ensure(TPClose); - ECall(EField(EIdent("Type"), "getClassName"), [ECall(EField(EIdent("Type"), "getSuperClass"), [e])]); case "getDefinitionByName": tokenizer.ensure(TPOpen); var e = parseExpr(false); @@ -321,7 +411,7 @@ class StructureParser { default: null; } } - + static function getParams(tokenizer:Tokenizer, parseExpr) { return switch(tokenizer.token()) { case TPOpen: diff --git a/src/as3hx/parsers/TypeParser.hx b/src/as3hx/parsers/TypeParser.hx index 4b1f26a..1a8af9f 100644 --- a/src/as3hx/parsers/TypeParser.hx +++ b/src/as3hx/parsers/TypeParser.hx @@ -23,6 +23,7 @@ class TypeParser { // for _i = new (obj as Class)() as DisplayObject; switch(tokenizer.peek()) { + //case TId("this"): return TComplex(parseExpr(false)); case TPOpen: return TComplex(parseExpr(false)); default: } @@ -36,7 +37,36 @@ class TypeParser { tokenizer.ensure(TOp(">")); types.seen.push(TVector(t)); return TVector(t); - } + } + var t2 = tokenizer.token(); + switch(t2) { + case TCommented(s, true, t3): + var typeFromComment:T = OverrideTypeComment.extractType(t, s, types); + if (typeFromComment != null) { + tokenizer.add(t3); + return typeFromComment; + } else { + tokenizer.add(t2); + } + default: + tokenizer.add(t2); + } + if (t == "Array") { + var k:T = null; + var t2 = tokenizer.token(); + switch(t2) { + case TCommented(s, true, t3): + var arg = s.substring(2, s.length - 2); + if (~/\w+/g.match(arg)) { + t = t + "<" + arg + ">"; + types.seen.push(TPath([arg])); + tokenizer.add(t3); + } + default: + tokenizer.add(t2); + } + return TPath([t]); + } if (t == "Dictionary") { var k:T = null; var v:T = null; @@ -56,10 +86,11 @@ class TypeParser { var t2 = tokenizer.token(); switch(t2) { case TCommented(s, true, t3): - var args = s.substring(2, s.length - 2).split(","); - if (args.length == 2) { - k = TPath([args[0]]); - v = TPath([args[1]]); + s = s.substring(2, s.length - 2); + var commaIndex:Int = s.indexOf(","); + if (commaIndex != -1) { + k = TPath(s.substr(0, commaIndex).split(".")); + v = TPath(s.substr(commaIndex + 1).split(".")); types.seen.push(TPath(["Dictionary"])); tokenizer.add(t3); } @@ -72,14 +103,12 @@ class TypeParser { } if (k == null) { k = TPath(["Object"]); - } else { - types.seen.push(k); } if (v == null) { v = TPath(["Object"]); - } else { - types.seen.push(v); } + types.seen.push(k); + types.seen.push(v); return TDictionary(k, v); } if(!cfg.functionToDynamic && t == "Function") { @@ -120,7 +149,7 @@ class TypeParser { for(it in types.seen) { switch(it) { case TPath(p): - if(Lambda.foreach(a, function(it) return p.indexOf(it) != -1)) { + if(Lambda.foreach(a, function(it) return p.indexOf(it) != -1)) {//this condition can fail on classes com.a.b.Class && com.b.a.Class return result; } default: @@ -129,7 +158,7 @@ class TypeParser { types.seen.push(result); return result; } - + private static function splitEndTemplateOps(tokenizer:Tokenizer) { switch( tokenizer.peek() ) { case TOp(s): From cb9890b586cc24684747a289757146e3d27486a5 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 20 Jul 2018 18:28:47 +0300 Subject: [PATCH 113/156] fix of try{} rebuild --- src/as3hx/Config.hx | 27 +++++++++++++++++++++++---- src/as3hx/RebuildUtils.hx | 2 +- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index bdf33e5..b05bdd1 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -114,9 +114,9 @@ class Config { /** source directory **/ - public var src : String; + public var src : Array; /** output directory **/ - public var dst : String; + public var dst : Array; var cfgFile : String; @@ -150,6 +150,9 @@ class Config { else return; cfgFile = toPath(home+"/.as3hx_config.xml"); + + src = []; + dst = []; } /** @@ -316,8 +319,24 @@ class Config { if (FileSystem.exists(cwd) && FileSystem.isDirectory(cwd)) { Sys.setCwd(cwd); } - src = Run.directory(arg); - dst = Run.directory(args.shift(), "./out"); + src.push(directory(arg)); + dst.push(directory(args.shift(), "./out")); + while (args.length > 1) { + src.push(directory(args.shift())); + dst.push(directory(args.shift(), "./out")); + } + } + + static var reabs = ~/^([a-z]:|\\\\|\/)/i; + static function directory(dir : String, alt = ".") { + if (dir == null) + dir = alt; + if(dir.endsWith("/") || dir.endsWith("\\")) + dir = dir.substr(0, -1); + if(!reabs.match(dir)) + dir = Sys.getCwd() + dir; + dir = StringTools.replace(dir, "\\", "/"); + return dir; } /* diff --git a/src/as3hx/RebuildUtils.hx b/src/as3hx/RebuildUtils.hx index 65d4a54..2fa8293 100644 --- a/src/as3hx/RebuildUtils.hx +++ b/src/as3hx/RebuildUtils.hx @@ -257,7 +257,7 @@ class RebuildUtils } if (re != null || needRebuild) { if (re == null) re = e; - return ETry(e, rcatches); + return ETry(re, rcatches); } else { return null; } From 8af1984cfd99393b5f84232a6f0b1bf2006771ff Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 20 Jul 2018 18:31:08 +0300 Subject: [PATCH 114/156] Batch conversion with multiple src's and dst's. Typer and Compat fixes. Deletion of unused code. --- src/AS3.hx | 37 +++- src/FileParser.hx | 64 ++++++ src/Run.hx | 281 ++++++++++---------------- src/as3hx/ClassFieldType.hx | 17 ++ src/as3hx/Compat.hx | 106 +++++----- src/as3hx/Typer.hx | 43 ++-- src/as3hx/Writer.hx | 388 ++++++++++++++++-------------------- src/as3hx/WriterImports.hx | 2 +- 8 files changed, 486 insertions(+), 452 deletions(-) create mode 100644 src/FileParser.hx create mode 100644 src/as3hx/ClassFieldType.hx diff --git a/src/AS3.hx b/src/AS3.hx index 5b221c7..8ed3604 100644 --- a/src/AS3.hx +++ b/src/AS3.hx @@ -22,9 +22,11 @@ class AS3 { return Std.is(e, haxe.Constraints.IMap) ? untyped e : null; } + #if openfl public static inline function asObject(e:Dynamic):openfl.utils.Object { return untyped e; } + #end public static inline function asClass(e:Dynamic, t:Class):T { return Std.is(e, t) ? untyped e : null; @@ -48,7 +50,9 @@ class AS3 { switch(type.expr) { //case EConst(CIdent("Dictionary")): return macro Std.is($e, haxe.Constraints.IMap) ? $e : null; case EConst(CIdent("Dictionary")): return macro AS3.asDictionary($e); + #if openfl case EConst(CIdent("Object")): return macro AS3.asObject($e); + #end case EConst(CIdent("Float")): return macro AS3.asFloat($e); case EConst(CIdent("Bool")): return macro AS3.asBool($e); @@ -95,8 +99,39 @@ class AS3 { } } #else - return false; + if (o == null) { + return false; + } else { + return Type.getInstanceFields(Type.getClass(o)).indexOf(field) != -1; + } #end } + + + + + /** + * Converts a typed expression into an Int. + */ + //#if js + macro public static function int(e:ExprOf, ?base:ExprOf):ExprOf { + return macro untyped ~~${e}; + } + //#else + //macro public static function int(e:ExprOf, ?base:ExprOf):ExprOf { + //var type = switch(Context.typeof(e)) { + //case TAbstract(t, _) if(t.get().pack.length == 0): t.get().name; + //case TInst(t, _) if(t.get().pack.length == 0): t.get().name; + //case _: null; + //} + //return switch(type) { + //case "Int": macro ${e}; + //case "Float": macro Std.int(${e}); + //case "String": macro as3hx.Compat.parseInt(${e}, ${base}); + //case "Bool": macro ${e} ? 1 : 0; + //case _: return macro as3hx.Compat.parseInt(Std.string(${e}), ${base}); + //} + //} + //#end } \ No newline at end of file diff --git a/src/FileParser.hx b/src/FileParser.hx new file mode 100644 index 0000000..7fb7b97 --- /dev/null +++ b/src/FileParser.hx @@ -0,0 +1,64 @@ +package; +import as3hx.Config; +import as3hx.ParserUtils; +import haxe.io.Path; +import sys.FileSystem; + +/** + * ... + * @author + */ +class FileParser { + private var cfg:Config; + private var fileExtension:String; + public function new(cfg:Config, fileExtension:String) { + this.cfg = cfg; + this.fileExtension = fileExtension; + if (this.fileExtension.indexOf(".") != 0) this.fileExtension = "." + fileExtension; + } + + + public function parseDirectory(src:String, excludes:List, handler:String->String->String->String->Void, relativeDestination:String = "/"):Void { + src = Path.normalize(src); + relativeDestination = Path.normalize(relativeDestination); + var subDirList = new Array(); + for(childName in FileSystem.readDirectory(src)) { + var childPath = Path.addTrailingSlash(src) + childName; + if (FileSystem.isDirectory(childPath)) { + subDirList.push(childName); + } else if(StringTools.endsWith(childName, fileExtension) && !isExcludeFile(excludes, childPath)) { + handler(src, childName, childPath, relativeDestination); + } + } + for (name in subDirList) { + parseDirectory((Path.addTrailingSlash(src) + name), excludes, handler, (Path.addTrailingSlash(relativeDestination) + ParserUtils.escapeName(name))); + } + } + + + static function isExcludeFile(excludes: List, file: String) { + return Lambda.filter(excludes, function (path) { + return as3hx.Config.toPath(file).indexOf(StringTools.replace(path, ".", "\\")) > -1; + }).length > 0; + } + + public static function ensureDirectoryExists(dir:String):Void { + var pathToCreate = []; + while (!FileSystem.exists(dir) && dir != '') { + var parts = dir.split("/"); + pathToCreate.unshift(parts.pop()); + dir = parts.join("/"); + } + for (part in pathToCreate) { + if (part == '') + continue; + dir += "/" + part; + try { + FileSystem.createDirectory(dir); + } catch (e : Dynamic) { + throw "unable to create dir: " + dir; + } + } + } + +} \ No newline at end of file diff --git a/src/Run.hx b/src/Run.hx index 86806d8..aac3848 100644 --- a/src/Run.hx +++ b/src/Run.hx @@ -11,166 +11,40 @@ using haxe.io.Path; class Run { - static function writeFile(name:String, program:Program, cfg:Config, f:String, src:String):Void { - Sys.println("target HX file: " + name); - var fw = File.write(name, false); - warnings.set(name, writer.process(program, fw)); - fw.close(); - if(cfg.postProcessor != "") { - postProcessor(cfg.postProcessor, name); - } - if(cfg.verifyGeneratedFiles) { - verifyGeneratedFile(f, src, name); - } - } - - static function errorString(e : Error) { - return switch(e) { - case EInvalidChar(c): "Invalid char '" + String.fromCharCode(c) + "' 0x" + StringTools.hex(c, 2); - case EUnexpected(src): "Unexpected " + src; - case EUnterminatedString: "Unterminated string"; - case EUnterminatedComment: "Unterminated comment"; - case EUnterminatedXML: "Unterminated XML"; - } - } - - static function loopImports(src:String, excludes:List) { - if (src == null) { - Sys.println("source path cannot be null"); - } - src = src.normalize(); - var subDirList = new Array(); - for(f in FileSystem.readDirectory(src)) { - var srcChildAbsPath = src.addTrailingSlash() + f; - if (FileSystem.isDirectory(srcChildAbsPath)) { - subDirList.push(f); - } else if(f.endsWith(".as") && !isExcludeFile(excludes, srcChildAbsPath)) { - var file = srcChildAbsPath; - Sys.println("import AS3 file: " + file); - var p = new as3hx.Parser(cfg); - var content = File.getContent(file); - var program = try p.parseString(content, src, f) catch(e : Error) { - #if macro - File.stderr().writeString(file + ":" + p.tokenizer.line + ": " + errorString(e) + "\n"); - #end - if(cfg.errorContinue) { - errors.push("In " + file + "(" + p.tokenizer.line + ") : " + errorString(e)); - continue; - } else { - #if neko - neko.Lib.rethrow("In " + file + "(" + p.tokenizer.line + ") : " + errorString(e)); - #elseif cpp - cpp.Lib.rethrow("In " + file + "(" + p.tokenizer.line + ") : " + errorString(e)); - null; - #end - } - } - writer.register(program); - } - } - for (name in subDirList) { - loopImports((src.addTrailingSlash() + name), excludes); - } - } - - static function loop(src:String, dst:String, excludes:List) { - if (src == null) { - Sys.println("source path cannot be null"); - } - if (dst == null) { - Sys.println("destination path cannot be null"); - } - src = src.normalize(); - dst = dst.normalize(); - var subDirList = new Array(); - if (!cfg.useFullTyping) { - writer = new Writer(cfg); - } - for(f in FileSystem.readDirectory(src)) { - var srcChildAbsPath = src.addTrailingSlash() + f; - var dstChildAbsPath = dst.addTrailingSlash() + f; - if (FileSystem.isDirectory(srcChildAbsPath)) { - subDirList.push(f); - } else if(f.endsWith(".as") && !isExcludeFile(excludes, srcChildAbsPath)) { - var file = srcChildAbsPath; - Sys.println("source AS3 file: " + file); - var p = new as3hx.Parser(cfg); - var content = File.getContent(file); - var program = try p.parseString(content, src, f) catch(e : Error) { - #if macro - File.stderr().writeString(file + ":" + p.tokenizer.line + ": " + errorString(e) + "\n"); - #end - if(cfg.errorContinue) { - errors.push("In " + file + "(" + p.tokenizer.line + ") : " + errorString(e)); - continue; - } else { - #if neko - neko.Lib.rethrow("In " + file + "(" + p.tokenizer.line + ") : " + errorString(e)); - #elseif cpp - cpp.Lib.rethrow("In " + file + "(" + p.tokenizer.line + ") : " + errorString(e)); - null; - #end - } - } - var out = dst; - ensureDirectoryExists(out); - var name = out.addTrailingSlash() + Writer.properCase(f.substr(0, -3), true) + ".hx"; - if (cfg.useFullTyping) { - writer.register(program); - files.push(new FileEntry(program, name, f, src)); - } else { - writeFile(name, program, cfg, f, src); - } - } - } - for (name in subDirList) { - loop((src.addTrailingSlash() + name), (dst.addTrailingSlash() + ParserUtils.escapeName(name)), excludes); - } - } - - static function postProcessor(?postProcessor:String = "", ?outFile:String = "") { - if(postProcessor != "" && outFile != "") { - Sys.println('Running post-processor ' + postProcessor + ' on file: ' + outFile); - Sys.command(postProcessor, [outFile]); - } - } - - //if a .hx file with the same name as the .as file is found in the .as - //file directory, then it is considered the expected output of the conversion - //and is diffed against the actual output - static function verifyGeneratedFile(file:String, src:String, outFile:String) { - var test = src.addTrailingSlash() + Writer.properCase(file.substr(0, -3), true) + ".hx"; - if (FileSystem.exists(test) && FileSystem.exists(outFile)) { - Sys.println("expected HX file: " + test); - var expectedFile = File.getContent(test); - var generatedFile = File.getContent(outFile); - if (generatedFile != expectedFile) { - Sys.println('Don\'t match generated file:' + outFile); - Sys.command('diff', [test, outFile]); - } - } - } - - static function isExcludeFile(excludes: List, file: String) - return Lambda.filter(excludes, function (path) return as3hx.Config.toPath(file).indexOf(path.replace(".", "\\")) > -1).length > 0; - static var errors : Array = new Array(); static var warnings : Map> = new Map(); static var cfg : as3hx.Config; static var writer:Writer; + static var currentDstPath:String; static var files:Array = new Array(); + public static function main() { cfg = new as3hx.Config(); if (cfg.useFullTyping) { writer = new Writer(cfg); } + var fileParser:FileParser = new FileParser(cfg, ".as"); + var libExcludes:List = new List(); for (libPath in cfg.libPaths) { - loopImports(libPath, cfg.excludePaths); + if (libPath == null) { + Sys.println("lib path cannot be null"); + } + fileParser.parseDirectory(libPath, libExcludes, parseLibFile); } - - - loop(cfg.src, cfg.dst, cfg.excludePaths); + for (i in 0...cfg.src.length) { + var src:String = cfg.src[i]; + var dst:String = cfg.dst[i]; + if (src == null) { + Sys.println("source path cannot be null"); + } + if (dst == null) { + Sys.println("destination path cannot be null"); + } + currentDstPath = Path.removeTrailingSlashes(Path.normalize(dst)); + fileParser.parseDirectory(src, cfg.excludePaths, parseSrcFile); + } + //loop(cfg.src, cfg.dst, cfg.excludePaths); if (cfg.useFullTyping) { writer.prepareTyping(); if (cfg.useOpenFlTypes) { @@ -196,37 +70,98 @@ class Run { } } - static function ensureDirectoryExists(dir : String) { - var tocreate = []; - while (!FileSystem.exists(dir) && dir != '') - { - var parts = dir.split("/"); - tocreate.unshift(parts.pop()); - dir = parts.join("/"); + static function parseLibFile(fileLocation:String, fileName:String, file:String, relativeDestination:String):Void { + Sys.println("import AS3 file: " + file); + var program = parseFile(fileLocation, fileName, file); + if (program == null) return; + writer.register(program); + } + + static function parseSrcFile(fileLocation:String, fileName:String, file:String, relativeDestination:String):Void { + Sys.println("source AS3 file: " + file); + var program = parseFile(fileLocation, fileName, file); + if (program == null) return; + var dst:String = currentDstPath + relativeDestination; + FileParser.ensureDirectoryExists(dst); + var resultPath = Path.addTrailingSlash(dst) + Writer.properCase(fileName.substr(0, -3), true) + ".hx"; + + if (cfg.useFullTyping) { + writer.register(program); + files.push(new FileEntry(program, resultPath, fileName, fileLocation)); + } else { + if (!cfg.useFullTyping) { + writer = new Writer(cfg); + } + writeFile(resultPath, program, cfg, fileName, fileLocation); } - for (part in tocreate) - { - if (part == '') - continue; - dir += "/" + part; - try { - FileSystem.createDirectory(dir); - } catch (e : Dynamic) { - throw "unable to create dir: " + dir; + } + + static function parseFile(fileLocation:String, fileName:String, file:String):Program { + var p = new as3hx.Parser(cfg); + var content = File.getContent(file); + var program = try p.parseString(content, fileLocation, fileName) catch(e : Error) { + #if macro + File.stderr().writeString(file + ":" + p.tokenizer.line + ": " + errorString(e) + "\n"); + #end + if(cfg.errorContinue) { + errors.push("In " + file + "(" + p.tokenizer.line + ") : " + errorString(e)); + null; + } else { + #if neko + neko.Lib.rethrow("In " + file + "(" + p.tokenizer.line + ") : " + errorString(e)); + #elseif cpp + cpp.Lib.rethrow("In " + file + "(" + p.tokenizer.line + ") : " + errorString(e)); + null; + #end } } + return program; } - static var reabs = ~/^([a-z]:|\\\\|\/)/i; - public static function directory(dir : String, alt = ".") { - if (dir == null) - dir = alt; - if(dir.endsWith("/") || dir.endsWith("\\")) - dir = dir.substr(0, -1); - if(!reabs.match(dir)) - dir = Sys.getCwd() + dir; - dir = StringTools.replace(dir, "\\", "/"); - return dir; + static function errorString(e : Error) { + return switch(e) { + case EInvalidChar(c): "Invalid char '" + String.fromCharCode(c) + "' 0x" + StringTools.hex(c, 2); + case EUnexpected(src): "Unexpected " + src; + case EUnterminatedString: "Unterminated string"; + case EUnterminatedComment: "Unterminated comment"; + case EUnterminatedXML: "Unterminated XML"; + } + } + + static function writeFile(name:String, program:Program, cfg:Config, f:String, src:String):Void { + Sys.println("target HX file: " + name); + var fw = File.write(name, false); + warnings.set(name, writer.process(program, fw)); + fw.close(); + if(cfg.postProcessor != "") { + postProcessor(cfg.postProcessor, name); + } + if(cfg.verifyGeneratedFiles) { + verifyGeneratedFile(f, src, name); + } + } + + static function postProcessor(?postProcessor:String = "", ?outFile:String = "") { + if(postProcessor != "" && outFile != "") { + Sys.println('Running post-processor ' + postProcessor + ' on file: ' + outFile); + Sys.command(postProcessor, [outFile]); + } + } + + //if a .hx file with the same name as the .as file is found in the .as + //file directory, then it is considered the expected output of the conversion + //and is diffed against the actual output + static function verifyGeneratedFile(file:String, src:String, outFile:String) { + var test = src.addTrailingSlash() + Writer.properCase(file.substr(0, -3), true) + ".hx"; + if (FileSystem.exists(test) && FileSystem.exists(outFile)) { + Sys.println("expected HX file: " + test); + var expectedFile = File.getContent(test); + var generatedFile = File.getContent(outFile); + if (generatedFile != expectedFile) { + Sys.println('Don\'t match generated file:' + outFile); + Sys.command('diff', [test, outFile]); + } + } } } diff --git a/src/as3hx/ClassFieldType.hx b/src/as3hx/ClassFieldType.hx new file mode 100644 index 0000000..5d78693 --- /dev/null +++ b/src/as3hx/ClassFieldType.hx @@ -0,0 +1,17 @@ +package as3hx; + +/** + * ... + * @author d.skvortsov + */ +class ClassFieldType +{ + public var name:String; + public var t:T; + public var host:String; + public var isStatic:Bool; + public function new() { + + } + +} \ No newline at end of file diff --git a/src/as3hx/Compat.hx b/src/as3hx/Compat.hx index 083f273..cba2e7f 100644 --- a/src/as3hx/Compat.hx +++ b/src/as3hx/Compat.hx @@ -42,8 +42,16 @@ class Compat { } public static inline function setArrayLength(a:Array>, length:Int) { + #if js + untyped a.length = length; + #else if (a.length > length) a.splice(length, a.length - length); - else a[length - 1] = null; + else { + for (i in a.length...length) { + a.push(null); + } + } + #end } /** @@ -158,7 +166,7 @@ class Compat { macro public static function getFunctionLength(f) { switch(Context.follow(Context.typeof(f))) { case TFun(args, _): return @:pos(Context.currentPos()) macro $v{args.length}; - default: throw new Error("not a function", f.pos); + default: return macro 0;// throw new Error("not a function", f.pos); } } @@ -183,8 +191,8 @@ class Compat { public static function isVector(p:Dynamic, T:Dynamic = null):Bool { if (p == null) return null; var c:Class = Type.getClass(p); - if (c == null) return null; - if (Type.getClassName(c) != "openfl._Vector.AbstractVector") return null; + if (c == null) return false; + if (Type.getClassName(c) != "openfl._Vector.AbstractVector") return false; var v:openfl.Vector = cast p; if (v.length > 0 && T != null && v[0] != null && !Std.is(v[0], T)) { return false; @@ -217,11 +225,12 @@ class Compat { } #end + public static inline function isClass(c:Dynamic):Bool { + return c != null && c.__name__ != null; + } + public static inline function castClass(c:Dynamic):Class { - return switch(Type.typeof(c)) { - case TClass(c): c; - default: null; - } + return isClass(c) ? untyped c : null; } public static inline function getQualifiedClassName(o:Dynamic):String { @@ -260,41 +269,7 @@ class Compat { } } - /** - * Converts a typed expression into a Float. - */ - macro public static function parseFloat(e:ExprOf):ExprOf { - var type = switch(Context.typeof(e)) { - case TAbstract(t, _) if(t.get().pack.length == 0): t.get().name; - case TInst(t, _) if(t.get().pack.length == 0): t.get().name; - case _: null; - } - return switch(type) { - case "Float" | "Int": macro ${e}; - case "String": macro Std.parseFloat(${e}); - case _: macro Std.parseFloat(Std.string(${e})); - } - } - - /** - * Converts a typed expression into an Int. - */ - macro public static function parseInt(e:ExprOf, ?base:ExprOf):ExprOf { - var type = switch(Context.typeof(e)) { - case TAbstract(t, _) if(t.get().pack.length == 0): t.get().name; - case TInst(t, _) if(t.get().pack.length == 0): t.get().name; - case _: null; - } - return switch(type) { - case "Int": macro ${e}; - case "Float": macro Std.int(${e}); - case "String": macro @:privateAccess as3hx.Compat._parseInt(${e}, ${base}); - case "Bool": macro ${e} ? 1 : 0; - case _: macro Std.parseInt(Std.string(${e})); - } - } - - static function _parseInt(s:String, ?base:Int):Null { + public static function parseInt(s:String, ?base:Int):Null { #if js if(base == null) base = s.indexOf("0x") == 0 ? 16 : 10; var v:Int = untyped __js__("parseInt")(s, base); @@ -307,18 +282,18 @@ class Compat { var BASE = "0123456789abcdefghijklmnopqrstuvwxyz"; if(base != null && (base < 2 || base > BASE.length)) return throw 'invalid base ${base}, it must be between 2 and ${BASE.length}'; - s = s.trim().toLowerCase(); - var sign = if(s.startsWith("+")) { + s = StringTools.trim(s).toLowerCase(); + var sign = if(StringTools.startsWith(s, "+")) { s = s.substring(1); 1; - } else if(s.startsWith("-")) { + } else if(StringTools.startsWith(s, "-")) { s = s.substring(1); -1; } else { 1; }; if(s.length == 0) return null; - if(s.startsWith('0x')) { + if(StringTools.startsWith(s, '0x')) { if(base != null && base != 16) return null; // attempting at converting a hex using a different base base = 16; s = s.substring(2); @@ -335,6 +310,22 @@ class Compat { #end } + /** + * Converts a typed expression into a Float. + */ + macro public static function parseFloat(e:ExprOf):ExprOf { + var type = switch(Context.typeof(e)) { + case TAbstract(t, _) if(t.get().pack.length == 0): t.get().name; + case TInst(t, _) if(t.get().pack.length == 0): t.get().name; + case _: null; + } + return switch(type) { + case "Float" | "Int": macro ${e}; + case "String": macro Std.parseFloat(${e}); + case _: macro Std.parseFloat(Std.string(${e})); + } + } + /** * Runs a function at a specified interval (in milliseconds). * @@ -487,7 +478,8 @@ class Compat { #if flash return untyped __global__['int'].MAX_VALUE; #elseif js - return untyped __js__('Number.MAX_SAFE_INTEGER'); + //return untyped __js__('Number.MAX_SAFE_INTEGER'); + return 2147483647; #elseif cs return untyped __cs__('int.MaxValue'); #elseif java @@ -511,7 +503,8 @@ class Compat { #if flash return untyped __global__['int'].MIN_VALUE; #elseif js - return untyped __js__('Number.MIN_SAFE_INTEGER'); + //return untyped __js__('Number.MIN_SAFE_INTEGER'); + return -2147483648; #elseif cs return untyped __cs__('int.MinValue'); #elseif java @@ -574,6 +567,21 @@ class Compat { } } + public static function toString(value:Int, base:Int = 10):String { + var BASE:String = "0123456789abcdefghijklmnopqrstuvwxyz"; + if(base < 2 || base > BASE.length) + throw 'invalid base $base, it must be between 2 and ${BASE.length}'; + if(base == 10 || value == 0) + return Std.string(value); + var buf:String = ""; + var abs:Int = value > 0 ? value : -value; + while(abs > 0) { + buf = BASE.charAt(abs % base) + buf; + abs = Std.int(abs / base); + } + return buf; + } + /** returns timezone offset in minutes */ public static function getTimezoneOffset():Int { #if flash diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index b3be476..ccbf94a 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -208,6 +208,12 @@ class Typer case "setTimeout": return "Dynamic->Int->Int"; case "getQualifiedClassName": return "Dynamic->String"; } + case "AS3": + switch(f) { + case "int": return "Dynamic->Int"; + case "parseInt": return "Dynamic->Int"; + case "hasOwnProperty": return "Dynamic->String->Bool"; + } case "Date": switch(f) { case "getTime": return "Void->Float"; @@ -310,6 +316,7 @@ class Typer case ECall(e, params): /* handling of as3 typing calls */ switch(e) { + case EIdent("Object"): return getExprType(params[0]); case EIdent("Number"): return "Float"; case EIdent("String"): return "String"; case EIdent("int"): return "Int"; @@ -423,7 +430,7 @@ class Typer var t1:String = getExprType(e1); var t2:String = getExprType(e2); if (op == "+" && t1 == "String" || t2 == "String") return "String"; - if (t1 != "Float" && t2 != "Float") return "Int"; + if (t1 != "Float" && t1 != "Dynamic" && t2 != "Float" && t2 != "Dynamic") return "Int"; return "Float"; } case ENew(t, params): @@ -594,7 +601,7 @@ class Typer public function addClass(p:Program, pack:String, path:String, c:ClassDef):Void { var classMap:Map = new Map(); if (!cfg.useFullTyping) { - parseClassFields(p, pack, c, classMap); + parseClassFields(p, pack, path, c, classMap); } classes[path] = classMap; classDefs[path] = c; @@ -604,7 +611,7 @@ class Typer public function parseParentClasses():Void { for (path in classes.keys()) { var c:ClassDef = classDefs[path]; - parseClassFields(classPrograms[c], classPacks[c], c, classes[path]); + parseClassFields(classPrograms[c], classPacks[c], path, c, classes[path]); } for (path in classes.keys()) { parseParentClass(path); @@ -872,6 +879,8 @@ class Typer case null: if (c != null) trace("null T for class ", c.name); return null; + case TVector(t): + return TVector(expandType(t, c)); case TFunction(p): var pr:Array = []; for (pi in p) { @@ -1215,7 +1224,6 @@ class Typer //classMap.remove(key); //} //} - //parseClassFields(path, c, classMap); context = classMap; if (contextStack.length > 0) { contextStack[contextStack.length - 1] = context; @@ -1345,6 +1353,7 @@ class Typer var etype:String = getExprType(e); var isMap:Bool = etype != null && (etype.indexOf("Map") == 0 || etype.indexOf("Dictionary") == 0 || etype.indexOf("openfl.utils.Dictionary") == 0); var isVector:Bool = etype != null && (etype.indexOf("Array") == 0 || etype.indexOf("Vector") == 0 || etype.indexOf("openfl.Vector") == 0); + var isXml:Bool = etype == "FastXML" || etype == "FastXMLList"; switch(ev) { case EVars(vars): if(vars.length == 1 && vars[0].val == null) { @@ -1356,8 +1365,10 @@ class Typer } } else if (isVector) { type = getVectorParam(etype); + } else if (isXml) { + type = etype; } else { - type = "String"; + type = "Dynamic"; } context.set(vars[0].name, type); var re2:Expr = RebuildUtils.rebuild(e, lookUpForTyping); @@ -1450,33 +1461,31 @@ class Typer } } - function parseClassFields(p:Program, pack:String, c:ClassDef, map:Map):Void { + function parseClassFields(p:Program, pack:String, path:String, c:ClassDef, map:Map):Void { var imports:Map = WriterImports.getImports(p, cfg, c); + this.pack = pack; + this.currentPath = path; + setImports(imports, null); for (field in c.fields) { - var type:String = null; + var type:T = null; switch(field.kind) { case FVar(t, val): - type = tstring(t); + type = t; case FFun(f): if (isSetter(field)) { - type = tstring(f.args[0].t); + type = f.args[0].t; } else if (isGetter(field)) { - type = tstring(f.ret.t); + type = f.ret.t; } else { var constructorReturnType:T = field.name == c.name ? TPath([pack.length > 0 ? pack + "." + c.name : c.name]) : null; - type = tstring(getFunctionType(f, constructorReturnType)); + type = getFunctionType(f, constructorReturnType); } default: } if (type != null) { - var t:String = WriterImports.getImportWithMap(type, cfg, classes, imports, pack); - if (t != null) { - type = t; - } - map.set(field.name, type); + map.set(field.name, tstring(expandType(type, c))); } } - //map.set(c.name, path); } inline function getRegexpType():String return cfg.useCompat ? "as3hx.Compat.Regex" : "flash.utils.RegExp"; diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index dac5cdb..72b14d0 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -32,8 +32,6 @@ class Writer var loopIncrements : Array; var varCount : Int; // vars added for ESwitch or EFor initialization var isInterface : Bool; // set if current class is an interface - var context : Map; - var contextStack : Array>; var inArrayAccess : Bool; var inEField : Bool; var inE4XFilter : Bool; @@ -56,8 +54,6 @@ class Writer this.lvl = 0; this.cfg = config; this.varCount = 0; - this.context = new Map(); - this.contextStack = new Array(); this.inArrayAccess = false; this.inEField = false; this.inE4XFilter = false; @@ -65,52 +61,12 @@ class Writer this.lineIsDirty = false; this.pendingTailComment = null; - //this.typeImportMap = new Map(); this.genTypes = []; this.imported = []; this.typer = new Typer(config); this.dictionaries = new DictionaryRebuild(typer, config); this.validVariableNameEReg = new EReg("^[a-zA-Z_$][0-9a-zA-Z_$]*$", ""); - - //var doNotImportClasses = [ - //"Array", "Bool", "Boolean", "Class", "Date", - //"Dynamic", "EReg", "Enum", "EnumValue", - //"Float", "Map", "Int", "IntIter", - //"Lambda", "List", "Math", "Number", "Reflect", - //"RegExp", "Std", "String", "StringBuf", - //"StringTools", "Sys", "Type", "Void", - //"Function", "XML", "XMLList" - //]; - //if (!cfg.useOpenFlTypes) { - //doNotImportClasses.push("Object"); - //} - //for(c in doNotImportClasses) { - //this.typeImportMap.set(c, c); - //} - //if (!cfg.functionToDynamic) typeImportMap.set("Function", "haxe.Constraints.Function"); - //if (cfg.useOpenFlTypes) { - //typeImportMap.set("Vector", "openfl.Vector"); - //typeImportMap.set("Object", "openfl.utils.Object"); - //} -// - //var topLevelErrorClasses = [ - //"ArgumentError", "DefinitionError", "Error", - //"EvalError", "RangeError", "ReferenceError", - //"SecurityError", "SyntaxError", "TypeError", - //"URIError", "VerifyError" - //]; -// - //for(c in topLevelErrorClasses) { - //this.typeImportMap.set(c, "flash.errors." + c); - //} -// - //for(c in cfg.importTypes.keys()) { - //this.typeImportMap.set(c, cfg.importTypes.get(c)); - //} - //typeImportMap.set("MD5", "MD5"); - //typeImportMap.set("Signal", "org.osflash.signals.Signal"); - //typeImportMap.set("AGALMiniAssembler", "openfl.utils.AGALMiniAssembler"); } public function prepareTyping():Void { @@ -137,24 +93,6 @@ class Writer typer.addProgram(p); } - /** - * Opens a new context for variable typing - */ - function openContext() { - var c = new Map(); - for(k in context.keys()) - c.set(k, context.get(k)); - contextStack.push(context); - context = c; - } - - /** - * Closes the current variable typing copntext - */ - function closeContext() { - context = contextStack.pop(); - } - function formatComment(s:String, isBlock:Bool):String { if(!isBlock) { return s; @@ -438,7 +376,6 @@ class Writer }; p.push(property); h.set(name, property); - context.set(name, tstring(t, true)); } return property; } @@ -527,8 +464,6 @@ class Writer writeNL(";"); } } - - context.set(property.name, tstring(property.ret)); } } if (c.isInterface) { @@ -766,7 +701,6 @@ class Writer } } writeVarType(t); - context.set(field.name, tstring(t)); if (val == null) { if (type == "Int") val = EConst(CInt("0")); @@ -998,7 +932,6 @@ class Writer } case ETypedExpr(_, t): writeVarType(arg.t); - context.set(arg.name, tstring(arg.t)); if(arg.val != null) { write(" = "); switch(tstring(t)) { @@ -1225,6 +1158,10 @@ class Writer writeETypedExpr(e, functionReturnType); } + function isArrayAccessable(etype:String):Bool { + return isArrayType(etype) || isVectorType(etype) || isOpenFlDictionaryType(etype) || isMapType(etype) || isByteArrayType(etype); + } + function writeEArray(e:Expr, index:Expr) { //write("/* EArray ("+Std.string(e)+","+Std.string(index)+") " + Std.string(getExprType(e, true)) + " */ "); var old = inArrayAccess; @@ -1260,6 +1197,7 @@ class Writer //write("/*!!!" + e + ":" + etype + "!!!*/"); var oldInLVA = inLvalAssign; inLvalAssign = false; + //oldInLVA = false; if (isArrayType(etype) || isVectorType(etype) || isOpenFlDictionaryType(etype) || isMapType(etype) || isByteArrayType(etype)/* || etype == "PropertyProxy"*/) { writeExpr(e); inArrayAccess = old; @@ -1272,8 +1210,6 @@ class Writer write("]"); } else { var isAnonymouse:Bool = isDynamicType(etype); - - //if(isObject || ((isArray || e.match(EIdent(_))) && itype != null && itype != "Int" && itype != "UInt" && !isOpenFlDictionaryType(etype))) { if(cfg.debugInferredType) { write("/* etype: " + etype + " itype: " + itype + " */"); } @@ -1295,6 +1231,7 @@ class Writer } write(")"); } + //inLvalAssign = false; inLvalAssign = oldInLVA; } } @@ -1773,7 +1710,6 @@ class Writer function writeEBlock(e:Array):BlockEnd { var result = Semi; if(!isInterface) { - openContext(); write("{"); lvl++; for (ex in e) { @@ -1782,7 +1718,6 @@ class Writer } lvl--; write(closeb()); - closeContext(); result = None; } else { write(";"); @@ -1910,27 +1845,10 @@ class Writer } } var type = tstring(v.t); - context.set(v.name, type); write("var " + typer.getModifiedIdent(v.name)); writeVarType(v.t); if(rvalue != null) { write(" = "); - if(isIntType(type)) { - switch(rvalue) { - case ETypedExpr(e, t) if(needCastToInt(e)): - rvalue = switch(e) { - case EBinop(op, e1, e2, newLineAfterOp) if(isBitwiseOp(op)): - if(needCastToInt(e1)) e1 = getCastToIntExpr(e1); - if(needCastToInt(e2)) e2 = getCastToIntExpr(e2); - EBinop(op, e1, e2, newLineAfterOp); - case EUnop(op, prefix, ex): - if(isBitwiseOp(op) && needCastToInt(ex)) EUnop(op, prefix, getCastToIntExpr(ex)); - else e; - default: getCastToIntExpr(e); - } - default: - } - } writeExpr(rvalue); if(i == vars.length - 1) { switch(rvalue) { @@ -1950,7 +1868,6 @@ class Writer write("("); writeExpr(e); write(")"); - //write("/*TYPE " + getExprType(e) + " " + e + "*/"); } } @@ -2002,13 +1919,18 @@ class Writer if(n.indexOf(".") == -1 && (c>=65 && c<=90) || c == 103) { handled = true; switch(n) { + case "Object": writeExpr(params[0]); case "Number": writeCastToFloat(params[0]); case "String": writeToString(params[0]); case "Boolean": - write("AS3.as("); - writeExpr(params[0]); - write(", "); - write("Bool)"); + if (getExprType(params[0]) == "Bool") { + writeEParent(params[0]); + } else { + write("AS3.as("); + writeExpr(params[0]); + write(", "); + write("Bool)"); + } case "XML": var type = tstring(TPath(["XML"])); var ts:String = getExprType(params[0]); @@ -2021,7 +1943,7 @@ class Writer write(")"); case "getQualifiedClassName": var t:String = getExprType(params[0]); - if (t == "Class" || t == "Class") { + if (isClassType(t)) { writeExpr(ECall(EField(EIdent("Type"), "getClassName"), params)); } else if (t == "Dynamic" || t == null) { writeExpr(ECall(EField(EIdent("as3hx.Compat"), "getQualifiedClassName"), params)); @@ -2032,7 +1954,7 @@ class Writer case "getQualifiedSuperclassName": var t:String = getExprType(params[0]); - if (t == "Class" || t == "Class") { + if (isClassType(t)) { writeExpr(ECall(EField(EIdent("Type"), "getClassName"), [ECall(EField(EIdent("Type"), "getSuperClass"), params)])); } else if (t == "Dynamic" || t == null) { writeExpr(ECall(EField(EIdent("as3hx.Compat"), "getQualifiedSuperclassName"), params)); @@ -2061,7 +1983,12 @@ class Writer write(")"); handled = true; case "int" | "uint": - writeExpr(getCastToIntExpr(params[0])); + var t:String = getExprType(params[0]); + if (t == "Int" || t == "UInt") { + writeEParent(params[0]); + } else { + writeExpr(getCastToIntExpr(params[0])); + } //writeCastToInt(params[0]); handled = true; } @@ -2241,6 +2168,14 @@ class Writer return writeExpr(e2); } + function getVarName(e:Expr):String { + switch(e) { + case EIdent(v): return v; + case EVars(vars) if (vars.length > 0): return vars[0].name; + default: return null; + } + } + inline function writeEWhile(cond:Expr, e:Expr, doWhile:Bool):BlockEnd { var result:BlockEnd; var rcond:Expr = rebuildIfExpr(cond); @@ -2266,7 +2201,6 @@ class Writer inline function writeEFor(inits:Array, conds:Array, incrs:Array, e:Expr):BlockEnd { //Sys.println('inits: ${inits}; conds: ${conds}; incrs: ${incrs}'); - openContext(); for (i in 0...inits.length - 1) { var e:Expr = inits[i]; writeExpr(ENL(e)); @@ -2274,7 +2208,6 @@ class Writer write("for ("); switch(inits[inits.length - 1]) { case EVars(v): - context.set(v[0].name, "Int"); write(v[0].name); write(" in "); writeExpr(v[0].val); @@ -2286,7 +2219,6 @@ class Writer switch (e1) { case EIdent(v): write(v); - context.set(v, "Int"); default: } write(" in "); @@ -2311,7 +2243,7 @@ class Writer case EConst(CInt(v)): //increment int constants var e = EConst(CInt(Std.string(Std.parseInt(v) + 1))); - writeExpr(e2); + writeExpr(e); case _: //when var used (like <= array.length), no choice but //to append "+1" @@ -2325,73 +2257,51 @@ class Writer } var es = formatBlockBody(e); writeLoop([], function() { writeExpr(EBlock(es)); }); - closeContext(); return None; } - inline function writeEForEach(ev:Expr, e:Expr, block:Expr):BlockEnd { - openContext(); - var varName = null; - write("for ("); - switch(ev) { - case EVars(vars): - if(vars.length == 1 && vars[0].val == null) { - write(vars[0].name); - varName = vars[0].name; - } else { - writeExpr(ev); - } - case EIdent(i): - varName = i; - writeExpr(ev); - default: - write("/* AS3HX ERROR unhandled " + ev + " */"); - writeExpr(ev); + function getForEachType(type:String):String { + //var isObject:Bool = type == "Object" || type == "openfl.utils.Object" || t == null; + if (isArrayType(type) || isVectorType(type)) { + return Typer.getVectorParam(type); + } else if (type == "FastXML" || type == "FastXMLList") { + return type; + } else if (isMapType(type) || isOpenFlDictionaryType(type)) { + type = Typer.getMapParam(type, 1); + if (type == null) { + return "Dynamic"; + } else { + return type; + } + } else { + return "String"; } + } + + inline function writeEForEach(ev:Expr, e:Expr, block:Expr):BlockEnd { var t = getExprType(e); - var regexpMap:EReg = ~/^Map<([^,]*, *)?(.*)>$/; - var regexpArray:EReg = ~/^Array<(.*)>$/; - var regexpVector:EReg = ~/^Vector<(.*)>$/; - var regexpDictionary:EReg = ~/^Dictionary<([^,]*, *)?(.*)>$/; - var regexpDictionaryOpenfl:EReg = ~/^openfl.utils.Dictionary<([^,]*, *)?(.*)>$/; - var isDictionary:Bool = false; - var isObject:Bool = false; - if(varName == null) { - write("/* AS3HX ERROR varName is null in expression " + e); - } else if(t == "FastXML" || t == "FastXMLList") { - context.set(varName, t); - } else if (t != null && regexpMap.match(t)) { - if (cfg.debugInferredType) { - write("/* inferred type: " + regexpMap.matched(1) + " */" ); - } - context.set(varName, regexpMap.matched(1)); - } else if (t != null && regexpArray.match(t)) { - if (cfg.debugInferredType) { - write("/* inferred type: " + regexpArray.matched(1) + " */" ); - } - context.set(varName, regexpArray.matched(1)); - } else if (t != null && regexpVector.match(t)) { - if (cfg.debugInferredType) { - write("/* inferred type: " + regexpVector.matched(1) + " */" ); - } - context.set(varName, regexpVector.matched(1)); - } else if (t != null && regexpDictionary.match(t)) { - if (cfg.debugInferredType) { - write("/* inferred type: " + regexpDictionary.matched(1) + " */" ); - } - isDictionary = true; - context.set(varName, regexpDictionary.matched(1)); - } else if (t != null && regexpDictionaryOpenfl.match(t)) { - if (cfg.debugInferredType) { - write("/* inferred type: " + regexpDictionaryOpenfl.matched(1) + " */" ); + + var isMap:Bool = isMapType(t); + //var isArray:Bool = isArrayType(t) || isVectorType(t); + //var isXml:Bool = t == "FastXML" || t == "FastXMLList"; + var isDictionary:Bool = isOpenFlDictionaryType(t); + var isObject:Bool = t == "Object" || t == "openfl.utils.Object" || t == null || t == "Dynamic"; + var eValueType:String = getForEachType(t); + + write("for ("); + var castLoopVariableType:String = null; + var varName:String = getVarName(ev); + if (varName != null) { + write(varName); + var varType:String = getExprType(ev); + if (varType != eValueType && (eValueType == "Dynamic" || typer.doImplements(varType, eValueType))) { + // as we are supposing that this was a valid as3 code, we are trying to cast values to as3-defined type + castLoopVariableType = varType; + write("_"); } - isDictionary = true; - context.set(varName, regexpDictionaryOpenfl.matched(1)); - } else if (t == "Object" || t == "openfl.utils.Object") { - isObject = true; } else { - write("/* AS3HX WARNING could not determine type for var: " + varName + " exp: " + e + " type: " + t + " */"); - isObject = true; + write("/* AS3HX ERROR unhandled " + e + " */"); + writeExpr(e); } write(" in "); var old = inArrayAccess; @@ -2407,45 +2317,42 @@ class Writer } inArrayAccess = old; writeCloseStatement(); - var result = writeExpr(EBlock(formatBlockBody(block))); - closeContext(); - return result; + var es:Array = formatBlockBody(block); + if (castLoopVariableType != null) { + es.unshift(ENL(EVars([{ + name:varName, + t:TPath([castLoopVariableType]), + //val:EBinop("as", EIdent(varName + "_"), EIdent(castLoopVariableType), false) + val:EIdent("cast " + varName + "_") + }]))); + } + return writeExpr(EBlock(es)); } function writeEForIn(ev:Expr, e:Expr, block:Expr):BlockEnd { - openContext(); var etype = getExprType(e); - var regexp:EReg; - var canBeDictionary:Bool = false; - if (isOpenFlDictionaryType(etype)) { - regexp = ~/^openfl.utils.Dictionary<([^,]*)?,?.*>$/; - canBeDictionary = true; - } else { - regexp = ~/^Map<([^,]*)?,?.*>$/; - } - var isMap:Bool = etype != null && regexp.match(etype); + var canBeDictionary:Bool = isOpenFlDictionaryType(etype); + var isMap:Bool = canBeDictionary || isMapType(etype); + var castLoopVariableType:String = null; write("for ("); - switch(ev) { - case EVars(vars): - if(vars.length == 1 && vars[0].val == null) { - write(vars[0].name); - var type:String; - if (!isMap || regexp.matched(1) == null) { - type = "String"; - } else if (isIntType(regexp.matched(1))) { - type = "Int"; - } else { - type = regexp.matched(1); - } - context.set(vars[0].name, type); - if (cfg.debugInferredType) { - write("/* inferred type: " + type + " */" ); - } - } else { - writeExpr(ev); - } - default: - writeExpr(ev); + var varName:String = getVarName(ev); + if (varName != null) { + write(varName); + var varType:String = getExprType(ev); + var mapKeyType:String; + if (isMap) { + mapKeyType = Typer.getMapParam(etype, 1); + } else { + mapKeyType = "String"; + } + if (varType != mapKeyType && typer.doImplements(varType, mapKeyType)) { + // as we are supposing that this was a valid as3 code, we are trying to cast values to as3-defined type + castLoopVariableType = varType; + write("_"); + } + } else { + write("/* AS3HX ERROR unhandled " + e + " */"); + writeExpr(e); } write(" in "); if (isMap) { @@ -2463,9 +2370,15 @@ class Writer write(")"); } writeCloseStatement(); - var result = writeExpr(EBlock(formatBlockBody(block))); - closeContext(); - return result; + var es:Array = formatBlockBody(block); + if (castLoopVariableType != null) { + es.unshift(EVars([{ + name:varName, + t:TPath([castLoopVariableType]), + val:EIdent(varName + "_") + }])); + } + return writeExpr(EBlock(es)); } function writeEBinop(op:String, e1:Expr, e2:Expr, newLineAfterOp:Bool):BlockEnd { @@ -2526,18 +2439,11 @@ class Writer default: throw "Unexpected " + Std.string(e2); } if (defaultCast) { - var e1t:String = typer.getExprType(e1); var e2t:String = typer.getExprType(e2, true); if (e2t == "Object" || e2t == "openfl.utils.Object" || e2t == "Dynamic") { write("(cast "); writeExpr(e1); write(")"); - } else if (typer.getIsInterface(e1) || typer.getIsInterface(e2) || e1t == "Object" || e1t == "openfl.utils.Object") { - write("AS3.as("); - writeExpr(e1); - write(", "); - writeExpr(e2); - write(")"); } else { write("AS3.as("); writeExpr(e1); @@ -2583,6 +2489,26 @@ class Writer var eBinop = rebuildBinopExpr(op, e1, e2); if (eBinop != null) return writeExpr(eBinop); + //if (op == "=") { + //switch(e1) { + //case EArray(e, index): + //var etype:String = getExprType(e); + //if (!isArrayAccessable(etype)) { + //if (isDynamicType(etype)) { + //write("Reflect.setField("); + //} else { + //write("Reflect.setProperty("); + //} + //writeExpr(e); + //write(", "); + //writeETypedExpr(index, TPath(["String"])); + //write(")"); + //} + //return Semi; + //default: + //} + //} + var lookForRValue:Bool = true; var oldInLVA = inLvalAssign; if (op.indexOf("=") != -1) { @@ -2689,7 +2615,7 @@ class Writer } inline function needCastToInt(e:Expr):Bool { - var isCompatParseInt:Expr->Bool = function(e) return e.match(ECall(EField(EIdent("as3hx.Compat"), "parseInt"), _)); + var isCompatParseInt:Expr->Bool = function(e) return e.match(ECall(EField(EIdent("AS3"), "int"), _)); return switch(e) { case EBinop(op,e1,_,_): !isCompatParseInt(e1) && (isBitwiseOp(op) || isNumericOp(op)); case EUnop(op,_,e): op == "~" && !isCompatParseInt(e); @@ -2701,7 +2627,7 @@ class Writer function getCastToIntExpr(e:Expr):Expr { if(cfg.useCompat) { - return getCompatCallExpr("parseInt", [e]); + return ECall(EField(EIdent("AS3"), "int"), [e]); } return ECall(EField(EIdent("Std"), "parseInt"), [getToStringExpr(e)]); } @@ -2864,8 +2790,6 @@ class Writer write("FastXML.filterNodes("); //write("/*"+Std.string(e1)+"*/"); var n = getBaseVar(e1); // make sure it's set to FastXML in the - if(n != null) - context.set(n, "FastXML"); // current context var old = inArrayAccess; inArrayAccess = true; // ensure 'nodes' vs. 'node' writeExpr(e1); @@ -3108,7 +3032,6 @@ class Writer var et:String = getExprType(e); if (et != "Int" && et != "UInt") { e = getCastToIntExpr(e); - //e = ECall(EField(EIdent("Std"), "int"), [ETypedExpr(e, null)]); } default: switch (e) { @@ -3366,6 +3289,8 @@ class Writer e1 = getToStringExpr(e1); } result = ECall(EField(EIdent("Reflect"), "hasField"), [e, e1]); + } else if (isClassType(type)) { + result = EParent(EBinop("!=", ECall(EField(ECall(EField(EIdent("Type"), "getClassFields"), [e]), "indexOf"), params), EConst(CInt("-1")), false)); } else { //(Type.getInstanceFields(Type.getClass(e)).indexOf(params[0]) != -1) result = EParent(EBinop("!=", ECall(EField(ECall(EField(EIdent("Type"), "getInstanceFields"), [ECall(EField(EIdent("Type"), "getClass"), [e])]), "indexOf"), params), EConst(CInt("-1")), false)); @@ -3504,6 +3429,19 @@ class Writer result = ECall(EField(EIdent("as3hx.Compat"), "filter"), [e, params[0]]); } } + else if (f == "sort") { + if (isArrayExpr(e)) { + switch(params[0]) { + case EField(e1, "RETURNINDEXEDARRAY"): + switch(e1) { + case EIdent("Array"): + result = getCompatCallExpr("sortIndexedArray", [e]); + default: + } + default: + } + } + } else if((f == "min" || f == "max") && params.length > 2) { if(getIdentString(e) == "Math") { result = ECall(EField(e, f), params.slice(0, 2)); @@ -3517,8 +3455,20 @@ class Writer result = getCompatCallExpr(f, [e].concat(params)); } } - else if(f == "toString") { - result = getToStringExpr(e); + else if (f == "toString") { + if (params.length == 1) { + var type:String = getExprType(e); + if (type == "Int" || type == "UInt" || type == "Float") { + if (type == "Float") { + e = getCastToIntExpr(e); + } + result = getCompatCallExpr(f, [e].concat(params)); + } else { + result = getToStringExpr(e); + } + } else { + result = getToStringExpr(e); + } } else if(f == "concat" && params.empty()) { if(isArrayExpr(e)) { @@ -3560,6 +3510,20 @@ class Writer result = ECall(EField(EIdent("StringTools"), f), params); } } + else if (f == "resolveClass") { + if (getIdentString(e) == "Type") { + if (params.length == 1) { + switch(params[0]) { + case ECall(EIdent("getQualifiedSuperClassName"), params2): + result = ECall(EField(EIdent("Type"), "getSuperClass"), [ECall(EField(EIdent("Type"), "getClass"), params2)]); + + case ECall(EIdent("getQualifiedClassName"), params2): + result = ECall(EField(EIdent("Type"), "getClass"), params2); + default: + } + } + } + } else if(f == "isWhitespace") { if(getIdentString(e) == "StringUtil") { params.push(EConst(CInt("0"))); @@ -3863,6 +3827,8 @@ class Writer inline function isBoolType(s:String):Bool return s == "Bool"; + inline function isClassType(s:String):Bool return s == "Class" || s == "Class"; + inline function isNumericOp(s:String):Bool return switch(s) { case "/" | "-" | "+" | "*" | "%" | "--" | "++": true; default: false; diff --git a/src/as3hx/WriterImports.hx b/src/as3hx/WriterImports.hx index 8c2c6a2..f2c4d01 100644 --- a/src/as3hx/WriterImports.hx +++ b/src/as3hx/WriterImports.hx @@ -8,7 +8,7 @@ import as3hx.As3.Program; */ class WriterImports { - public static function getImportWithMap(ident:String, cfg:Config, allClasses:Map, imports:Map, currentPackage:String = null):String { + public static function getImportWithMap(ident:String, allClasses:Map, imports:Map, currentPackage:String = null):String { if (imports.exists(ident)) return imports.get(ident); if (currentPackage != null) { var currentPackageIdent:String = currentPackage + "." + ident; From 1cc9acad06045cec5896f327e333a8214d0d02f4 Mon Sep 17 00:00:00 2001 From: "d.sigalov" Date: Tue, 24 Jul 2018 17:53:26 +0300 Subject: [PATCH 115/156] idea ignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 971f766..0a1ddb5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,6 @@ report/ test/issues/generated/ run.n *.hxproj -out/ \ No newline at end of file +out/ +*.iml +.idea \ No newline at end of file From 9494329a14d462fe63741d3a3245a507d14eee34 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Mon, 8 Oct 2018 10:54:39 +0300 Subject: [PATCH 116/156] prerelease fixes --- src/AS3.hx | 84 +++++++- src/FastXML.hx | 4 +- src/Run.hx | 7 +- src/as3hx/CallbackRebuild.hx | 6 +- src/as3hx/Compat.hx | 11 +- src/as3hx/Config.hx | 2 + src/as3hx/ParserUtils.hx | 23 +- src/as3hx/Typer.hx | 45 +++- src/as3hx/Writer.hx | 319 +++++++++++++++++++++------- src/as3hx/parsers/ClassParser.hx | 24 ++- src/as3hx/parsers/ExprParser.hx | 28 ++- src/as3hx/parsers/FunctionParser.hx | 9 +- src/as3hx/parsers/TypeParser.hx | 30 ++- 13 files changed, 457 insertions(+), 135 deletions(-) diff --git a/src/AS3.hx b/src/AS3.hx index 8ed3604..021d628 100644 --- a/src/AS3.hx +++ b/src/AS3.hx @@ -38,7 +38,16 @@ class AS3 { } public static inline function asBool(e:Dynamic):Bool { + #if (js || flash) + return untyped e ? __js__("true") : __js__("false"); + #else return e != false && e != null && e != 0 && !(Std.is(e, String) && e.length == 0); + #end + } + + + public static inline function asArray(e:Dynamic):Array { + return Std.is(e, Array) ? untyped e : null; } public static function AS(e:Dynamic, type:Dynamic):Dynamic { @@ -92,12 +101,22 @@ class AS3 { var tmp1; if(untyped o.__properties__ && o.__properties__["get_" + field]) { return true; - } else if (untyped o.prototype) { - return untyped o.prototype.hasOwnProperty(field); + } else if (Reflect.hasField(o, field)) { + return true; + } else if (untyped o.prototype && untyped o.prototype.hasOwnProperty(field)) { + return true; + } else if (untyped o.__proto__ && untyped o.__proto__.hasOwnProperty(field)) { + return true; } else { - return Reflect.hasField(o, field); + return false; } } + #elseif flash + if (o == null) { + return null; + } else { + return untyped o.hasOwnProperty(field); + } #else if (o == null) { return false; @@ -107,9 +126,62 @@ class AS3 { #end } - - - + /* AS3.string(null) == null but Std.string(null) == "null" */ + public static function string(o:Dynamic):String { + #if js + untyped { + if( o == null ) + return null;//not "null"! this is for another purposes + var t = __js__("typeof(o)"); + if( t == "function" && (js.Boot.isClass(o) || js.Boot.isEnum(o)) ) + t = "object"; + switch( t ) { + case "object": + if( __js__("o instanceof Array") ) { + if( o.__enum__ ) { + if( o.length == 2 ) + return o[0]; + var str = o[0]+"("; + for( i in 2...o.length ) { + if( i != 2 ) + str += "," + js.Boot.__string_rec(o[i],"\t"); + else + str += js.Boot.__string_rec(o[i],"\t"); + } + return str + ")"; + } + var l = o.length; + var i; + var str = "["; + for( i in 0...l ) + str += (if (i > 0) "," else "") + js.Boot.__string_rec(o[i],"\t"); + str += "]"; + return str; + } + var tostr; + try { + tostr = untyped o.toString; + } catch( e : Dynamic ) { + // strange error on IE + return "???"; + } + if( tostr != null && tostr != __js__("Object.toString") && __typeof__(tostr) == "function" ) { + var s2 = o.toString(); + //if( s2 != "[object Object]") + return s2; + } + var t:Class = Type.getClass(o); + return t == null ? Std.string(o) : "[object " + Type.getClassName(t) + "]"; + case "function": + return ""; + default: + return String(o); + } + } + #else + return o == null ? null : Std.string(o); + #end + } /** * Converts a typed expression into an Int. diff --git a/src/FastXML.hx b/src/FastXML.hx index 9eedad3..e3e7811 100644 --- a/src/FastXML.hx +++ b/src/FastXML.hx @@ -209,7 +209,9 @@ class FastXML { var x = Xml.parse(ss); var lastNode:Xml = null; for (e in x) { - lastNode = e; + if (e.nodeType == Xml.XmlType.Element) { + lastNode = e; + } } return new FastXML(lastNode); } diff --git a/src/Run.hx b/src/Run.hx index aac3848..f230aa3 100644 --- a/src/Run.hx +++ b/src/Run.hx @@ -99,7 +99,10 @@ class Run { static function parseFile(fileLocation:String, fileName:String, file:String):Program { var p = new as3hx.Parser(cfg); var content = File.getContent(file); - var program = try p.parseString(content, fileLocation, fileName) catch(e : Error) { + var program = p.parseString(content, fileLocation, fileName); + /*/try { + p.parseString(content, fileLocation, fileName); + } catch (e : Error) { #if macro File.stderr().writeString(file + ":" + p.tokenizer.line + ": " + errorString(e) + "\n"); #end @@ -114,7 +117,7 @@ class Run { null; #end } - } + }//*/ return program; } diff --git a/src/as3hx/CallbackRebuild.hx b/src/as3hx/CallbackRebuild.hx index 149450e..508e89e 100644 --- a/src/as3hx/CallbackRebuild.hx +++ b/src/as3hx/CallbackRebuild.hx @@ -34,8 +34,10 @@ class CallbackRebuild { var t:String = typer.tstring(a); if (t != null && t.indexOf("->") != -1) { var ps:Array = t.split("->"); - var pt:Array = ps.map(function(s:String):T { return TPath([typer.expandStringType(s)]); }); - typer.overrideExprType(params[i], TFunction(pt)); + if (ps[0] != "T") { + var pt:Array = ps.map(function(s:String):T { return TPath([typer.expandStringType(s)]); }); + typer.overrideExprType(params[i], TFunction(pt)); + } } } } diff --git a/src/as3hx/Compat.hx b/src/as3hx/Compat.hx index cba2e7f..f2fe2c6 100644 --- a/src/as3hx/Compat.hx +++ b/src/as3hx/Compat.hx @@ -170,7 +170,7 @@ class Compat { } } - #if openfl + #if (openfl && !macro) public static inline function newByteArray():openfl.utils.ByteArray { var ba:openfl.utils.ByteArray = new openfl.utils.ByteArray(); ba.endian = openfl.utils.Endian.BIG_ENDIAN; @@ -181,7 +181,7 @@ class Compat { if (p == null) return null; var c:Class = Type.getClass(p); if (c == null) return null; - if (Type.getClassName(c) != "openfl._Vector.AbstractVector") return null; + if (Type.getClassName(c).indexOf("openfl._Vector.") != 0) return null; //var type:String = Type.getClassName(Type.getClass(p.data)); //} else if (TType == Function && type == "openfl._Vector.FunctionVector") { return cast p; @@ -192,7 +192,8 @@ class Compat { if (p == null) return null; var c:Class = Type.getClass(p); if (c == null) return false; - if (Type.getClassName(c) != "openfl._Vector.AbstractVector") return false; + //if (Type.getClassName(c) != "openfl._Vector.AbstractVector") return false; + if (Type.getClassName(c).indexOf("openfl._Vector.") != 0) return null; var v:openfl.Vector = cast p; if (v.length > 0 && T != null && v[0] != null && !Std.is(v[0], T)) { return false; @@ -772,6 +773,9 @@ private class FlashRegExpExecResult { public var matches(default,null) : Array; function populateMatches(ereg:EReg) { + #if js + matches = untyped ereg.r.m.slice(0); + #else matches = []; try { var group = 0; @@ -781,6 +785,7 @@ private class FlashRegExpExecResult { } } catch (ignored:Dynamic) { } + #end } } #end diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index b05bdd1..719b040 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -14,6 +14,8 @@ using StringTools; * @author Russell Weir */ class Config { + public var verbouseConditionalCompilationEnd:Bool = false; + /** Indent character(s) **/ public var indentChars : String; /** newline character **/ diff --git a/src/as3hx/ParserUtils.hx b/src/as3hx/ParserUtils.hx index 67607b1..8bd83d4 100644 --- a/src/as3hx/ParserUtils.hx +++ b/src/as3hx/ParserUtils.hx @@ -146,6 +146,7 @@ class ParserUtils { */ public static function removeNewLineExpr(e : Expr, removeComments : Bool = true) : Expr { return switch(e) { + case null: null; case ENL(e2): removeNewLineExpr(e2, removeComments); case ECommented(s,b,t,e2): if (removeComments) { @@ -321,21 +322,33 @@ class ParserUtils { */ public static function opt2(tokenizer:Tokenizer, tk:Token, cmntOut:Array) : Bool { var t = tokenizer.token(); - var tu = ParserUtils.uncomment(t); - var trnl = ParserUtils.removeNewLine(tu); + var tu = ParserUtils.removeNewLine(t); Debug.dbgln(Std.string(t) + " to " + Std.string(tu) + " ?= " + Std.string(tk)); - if( ! Type.enumEq(trnl, tk) ) { + if( ! Type.enumEq(tu, tk) ) { tokenizer.add(t); return false; } switch(t) { - case TCommented(_,_,_): - cmntOut.push(ParserUtils.makeECommented(t, null)); + case TCommented(_, _, _): + cmntOut.push(ParserUtils.makeEmptyECommentedRecursive(t)); default: } return true; } + private static function makeEmptyECommentedRecursive(ctk:Token) : Expr { + return switch(ctk) { + case TCommented(s, b, t): + ECommented(s,b,false,makeEmptyECommentedRecursive(t)); + case TNL(t): + var r = makeEmptyECommentedRecursive(t); + // remove trailing new lines + r == null ? null : ENL(r); + default: + null; + } + } + public static function makeUnop(op:String, e:Expr):Expr { return switch(e) { case ETernary(cond, e1, e2): ETernary(EUnop(op, true, cond), e1, e2); diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index ccbf94a..668d080 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -169,7 +169,8 @@ class Typer } public function isVariable(ident:String):Bool { - return context.exists(ident) || staticContext.exists(ident); + var isConstructor:Bool = classDefs[currentPath] != null && classDefs[currentPath].name == ident; + return !isConstructor && (context.exists(ident) || staticContext.exists(ident)); } public function getExprType(e:Expr, isFieldAccess:Bool = false):Null { @@ -177,13 +178,25 @@ class Typer case null: return null; case ETypedExpr(e2, t): return tstring(t); case EField(e2, f): + var t2 = null; switch(e2) { + case EIdent("super"): + var c:ClassDef = classDefs[currentPath]; + if (c != null && c.extend != null) { + var classPackage:String = classPacks.get(c); + var parentPath:String = getPathByType(c.extend, c, null, classPackage); + if (parentPath != null && classDefs[parentPath] != null) { + t2 = parentPath; + } + } case EIdent("this"): return contextStack.length > 0 ? contextStack[0].get(f) : context.get(f); default: } - var t2 = getExprType(e2, true); - if (t2 != null && (t2.indexOf("Array<") == 0 || t2.indexOf("Vector<") == 0)) { + if (t2 == null) { + t2 = getExprType(e2, true); + } + if (t2 != null && (t2.indexOf("Array<") == 0 || t2.indexOf("Vector<") == 0 || t2.indexOf("openfl.Vector<") == 0)) { switch(f) { case "length": return "Int"; case "sort" : return "Function->Void"; @@ -210,6 +223,7 @@ class Typer } case "AS3": switch(f) { + case "string": return "Dynamic->String"; case "int": return "Dynamic->Int"; case "parseInt": return "Dynamic->Int"; case "hasOwnProperty": return "Dynamic->String->Bool"; @@ -293,6 +307,12 @@ class Typer } } if (t2 != null) { + var index:Int = t2.indexOf("<"); + var typeParam:String = null; + if (index != -1) { + typeParam = t2.substring(index + 1, t2.length - 1); + t2 = t2.substr(0, index); + } var cl:String = resolveClassIdent(t2); if (context.exists(t2)) { t2 = context.get(t2); @@ -308,8 +328,17 @@ class Typer t2 = getImportString(t2Array, true); } if (classes.exists(t2)) { - t2 = classes.get(t2).get(f); - return t2; + var t:String = classes.get(t2).get(f); + if (t != null) { + var index:Int = t.indexOf("<"); + if (index != -1) { + var resultTypeParam = t.substring(index, t.length); + if (resultTypeParam == classDefs[t2].typeParams) { + t = t.substring(0, index + 1) + typeParam + ">"; + } + } + return t; + } } } return null; @@ -322,6 +351,7 @@ class Typer case EIdent("int"): return "Int"; case EIdent("uint"): return "Int"; case EIdent("getQualifiedClassName"): return "String"; + case EVector(t): return "Vector<" + tstring(t) + ">"; case EField(e, "instance"): switch(e) { case EIdent("Std"): @@ -392,6 +422,8 @@ class Typer return tn.substring(6, tn.lastIndexOf(">")); } else if (StringTools.startsWith(tn, "Vector")) { return expandStringType(tn.substring(7, tn.lastIndexOf(">"))); + } else if (StringTools.startsWith(tn, "openfl.Vector")) { + return expandStringType(tn.substring(14, tn.lastIndexOf(">"))); } else if (StringTools.startsWith(tn, "Dictionary") || StringTools.startsWith(tn, "openfl.utils.Dictionary")) { var bothTypes:String = tn.substring(tn.indexOf("<") + 1, tn.lastIndexOf(">")); var commaPosition:Int = -1; @@ -1386,6 +1418,7 @@ class Typer case EForIn(ev, e, block): var etype:String = getExprType(e); var isMap:Bool = etype != null && (etype.indexOf("Map") == 0 || etype.indexOf("Dictionary") == 0 || etype.indexOf("openfl.utils.Dictionary") == 0); + var isArray:Bool = etype != null && (etype.indexOf("Array<") == 0 || etype.indexOf("Vector<") == 0 || etype.indexOf("openfl.Vector<") == 0); switch(ev) { case EVars(vars): if(vars.length == 1 && vars[0].val == null) { @@ -1395,6 +1428,8 @@ class Typer if (type == null) { type = "Dynamic"; } + } else if (isArray) { + type = "Int"; } else { type = "String"; } diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 72b14d0..c4cc6a1 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -97,27 +97,76 @@ class Writer if(!isBlock) { return s; } - var r = new EReg("^(" + cfg.indentChars + ")+", "mg"); - return StringTools.ltrim(r.replace(s,indent())); + var a:Array = s.split("\n"); + var spacesInTab:Int = 4; + a[0] = StringTools.ltrim(a[0]); + var n:Int = 999; + var indent:String = this.indent(); + for (i in 1...a.length) { + var p:Int = countWhitespaces(a[i]); + if (p < n) n = p; + } + for (i in 1...a.length) { + a[i] = indent + consumeWhitespaces(a[i], n); + } + return a.join("\n"); + } + + private function countWhitespaces(s:String):Int { + var n:Int = 0; + var i:Int = 0; + do { + if (s.indexOf("\t", i) == i) { + n++; + i++; + } else if (s.indexOf(" ", i) == i) { + n++; + i += 4; + } else { + break; + } + } while (true); + return n; + } + + private function consumeWhitespaces(s:String, n:Int):String { + var i:Int = 0; + while (n > 0) { + if (s.indexOf("\t", i) == i) { + n--; + i++; + } else if (s.indexOf(" ", i) == i) { + n--; + i += 4; + } else { + break; + } + } + return s.substr(i); + } + + function formatBlockBodyRecursive(e:Expr, result:Array):Void { + switch(e) { + case null: + case EBlock(ex): + for(i in 0...ex.length) { + if (i == 0) formatBlockBodyRecursive(ex[0], result); + else result.push(ex[i]); + } + case ENL(ex): + if (ex != null) { + formatBlockBodyRecursive(ex, result); + } else { + result.push(e); + } + case EObject(fl) if(fl.empty()): + default: result.push(ENL(e)); + } } function formatBlockBody(expr:Expr):Array { var result = []; - var f:Expr->Void = null; - f = function(e) { - if(e == null) return; - switch(e) { - case EBlock(ex): - for(i in 0...ex.length) { - if (i == 0) f(ex[0]); - else result.push(ex[i]); - } - case ENL(ex): f(ex); - case EObject(fl) if(fl.empty()): - default: result.push(ENL(e)); - } - } - f(expr); + formatBlockBodyRecursive(expr, result); return result; } @@ -126,20 +175,26 @@ class Writer function writeComments(comments : Array) { for(c in comments) { switch(c) { - case ECommented(s,b,t,e): - writeComment(indent() + formatComment(s,b), b); - if (e != null) { - switch (e) { - case ECommented(_): - writeComments([e]); - default: - throw "Unexpected " + e + " in comments"; - } - } + case null: + case ECommented(s, b, t, e): + writeExpr(c); + //writeComment(formatComment(s,b), b); + //if (e != null) { + //switch (e) { + //case ECommented(_): + //writeComments([e]); + //case ENL(_): + //writeComments([e]); + //default: + //throw "Unexpected " + e + " in comments"; + //} + //} case EImport(i): writeImport(i); case ENL(e): - writeNL(); + writeExpr(c); + //writeNL(); + //writeComments([e]); default: throw "Unexpected " + c + " in header"; } @@ -580,8 +635,6 @@ class Writer if ((isGet || isSet) && c.isInterface) return; - writeMetaData(field.meta); - var namespaceMetadata:Array = null; if (isFun) { switch(field.kind) { @@ -683,6 +736,7 @@ class Writer } switch(field.kind) { case FVar(t, val): + writeMetaData(field.meta); var isInlined:Bool = start(field.name, false); write("var " + typer.getModifiedIdent(field.name)); if (!isInlined && isConst(field.kwds)) { @@ -717,6 +771,7 @@ class Writer write(";"); case FFun( f ): + writeMetaData(field.meta); RebuildUtils.rebuild(f.expr, lookUpForNamespaces); if (field.name == c.name) { @@ -756,8 +811,7 @@ class Writer } case FComment: - //writeComments(field.meta); - null; + writeComments(field.meta); } if (isFun) { @@ -861,13 +915,11 @@ class Writer function writeECondCompEnd(condComps : Array) : Void { for (i in 0...condComps.length) { - if (i == 0) { - writeNL(); - writeIndent("#end // "); - } else { - write(" && "); + writeNL(); + writeIndent("#end"); + if (cfg.verbouseConditionalCompilationEnd) { + write(" // " + condComps[i]); } - write(condComps[i]); } } @@ -1224,6 +1276,9 @@ class Writer if(!isString) write("Std.string("); writeExpr(index); if(!isString) write(")"); + //if (isAnonymouse) { + //writeInComment(rvalue); + //} if(oldInLVA && !inEField) { write(", "); writeExpr(rvalue); @@ -1611,7 +1666,7 @@ class Writer switch(e) { case EBlock(elist): for (ex in elist) { - writeFinish(writeExpr(ex)); + writeBlockLine(ex); } case ENL(e): writeECondComp(e); @@ -1640,24 +1695,27 @@ class Writer if (oneLiner) { write(" "); } else { - writeNL(indent()); + writeNL(); + writeIndent(); } if (e2 != null) { write("#else"); oneLiner = isOneLiner(e2, true); if (oneLiner) { write(" "); - } else { - writeNL(indent()); } writeECondComp(e2); if (oneLiner) { write(" "); } else { - writeNL(indent()); + writeNL(); + writeIndent(); } } - writeIndent("#end // " + kwd); + write("#end"); + if (cfg.verbouseConditionalCompilationEnd) { + write(" // " + kwd); + } } rv = Ret; @@ -1713,8 +1771,8 @@ class Writer write("{"); lvl++; for (ex in e) { - - writeFinish(writeETypedExpr(ex, TPath([null]))); + writeBlockLine(ex); + //writeFinish(writeETypedExpr(ex, TPath([null]))); } lvl--; write(closeb()); @@ -1726,6 +1784,37 @@ class Writer return result; } + inline function fixBlockLine(e:Expr):Expr { + switch(e) { + case null: + return null; + case ENL(e): + var fix = fixBlockLine(e); + if (fix != null) { + return ENL(fix); + } else { + return null; + } + case ECommented(s, isBlock, isTail, e): + var fix = fixBlockLine(e); + if (fix != null) { + return ECommented(s, isBlock, isTail, fix); + } else { + return null; + } + case EBinop("&&", e1, e2, _): + return EIf(e1, e2); + case EBinop("||", e1, e2, _): + return EIf(EUnop("!", true, e1), e2); + default: + return null; + } + } + function writeBlockLine(e:Expr):Void { + var fix = fixBlockLine(e); + writeFinish(writeExpr(fix == null ? e : fix)); + } + function writeEField(fullExpr:Expr, e:Expr, f:String):BlockEnd { var n = checkE4XDescendants(fullExpr); if(n != null) return writeExpr(n); @@ -1997,9 +2086,20 @@ class Writer if(cfg.vectorToArray) { writeExpr(params[0]); } else if (cfg.useOpenFlTypes) { - write("openfl.Vector.ofArray(cast "); - writeExpr(params[0]); - write(")"); + var needCast:Bool = true; + switch(params[0]) { + case EArrayDecl(es): + if (es.length == 0) { + write("new Vector<" + tstring(t) + ">()"); + needCast = false; + } + default: + } + if (needCast) { + write("openfl.Vector.ofArray("); + writeExpr(params[0]); + write(")"); + } } default: } @@ -2139,12 +2239,12 @@ class Writer elseif = e2; default: } - writeNL(); + //writeNL(); if (elseif != null) { - writeIndent("else "); + writeIndent(" else "); result = writeExpr(elseif); } else { - writeIndent("else"); + writeIndent(" else"); writeStartStatement(); result = writeExpr(e2); } @@ -2161,9 +2261,14 @@ class Writer else writeExpr(cond); write(") ? "); writeExpr(e1); - write(getColon()); - if (e2 != null && getExprType(e1) == "String" && getExprType(e2) != "String") { - e2 = getToStringExpr(e2); + write(" : "); + switch (e2) { + case null: + case EIdent("null"): + default: + if (getExprType(e1) == "String" && getExprType(e2) != "String") { + e2 = getToStringExpr(e2); + } } return writeExpr(e2); } @@ -2333,6 +2438,7 @@ class Writer var etype = getExprType(e); var canBeDictionary:Bool = isOpenFlDictionaryType(etype); var isMap:Bool = canBeDictionary || isMapType(etype); + var isArray:Bool = isArrayType(etype) || isVectorType(etype); var castLoopVariableType:String = null; write("for ("); var varName:String = getVarName(ev); @@ -2342,6 +2448,8 @@ class Writer var mapKeyType:String; if (isMap) { mapKeyType = Typer.getMapParam(etype, 1); + //} else if (isArray) { + //mapKeyType = "Int"; } else { mapKeyType = "String"; } @@ -2360,7 +2468,7 @@ class Writer if (!canBeDictionary) { write(".keys()"); } - } else if (isArrayExpr(e)) { + } else if (isArray) { write("0..."); writeExpr(e); write(".length"); @@ -2391,10 +2499,9 @@ class Writer case "int", "Int", "uint", "UInt": writeCastToInt(e1); case "Number": writeCastToFloat(e1); case "Array": - write("(try cast("); + write("AS3.asArray("); writeExpr(e1); - write(", Array) catch(e:Dynamic) null)"); - addWarning("as array", true); + write(")"); case "Class": //addWarning("as Class", true); write("as3hx.Compat.castClass("); @@ -2409,7 +2516,7 @@ class Writer write("AS3.as("); writeExpr(e1); write(", " + s + ")"); - } else if (s == "ByteArray" || s == "Bitmap" || s.indexOf("Vector") == 0 || s == "Dictionary") { + } else if (s == "ByteArray" || s == "Bitmap" || s.indexOf("Vector") == 0 || s.indexOf("openfl.Vector") == 0 || s == "Dictionary") { write("(try cast("); writeExpr(e1); write(", "); @@ -2463,6 +2570,8 @@ class Writer write(ts); } write(")"); + case EIdent("Object"): + writeEBinop("!=", e1, EIdent("null"), false); default: write("Std.is("); writeExpr(e1); @@ -2511,12 +2620,17 @@ class Writer var lookForRValue:Bool = true; var oldInLVA = inLvalAssign; - if (op.indexOf("=") != -1) { + if (op.indexOf("=") != -1 /*&& op != "=="*/ && op != "!=") { if (op == "=") inLvalAssign = true; rvalue = e2; var t = getExprType(e1); if (t != null) { - e2 = ETypedExpr(e2, TPath([t])); + switch (e2) { + case null: + case EIdent("null"): + default: + e2 = ETypedExpr(e2, TPath([t])); + } } } else { switch(e1) { @@ -2554,7 +2668,6 @@ class Writer case ENL(_): default: write(" "); } - switch(e2) { case EIdent(s): writeModifiedIdent(s); default: writeExpr(e2); @@ -2985,12 +3098,16 @@ class Writer } function writeETypedExpr(e:Expr, t:T):BlockEnd { + var nullable:Bool = false; switch(e) { case null: - write("(null as " + tstring(t) + ")"); + write("intended error: ETypedExpr(null as " + tstring(t) + ")"); return None; case ENL(e2): - return writeExpr(ENL(ETypedExpr(e2, t))); + writeNL(); + writeIndent(); + return writeETypedExpr(e2, t); + //return writeExpr(ENL(ETypedExpr(e2, t))); case ECommented(s, isBlock, isTail, e2): return writeECommented(s, isBlock, isTail, ETypedExpr(e2, t)); case ETernary(cond, e1, e2): @@ -2999,6 +3116,16 @@ class Writer if (isOpenFlDictionaryTypeT(t2) && isOpenFlDictionaryTypeT(t)) { return writeExpr(ENew(typer.shortenType(t), params)); } + case EField(e, field): + var t:String = getExprType(e); + if (isDynamicType(t)) { + nullable = true; + } + case EArray(e, index): + var t:String = getExprType(e); + if (isMapType(t) || isOpenFlDictionaryType(t)) { + nullable = true; + } case EIdent("null"): switch(tstring(t)) { case "String": @@ -3011,7 +3138,8 @@ class Writer default: } // fix of such constructions var tail:Signal = s || p; - switch(tstring(t)) { + var type:String = tstring(t); + switch(type) { case "Function", "haxe.Constraints.Function": var et:String = getExprType(e); if (et == "Function" || et == "haxe.Constraints.Function") { @@ -3021,7 +3149,11 @@ class Writer write("cast "); case "String": if (getExprType(e) != "String") { - e = getToStringExpr(e); + if (nullable) { + e = ECall(EField(EIdent("AS3"), "string"), [e]); + } else { + e = getToStringExpr(e); + } } case "Bool": var re:Expr = rebuildIfExpr(e); @@ -3029,17 +3161,31 @@ class Writer e = re; } case "Int", "UInt": - var et:String = getExprType(e); - if (et != "Int" && et != "UInt") { - e = getCastToIntExpr(e); + if (nullable) { + e = ECall(EField(EIdent("AS3"), "int"), [e]); + } else { + var et:String = getExprType(e); + if (et != "Int" && et != "UInt") { + e = getCastToIntExpr(e); + } } default: switch (e) { case EBinop("||", e1, e2, nl): - e = ETernary(EBinop("!=", e1, EIdent("null"), false), e1, e2); + e = ETernary(e1, e1, e2); case EBinop("&&", e1, e2, nl): - e = ETernary(EBinop("==", e1, EIdent("null"), false), e1, e2); + e = ETernary(EUnop("!", true, e1), e1, e2); + case ECall(EVector(t), params): + if (type == "Object" || type == "openfl.utils.Object" || (isVectorType(type) && getExprType(e) != type)) { + write("cast "); + } default: + if (isArrayType(type)) { + var eType:String = getExprType(e); + if (isArrayType(eType) && type != eType) { + write("cast "); + } + } } } return writeExpr(e); @@ -3200,7 +3346,10 @@ class Writer case EIdent("null"): return null; case EIdent(_), EField(_, _), ECall(_, _): var t = getExprType(e); - if(t == null || t == "Bool") return null; + if (t == "Bool") return null; + if (t == null) { + return ECall(EField(EIdent("AS3"), "as"), [e, EIdent("Bool")]); + } return switch(t) { case "Int" | "UInt": EBinop("!=", e, EConst(CInt("0")), false); @@ -3289,11 +3438,13 @@ class Writer e1 = getToStringExpr(e1); } result = ECall(EField(EIdent("Reflect"), "hasField"), [e, e1]); - } else if (isClassType(type)) { - result = EParent(EBinop("!=", ECall(EField(ECall(EField(EIdent("Type"), "getClassFields"), [e]), "indexOf"), params), EConst(CInt("-1")), false)); + } else if (true || isClassType(type)) { + result = ECall(EField(EIdent("AS3"), "hasOwnProperty"), [e, params[0]]); + //result = EParent(EBinop("!=", ECall(EField(ECall(EField(EIdent("Type"), "getClassFields"), [e]), "indexOf"), params), EConst(CInt("-1")), false)); } else { //(Type.getInstanceFields(Type.getClass(e)).indexOf(params[0]) != -1) - result = EParent(EBinop("!=", ECall(EField(ECall(EField(EIdent("Type"), "getInstanceFields"), [ECall(EField(EIdent("Type"), "getClass"), [e])]), "indexOf"), params), EConst(CInt("-1")), false)); + //result = EParent(EBinop("!=", ECall(EField(ECall(EField(EIdent("Type"), "getInstanceFields"), [ECall(EField(EIdent("Type"), "getClass"), [e])]), "indexOf"), params), EConst(CInt("-1")), false)); + result = ECall(EField(EIdent("AS3"), "hasOwnProperty"), [e, params[0]]); } } else if(f == "replace") { @@ -3464,7 +3615,7 @@ class Writer } result = getCompatCallExpr(f, [e].concat(params)); } else { - result = getToStringExpr(e); + //result = getToStringExpr(e); // valid call } } else { result = getToStringExpr(e); @@ -3726,7 +3877,8 @@ class Writer case ENL(e): //ignore newline return isOneLiner(e, threatOneLineBlockAsOneLiner); - case ECommented(s,b,t,e): //ignore comment + case ECommented(s, b, t, e): //ignore comment + if (isHaxeCodeComment(s)) return false; return isOneLiner(e, threatOneLineBlockAsOneLiner); case EBlock(e): //it is a regular block @@ -3796,7 +3948,7 @@ class Writer } static inline function isVectorType(s:String):Bool { - return s != null && s.indexOf("Vector<") == 0; + return s != null && (s.indexOf("Vector<") == 0 || s.indexOf("openfl.Vector<") == 0); } static inline function isDynamicType(s:String):Bool return s == "Dynamic" || s == "Object" || s == "openfl.utils.Object"; @@ -4096,6 +4248,10 @@ class Writer writeIndent(); } + private inline function isHaxeCodeComment(s:String):Bool { + return s.indexOf("haxe:") == 2; + } + /** * Writing for block and line comment. If * comment written on dirty line (not first text on line), @@ -4104,7 +4260,7 @@ class Writer function writeComment(s : String, blockComment : Bool) { if (blockComment) { - if (s.indexOf("haxe:") == 2) { + if (isHaxeCodeComment(s)) { write(s.substring(7, s.length - 2)); } else if (lineIsDirty) { write(" " + s + " "); @@ -4139,14 +4295,13 @@ class Writer function writeNL(s = "") { - lineIsDirty = false; //reset line dirtyness - write(s); if (pendingTailComment != null) { write(pendingTailComment); pendingTailComment = null; } write(cfg.newlineChars); + lineIsDirty = false; } inline function writeStartStatement() { diff --git a/src/as3hx/parsers/ClassParser.hx b/src/as3hx/parsers/ClassParser.hx index 03eaf29..573623e 100644 --- a/src/as3hx/parsers/ClassParser.hx +++ b/src/as3hx/parsers/ClassParser.hx @@ -87,7 +87,10 @@ class ClassParser { pf = function(included:Bool,inCondBlock:Bool) { while( true ) { // check for end of class - if( ParserUtils.opt2(tokenizer, TBrClose, meta) ) break; + + if ( ParserUtils.opt2(tokenizer, TBrClose, meta) ) { + break; + } var kwds = []; // parse all comments and metadata before next field while( true ) { @@ -252,16 +255,19 @@ class ClassParser { for(m in meta) { switch(m) { case ECommented(s,b,t,e): - if(ParserUtils.uncommentExpr(m) != null) + if(ParserUtils.removeNewLineExpr(m) != null) throw "Assert error: " + m; var a = ParserUtils.explodeCommentExpr(m); for(i in a) { - switch(i) { - case ECommented(s,b,t,e): - fields.push({name:null, meta:[ECommented(s,b,false,null)], kwds:[], kind:FComment, condVars:[]}); - default: - throw "Assert error: " + i; - } + fields.push({name:null, meta:[i], kwds:[], kind:FComment, condVars:[]}); + //switch(i) { + //case ENL(null): + //fields.push({name:null, meta:[i], kwds:[], kind:FComment, condVars:[]}); + //case ECommented(s,b,t,e): + //fields.push({name:null, meta:[i], kwds:[], kind:FComment, condVars:[]}); + //default: + //throw "Assert error: " + i; + //} } case ENL(_): default: @@ -293,6 +299,7 @@ class ClassParser { var t = null, val = null; if( ParserUtils.opt(tokenizer, TColon) ) t = parseType(); + if( ParserUtils.opt(tokenizer, TOp("=")) ) val = parseExpr(false); @@ -337,7 +344,6 @@ class ClassParser { tokenizer.add(t); Debug.dbgln(Std.string(kwds) + " " + name + ")", tokenizer.line, false); var f = parseFunction(isInterface); - tokenizer.end(); Debug.closeDebug("end parseClassFun()", tokenizer.line); return { meta : meta, diff --git a/src/as3hx/parsers/ExprParser.hx b/src/as3hx/parsers/ExprParser.hx index 90e258f..b6ad8b8 100644 --- a/src/as3hx/parsers/ExprParser.hx +++ b/src/as3hx/parsers/ExprParser.hx @@ -39,7 +39,7 @@ class ExprParser { Debug.dbgln("parseExpr: " + tk, tokenizer.line); - switch(ParserUtils.removeNewLine(tk)) { + switch(ParserUtils.removeNewLine(tk, false)) { case TBrClose: if(funcStart) return EBlock([]); return parseExprNext(EObject([]), 0); @@ -57,23 +57,19 @@ class ExprParser { } var a = new Array(); - //check for corner case, block contains only comments and - //newlines. In this case, get all comments and add them to - //content of block expression - if (ParserUtils.uncomment(ParserUtils.removeNewLine(tk)) == TBrClose) { - var ta = ParserUtils.explodeComment(tk); - for (t in ta) { - switch (t) { - case TCommented(s,b,t): a.push(ECommented(s,b,false, null)); - case TNL(t): a.push(ENL(null)); - default: - } - } + while(tokenizer.peek() != TBrClose) { + a.push(parseFullExpr()); } - while(!ParserUtils.opt(tokenizer, TBrClose)) { - var e = parseFullExpr(); - a.push(e); + var ta = ParserUtils.explodeComment(tokenizer.token()); + for (i in 0...ta.length) { + var t = ta[i]; + switch (t) { + case TCommented(s,b,t): a.push(ECommented(s,b,false, null)); + case TNL(t) if (i != ta.length - 2): //last TNL in block is redundant, previous should be kept + a.push(ENL(null)); + default: + } } return EBlock(a); case TOp(op): diff --git a/src/as3hx/parsers/FunctionParser.hx b/src/as3hx/parsers/FunctionParser.hx index e127215..7395c1f 100644 --- a/src/as3hx/parsers/FunctionParser.hx +++ b/src/as3hx/parsers/FunctionParser.hx @@ -114,15 +114,19 @@ class FunctionParser { retExpressions.push(ENL(null)); } - case TCommented(s,b,t): //comment before '{' or ';' + case TCommented(s,b,t): //comment before '{' or ';' tokenizer.add(t); retExpressions.push(ParserUtils.makeECommented(tk, null)); - case TBrOpen, TSemicolon: //end of method return + case TBrOpen: //end of method return tokenizer.add(tk); f.ret.exprs = retExpressions; break; + case TSemicolon: //end of method return + f.ret.exprs = retExpressions; + break; + default: } } @@ -142,6 +146,7 @@ class FunctionParser { throw "unexpected " + Std.string(f.expr); } } + tokenizer.end(); Debug.closeDebug("end parseFun()", tokenizer.line); if (cfg.rebuildLocalFunctions) { rebuildLocalFunctions(f); diff --git a/src/as3hx/parsers/TypeParser.hx b/src/as3hx/parsers/TypeParser.hx index 1a8af9f..ba0fbca 100644 --- a/src/as3hx/parsers/TypeParser.hx +++ b/src/as3hx/parsers/TypeParser.hx @@ -29,14 +29,37 @@ class TypeParser { } var t = tokenizer.id(); - if(t == "Vector") { + var vectorType = null; + if (t == "Vector") { + function u() { + var t = tokenizer.token(); + tokenizer.add(t); + return t; + } + var typeFromComment:T = null; + var t2 = tokenizer.token(); + switch(t2) { + case TCommented(s, true, t3): + typeFromComment = OverrideTypeComment.extractType(t, s, types); + if (typeFromComment != null) { + tokenizer.add(t3); + } else { + tokenizer.add(t2); + } + default: + tokenizer.add(t2); + } tokenizer.ensure(TDot); tokenizer.ensure(TOp("<")); var t = parseType(); splitEndTemplateOps(tokenizer); tokenizer.ensure(TOp(">")); types.seen.push(TVector(t)); - return TVector(t); + if (typeFromComment == null) { + vectorType = TVector(t); + } else { + vectorType = typeFromComment; + } } var t2 = tokenizer.token(); switch(t2) { @@ -51,6 +74,9 @@ class TypeParser { default: tokenizer.add(t2); } + if (vectorType != null) { + return vectorType; + } if (t == "Array") { var k:T = null; var t2 = tokenizer.token(); From 4a887ef0a8dcbb9da81e9e3175dbcb371c8733ed Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 24 Oct 2018 03:52:02 +0300 Subject: [PATCH 117/156] custom error type XError, custom Vector type, fix of splice conversion, fix of method compare --- src/as3hx/CommonImports.hx | 2 +- src/as3hx/Compat.hx | 44 +++++++++++++++-------- src/as3hx/Config.hx | 2 ++ src/as3hx/Typer.hx | 11 +++--- src/as3hx/Writer.hx | 74 +++++++++++++++++++++++++++----------- 5 files changed, 93 insertions(+), 40 deletions(-) diff --git a/src/as3hx/CommonImports.hx b/src/as3hx/CommonImports.hx index 9f91867..7373edc 100644 --- a/src/as3hx/CommonImports.hx +++ b/src/as3hx/CommonImports.hx @@ -43,7 +43,7 @@ class CommonImports } if (cfg.useOpenFlTypes) { - map.set("Vector", "openfl.Vector"); + //map.set("Vector", "openfl.Vector"); map.set("Object", "openfl.utils.Object"); } diff --git a/src/as3hx/Compat.hx b/src/as3hx/Compat.hx index f2fe2c6..d100f89 100644 --- a/src/as3hx/Compat.hx +++ b/src/as3hx/Compat.hx @@ -1,7 +1,6 @@ package as3hx; import Type; -import haxe.ds.Vector; import haxe.macro.Expr; import haxe.macro.Context; @@ -170,6 +169,24 @@ class Compat { } } + public static function castVector(p:Dynamic):Vector { + if (p == null || !Std.is(p, Array)) { + return null; + } + return cast p; + } + + public static function filter(v:Vector, filterMethod:T->Int->Vector->Bool):Vector { + var r:Vector = new Vector(); + for (i in 0...v.length) { + if (filterMethod(v[i], i, v)) { + r.push(v[i]); + } + } + return r; + } + + #if (openfl && !macro) public static inline function newByteArray():openfl.utils.ByteArray { var ba:openfl.utils.ByteArray = new openfl.utils.ByteArray(); @@ -177,15 +194,15 @@ class Compat { return ba; } - public static function castVector(p:Dynamic):openfl.Vector { + /*public static function castVector(p:Dynamic):openfl.Vector { if (p == null) return null; var c:Class = Type.getClass(p); if (c == null) return null; if (Type.getClassName(c).indexOf("openfl._Vector.") != 0) return null; - //var type:String = Type.getClassName(Type.getClass(p.data)); + //var type:String = Type.getClassName(Type.getClass(p.data)); //oldopenfl //} else if (TType == Function && type == "openfl._Vector.FunctionVector") { return cast p; - } + }*/ /** T==null is Vector.<*>, otherwise T could be Abstract of Class */ public static function isVector(p:Dynamic, T:Dynamic = null):Bool { @@ -204,16 +221,15 @@ class Compat { public static inline function each(obj:openfl.utils.Object):Iterator { return new ObjectIterator(obj); } - - public static function filter(v:openfl.Vector, filterMethod:T->Int->openfl.Vector->Bool):openfl.Vector { - var r:openfl.Vector = new openfl.Vector(); - for (i in 0...v.length) { - if (filterMethod(v[i], i, v)) { - r.push(v[i]); - } - } - return r; - } + //public static function filter(v:openfl.Vector, filterMethod:T->Int->openfl.Vector->Bool):openfl.Vector { + //var r:openfl.Vector = new openfl.Vector(); + //for (i in 0...v.length) { + //if (filterMethod(v[i], i, v)) { + //r.push(v[i]); + //} + //} + //return r; + //} public static inline function vectorSplice(a:openfl.Vector, startIndex:Int, deleteCount:Int, ?values:Array):openfl.Vector { var result = a.splice(startIndex, deleteCount); diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index 719b040..58bb98c 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -88,6 +88,8 @@ class Config { */ public var postProcessor : String = ""; + public var arrayTypePath : String = "Vector"; + /** * a list of absolute or relative directory paths. * as3 files from this paths are parsed as a source for type info diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index 668d080..b0cecf2 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -196,7 +196,7 @@ class Typer if (t2 == null) { t2 = getExprType(e2, true); } - if (t2 != null && (t2.indexOf("Array<") == 0 || t2.indexOf("Vector<") == 0 || t2.indexOf("openfl.Vector<") == 0)) { + if (t2 != null && (t2.indexOf("Array<") == 0 || t2.indexOf("Vector<") == 0 || t2.indexOf(cfg.arrayTypePath + "<") == 0)) { switch(f) { case "length": return "Int"; case "sort" : return "Function->Void"; @@ -208,6 +208,7 @@ class Typer case "hasField": return "Dynamic->String->Bool"; case "field": return "Dynamic->String->Dynamic"; case "setField": return "Dynamic->String->Dynamic->Void"; + case "compareMethods": return "Dynamic->Dynamic->Bool"; } case "Signal","signals.Signal": switch(f) { @@ -420,10 +421,10 @@ class Typer if (tn != null) { if (StringTools.startsWith(tn, "Array")) { return tn.substring(6, tn.lastIndexOf(">")); + } else if (StringTools.startsWith(tn, cfg.arrayTypePath)) { + return expandStringType(tn.substring(cfg.arrayTypePath.length + 1, tn.lastIndexOf(">"))); } else if (StringTools.startsWith(tn, "Vector")) { return expandStringType(tn.substring(7, tn.lastIndexOf(">"))); - } else if (StringTools.startsWith(tn, "openfl.Vector")) { - return expandStringType(tn.substring(14, tn.lastIndexOf(">"))); } else if (StringTools.startsWith(tn, "Dictionary") || StringTools.startsWith(tn, "openfl.utils.Dictionary")) { var bothTypes:String = tn.substring(tn.indexOf("<") + 1, tn.lastIndexOf(">")); var commaPosition:Int = -1; @@ -1384,7 +1385,7 @@ class Typer case EForEach(ev, e, block): var etype:String = getExprType(e); var isMap:Bool = etype != null && (etype.indexOf("Map") == 0 || etype.indexOf("Dictionary") == 0 || etype.indexOf("openfl.utils.Dictionary") == 0); - var isVector:Bool = etype != null && (etype.indexOf("Array") == 0 || etype.indexOf("Vector") == 0 || etype.indexOf("openfl.Vector") == 0); + var isVector:Bool = etype != null && (etype.indexOf("Array") == 0 || etype.indexOf("Vector") == 0 || etype.indexOf(cfg.arrayTypePath) == 0); var isXml:Bool = etype == "FastXML" || etype == "FastXMLList"; switch(ev) { case EVars(vars): @@ -1418,7 +1419,7 @@ class Typer case EForIn(ev, e, block): var etype:String = getExprType(e); var isMap:Bool = etype != null && (etype.indexOf("Map") == 0 || etype.indexOf("Dictionary") == 0 || etype.indexOf("openfl.utils.Dictionary") == 0); - var isArray:Bool = etype != null && (etype.indexOf("Array<") == 0 || etype.indexOf("Vector<") == 0 || etype.indexOf("openfl.Vector<") == 0); + var isArray:Bool = etype != null && (etype.indexOf("Array<") == 0 || etype.indexOf("Vector<") == 0 || etype.indexOf(cfg.arrayTypePath + "<") == 0); switch(ev) { case EVars(vars): if(vars.length == 1 && vars[0].val == null) { diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index c4cc6a1..5b86cfb 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1431,21 +1431,44 @@ class Writer } switch (e) { case ENew(t, params): - var c = params.copy(); - c.unshift(EConst(CString(tstring(t) + ": "))); - writeExpr(joinToString(c)); + //var c = params.copy(); + //c.unshift(EConst(CString(tstring(t) + ": "))); + var args:Array = [EConst(CString(tstring(t)))]; + if (params.length > 0) { + args.push(joinToString(params)); + } + writeExpr(ENew(TPath(["XError"]), args)); case ECall(e1, params): switch(e1) { case EIdent(s): - var c = params.copy(); - c.unshift(EConst(CString(s + ": "))); - writeExpr(joinToString(c)); + var args:Array = [EConst(CString(s))]; + if (params.length > 0) { + args.push(joinToString(params)); + } + writeExpr(ENew(TPath(["XError"]), args)); default: writeExpr(e); } default: writeExpr(e); } + //switch (e) { + //case ENew(t, params): + //var c = params.copy(); + //c.unshift(EConst(CString(tstring(t) + ": "))); + //writeExpr(joinToString(c)); + //case ECall(e1, params): + //switch(e1) { + //case EIdent(s): + //var c = params.copy(); + //c.unshift(EConst(CString(s + ": "))); + //writeExpr(joinToString(c)); + //default: + //writeExpr(e); + //} + //default: + //writeExpr(e); + //} case ETry(e, catches): rv = writeETry(e, catches); case EObject(fl): if (fl.empty()) { @@ -2096,7 +2119,7 @@ class Writer default: } if (needCast) { - write("openfl.Vector.ofArray("); + write(cfg.arrayTypePath + ".ofArray("); writeExpr(params[0]); write(")"); } @@ -2241,10 +2264,12 @@ class Writer } //writeNL(); if (elseif != null) { - writeIndent(" else "); + //writeIndent(" else "); + write(" else "); result = writeExpr(elseif); } else { - writeIndent(" else"); + //writeIndent(" else"); + write(" else"); writeStartStatement(); result = writeExpr(e2); } @@ -2366,7 +2391,6 @@ class Writer } function getForEachType(type:String):String { - //var isObject:Bool = type == "Object" || type == "openfl.utils.Object" || t == null; if (isArrayType(type) || isVectorType(type)) { return Typer.getVectorParam(type); } else if (type == "FastXML" || type == "FastXMLList") { @@ -2516,7 +2540,7 @@ class Writer write("AS3.as("); writeExpr(e1); write(", " + s + ")"); - } else if (s == "ByteArray" || s == "Bitmap" || s.indexOf("Vector") == 0 || s.indexOf("openfl.Vector") == 0 || s == "Dictionary") { + } else if (s == "ByteArray" || s == "Bitmap" || isVectorType(s) || s == "Dictionary") { write("(try cast("); writeExpr(e1); write(", "); @@ -3483,7 +3507,7 @@ class Writer //replace AS3 slice by Haxe substr var rebuiltExpr = EField(e, "substring"); result = ECall(rebuiltExpr, params); - } else if(isArrayType(type) && params.empty()) { + } else if((isArrayType(type) || isVectorExpr(e)) && params.empty()) { var rebuiltExpr = EField(e, "copy"); result = ECall(rebuiltExpr, params); } @@ -3497,10 +3521,17 @@ class Writer params.push(EField(e, "length")); result = ECall(EField(e, f), params); default: - if(cfg.useCompat) { - var p = [e].concat(params.slice(0, 2)); - p.push(EArrayDecl(params.slice(2, params.length))); - result = getCompatCallExpr("arraySplice", p); + if (cfg.useCompat) { + switch (params[1]) { + case EConst(CInt("1")) if (params.length == 3): + result = EBinop("=", EArray(e, params[0]), params[2], false); + case EConst(CInt("0")) if (params.length == 3): + result = ECall(EField(e, "insert"), [params[0], params[2]]); + default: + var p = [e].concat(params.slice(0, 2)); + p.push(EArrayDecl(params.slice(2, params.length))); + result = getCompatCallExpr("arraySplice", p); + } } } } @@ -3622,7 +3653,7 @@ class Writer } } else if(f == "concat" && params.empty()) { - if(isArrayExpr(e)) { + if(isArrayExpr(e) || isVectorExpr(e)) { var rebuildExpr = EField(e, "copy"); result = ECall(rebuildExpr, params); } @@ -3806,6 +3837,8 @@ class Writer if(type == "Bool") { return EBinop("=", lvalue, EBinop("&&", lvalue, rvalue, false), false); } + case "==" if (isFunctionExpr(lvalue) || isFunctionExpr(rvalue)): + return ECall(EField(EIdent("Reflect"), "compareMethods"), [lvalue, rvalue]); case "=" | "+=" | "-=" | "*=" | "/=": if(cfg.useCompat) { switch(lvalue) { @@ -3947,8 +3980,8 @@ class Writer return s != null && ((s.indexOf("Array<") == 0) || s == "Array"); } - static inline function isVectorType(s:String):Bool { - return s != null && (s.indexOf("Vector<") == 0 || s.indexOf("openfl.Vector<") == 0); + inline function isVectorType(s:String):Bool { + return s != null && (s.indexOf("Vector<") == 0 || s.indexOf("openfl.Vector<") == 0 || s.indexOf(cfg.arrayTypePath + "<") == 0); } static inline function isDynamicType(s:String):Bool return s == "Dynamic" || s == "Object" || s == "openfl.utils.Object"; @@ -4235,8 +4268,9 @@ class Writer { //set line as dirty if string contains something other //than whitespace/indent - if (!containsOnlyWhiteSpace(s) && s != cfg.indentChars) + if (!containsOnlyWhiteSpace(s) && s != cfg.indentChars) { lineIsDirty = true; + } o.writeString(s); } From 553a0580eb2fc44825651a244eeca755090425b6 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 24 Oct 2018 14:19:23 +0300 Subject: [PATCH 118/156] custom Vector and XError implementation for js target --- src/Vector.hx | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/XError.hx | 40 +++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 src/Vector.hx create mode 100644 src/XError.hx diff --git a/src/Vector.hx b/src/Vector.hx new file mode 100644 index 0000000..8963262 --- /dev/null +++ b/src/Vector.hx @@ -0,0 +1,75 @@ +package; +import haxe.Constraints.Function; +/** + * ... + * @author xmi + */ +@:forward +@:arrayAccess +abstract Vector(Array) from Array to Array { + public inline function new(_length:Int = 0, fixed_ignored:Bool = false) { + this = []; + if (_length != 0) length = _length; + } + + public var fixed(never, set):Bool; + public inline function set_fixed(value:Bool):Bool { + return value; + } + + + public var length(get, set):Int; + public inline function get_length():Int { + return this.length; + } + public inline function set_length(value:Int):Int { + #if js + return untyped this.length = value; + #else + var l:Int = this.length; + if (value > l) { + while (l < value) { + this.push(null); + l++; + } + } else if (value < l) { + while (l < value) { + this.pop(); + } + } + return value; + #end + } + + public inline function insertAt(pos:Int, x:T):Void { + return this.insert(pos, x); + } + + public inline function removeAt(index:Int):T { + return this.splice(index, 1)[0]; + } + + public inline function concat(?v:Vector):Vector { + if (v == null) { + return this.copy(); + } else { + return this.concat(v); + } + } + + public static inline function ofArray(a:Array):Vector { + return untyped a; + } + + #if openfl + @:to public function toOpenFlVector():openfl.Vector { + return untyped new openfl.Vector(this.length, false, untyped this); + } + @:from public static function fromOpenFlVector(v:openfl.Vector):Vector { + return untyped v.__array; + } + @:to public function toOpenFlObject():openfl.utils.Object { + return untyped this; + } + #end +} \ No newline at end of file diff --git a/src/XError.hx b/src/XError.hx new file mode 100644 index 0000000..4f45ac1 --- /dev/null +++ b/src/XError.hx @@ -0,0 +1,40 @@ +package; +import js.Error; + +/** + * ... + * @author xmi + */ +#if js +class XError extends js.Error { + public function new(name:String, message:String = null) { + super(); + untyped Object.defineProperty(this, 'name', { + enumerable: false, + writable: false, + value: name + }); + + untyped Object.defineProperty(this, 'message', { + enumerable: false, + writable: true, + value: message || '' + }); + + if (untyped Error.hasOwnProperty('captureStackTrace')) { // V8 + untyped Error.captureStackTrace(this, XError); + } else { + untyped Object.defineProperty(this, 'stack', { + enumerable: false, + writable: false, + value: (new Error(message)).stack + }); + } + } +} + +#elseif flash +typedef XError = flash.errors.Error; +#else +typedef XError = Error; +#end \ No newline at end of file From e4488b243a31fb57c1dbae8140535c3bb998cacc Mon Sep 17 00:00:00 2001 From: Xmitre Date: Thu, 1 Nov 2018 16:32:46 +0300 Subject: [PATCH 119/156] comment with type after star `*` type --- src/as3hx/parsers/TypeParser.hx | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/as3hx/parsers/TypeParser.hx b/src/as3hx/parsers/TypeParser.hx index ba0fbca..4bcf06d 100644 --- a/src/as3hx/parsers/TypeParser.hx +++ b/src/as3hx/parsers/TypeParser.hx @@ -16,8 +16,26 @@ class TypeParser { var tmp = tokenizer.opPriority.get("*="); tokenizer.opPriority.remove("*="); if(ParserUtils.opt(tokenizer, TOp("*"))) { - tokenizer.opPriority.set("*=",tmp); - return TStar; + tokenizer.opPriority.set("*=", tmp); + + var typeFromComment:T = null; + var t2 = tokenizer.token(); + switch(t2) { + case TCommented(s, true, t3): + typeFromComment = OverrideTypeComment.extractType("*", s, types); + if (typeFromComment != null) { + tokenizer.add(t3); + } else { + tokenizer.add(t2); + } + default: + tokenizer.add(t2); + } + if (typeFromComment != null) { + return typeFromComment; + } else { + return TStar; + } } tokenizer.opPriority.set("*=",tmp); From 60850d0c43178c433aff78a981e05cfa6e6edb66 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Thu, 1 Nov 2018 04:33:03 +0300 Subject: [PATCH 120/156] custom Vector Compat splice --- src/as3hx/Compat.hx | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/as3hx/Compat.hx b/src/as3hx/Compat.hx index d100f89..00fba06 100644 --- a/src/as3hx/Compat.hx +++ b/src/as3hx/Compat.hx @@ -207,11 +207,13 @@ class Compat { /** T==null is Vector.<*>, otherwise T could be Abstract of Class */ public static function isVector(p:Dynamic, T:Dynamic = null):Bool { if (p == null) return null; - var c:Class = Type.getClass(p); - if (c == null) return false; + //var c:Class = Type.getClass(p); + //if (c == null) return false; //if (Type.getClassName(c) != "openfl._Vector.AbstractVector") return false; - if (Type.getClassName(c).indexOf("openfl._Vector.") != 0) return null; - var v:openfl.Vector = cast p; + //if (Type.getClassName(c).indexOf("openfl._Vector.") != 0) return null; + if (!Std.is(p, Array)) return null; + //var v:openfl.Vector = cast p; + var v:Vector = cast p; if (v.length > 0 && T != null && v[0] != null && !Std.is(v[0], T)) { return false; } @@ -231,7 +233,17 @@ class Compat { //return r; //} - public static inline function vectorSplice(a:openfl.Vector, startIndex:Int, deleteCount:Int, ?values:Array):openfl.Vector { + //public static inline function vectorSplice(a:openfl.Vector, startIndex:Int, deleteCount:Int, ?values:Array):openfl.Vector { + //var result = a.splice(startIndex, deleteCount); + //if(values != null) { + //for (i in 0...values.length) { + //a.insertAt(startIndex + i, values[i]); + //} + //} + //return result; + //} + #end + public static inline function vectorSplice(a:Vector, startIndex:Int, deleteCount:Int, ?values:Array):Vector { var result = a.splice(startIndex, deleteCount); if(values != null) { for (i in 0...values.length) { @@ -240,7 +252,6 @@ class Compat { } return result; } - #end public static inline function isClass(c:Dynamic):Bool { return c != null && c.__name__ != null; From 308b6f1b6fc0af524b2c740fe76af347e0d2bbf1 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Thu, 1 Nov 2018 16:34:58 +0300 Subject: [PATCH 121/156] feathers.core.PropertyProxy type handling in specific environment --- src/as3hx/Writer.hx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 5b86cfb..e386250 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1250,11 +1250,14 @@ class Writer var oldInLVA = inLvalAssign; inLvalAssign = false; //oldInLVA = false; - if (isArrayType(etype) || isVectorType(etype) || isOpenFlDictionaryType(etype) || isMapType(etype) || isByteArrayType(etype)/* || etype == "PropertyProxy"*/) { + var isProxy:Bool = etype == "PropertyProxy" || etype == "feathers.core.PropertyProxy"; + if (isArrayType(etype) || isVectorType(etype) || isOpenFlDictionaryType(etype) || isMapType(etype) || isByteArrayType(etype) || isProxy) { writeExpr(e); inArrayAccess = old; write("["); - if (isOpenFlDictionaryType(etype) || isMapType(etype)) { + if (isProxy) { + writeExpr(index); + } else if (isOpenFlDictionaryType(etype) || isMapType(etype)) { writeETypedExpr(index, TPath([typer.getMapIndexType(etype)])); } else { writeETypedExpr(index, TPath(["Int"])); From 925b53c87b51515160710f304d203c7b2d8be05a Mon Sep 17 00:00:00 2001 From: Xmitre Date: Tue, 6 Nov 2018 12:52:55 +0300 Subject: [PATCH 122/156] FastXML type compatibility fix --- src/FastXML.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FastXML.hx b/src/FastXML.hx index e3e7811..5f55444 100644 --- a/src/FastXML.hx +++ b/src/FastXML.hx @@ -187,10 +187,10 @@ class FastXML { return 1; } - public function setAttribute(name:String, value:String) : Void { + public function setAttribute(name:String, value:Dynamic) : Void { if( x.nodeType == Xml.Document ) throw "Cannot access document attribute "+name; - x.set(name,value); + x.set(name,Std.string(value)); } public function toString() : String { From 65a5a2bc5e5e8ebfb428ffab395a3f043a65e557 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 9 Nov 2018 01:11:52 +0300 Subject: [PATCH 123/156] enclosing String() cast in parentheses when no actual cast is needed and String wrapper is being removed --- src/as3hx/Writer.hx | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index e386250..4ad0834 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1499,8 +1499,7 @@ class Writer var testVar = switch(e) { case EParent(ex): switch(ex) { - case EIdent(i): ex; - case ECall(_): ex; + case EIdent(_), ECall(_), EField(_): ex; default: null; } default: @@ -1546,12 +1545,10 @@ class Writer writeExpr(testVar); write(" = "); writeFinish(writeExpr(e)); - writeIndent(""); } //start the switch on a new line if (lineIsDirty) { - writeNL(); writeNL(); writeIndent(); } @@ -2036,7 +2033,12 @@ class Writer switch(n) { case "Object": writeExpr(params[0]); case "Number": writeCastToFloat(params[0]); - case "String": writeToString(params[0]); + case "String": + if (getExprType(params[0]) == "String") { + writeEParent(params[0]); + } else { + writeExpr(getToStringExpr(params[0])); + } case "Boolean": if (getExprType(params[0]) == "Bool") { writeEParent(params[0]); @@ -2522,7 +2524,12 @@ class Writer switch(e2) { case EIdent(s): switch(s) { - case "String": writeToString(e1); + case "String": + if (getExprType(e1) == "String") { + writeExpr(e1); + } else { + writeExpr(getToStringExpr(e1)); + } case "int", "Int", "uint", "UInt": writeCastToInt(e1); case "Number": writeCastToFloat(e1); case "Array": @@ -2736,14 +2743,6 @@ class Writer return result; } - function writeToString(e:Expr) { - var type = getExprType(e); - if (type != "String") { - e = getToStringExpr(e); - } - writeExpr(e); - } - inline function getToStringExpr(e:Expr):Expr return ECall(EField(EIdent("Std"), "string"), [e]); function writeCastToInt(e:Expr) { From 562a7df543cb439365ced495068f2d194071a482 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 9 Nov 2018 13:12:39 +0300 Subject: [PATCH 124/156] fulfilling of Type params during conversion, hasOwnProperty typing. --- src/as3hx/Typer.hx | 34 ++++++++++++++++++++++++++++++-- src/as3hx/Writer.hx | 2 +- src/as3hx/parsers/ClassParser.hx | 2 +- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index b0cecf2..a186a3b 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -203,6 +203,10 @@ class Typer } } switch(t2) { + case "Object", "Dynamic": + switch(f) { + case "hasOwnProperty": return "String->Bool"; + } case "Reflect": switch(f) { case "hasField": return "Dynamic->String->Bool"; @@ -331,12 +335,27 @@ class Typer if (classes.exists(t2)) { var t:String = classes.get(t2).get(f); if (t != null) { + var typeParams:String = classDefs[t2].typeParams; var index:Int = t.indexOf("<"); if (index != -1) { - var resultTypeParam = t.substring(index, t.length); - if (resultTypeParam == classDefs[t2].typeParams) { + var resultTypeParam = t.substring(index + 1, t.length - 1); + if (resultTypeParam == typeParams) { t = t.substring(0, index + 1) + typeParam + ">"; } + } else if (t.indexOf(typeParams) != -1) { + var delimiters:Array = []; + var instanceTypeParams:Array> = getTypeParams(t, delimiters); + var hasChange:Bool = false; + for (tt in instanceTypeParams) { + if (tt.length == 1 && tt[0] == typeParams) { + tt[0] = typeParam; + hasChange = true; + } + } + if (hasChange) { + t = reuniteTypeParams(instanceTypeParams, delimiters); + trace(t, t2); + } } return t; } @@ -864,6 +883,17 @@ class Typer } } + public static function reuniteTypeParams(t:Array>, delimiters:Array):String { + var s:String = t[0].join("."); + for (i in 1...t.length) { + s += delimiters[i - 1] + t[i].join("."); + } + if (delimiters.length == t.length) { + s += delimiters[delimiters.length - 1]; + } + return s; + } + public static function getTypeParams(type:String, delimiters:Array = null):Array> { var result:Array> = new Array>(); var name:String = ""; diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 4ad0834..6e100bf 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -372,7 +372,7 @@ class Writer buf.add(properCase(c.name, true)); if (c.typeParams != null) { - buf.add(c.typeParams); + buf.add("<" + c.typeParams + ">"); } var parents = []; diff --git a/src/as3hx/parsers/ClassParser.hx b/src/as3hx/parsers/ClassParser.hx index 573623e..61ae274 100644 --- a/src/as3hx/parsers/ClassParser.hx +++ b/src/as3hx/parsers/ClassParser.hx @@ -32,7 +32,7 @@ class ClassParser { cname = p.join("."); var i:Int = cname.indexOf("<"); if (i != -1) { - typeParams = cname.substr(i); + typeParams = cname.substring(i + 1, cname.length - 1); cname = cname.substr(0, i); } tokenizer.add(t); From 4bd2ee00cfc8dfeab073a9b653eef1e159994abb Mon Sep 17 00:00:00 2001 From: Xmitre Date: Mon, 12 Nov 2018 15:00:49 +0300 Subject: [PATCH 125/156] deprecation of temporary variable in switch for array[index] expression --- src/as3hx/Writer.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 6e100bf..b5346f3 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1499,7 +1499,7 @@ class Writer var testVar = switch(e) { case EParent(ex): switch(ex) { - case EIdent(_), ECall(_), EField(_): ex; + case EIdent(_), ECall(_), EField(_), EArray(_, _): ex; default: null; } default: From b90e9d48fd1f0c2005249c95f1cecb9aa1fa2fed Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 21 Nov 2018 16:48:37 +0300 Subject: [PATCH 126/156] apply, call fixes --- src/as3hx/Writer.hx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index b5346f3..ffa9baa 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -3672,14 +3672,16 @@ class Writer } } else if (f == "apply") { - if(isFunctionExpr(e)) { - params = [EIdent("null"), e].concat(params.slice(1)); + if (isFunctionExpr(e)) { + var thisArg = params.length == 0 ? EIdent("null") : params.shift(); + params = [thisArg, e].concat(params); result = ECall(EField(EIdent("Reflect"), "callMethod"), params); } } else if(f == "call") { if(isFunctionExpr(e)) { - params = [EIdent("null"), e].concat([EArrayDecl(params.slice(1))]); + var thisArg = params.length == 0 ? EIdent("null") : params.shift(); + params = [thisArg, e, EArrayDecl(params)]; result = ECall(EField(EIdent("Reflect"), "callMethod"), params); } } From e5c9507dff6b0b028b1f8e662e4fec435aa49a64 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 28 Nov 2018 19:17:45 +0300 Subject: [PATCH 127/156] verbose setter return error message --- src/as3hx/Writer.hx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index ffa9baa..8b15113 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1163,7 +1163,12 @@ class Writer // haxe setters must return the provided type if(isSetter && !isNative && f.args.length == 1) { var result = EIdent(f.args[0].name); - formatBlock(es, function(e) return result); + formatBlock(es, function(e) { + if (e != null) { + throw "Unexpected return value: " + e + " in as3 setter"; + } + return result; + }); es.push(ENL(EReturn(result))); } es = WriterUtils.moveFunctionDeclarationsToTheTop(es); From 85148e59cda2c5398d62181aed69548388912f48 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Thu, 6 Dec 2018 11:57:10 +0300 Subject: [PATCH 128/156] `if (arrayOfBool[index])` conversion fix --- src/as3hx/Writer.hx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 8b15113..d74bd68 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -3373,15 +3373,18 @@ class Writer return (s == "Float" || isIntType(s) || s == "UInt"); } switch(e) { - case EArray(_,_): return EBinop("!=", e, EIdent("null"), false); + case EArray(_,_): + var t = getExprType(e); + if (t == "Bool") return null; + return EBinop("!=", e, EIdent("null"), false); case EIdent("null"): return null; case EIdent(_), EField(_, _), ECall(_, _): var t = getExprType(e); - if (t == "Bool") return null; - if (t == null) { - return ECall(EField(EIdent("AS3"), "as"), [e, EIdent("Bool")]); - } return switch(t) { + case "Bool": + null; + case null: + ECall(EField(EIdent("AS3"), "as"), [e, EIdent("Bool")]); case "Int" | "UInt": EBinop("!=", e, EConst(CInt("0")), false); case "Float": From 29c8c0ed5188137df883873d4936d39a3416e3d7 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 21 Dec 2018 11:24:45 +0300 Subject: [PATCH 129/156] signal typing fix --- src/as3hx/SignalRebuild.hx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/as3hx/SignalRebuild.hx b/src/as3hx/SignalRebuild.hx index c31d708..7c53099 100644 --- a/src/as3hx/SignalRebuild.hx +++ b/src/as3hx/SignalRebuild.hx @@ -65,8 +65,11 @@ class SignalRebuild var p:Array = []; var types:String = s.substring(s.indexOf("<") + 1, s.length - 1); if (types == "T" || types == "Type" || types == "T->Void" || types == "Type->Void") return null; - if (types == "Void") types = "Void->Void"; - for (s in types.split("->")) { + var split:Array = types.split("->"); + if (split.length == 1) { + split.push("Void"); + } + for (s in split) { p.push(typer.expandType(TPath([s]))); } typer.overrideExprType(params[0], TFunction(p)); From ccbd5537a1c61f992561f1577f4ed10dc5c6f42a Mon Sep 17 00:00:00 2001 From: Xmitre Date: Mon, 24 Dec 2018 11:58:19 +0300 Subject: [PATCH 130/156] "".join("") typing, redundant trace fix --- src/as3hx/Typer.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index a186a3b..fe613de 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -199,6 +199,7 @@ class Typer if (t2 != null && (t2.indexOf("Array<") == 0 || t2.indexOf("Vector<") == 0 || t2.indexOf(cfg.arrayTypePath + "<") == 0)) { switch(f) { case "length": return "Int"; + case "join": return "String->String"; case "sort" : return "Function->Void"; } } @@ -354,7 +355,6 @@ class Typer } if (hasChange) { t = reuniteTypeParams(instanceTypeParams, delimiters); - trace(t, t2); } } return t; From f3c42ff03613e61017a0548195eed044ce356c5d Mon Sep 17 00:00:00 2001 From: Xmitre Date: Tue, 15 Jan 2019 19:56:47 +0300 Subject: [PATCH 131/156] generated property declarations are moved to first getter or setter. some dirty code left --- src/as3hx/Writer.hx | 245 +++++++++++++++++++++++++------------------- 1 file changed, 137 insertions(+), 108 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index d74bd68..32831c5 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -409,33 +409,87 @@ class Writer writeECondCompEnd(getCondComp(c.meta)); } - function writeProperties(c : ClassDef) + var propertyMap = new Map(); + function tryAddProperty(field:ClassField, f:Function):Void { - var p = []; - var h = new Map(); - var getOrCreateProperty = function(name, t, stat, internal) + var isGetter:Bool = this.isGetter(field.kwds); + var isSetter:Bool = !isGetter && this.isSetter(field.kwds); + if (isGetter || isSetter) { - var property = h.get(name); + var property = propertyMap.get(field.name); if (property == null) { property = { - name : name, + name : field.name, get : "never", set : "never", - ret : t, - sta : stat, - internal : internal, - pub : false, + ret : isGetter ? f.ret.t : f.args[0].t, + sta : isStatic(field.kwds), + internal : isInternal(field.kwds), + pub : isPublic(field.kwds), getMeta : null, setMeta : null }; - p.push(property); - h.set(name, property); + propertyMap.set(field.name, property); + } + if (isGetter) + { + property.get = "get"; + property.setMeta = field.meta; + } + if (isSetter) + { + property.set = "set"; + property.setMeta = field.meta; } - return property; } + } + function tryWritePropertyVar(field:ClassField, c:ClassDef):Void + { + if (!propertyMap.exists(field.name)) + return; + var property = propertyMap.get(field.name); + propertyMap.remove(field.name); + + //for insterface, func prototype will be removed, + //so write meta on top of properties instead + if (c.isInterface) { + writeMetaData(property.setMeta); + writeMetaData(property.getMeta); + } + if (property.internal) + writeAllow(); + if(cfg.getterSetterStyle == "combined") + write("#if !flash "); + if (property.pub) { + write("public "); + } + else { + if (! isInterface) { + write("private "); + } + } + if (property.sta) + write("static "); + write("var " + property.name + "(" + property.get + ", " + property.set + ")"); + writeVarType(property.ret); + if(cfg.getterSetterStyle == "combined") + writeNL("; #end"); + else { + if (c.isInterface) { //if interface, newline handled be metadata + write(";"); + } + else { + writeNL(";"); + writeIndent(); + } + } + } + + function writeProperties(c : ClassDef) + { for (field in c.fields) { switch(field.kind) @@ -443,89 +497,61 @@ class Writer case FFun( f ): if (isOverride(field.kwds)) continue; - if (isGetter(field.kwds)) - { - var getterDirective : String = "get"; // haxe 3 - // haxe 2: cfg.makeGetterName(field.name); - - var property = getOrCreateProperty(field.name, f.ret.t, isStatic(field.kwds), isInternal(field.kwds)); - property.getMeta = field.meta; - if (isPublic(field.kwds)) - { - property.get = getterDirective; - property.pub = true; - } else { - property.get = getterDirective; - } - } - else if (isSetter(field.kwds)) - { - var setterDirective : String = "set"; // haxe 3 - // haxe 2: cfg.makeSetterName(field.name); - - var property = getOrCreateProperty(field.name, f.args[0].t, isStatic(field.kwds), isInternal(field.kwds)); - property.setMeta = field.meta; - if (isPublic(field.kwds)) - { - property.set = setterDirective; - property.pub = true; - } else { - property.set = setterDirective; - } - } + tryAddProperty(field, f); default: continue; } } - - if (p.length > 0) { - writeNL(); - } - - if(cfg.getterSetterStyle == "haxe" || cfg.getterSetterStyle == "combined") { - for (property in p) - { - writeIndent(); - //for insterface, func prototype will be removed, - //so write meta on top of properties instead - if (c.isInterface) { - writeMetaData(property.setMeta); - writeMetaData(property.getMeta); - } - - if (property.internal) - writeAllow(); - if(cfg.getterSetterStyle == "combined") - write("#if !flash "); - if (property.pub) { - write("public "); - } - else { - if (! isInterface) { - write("private "); - } - } - if (property.sta) - write("static "); - write("var " + property.name + "(" + property.get + ", " + property.set + ")"); - writeVarType(property.ret); - if(cfg.getterSetterStyle == "combined") - writeNL("; #end"); - else { - if (c.isInterface) { //if interface, newline handled be metadata - write(";"); - } - else { - writeNL(";"); - } - } - } - } - if (c.isInterface) { - writeNL(); - } } + //if (p.length > 0) { + //writeNL(); + //} +// + //if(cfg.getterSetterStyle == "haxe" || cfg.getterSetterStyle == "combined") { + //for (property in p) + //{ + //writeIndent(); + ////for insterface, func prototype will be removed, + ////so write meta on top of properties instead + //if (c.isInterface) { + //writeMetaData(property.setMeta); + //writeMetaData(property.getMeta); + //} +// + //if (property.internal) + //writeAllow(); + //if(cfg.getterSetterStyle == "combined") + //write("#if !flash "); + //if (property.pub) { + //write("public "); + //} + //else { + //if (! isInterface) { + //write("private "); + //} + //} + //if (property.sta) + //write("static "); + //write("var " + property.name + "(" + property.get + ", " + property.set + ")"); + //writeVarType(property.ret); + //if(cfg.getterSetterStyle == "combined") + //writeNL("; #end"); + //else { + //if (c.isInterface) { //if interface, newline handled be metadata + //write(";"); + //} + //else { + //writeNL(";"); + //} + //} + //} + //} + //if (c.isInterface) { + //writeNL(); + //} + //} + function writeFields(c : ClassDef) { if (c.isInterface) { @@ -632,8 +658,10 @@ class Writer //if writing an Interface, get/set field will be added //as a property instead of func - if ((isGet || isSet) && c.isInterface) + if ((isGet || isSet) && c.isInterface) { + tryWritePropertyVar(field, c); return; + } var namespaceMetadata:Array = null; if (isFun) { @@ -664,23 +692,24 @@ class Writer } var start = function(name:String, isFlashNative:Bool=false, isConstructor=false):Bool { - if((isGet || isSet) && cfg.getterSetterStyle == "combined") { - writeNL(isFlashNative ? "#if flash" : "#else"); - //writeNL(""); - } - - if(isFlashNative) { - if(isGet) { - write("@:getter("); - write(name); - write(") "); - } else if(isSet) { - write("@:setter("); - write(name); - write(") "); - } - if((isGet || isSet) && isProtected(field.kwds)) { - write("@:protected "); + if (isGet || isSet) { + tryWritePropertyVar(field, c); + if (cfg.getterSetterStyle == "combined") { + writeNL(isFlashNative ? "#if flash" : "#else"); + } + if (isFlashNative) { + if(isGet) { + write("@:getter("); + write(name); + write(") "); + } else if(isSet) { + write("@:setter("); + write(name); + write(") "); + } + if (isProtected(field.kwds)) { + write("@:protected "); + } } } if(isFinal(field.kwds)) From b7b9f906175db5423bc76e186a848d783335078b Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 6 Feb 2019 10:22:47 +0300 Subject: [PATCH 132/156] exclude pattern fix. "pack" exclude now does not affect "package.Class" path --- src/FileParser.hx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/FileParser.hx b/src/FileParser.hx index 7fb7b97..96eef74 100644 --- a/src/FileParser.hx +++ b/src/FileParser.hx @@ -37,8 +37,24 @@ class FileParser { static function isExcludeFile(excludes: List, file: String) { + var filePath:String = as3hx.Config.toPath(file); return Lambda.filter(excludes, function (path) { - return as3hx.Config.toPath(file).indexOf(StringTools.replace(path, ".", "\\")) > -1; + var excludePath:String = StringTools.replace(path, ".", "\\"); + var excludeIndex:Int = filePath.indexOf(excludePath); + var excludeEndIndex:Int = excludeIndex + excludePath.length; + if (excludeIndex > -1) { + if (excludeEndIndex < filePath.length) { + var nextCharCode:Int = filePath.charCodeAt(excludeEndIndex); + if (nextCharCode == ".".code || nextCharCode == "\\".code) { + return true; + } else { + return false; + } + } else { + return true; + } + } + return false; }).length > 0; } From 2f51a240c097259ef485466ce56e378070d64912 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 6 Feb 2019 10:23:45 +0300 Subject: [PATCH 133/156] ignoring of nested local function internal vars while fixing enclosing function vars --- src/as3hx/VarExprFix.hx | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/as3hx/VarExprFix.hx b/src/as3hx/VarExprFix.hx index 412f199..61773f3 100644 --- a/src/as3hx/VarExprFix.hx +++ b/src/as3hx/VarExprFix.hx @@ -24,6 +24,7 @@ class VarExprFix var blockVars:Array = new Array(); var restrictedVars:Array = new Array(); var varsToIgnore:Array = new Array(); + var localFunctionVars:Map; var hasVarsToInsert:Bool = false; var inLocalFunction:Bool = false; var line:Int = 0; @@ -65,10 +66,23 @@ class VarExprFix if (hasChange) { return RebuildResult.RReplaceArray(newVars); } + case EFunction(f, name): + return RebuildResult.RSkip; default: } return null; } + function rebuildMethodGetLocalFunctionVars(e:Expr):RebuildResult { + switch (e) { + case EFunction(f, name): return RebuildResult.RSkip; + case EVars(vars): + for (vr in vars) { + localFunctionVars.set(vr.name, true); + } + return RebuildResult.RSkip; + default: return null; + } + } function rebuildMethodLookForVars(e:Expr):RebuildResult { switch(e) { case EFor(inits, conds, incrs, e): @@ -120,6 +134,9 @@ class VarExprFix } case EIdent(v): if (v != null) { + if (inLocalFunction && localFunctionVars.exists(v)) { + return RebuildResult.RSkip; + } if (!localVar.exists(v)) { if (!inLocalFunction && v == "arguments") { var arguments:Array = []; @@ -149,12 +166,16 @@ class VarExprFix } var oldInLocalFunction = inLocalFunction; inLocalFunction = true; + localFunctionVars = new Map(); + RebuildUtils.rebuild(f.expr, rebuildMethodGetLocalFunctionVars); var rexpr = RebuildUtils.rebuild(f.expr, rebuildMethodLookForVars); inLocalFunction = oldInLocalFunction; - if (rexpr == null) return null; + if (rexpr == null) return RebuildResult.RSkip; return RebuildResult.RReplace(EFunction({args:f.args, varArgs:f.varArgs, ret:f.ret, expr:rexpr}, name)); case EVars(vars/*Array<{ name : String, t : Null, val : Null }>*/): - if (inLocalFunction) return null; + if (inLocalFunction) { + return RebuildResult.RSkip; + } var newVars:Array = []; var hasChange:Bool = false; for (vr in vars) { From 60481f3928d2418799f7697a5cd70a582c632b35 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Wed, 6 Feb 2019 22:24:32 +0300 Subject: [PATCH 134/156] Hardcode-customizable Object type path. Dirty fix of rawData.split/length/indexOf conversion. All object field names in {field:value} are enclosed in quotes: {"field":value} for advanced minification with closure --- src/as3hx/CommonImports.hx | 7 +- src/as3hx/DictionaryRebuild.hx | 6 +- src/as3hx/Typer.hx | 91 +++++++++++++++++++++-- src/as3hx/Writer.hx | 130 +++++++++++++++++++++------------ 4 files changed, 177 insertions(+), 57 deletions(-) diff --git a/src/as3hx/CommonImports.hx b/src/as3hx/CommonImports.hx index 7373edc..8ff5453 100644 --- a/src/as3hx/CommonImports.hx +++ b/src/as3hx/CommonImports.hx @@ -6,6 +6,9 @@ package as3hx; */ class CommonImports { + public static inline var ObjectImport:String = "openfl.utils.Object"; + public static inline var ObjectType:String = "Object"; + private static var imports:Map> = new Map>(); public static function getImports(cfg:Config):Map { if (imports.exists(cfg)) { @@ -44,7 +47,9 @@ class CommonImports if (cfg.useOpenFlTypes) { //map.set("Vector", "openfl.Vector"); - map.set("Object", "openfl.utils.Object"); + //map.set("Object", "openfl.utils.Object"); + map.set("Object", ObjectImport); + map.set(ObjectType, ObjectImport); } var topLevelErrorClasses = [ diff --git a/src/as3hx/DictionaryRebuild.hx b/src/as3hx/DictionaryRebuild.hx index 2a92378..b07ec5a 100644 --- a/src/as3hx/DictionaryRebuild.hx +++ b/src/as3hx/DictionaryRebuild.hx @@ -126,7 +126,7 @@ class DictionaryRebuild default: var newType:String = typer.getExprType(e); if (isOpenFlDictionaryType(newType)) { - var oldType:String = typer.tstring(returnType); + var oldType:String = typer.expandStringType(typer.tstring(returnType)); newType = foldDictionaryType2(oldType, newType); newType = typer.shortenStringType(newType); if (oldType != newType) { @@ -235,8 +235,8 @@ class DictionaryRebuild if (a == "T") return a; if (b == "T") return b; - var aIsAny:Bool = a == "Dynamic" || a == "Object" || a == "openfl.utils.Object" || a == null || a == "null"; - var bIsAny:Bool = b == "Dynamic" || b == "Object" || b == "openfl.utils.Object" || b == null || b == "null"; + var aIsAny:Bool = a == "Dynamic" || a == "Object" || a == CommonImports.ObjectImport || a == null || a == "null"; + var bIsAny:Bool = b == "Dynamic" || b == "Object" || b == "openfl.utils.Object" || b== "" || b == null || b == "null"; if (aIsAny && bIsAny) return "Dynamic"; if (aIsAny) return b; if (bIsAny) return a; diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index fe613de..6babe16 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -204,10 +204,11 @@ class Typer } } switch(t2) { - case "Object", "Dynamic": + case "Object", "Dynamic", CommonImports.ObjectType, CommonImports.ObjectImport: switch(f) { case "hasOwnProperty": return "String->Bool"; } + return "Dynamic"; case "Reflect": switch(f) { case "hasField": return "Dynamic->String->Bool"; @@ -276,7 +277,7 @@ class Typer default: return "String"; } case "FastXMLNodeAccess": return "FastXML"; - case "FastXMLNodeListAccess": return "FastXMLList"; + case "FastXMLNodeListAccess": return "Void->FastXMLList"; case "FastXMLAttribAccess": return "String"; case "FastXMLHasAttribAccess": return "Bool"; case "FastXMLHasNodeAccess": return "Bool"; @@ -288,7 +289,7 @@ class Typer case "att":"FastXMLAttribAccess"; case "has":"FastXMLHasAttribAccess"; case "hasNode":"FastXMLHasNodeAccess"; - case "name":"String"; + case "name":"Void->String"; case "innerData":"String"; case "innerHTML":"String"; case "descendants": "String->FastXMLList"; @@ -464,10 +465,29 @@ class Typer if (commaPosition != -1) { return bothTypes.substr(commaPosition + 1); } + } else if (tn == "Object" || tn == CommonImports.ObjectType || tn == CommonImports.ObjectImport) { + return "Dynamic"; } } return tn; - case EArrayDecl(_): return "Array"; + case EArrayDecl(a): + var type:String = null; + for (e in a) { + var t:String = getExprType(e); + if (type != t) { + if (type == null) { + type = t; + } else { + type = null; + break; + } + } + } + if (type == null) { + return "Array"; + } else { + return "Array<" + type + ">"; + } case EUnop(_, _, e2): return getExprType(e2); case EParent(e): return getExprType(e); case ETernary(cond, e1, e2): return getExprType(e1); @@ -503,6 +523,7 @@ class Typer case EVector(t): types.push(tstring(TVector(t))); case EIdent(v): + v = getModifiedIdent(v); var fullPath:String = resolveClassIdent(v); types.push(tstring(TPath([fullPath == null ? v : fullPath]))); //types.push(tstring(TPath([fullPath]))); @@ -522,6 +543,8 @@ class Typer return getExprType(e); case ENL(e): return getExprType(e); + case EObject(fl): + return CommonImports.ObjectType; case EBlock(es): if (es.length == 1) { return getExprType(es[0]); @@ -552,7 +575,7 @@ class Typer case "Number": "Float"; case "Boolean": "Bool"; case "Function": cfg.functionToDynamic ? "Dynamic" : s; - case "Object": cfg.useOpenFlTypes ? "Object" : "Dynamic"; + case "Object": cfg.useOpenFlTypes ? CommonImports.ObjectType : "Dynamic"; case "undefined": "null"; //case "Error": cfg.mapFlClasses ? "flash.errors.Error" : s; case "XML": "FastXML"; @@ -598,12 +621,30 @@ class Typer case "uint" : cfg.uintToInt ? "Int" : "UInt"; case "void" : "Void"; case "Function" : cfg.functionToDynamic ? "Dynamic" : c; - case "Object" : isNativeGetSet ? "{}" : (cfg.useOpenFlTypes ? "Object" : "Dynamic"); + case "Object", CommonImports.ObjectType : isNativeGetSet ? "{}" : (cfg.useOpenFlTypes ? CommonImports.ObjectType : "Dynamic"); case "XML" : cfg.useFastXML ? "FastXML" : "Xml"; case "XMLList" : cfg.useFastXML ? "FastXMLList" : "Iterator"; case "RegExp" : cfg.useCompat ? "as3hx.Compat.Regex" : "flash.utils.RegExp"; //default : fixCase ? properCase(c, true) : c; - default : cfg.importExclude.indexOf(c) != -1 ? p[p.length - 1] : fixCase ? properCase(c, true) : c; + default : + if (cfg.importExclude.indexOf(c) != -1) { + c = p[p.length - 1]; + } else { + if (fixCase) c = properCase(c, true); + } + var s:String = c; + if (s.indexOf("<") != -1) { + var delimiters:Array = new Array(); + var t:Array> = getTypeParams(s, delimiters); + s = getModifiedIdent(t[0].join(".")); + for (i in 1...t.length) { + s += delimiters[i - 1] + getModifiedIdent(t[i].join(".")); + } + if (delimiters.length == t.length) { + s += delimiters[delimiters.length - 1]; + } + } + s; } case TComplex(e): return getExprType(e); // not confirmed case TDictionary(k, v): (cfg.dictionaryToHash ? "haxe.ds.ObjectMap" : "Dictionary") + "<" + tstring(k) + "," + tstring(v) + ">"; @@ -1410,8 +1451,19 @@ class Typer if (f.varArgs != null) { context.set(f.varArgs, "Array"); } + var localTyping:Map = new Map(); function lookUpForTyping(expr:Expr):RebuildResult { switch(expr) { + case EBinop("=", EIdent(v), e2, _): + if (localTyping.exists(v)) { + if (localTyping.get(v) == null) { + context.set(v, resolveArrayType(context.get(v), getExprType(e2))); + } else { + localTyping.set(v, resolveArrayType(localTyping.get(v), getExprType(e2))); + } + } else { + localTyping.set(v, getExprType(e2)); + } case EForEach(ev, e, block): var etype:String = getExprType(e); var isMap:Bool = etype != null && (etype.indexOf("Map") == 0 || etype.indexOf("Dictionary") == 0 || etype.indexOf("openfl.utils.Dictionary") == 0); @@ -1479,7 +1531,20 @@ class Typer } case EVars(vars): for (v in vars) { - context.set(v.name, tstring(v.t)); + var t:String; + switch(v.val) { + case ETypedExpr(e, _): + t = getExprType(e); + default: + t = getExprType(v.val); + } + t = resolveArrayType(tstring(v.t), t); + + if (localTyping.get(v.name) != null) { + t = resolveArrayType(t, localTyping.get(v.name)); + localTyping.set(v.name, null); + } + context.set(v.name, t); } case EFunction(f, name): if (name != null) { @@ -1494,6 +1559,16 @@ class Typer RebuildUtils.rebuild(f.expr, lookUpForTyping); } + private static var arrayDynamicIdent:String = "Array"; + private static var arrayIdent:String = "Array<"; + private function resolveArrayType(a:String, b:String):String { + if (a == null || (a == arrayDynamicIdent && b != null && b.indexOf(arrayIdent) == 0 && a != b)) { + return b; + } else { + return a; + } + } + public function leaveFunction():Void { closeContext(); } diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 32831c5..0c6f770 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -754,14 +754,14 @@ class Writer //static non-inlined field would prevent Haxe compilation switch(val) { case EConst(c): write("inline "); - return true; + return true; default: } default: } } } - return false; + return false; } switch(field.kind) { case FVar(t, val): @@ -1285,13 +1285,14 @@ class Writer inLvalAssign = false; //oldInLVA = false; var isProxy:Bool = etype == "PropertyProxy" || etype == "feathers.core.PropertyProxy"; - if (isArrayType(etype) || isVectorType(etype) || isOpenFlDictionaryType(etype) || isMapType(etype) || isByteArrayType(etype) || isProxy) { + var isRawData:Bool = etype == "Object" || etype == CommonImports.ObjectType || etype == CommonImports.ObjectImport; + if (isArrayType(etype) || isVectorType(etype) || isOpenFlDictionaryType(etype) || isMapType(etype) || isByteArrayType(etype) || isProxy || isRawData) { writeExpr(e); inArrayAccess = old; write("["); if (isProxy) { writeExpr(index); - } else if (isOpenFlDictionaryType(etype) || isMapType(etype)) { + } else if (isOpenFlDictionaryType(etype) || isMapType(etype) || isRawData) { writeETypedExpr(index, TPath([typer.getMapIndexType(etype)])); } else { writeETypedExpr(index, TPath(["Int"])); @@ -1313,9 +1314,6 @@ class Writer if(!isString) write("Std.string("); writeExpr(index); if(!isString) write(")"); - //if (isAnonymouse) { - //writeInComment(rvalue); - //} if(oldInLVA && !inEField) { write(", "); writeExpr(rvalue); @@ -1348,7 +1346,11 @@ class Writer write(getColon() + alt); return; } - write(getColon() + tstring(t, isNativeGetSet)); + var s:String = tstring(t, isNativeGetSet); + if (s.indexOf("Dictionary<" + CommonImports.ObjectType) == 0) { + s = StringTools.replace(s, "Dictionary<" + CommonImports.ObjectType, "Dictionary<{}"); + } + write(getColon() + s); } function writeInits(c : ClassDef) { @@ -1399,7 +1401,8 @@ class Writer } function writeModifiedIdent(s : String) { - write(typer.getModifiedIdent(s)); + s = typer.getModifiedIdent(s); + write(s); } /** @@ -1872,6 +1875,8 @@ class Writer writeFinish(writeExpr(fix == null ? e : fix)); } + private var restrictedFieldArrayAccessConversion:Array = ["length", "split", "indexOf"]; + function writeEField(fullExpr:Expr, e:Expr, f:String):BlockEnd { var n = checkE4XDescendants(fullExpr); if(n != null) return writeExpr(n); @@ -1879,7 +1884,9 @@ class Writer var t2 = getExprType(e); //write("/* EField ("+Std.string(e)+","+Std.string(f)+") " +t1 + ":"+t2+ " */\n"); var old = inArrayAccess; - if (t2 == "FastXMLList" && t1 == "FastXMLList") { + if (isDynamicType(t2) && restrictedFieldArrayAccessConversion.indexOf(f) == -1) { + writeEArray(e, EConst(CString(f))); + } else if (t2 == "FastXMLList" && t1 == "FastXMLList") { writeExpr(ECall(EField(e, "descendants"), [EConst(CString(f))])); } else if(t1 == "FastXMLList" || (t1 == null && t2 == "FastXML")) { //write("/* t1 : " + t1 + " */"); @@ -1943,7 +1950,7 @@ class Writer if (type == "Function" || type == "haxe.Constraints.Function") { write("1 /*# of arguments of " + v + "*/"); return None; - } else if (type != null && type.indexOf("->") != -1) { + } else if (type != null && isFunctionType(type)) { writeExpr(getCompatCallExpr("getFunctionLength", [e])); return None; } @@ -1975,10 +1982,12 @@ class Writer writeIndent(); } var v = vars[i]; + var rExpr = null; var rvalue = v.val; if(rvalue != null) { switch(rvalue) { - case ETypedExpr(e,_): + case ETypedExpr(e, _): + rExpr = e; switch(e) { case EBinop("||=", e1,_,_): writeExpr(e); @@ -1990,9 +1999,19 @@ class Writer default: } } - var type = tstring(v.t); + var vt = v.t; + var type = tstring(vt); write("var " + typer.getModifiedIdent(v.name)); - writeVarType(v.t); + if (type == "Array") { + var fieldType:String = typer.getExprType(EIdent(v.name)); + if (fieldType != type) { + vt = TPath([typer.shortenStringType(fieldType)]); + if (rExpr != null) { + rvalue = ETypedExpr(rExpr, TPath([fieldType])); + } + } + } + writeVarType(vt); if(rvalue != null) { write(" = "); writeExpr(rvalue); @@ -2453,7 +2472,7 @@ class Writer //var isArray:Bool = isArrayType(t) || isVectorType(t); //var isXml:Bool = t == "FastXML" || t == "FastXMLList"; var isDictionary:Bool = isOpenFlDictionaryType(t); - var isObject:Bool = t == "Object" || t == "openfl.utils.Object" || t == null || t == "Dynamic"; + var isObject:Bool = t == "Object" || t == CommonImports.ObjectType || t == CommonImports.ObjectImport || t == null || t == "Dynamic"; var eValueType:String = getForEachType(t); write("for ("); @@ -2580,7 +2599,7 @@ class Writer write("cast "); writeExpr(e1); default: - if (s == "Dictionary" || s == "PropertyProxy" || s == "Object") { + if (s == "Dictionary" || s == "PropertyProxy" || s == "Object" || s == CommonImports.ObjectType) { write("AS3.as("); writeExpr(e1); write(", " + s + ")"); @@ -2615,7 +2634,7 @@ class Writer } if (defaultCast) { var e2t:String = typer.getExprType(e2, true); - if (e2t == "Object" || e2t == "openfl.utils.Object" || e2t == "Dynamic") { + if (e2t == "Object" || e2t == CommonImports.ObjectType || e2t == CommonImports.ObjectImport || e2t == "Dynamic") { write("(cast "); writeExpr(e1); write(")"); @@ -2692,14 +2711,19 @@ class Writer if (op == "=") inLvalAssign = true; rvalue = e2; var t = getExprType(e1); - if (t != null) { - switch (e2) { - case null: - case EIdent("null"): - default: - e2 = ETypedExpr(e2, TPath([t])); + //if (t != getExprType(e2)) { + if (t != null) { + switch (e2) { + case null: + case EIdent("null"): + case EArrayDecl(es) if (es.length == 0): + case ETypedExpr(e, _): + e2 = ETypedExpr(e, TPath([t])); + default: + e2 = ETypedExpr(e2, TPath([t])); + } } - } + //} } else { switch(e1) { case EArrayDecl(_): rvalue = e2; @@ -3008,8 +3032,8 @@ class Writer private inline function writeDictionaryTypeConstructor(k:String, v:String):Void { //write("new "); - //if (k == "Dynamic" || k == "Object" || k == "openfl.utils.Object") { - //if (k == "Object" || k == "openfl.utils.Object") k = "Dynamic"; + //if (k == "Dynamic" || k == "Object" || k == CommonImports.ObjectImport) { + //if (k == "Object" || k == CommonImports.ObjectImport) k = "Dynamic"; //write("haxe.ds.ObjectMap<" + k + ", "); //} else if (k == "Float" || k == "Class" || k == "Class") { //write("Dictionary<" + k + ","); @@ -3017,8 +3041,11 @@ class Writer //write("Map<" + k + ","); //} //write(v + ">("); - if (k == "Dynamic") k = "Object"; - write("new Dictionary<" + k + "," + v + ">("); + if (k == "Dynamic" || k == CommonImports.ObjectType || k == CommonImports.ObjectImport && cfg.useOpenFlTypes) { + write("new Dictionary<{}, " + v + ">("); + } else { + write("new Dictionary<" + k + ", " + v + ">("); + } } inline function writeENew(t : T, params : Array):Void { @@ -3089,7 +3116,7 @@ class Writer writeDictionaryTypeConstructor(ks, kv); isDictionary = true; } - case TPath(p) if (p[0] == "Object" || p[0] == "openfl.utils.Object"): isObject = true; + case TPath(p) if (p[0] == "Object" || p[0] == CommonImports.ObjectType || p[0] == CommonImports.ObjectImport): isObject = true; case TPath(p) if (p[0] == "ByteArray" || p[0] == "openfl.utils.ByteArray"): writeExpr(getCompatCallExpr("newByteArray", params)); handled = true; @@ -3183,7 +3210,7 @@ class Writer } case EArray(e, index): var t:String = getExprType(e); - if (isMapType(t) || isOpenFlDictionaryType(t)) { + if (isMapType(t) || isOpenFlDictionaryType(t) || isDynamicType(t)) { nullable = true; } case EIdent("null"): @@ -3236,7 +3263,7 @@ class Writer case EBinop("&&", e1, e2, nl): e = ETernary(EUnop("!", true, e1), e1, e2); case ECall(EVector(t), params): - if (type == "Object" || type == "openfl.utils.Object" || (isVectorType(type) && getExprType(e) != type)) { + if (type == "Object" || type == CommonImports.ObjectType || type == CommonImports.ObjectImport || (isVectorType(type) && getExprType(e) != type)) { write("cast "); } default: @@ -3259,7 +3286,7 @@ class Writer write(".remove("); writeExpr(index); write(")"); - } else if (atype == "Dynamic" || atype == "Object" || atype == "openfl.utils.Object") { + } else if (atype == "Dynamic" || atype == "Object" || atype == CommonImports.ObjectType || atype == CommonImports.ObjectImport) { switch(index) { case EConst(c): switch(c) { @@ -3284,7 +3311,7 @@ class Writer addWarning("EDelete"); writeNL("This is an intentional compilation error. See the README for handling the delete keyword"); writeIndent('delete ${getIdentString(object)}[${getIdentString(index)}]'); - writeInComment(atype); + write("/* " + atype + " */"); } } } @@ -3412,7 +3439,7 @@ class Writer return switch(t) { case "Bool": null; - case null: + case null, "Dynamic": ECall(EField(EIdent("AS3"), "as"), [e, EIdent("Bool")]); case "Int" | "UInt": EBinop("!=", e, EConst(CInt("0")), false); @@ -3496,10 +3523,10 @@ class Writer result = ECall(rebuiltExpr, params); } else if (isDynamicType(type)) { //Reflect.hasField(e, f); - var e1:Expr = params[0]; - if (getExprType(e1) != "String") { - e1 = getToStringExpr(e1); - } + var e1:Expr = params[0]; + if (getExprType(e1) != "String") { + e1 = getToStringExpr(e1); + } result = ECall(EField(EIdent("Reflect"), "hasField"), [e, e1]); } else if (true || isClassType(type)) { result = ECall(EField(EIdent("AS3"), "hasOwnProperty"), [e, params[0]]); @@ -3991,11 +4018,11 @@ class Writer } function prepareObjectFieldName(name:String):String { - if (validVariableNameEReg.match(name)) { - return name; - } else { + //if (validVariableNameEReg.match(name)) { + //return name; + //} else { return '"' + name + '"'; - } + //} } /** @@ -4025,7 +4052,7 @@ class Writer return s != null && (s.indexOf("Vector<") == 0 || s.indexOf("openfl.Vector<") == 0 || s.indexOf(cfg.arrayTypePath + "<") == 0); } - static inline function isDynamicType(s:String):Bool return s == "Dynamic" || s == "Object" || s == "openfl.utils.Object"; + static inline function isDynamicType(s:String):Bool return s == "Dynamic" || s == "Object" || s == CommonImports.ObjectType || s == CommonImports.ObjectImport; inline function isMapType(s:String):Bool { return s != null && (s.indexOf("Map") == 0 || s.indexOf("haxe.ds.ObjectMap") == 0); @@ -4039,9 +4066,22 @@ class Writer return s != null && (s.indexOf("Dictionary") == 0 || s.indexOf("openfl.utils.Dictionary") == 0) && cfg.useOpenFlTypes; } + inline function isFunctionType(type:String):Bool { + if (type == "Function" || type == "haxe.Constraints.Function") return true; + if (type == null) return false; + var delimeters:Array = []; + Typer.getTypeParams(type, delimeters); + var level:Int = 0; + for (d in delimeters) { + if (d == "<" || d == "(") level++; + if (d == ">" || d == ")") level--; + if (d == "->" && level == 0) return true; + } + return false; + } + inline function isFunctionExpr(e:Expr):Bool { - var type:String = getExprType(e); - return type == "Function" || type == "haxe.Constraints.Function" || (type != null && type.indexOf("->") != -1); + return isFunctionType(getExprType(e)); } inline function isIntExpr(e:Expr):Bool { From 951fae4eecf4f15a2112beea4981932a17572f02 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 8 Feb 2019 17:42:16 +0300 Subject: [PATCH 135/156] alternative switch case formatting --- src/as3hx/Writer.hx | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 0c6f770..aa6dc9f 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1612,21 +1612,23 @@ class Writer } write(":"); - //prevent switch case indenting if begins - //with block expr - var didIndent = if (shouldIndentCase(c.el)) { - lvl++; - true; - } else { - false; + // consume and ignore block {} in switch + function writeCase(e:Expr):Void { + switch(e) { + case ENL(e): writeCase(e); + case EBlock(exprs): + for (inBlockExpr in exprs) { + writeFinish(writeExpr(inBlockExpr)); + } + default: + writeFinish(writeExpr(ENL(e))); + } } - - for (i in 0...c.el.length) - { - writeFinish(writeExpr(c.el[i])); + lvl++; + for (e in c.el) { + writeCase(e); } - if (didIndent) - lvl--; + lvl--; } if(def != null) { writeSwitchDefault(def); From 3476cf1b31dadd5681aa59e190fb0f0ff64c086e Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 8 Feb 2019 17:45:12 +0300 Subject: [PATCH 136/156] js Boolean cast --- src/AS3.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AS3.hx b/src/AS3.hx index 021d628..55497ca 100644 --- a/src/AS3.hx +++ b/src/AS3.hx @@ -39,7 +39,7 @@ class AS3 { public static inline function asBool(e:Dynamic):Bool { #if (js || flash) - return untyped e ? __js__("true") : __js__("false"); + return untyped Boolean(e); #else return e != false && e != null && e != 0 && !(Std.is(e, String) && e.length == 0); #end From b14037b8a58fca6646048b0be619dd321c5d219f Mon Sep 17 00:00:00 2001 From: Xmitre Date: Fri, 8 Feb 2019 19:40:03 +0300 Subject: [PATCH 137/156] field call on Dynamic type left intact (replace, split, etc on untyped data) --- src/as3hx/Writer.hx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index aa6dc9f..c4f9e8e 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -2217,7 +2217,14 @@ class Writer var tstring:String = typer.getExprType(expr); var types:Array = tstring == null ? [] : tstring.split("->"); - writeExpr(expr); + + switch(expr) { + case EField(e, f) if(isDynamicType(getExprType(e))): + writeExpr(e); + write("." + f); + default: + writeExpr(expr); + } write("("); var enl = false; var hadArguments:Bool = false; From 445f6874598f8bff6188da25c0f4b0855ca33cbe Mon Sep 17 00:00:00 2001 From: xmitre Date: Tue, 19 Mar 2019 23:43:52 +0300 Subject: [PATCH 138/156] Update README.md --- README.md | 108 ++++++++++++++++++++++++++---------------------------- 1 file changed, 51 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 8e81b04..a3087cf 100644 --- a/README.md +++ b/README.md @@ -61,62 +61,56 @@ http://www.kirupa.com/forum/showthread.php?223798-ActionScript-3-Tip-of-the-Day/ E4X is currently partly done. This will fail in some cases, just examine source and output carefully. -#### For Initializations: -The output of - -```as3 -if (true) { - for (var i:uint = 0; i < 7; i++) - val += "0"; -} else { - for (i = 0; i < 8; i++) - val += "0"; -} -``` - -is - -```haxe -if (true) { - var i:UInt = 0; - while (i < 7) { - val += "0"; - i++; +### AS3 markup +You can use comments in ActionScript 3 code to enchance quality of conversion + +#### Haxe code injection +Use comment `/*haxe:*/` in arbitrary place in code to inject enclosed string as a raw Haxe code. + + /*haxe: + methodToCallInHaxe(); + */ + + var trueInHaxe:Boolean = /*haxe:true;//*/false; + +Use conditional compilation blocks to hide AS3 code from Haxe compiler + + CONFIG::AS3 { + methodToCallInAs3(); } -} else { - i = 0; - while (i < 8) { - val += "0"; - i++; + +#### Type hints +Use comment `/*haxe:*/` after AS3 type to override AS3 type with type from comment. + + var o:*/*haxe:utils.RawData*/ = {}; + +You can use it to define strict Haxe function types: + + function registerCallback(callback:Function/*haxe:Event->Void*/):void { } + + + +Use comment `/*<>*/` to force Haxe type parameters on AS3 types: + + var b:Dictionary = new Dictionary/**/(); + + public class ItemRenderer/**/ { } -} -``` - -As you can see, the scope of `i` in Flash is not the same as in Haxe, -so the `else` section will produce Unknown identifier : i. The solution -is to move the `var i : UInt = 0;` outside of the blocks in the generated -code. - -This can not be avoided by always creating the `i` variable, as the code - -```as3 -for (var i:uint = 0; i < 7; i++) - val += "0"; -for (i = 0; i < 8; i++) - val += "0"; -``` - -would then produce a double initialization of `i`, also causing a compiler error. - -```haxe -var i:UInt = 0; -while (i < 7) { - val += "0"; - i++; -} -var i = 0; -while (i < 8) { - val += "0"; - i++; -} -``` + +### Conversion tips +The bigger part of the complete project is converted at once, the better results you will get since type info takes a great role in conversion. + +You can chain src paths `neko as3hx.n "src\path\1" "src\path\2" "src\path\2"` if your project has more than one src path. + +Use `-libPath "path\to\as3\classes"` command line parameter to define path with all related code that should be taken into account during conversion but should not be converted by itself. The internal directory structure is not important since only package names are taken into consideration. + +For better results include interfaces to swc libraries that you use in your project. You can decompile swcs to get such interfaces. + +It's a good idea to include decompiled interfaces from playerglobal.swc to enhance interaction with Flash API. + + + +### Disclaimer +This fork is made for a single project in mind. So there are probably some breaking changes in formatting of converted code for different code styles. + +Also there are no publicly available test cases for added functionality. From 98b2127afebda9411be113dc96709014924c6e93 Mon Sep 17 00:00:00 2001 From: Xmitre Date: Tue, 19 Mar 2019 23:49:01 +0300 Subject: [PATCH 139/156] minor refactoring and clean up --- src/AS3.hx | 56 +---- src/as3hx/ForLoopRebuild.hx | 41 ++-- src/as3hx/VarExprFix.hx | 469 +++++++++++++++++++----------------- 3 files changed, 276 insertions(+), 290 deletions(-) diff --git a/src/AS3.hx b/src/AS3.hx index 55497ca..e5abcea 100644 --- a/src/AS3.hx +++ b/src/AS3.hx @@ -33,7 +33,6 @@ class AS3 { } public static inline function asFloat(e:Dynamic):Float { - //return cast(e, Float); return as3hx.Compat.parseFloat(e); } @@ -55,41 +54,15 @@ class AS3 { } public static macro function as(e:Expr, type:Expr):Expr { - //switch(Context.typeof(e)) { - switch(type.expr) { - //case EConst(CIdent("Dictionary")): return macro Std.is($e, haxe.Constraints.IMap) ? $e : null; - case EConst(CIdent("Dictionary")): return macro AS3.asDictionary($e); + return switch(type.expr) { + case EConst(CIdent("Dictionary")): macro AS3.asDictionary($e); #if openfl - case EConst(CIdent("Object")): return macro AS3.asObject($e); + case EConst(CIdent("Object")): macro AS3.asObject($e); #end - case EConst(CIdent("Float")): return macro AS3.asFloat($e); - case EConst(CIdent("Bool")): return macro AS3.asBool($e); - - //write("(try cast("); - //writeExpr(e1); - //write(", "); - //switch(e2) { - //case EIdent(s): writeModifiedIdent(s); - //default: writeExpr(e2); - //} - //case TAbstract(t, _) if(t.get().name == "Dictionary"): return macro Std.is($e, haxe.Constraints.IMap) ? $e : null; - //case TInst(t, _) if(t.get().pack.length == 0): t.get().name; - case _: + case EConst(CIdent("Float")): macro AS3.asFloat($e); + case EConst(CIdent("Bool")): macro AS3.asBool($e); + default: macro AS3.asClass($e, $type); } - //throw Context.typeExpr(type); - //throw Context.typeof(type); - return macro AS3.asClass($e, $type); - //return macro { - //cast AS3.AS(${e}, ${type}); - //cast(AS3.AS(${e}, ${type}), ); - //} - //return switch(type) { - //case "Int": macro ${e}; - //case "Float": macro Std.int(${e}); - //case "String": macro @:privateAccess as3hx.Compat._parseInt(${e}, ${base}); - //case "Bool": macro ${e} ? 1 : 0; - //case _: macro Std.parseInt(Std.string(${e})); - //} } public static inline function hasOwnProperty(o:Dynamic, field:String):Bool { @@ -186,24 +159,7 @@ class AS3 { /** * Converts a typed expression into an Int. */ - //#if js macro public static function int(e:ExprOf, ?base:ExprOf):ExprOf { return macro untyped ~~${e}; } - //#else - //macro public static function int(e:ExprOf, ?base:ExprOf):ExprOf { - //var type = switch(Context.typeof(e)) { - //case TAbstract(t, _) if(t.get().pack.length == 0): t.get().name; - //case TInst(t, _) if(t.get().pack.length == 0): t.get().name; - //case _: null; - //} - //return switch(type) { - //case "Int": macro ${e}; - //case "Float": macro Std.int(${e}); - //case "String": macro as3hx.Compat.parseInt(${e}, ${base}); - //case "Bool": macro ${e} ? 1 : 0; - //case _: return macro as3hx.Compat.parseInt(Std.string(${e}), ${base}); - //} - //} - //#end } \ No newline at end of file diff --git a/src/as3hx/ForLoopRebuild.hx b/src/as3hx/ForLoopRebuild.hx index a6ba5fd..1272b1c 100644 --- a/src/as3hx/ForLoopRebuild.hx +++ b/src/as3hx/ForLoopRebuild.hx @@ -1,7 +1,6 @@ package as3hx; import as3hx.As3.Expr; import as3hx.RebuildUtils.RebuildResult; -import neko.Lib; /** * ... @@ -46,10 +45,10 @@ class ForLoopRebuild return null; } } - + public function replaceForLoopsWithWhile(expressions:Array):Array { forLoopNum = 0; - + var re:Array = rebuildLookUpPassArray(expressions); var rexpr:Expr = RebuildUtils.rebuild(EBlock(expressions), rebuildLookUpPass); switch(rexpr) { @@ -58,7 +57,7 @@ class ForLoopRebuild expressions = es; default: } - + forLoopNum = 0; re = RebuildUtils.rebuildArray(expressions, rebuildReplacePass); if (re != null) { @@ -66,7 +65,7 @@ class ForLoopRebuild } return expressions; } - + private function openBlockContext():Void { loopsListPerLoopVarStack.push(loopsListPerLoopVar); @@ -101,7 +100,7 @@ class ForLoopRebuild if (r == null) { r = expr; } - + var condition:Expr; if (conds.length == 0) { condition = EIdent("true"); @@ -111,19 +110,19 @@ class ForLoopRebuild condition = EBinop("&&", condition, conds[i], false); } } - + var whileBody:Array = switch(r) { case EBlock(e): e; default: [r]; } whileBody = whileBody.concat(incrs); - + var result:Array = []; for (init in inits) { result.push(init); } result.push(EWhile(condition, EBlock(whileBody), false)); - + return result; } @@ -151,12 +150,12 @@ class ForLoopRebuild case EFor(inits, conds, incrs, e): if (loopNumToReplace.exists(forLoopNum++)) { var res:Array = convertEForToEWhile(inits, conds, incrs, e); - + var resRebuild:Array = RebuildUtils.rebuildArray(res, rebuildReplacePass); if (resRebuild != null) { res = resRebuild; } - + return RebuildResult.RReplaceArray(res); } default: @@ -182,12 +181,12 @@ class ForLoopRebuild if (loopsListPerLoopVar.exists(loopVariable)) { for (f in loopsListPerLoopVar.get(loopVariable)) { loopNumToReplace.set(f.num, true); - + } loopsListPerLoopVar.remove(loopVariable); } } - + private function processLookUpPassExpr(expr:Expr):Void { var loopVariablesAccess:Map = getOverwrittenIdents(expr, loopsListPerLoopVar); for (loopVariable in loopVariablesAccess.keys()) { @@ -214,7 +213,7 @@ class ForLoopRebuild loop.expr = expr; loop.num = forLoopNum++; storeLoop(loopVariable, loop); - + var r:Expr = RebuildUtils.rebuild(e, rebuildLookUpPass); if (r != null) { return RebuildResult.RReplace(EFor(inits, conds, incrs, r)); @@ -235,7 +234,7 @@ class ForLoopRebuild } return null; } - + private static function canUseForLoop(inits:Array, conds:Array, incrs:Array, e:Expr):Bool { if (inits.length == 0 || conds.length != 1 || incrs.length != 1) return false; var loopVariable:String = getForLoopVariable(incrs); @@ -268,7 +267,7 @@ class ForLoopRebuild } default: return false; } - + // if variable is not incremented by 1, no FOR switch(incrs[0]) { case EUnop("++", _, e1): @@ -287,10 +286,10 @@ class ForLoopRebuild if (checkIfUsesIdentForWriting(loopVariable, e, false)) { return false; } - + return true; } - + private function getOverwrittenIdents(e:Expr, blockContext:Map>):Map { var result:Map = new Map(); for (key in loopsListPerLoopVar.keys()) { @@ -302,7 +301,7 @@ class ForLoopRebuild } return result; } - + public static function checkIfUsesIdentValue(ident:String, expr:Expr):Bool { var wasUsed:Bool = false; function rebuild(e:Expr):RebuildResult { @@ -361,7 +360,7 @@ class ForLoopRebuild RebuildUtils.rebuild(expr, rebuild); return wasUsed; } - + public static function checkIfUsesIdentForWriting(ident:String, expr:Expr, definitelyOverwritten:Bool):Bool { var result:Bool = false; function rebuild(e:Expr):RebuildResult { @@ -397,7 +396,7 @@ class ForLoopRebuild RebuildUtils.rebuild(expr, rebuild); return result; } - + public static function isIdent(e:Expr, ident:String):Bool { switch(e) { case EParent(e): return isIdent(e, ident); diff --git a/src/as3hx/VarExprFix.hx b/src/as3hx/VarExprFix.hx index 61773f3..72eb5bb 100644 --- a/src/as3hx/VarExprFix.hx +++ b/src/as3hx/VarExprFix.hx @@ -17,258 +17,289 @@ class VarExprFix } public function apply(f:Function, es:Array, typer:Typer):Array { - var map:Map = typer.getContextClone(0); - var localVar:Map = new Map(); - var firstUse:Map = new Map(); - var firstUseLine:Map> = new Map>(); - var blockVars:Array = new Array(); - var restrictedVars:Array = new Array(); - var varsToIgnore:Array = new Array(); - var localFunctionVars:Map; - var hasVarsToInsert:Bool = false; - var inLocalFunction:Bool = false; - var line:Int = 0; - var depth:Int = 0; + return new VarExprFixImplementation(cfg, f, es, typer).getResult(); + } +} + + +private class VarExprFixImplementation +{ + private static inline var FIRST_USE_IN_HEADER:Int = -1; + private static inline var FIRST_USE_IN_VAR:Int = -2; + + var cfg:Config; + var typer:Typer; + var result:Array; + + var f:Function; + var map:Map; + var localVar:Map = new Map(); + var firstUse:Map = new Map(); + var firstUseVarsByLine:Map> = new Map>(); + var blockVars:Array = new Array(); + var restrictedVars:Array = new Array(); + var varStatementsToReplace:Array = new Array(); + var localFunctionVars:Map; + var hasVarsToInsert:Bool = false; + var inLocalFunction:Bool = false; + var line:Int = 0; + var depth:Int = 0; + + public function new(cfg:Config, f:Function, es:Array, typer:Typer):Void { + this.cfg = cfg; + this.f = f; + this.typer = typer; + + map = typer.getContextClone(0); + for (v in map.keys()) { - firstUse.set(v, -1); + firstUse.set(v, FIRST_USE_IN_HEADER); localVar.set(v, false); } for (arg in f.args) { - firstUse.set(arg.name, -1); + firstUse.set(arg.name, FIRST_USE_IN_HEADER); localVar.set(arg.name, true); } if (f.varArgs != null && !cfg.replaceVarArgsWithOptionalArguments) { - firstUse.set(f.varArgs, -1); + firstUse.set(f.varArgs, FIRST_USE_IN_HEADER); localVar.set(f.varArgs, true); } - function rebuildMethodCleanUp(e:Expr):RebuildResult { - switch(e) { - case EVars(vars/*Array<{ name : String, t : Null, val : Null }>*/): - var newVars:Array = []; - var hasChange:Bool = false; - for (vr in vars) { - var v:String = vr.name; - if (varsToIgnore.indexOf(v) != -1 && (!firstUseLine.exists(line) || firstUseLine.get(line).indexOf(v) == -1)) { - hasChange = true; - if (firstUseLine.exists(line)) { - firstUseLine.get(line).push(v); - } else { - firstUseLine.set(line, [v]); - hasVarsToInsert = true; - } - if (vr.val != null) { - newVars.push(EBinop("=", EIdent(v), vr.val, false)); - } - } else { - newVars.push(EVars([vr])); - } - } - if (hasChange) { - return RebuildResult.RReplaceArray(newVars); - } - case EFunction(f, name): - return RebuildResult.RSkip; - default: - } - return null; + es = rebuildByLine(es, rebuildMethodLookForVars); + if (varStatementsToReplace.length > 0) { + es = rebuildByLine(es, rebuildMethodCleanUp); } - function rebuildMethodGetLocalFunctionVars(e:Expr):RebuildResult { - switch (e) { - case EFunction(f, name): return RebuildResult.RSkip; - case EVars(vars): - for (vr in vars) { - localFunctionVars.set(vr.name, true); - } - return RebuildResult.RSkip; - default: return null; + if (hasVarsToInsert) { + es = rebuildByLine(es, rebuildMethodInsertVars); + } + result = es; + } + + public function getResult():Array { + return result; + } + + function rebuildByLine(es:Array, rebuildMethod:Expr->RebuildResult):Array { + var needRebuild:Bool = false; + var rs:Array = new Array(); + for (i in 0...es.length) { + line = i; + if (RebuildUtils.rebuildToArray(es[i], rebuildMethod, rs)) { + needRebuild = true; } } - function rebuildMethodLookForVars(e:Expr):RebuildResult { - switch(e) { - case EFor(inits, conds, incrs, e): - if (inLocalFunction) return null; - depth++; - var oldBlockVars:Array = blockVars; - blockVars = new Array(); + if (needRebuild) { + return rs; + } else { + return es; + } + } - var rinits:Array = RebuildUtils.rebuildArray(inits, rebuildMethodLookForVars); - var rconds:Array = RebuildUtils.rebuildArray(conds, rebuildMethodLookForVars); - var rincrs:Array = RebuildUtils.rebuildArray(incrs, rebuildMethodLookForVars); - var re:Expr = null; - switch(e) { - case EBlock(es): - var res:Array = RebuildUtils.rebuildArray(es, rebuildMethodLookForVars); - if (res != null) re = EBlock(res); - default: - re = RebuildUtils.rebuild(e, rebuildMethodLookForVars); - } - for (v in blockVars) { - restrictedVars.push(v); - } - blockVars = oldBlockVars; - depth--; - if (rinits == null && rconds == null && rincrs == null && re == null) { - return RebuildResult.RSkip; + function rebuildMethodCleanUp(e:Expr):RebuildResult { + switch(e) { + case EVars(vars/*Array<{ name : String, t : Null, val : Null }>*/): + var newVars:Array = []; + var hasChange:Bool = false; + for (vr in vars) { + var v:String = vr.name; + if (varStatementsToReplace.indexOf(v) != -1 && (!firstUseVarsByLine.exists(line) || firstUseVarsByLine.get(line).indexOf(v) == -1)) { + hasChange = true; + setFirstUseLine(v, line); + if (vr.val != null) { + newVars.push(EBinop("=", EIdent(v), vr.val, false)); + } } else { - if (rinits == null) rinits = inits; - if (rconds == null) rconds = conds; - if (rincrs == null) rincrs = incrs; - if (re == null) re = e; - return RebuildResult.RReplace(EFor(rinits, rconds, rincrs, re)); - } - case EBlock(es): - if (inLocalFunction) return null; - depth++; - var oldBlockVars:Array = blockVars; - blockVars = new Array(); - var r:Array = RebuildUtils.rebuildArray(es, rebuildMethodLookForVars); - for (v in blockVars) { - restrictedVars.push(v); + newVars.push(EVars([vr])); } - blockVars = oldBlockVars; - depth--; - if (r == null) { + } + if (hasChange) { + return RebuildResult.RReplaceArray(newVars); + } + case EFunction(f, name): + return RebuildResult.RSkip; + default: + } + return null; + } + + function rebuildMethodGetLocalFunctionVars(e:Expr):RebuildResult { + switch (e) { + case EFunction(f, name): return RebuildResult.RSkip; + case EVars(vars): + for (vr in vars) { + localFunctionVars.set(vr.name, true); + } + return RebuildResult.RSkip; + default: return null; + } + } + + function rebuildMethodLookForVars(e:Expr):RebuildResult { + switch(e) { + case EFor(inits, conds, incrs, e): + if (inLocalFunction) return null; + depth++; + var oldBlockVars:Array = blockVars; + blockVars = new Array(); + + var rinits:Array = RebuildUtils.rebuildArray(inits, rebuildMethodLookForVars); + var rconds:Array = RebuildUtils.rebuildArray(conds, rebuildMethodLookForVars); + var rincrs:Array = RebuildUtils.rebuildArray(incrs, rebuildMethodLookForVars); + var re:Expr = null; + switch(e) { + case EBlock(es): + var res:Array = RebuildUtils.rebuildArray(es, rebuildMethodLookForVars); + if (res != null) re = EBlock(res); + default: + re = RebuildUtils.rebuild(e, rebuildMethodLookForVars); + } + for (v in blockVars) { + restrictedVars.push(v); + } + blockVars = oldBlockVars; + depth--; + if (rinits == null && rconds == null && rincrs == null && re == null) { + return RebuildResult.RSkip; + } else { + if (rinits == null) rinits = inits; + if (rconds == null) rconds = conds; + if (rincrs == null) rincrs = incrs; + if (re == null) re = e; + return RebuildResult.RReplace(EFor(rinits, rconds, rincrs, re)); + } + case EBlock(es): + if (inLocalFunction) return null; + depth++; + var oldBlockVars:Array = blockVars; + blockVars = new Array(); + var r:Array = RebuildUtils.rebuildArray(es, rebuildMethodLookForVars); + for (v in blockVars) { + restrictedVars.push(v); + } + blockVars = oldBlockVars; + depth--; + if (r == null) { + return RebuildResult.RSkip; + } else { + return RebuildResult.RReplace(EBlock(r)); + } + case EIdent(v): + if (v != null) { + if (inLocalFunction && localFunctionVars.exists(v)) { return RebuildResult.RSkip; - } else { - return RebuildResult.RReplace(EBlock(r)); } - case EIdent(v): - if (v != null) { - if (inLocalFunction && localFunctionVars.exists(v)) { - return RebuildResult.RSkip; - } - if (!localVar.exists(v)) { - if (!inLocalFunction && v == "arguments") { - var arguments:Array = []; - for (arg in f.args) { - arguments.push(EIdent(arg.name)); - } - return RebuildResult.RReplace(ECommented("/*arguments*/", true, true, EArrayDecl(arguments))); + if (!localVar.exists(v)) { + if (!inLocalFunction && v == "arguments") { + var arguments:Array = []; + for (arg in f.args) { + arguments.push(EIdent(arg.name)); } - return null; - } - if (!firstUse.exists(v) || firstUse.get(v) == -1) { - firstUse.set(v, line); - if (firstUseLine.exists(line)) { - firstUseLine.get(line).push(v); - } else { - firstUseLine.set(line, [v]); - hasVarsToInsert = true; - } - } else if (restrictedVars.indexOf(v) != -1) { - varsToIgnore.push(v); - restrictedVars.remove(v); + return RebuildResult.RReplace(ECommented("/*arguments*/", true, true, EArrayDecl(arguments))); } + return null; } - case EFunction(f, name): - if (name != null) { - map.set(name, "Function"); + if (!firstUse.exists(v) || firstUse.get(v) == FIRST_USE_IN_HEADER) { + firstUse.set(v, line); + setFirstUseLine(v, line); + } else if (restrictedVars.indexOf(v) != -1) { + varStatementsToReplace.push(v); + restrictedVars.remove(v); } - var oldInLocalFunction = inLocalFunction; - inLocalFunction = true; - localFunctionVars = new Map(); - RebuildUtils.rebuild(f.expr, rebuildMethodGetLocalFunctionVars); - var rexpr = RebuildUtils.rebuild(f.expr, rebuildMethodLookForVars); - inLocalFunction = oldInLocalFunction; - if (rexpr == null) return RebuildResult.RSkip; - return RebuildResult.RReplace(EFunction({args:f.args, varArgs:f.varArgs, ret:f.ret, expr:rexpr}, name)); - case EVars(vars/*Array<{ name : String, t : Null, val : Null }>*/): - if (inLocalFunction) { - return RebuildResult.RSkip; - } - var newVars:Array = []; - var hasChange:Bool = false; - for (vr in vars) { - var v:String = vr.name; - if (!localVar.exists(v)) continue; - if (firstUse.exists(v) && firstUse.get(v) != -1) { - hasChange = true; - if (vr.val != null) { - newVars.push(EBinop("=", EIdent(v), vr.val, false)); - } - if (restrictedVars.indexOf(v) != -1) { - varsToIgnore.push(v); - restrictedVars.remove(v); - } - } else { - if (depth > 0) { - blockVars.push(v); - } - newVars.push(EVars([vr])); + } + case EFunction(f, name): + if (name != null) { + map.set(name, "Function"); + } + var oldInLocalFunction = inLocalFunction; + inLocalFunction = true; + localFunctionVars = new Map(); + RebuildUtils.rebuild(f.expr, rebuildMethodGetLocalFunctionVars); + var rexpr = RebuildUtils.rebuild(f.expr, rebuildMethodLookForVars); + inLocalFunction = oldInLocalFunction; + if (rexpr == null) return RebuildResult.RSkip; + return RebuildResult.RReplace(EFunction({args:f.args, varArgs:f.varArgs, ret:f.ret, expr:rexpr}, name)); + case EVars(vars/*Array<{ name : String, t : Null, val : Null }>*/): + if (inLocalFunction) { + return RebuildResult.RSkip; + } + var newVars:Array = []; + var hasChange:Bool = false; + for (vr in vars) { + var v:String = vr.name; + if (!localVar.exists(v)) continue; + if (firstUse.exists(v) && firstUse.get(v) != FIRST_USE_IN_HEADER) { + hasChange = true; + if (vr.val != null) { + newVars.push(EBinop("=", EIdent(v), vr.val, false)); } - firstUse.set(v, -2); - localVar.set(v, true); - map.set(v, typer.tstring(vr.t)); - } - if (hasChange) { - return RebuildResult.RReplaceArray(newVars); + if (restrictedVars.indexOf(v) != -1) { + varStatementsToReplace.push(v); + restrictedVars.remove(v); + } + } else { + if (depth > 0) { + blockVars.push(v); + } + newVars.push(EVars([vr])); } - default: - } - return null; + firstUse.set(v, FIRST_USE_IN_VAR); + localVar.set(v, true); + map.set(v, typer.tstring(vr.t)); + } + if (hasChange) { + return RebuildResult.RReplaceArray(newVars); + } + default: } - function rebuildMethodInsertVars(e:Expr):RebuildResult { - if (firstUseLine.exists(line)) { - var res:Array = null; - for (name in firstUseLine.get(line)) { - if (firstUse.get(name) != -2) continue; - var type:String = map.get(name); - if (type == null || type == "Function") continue; - var defaultValue:Expr = null; - switch(type) { + return null; + } + + function rebuildMethodInsertVars(e:Expr):RebuildResult { + if (firstUseVarsByLine.exists(line)) { + var res:Array = null; + for (name in firstUseVarsByLine.get(line)) { + if (firstUse.get(name) != FIRST_USE_IN_VAR) continue; + var type:String = map.get(name); + if (type == null || type == "Function") continue; + var defaultValue:Expr = switch(type) { case "int", "Int", "UInt": - defaultValue = EConst(CInt("0")); + EConst(CInt("0")); case "Float": - defaultValue = EConst(CInt("Math.NaN")); + EConst(CInt("Math.NaN")); default: - defaultValue = EIdent("null"); - } - if (res == null) res = []; - res.push(ENL(EVars([ { name:name, t:TPath([type]), val:defaultValue } ]))); + EIdent("null"); } - if (res != null && res.length > 0) { - var te:Expr = e; - var newLines:Int = 0; - while (true) { - switch(te) { - case ENL(e): - te = e; - newLines++; - default: - break; - } - } - while (newLines-- > 1) { - res[0] = ENL(res[0]); + if (res == null) res = []; + res.push(ENL(EVars([ { name:name, t:TPath([type]), val:defaultValue } ]))); + } + if (res != null && res.length > 0) { + var te:Expr = e; + var newLines:Int = 0; + while (true) { + switch(te) { + case ENL(e): + te = e; + newLines++; + default: + break; } - res.push(ENL(te)); - return RebuildResult.RReplaceArray(res); } - } - return RebuildResult.RSkip; - } - function rebuildByLine(es:Array, rebuildMethod:Expr->RebuildResult):Array { - var needRebuild:Bool = false; - var rs:Array = new Array(); - for (i in 0...es.length) { - line = i; - if (RebuildUtils.rebuildToArray(es[i], rebuildMethod, rs)) { - needRebuild = true; + while (newLines-- > 1) { + res[0] = ENL(res[0]); } + res.push(ENL(te)); + return RebuildResult.RReplaceArray(res); } - if (needRebuild) { - return rs; - } else { - return es; - } - } - es = rebuildByLine(es, rebuildMethodLookForVars); - if (varsToIgnore.length > 0) { - es = rebuildByLine(es, rebuildMethodCleanUp); } - if (hasVarsToInsert) { - es = rebuildByLine(es, rebuildMethodInsertVars); + return RebuildResult.RSkip; + } + + + private function setFirstUseLine(varName:String, line:Int):Void { + if (firstUseVarsByLine.exists(line)) { + firstUseVarsByLine.get(line).push(varName); + } else { + firstUseVarsByLine.set(line, [varName]); + hasVarsToInsert = true; } - return es; } } \ No newline at end of file From 7fbd395c684991d726f531500f74110017ae31e1 Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Sat, 6 Apr 2019 21:25:27 +0300 Subject: [PATCH 140/156] Add vscode --- .vscode/settings.json | 9 +++++++++ .vscode/tasks.json | 28 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..feea8e9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "haxeTestExplorer.testCommand": [ + "haxelib", + "run", + "munit", + "test", + "-neko" + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..3d5ce68 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,28 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "hxml", + "file": "as3hx.hxml", + "problemMatcher": [ + "$haxe-absolute", + "$haxe", + "$haxe-error", + "$haxe-trace" + ] + }, + { + "label": "test", + "type": "shell", + "command": ["neko", "run", "test/", "out/", "-convert-flexunit", "."], //"-debug-inferred-type" + "dependsOn": "build", + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} \ No newline at end of file From 2fe7db22084f56dc03573e67faa65dac6f1a9172 Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Sun, 7 Apr 2019 20:01:16 +0300 Subject: [PATCH 141/156] Add checkstyle and update tests --- checkstyle.json | 504 ++++++++++++++++++++ src/Run.hx | 33 +- src/as3hx/Config.hx | 78 ++- src/as3hx/ParserUtils.hx | 3 +- src/as3hx/Typer.hx | 8 +- src/as3hx/Writer.hx | 4 +- test/e2e/mxml/First.mxml | 20 + test/e2e/mxml/pack/Second.mxml | 16 + test/e2e/simple/Attr.hx | 15 +- test/e2e/simple/Dictionary.hx | 16 +- test/e2e/simple/ForLoop.hx | 13 +- test/e2e/simple/Func.hx | 17 +- test/e2e/simple/Interface.hx | 8 +- test/e2e/simple/Min.hx | 10 +- test/e2e/simple/Package.hx | 10 +- test/e2e/simple/Var.hx | 13 +- test/issues/Issue.as | 9 - test/issues/Issue.hx | 10 - test/issues/Issue103.hx | 17 +- test/issues/Issue112.hx | 23 +- test/issues/Issue115.hx | 72 ++- test/issues/Issue119_notUseCompat.hx | 21 +- test/issues/Issue119_useCompat.hx | 21 +- test/issues/Issue120.hx | 20 +- test/issues/Issue121.hx | 58 +-- test/issues/Issue124.hx | 33 +- test/issues/Issue128.hx | 22 +- test/issues/Issue133.hx | 31 +- test/issues/Issue134.hx | 37 +- test/issues/Issue139.hx | 31 +- test/issues/Issue14.hx | 18 +- test/issues/Issue142.hx | 21 +- test/issues/Issue143.hx | 10 +- test/issues/Issue144.hx | 30 +- test/issues/Issue148.hx | 16 +- test/issues/Issue15.hx | 194 ++++---- test/issues/Issue150.hx | 43 +- test/issues/Issue152.hx | 40 +- test/issues/Issue156.hx | 23 +- test/issues/Issue158.hx | 13 +- test/issues/Issue162.hx | 17 +- test/issues/Issue164.hx | 13 +- test/issues/Issue165.hx | 19 +- test/issues/Issue166.hx | 15 +- test/issues/Issue167.hx | 37 +- test/issues/Issue176.hx | 16 +- test/issues/Issue178.hx | 22 +- test/issues/Issue184.hx | 15 +- test/issues/Issue185.hx | 17 +- test/issues/Issue187.hx | 41 +- test/issues/Issue192.hx | 25 +- test/issues/Issue198.hx | 15 +- test/issues/Issue2.hx | 17 +- test/issues/Issue200.hx | 15 +- test/issues/Issue202.hx | 17 +- test/issues/Issue204.hx | 31 +- test/issues/Issue205.hx | 30 +- test/issues/Issue208.hx | 49 +- test/issues/Issue210.hx | 13 +- test/issues/Issue213.hx | 25 +- test/issues/Issue214.hx | 30 +- test/issues/Issue215.hx | 20 +- test/issues/Issue218.hx | 19 +- test/issues/Issue223.hx | 15 +- test/issues/Issue226.hx | 17 +- test/issues/Issue228.hx | 15 +- test/issues/Issue23.hx | 42 +- test/issues/Issue230.hx | 13 +- test/issues/Issue234.hx | 13 +- test/issues/Issue235.hx | 23 +- test/issues/Issue238.hx | 17 +- test/issues/Issue24.hx | 88 ++-- test/issues/Issue241.hx | 15 +- test/issues/Issue244.hx | 29 +- test/issues/Issue246.hx | 31 +- test/issues/Issue247.hx | 16 +- test/issues/Issue250.hx | 40 +- test/issues/Issue254.hx | 27 +- test/issues/Issue255.hx | 13 +- test/issues/Issue257.hx | 15 +- test/issues/Issue26.hx | 61 +-- test/issues/Issue261.hx | 15 +- test/issues/Issue261_1.hx | 19 +- test/issues/Issue261_2.hx | 17 +- test/issues/Issue264.hx | 44 +- test/issues/Issue265.hx | 13 +- test/issues/Issue27.hx | 24 +- test/issues/Issue273.hx | 56 ++- test/issues/Issue274.hx | 21 +- test/issues/Issue275.hx | 21 +- test/issues/Issue277.hx | 78 ++- test/issues/Issue28.hx | 61 ++- test/issues/Issue285.hx | 22 +- test/issues/Issue29.hx | 24 +- test/issues/Issue293.hx | 18 +- test/issues/Issue296.as | 24 + test/issues/Issue296.hx | 38 ++ test/issues/Issue296_1.as | 10 + test/issues/Issue296_1.hx | 14 + test/issues/Issue298.hx | 13 +- test/issues/Issue300.hx | 13 +- test/issues/Issue302.hx | 10 +- test/issues/Issue303.hx | 10 +- test/issues/Issue314.hx | 30 +- test/issues/Issue32.hx | 23 +- test/issues/Issue323.as | 12 + test/issues/Issue323.hx | 15 + test/issues/Issue36.hx | 15 +- test/issues/Issue37.hx | 15 +- test/issues/Issue38.hx | 26 +- test/issues/Issue52.hx | 13 +- test/issues/Issue53.hx | 20 +- test/issues/Issue54.hx | 13 +- test/issues/Issue63.hx | 19 +- test/issues/Issue64.hx | 44 +- test/issues/Issue65.hx | 30 +- test/issues/Issue66.hx | 21 +- test/issues/Issue68.hx | 23 +- test/issues/Issue69.hx | 15 +- test/issues/Issue70.hx | 22 +- test/issues/Issue71.hx | 34 +- test/issues/Issue81.hx | 17 +- test/issues/Issue83.hx | 15 +- test/issues/Issue85.hx | 13 +- test/issues/Issue87.hx | 48 +- test/issues/Issue89.hx | 28 +- test/issues/Issue91.hx | 15 +- test/issues/Issue93.hx | 17 +- test/issues/Issue94.hx | 35 +- test/issues/Issue95.hx | 28 +- test/issues/Issue96.hx | 15 +- test/unit/TestSuite.hx | 16 +- test/unit/as3hx/AS3HXTest.hx | 20 + test/unit/as3hx/CompatTest.hx | 2 +- test/unit/as3hx/parsers/ImportParserTest.hx | 5 +- 135 files changed, 2092 insertions(+), 1726 deletions(-) create mode 100644 checkstyle.json create mode 100644 test/e2e/mxml/First.mxml create mode 100644 test/e2e/mxml/pack/Second.mxml delete mode 100644 test/issues/Issue.as delete mode 100644 test/issues/Issue.hx create mode 100644 test/issues/Issue296.as create mode 100644 test/issues/Issue296.hx create mode 100644 test/issues/Issue296_1.as create mode 100644 test/issues/Issue296_1.hx create mode 100644 test/issues/Issue323.as create mode 100644 test/issues/Issue323.hx diff --git a/checkstyle.json b/checkstyle.json new file mode 100644 index 0000000..0be67b2 --- /dev/null +++ b/checkstyle.json @@ -0,0 +1,504 @@ +{ + "defaultSeverity": "INFO", + "checks": [ + { + "type": "Anonymous" + }, + { + "type": "ArrayAccess" + }, + { + "type": "ArrayLiteral" + }, + { + "type": "AvoidStarImport" + }, + { + "props": { + "format": "^(_|[a-z]*)$" + }, + "type": "CatchParameterName" + }, + { + "type": "ConditionalCompilation" + }, + { + "props": { + "ignoreExtern": true, + "tokens": [ + "INLINE" + ], + "format": "^[A-Z][A-Z0-9]*(_[A-Z0-9_]+)*$" + }, + "type": "ConstantName" + }, + { + "props": { + "thresholds": [ + { + "complexity": 32, + "severity": "WARNING" + }, + { + "complexity": 45, + "severity": "ERROR" + } + ] + }, + "type": "CyclomaticComplexity" + }, + { + "type": "DefaultComesLast" + }, + { + "type": "ERegLiteral" + }, + { + "props": { + "tokens": [ + "CLASS_DEF", + "ENUM_DEF", + "ABSTRACT_DEF", + "TYPEDEF_DEF", + "INTERFACE_DEF", + "OBJECT_DECL", + "FUNCTION", + "FOR", + "IF", + "WHILE", + "SWITCH", + "TRY", + "CATCH" + ], + "option": "empty" + }, + "type": "EmptyBlock" + }, + { + "props": { + "max": 1, + "requireEmptyLineAfterAbstract": false, + "requireEmptyLineAfterClass": false + }, + "type": "EmptyLines" + }, + { + "type": "EmptyPackage" + }, + { + "props": { + "max": 2000 + }, + "type": "FileLength" + }, + { + "props": { + "option": "upperCase" + }, + "type": "HexadecimalLiteral" + }, + { + "props": { + "ignoreSetter": true, + "ignoreFormat": "^(main|run|new)$", + "ignoreConstructorParameter": true + }, + "type": "HiddenField" + }, + { + "props": { + "character": "space" + }, + "type": "IndentationCharacter" + }, + { + "type": "InnerAssignment" + }, + { + "props": { + "allowMarkerInterfaces": true, + "allowProperties": false + }, + "type": "Interface" + }, + { + "props": { + "tokens": [ + "CLASS_DEF", + "ENUM_DEF", + "ABSTRACT_DEF", + "TYPEDEF_DEF", + "INTERFACE_DEF", + "FUNCTION", + "FOR", + "IF", + "WHILE", + "SWITCH", + "TRY", + "CATCH" + ], + "ignoreEmptySingleline": true, + "option": "eol" + }, + "type": "LeftCurly" + }, + { + "props": { + "max": 160, + "ignorePattern": "(^@desc)|(LONG LINE TEST)" + }, + "type": "LineLength" + }, + { + "props": { + "listeners": [ + "addEventListener", + "addListener", + "on", + "once" + ], + "format": "^_?[a-z][a-zA-Z0-9]*$" + }, + "type": "ListenerName" + }, + { + "props": { + "ignoreExtern": true, + "format": "^[_a-z][_a-zA-Z0-9]*$" + }, + "type": "LocalVariableName" + }, + { + "props": { + "ignoreNumbers": [-1, 0, 1, 2, 3, 5, 8, 13, 21, 34, 100, 1000] + }, + "type": "MagicNumber" + }, + { + "props": { + "ignoreExtern": true, + "format": "^[_a-z][_a-zA-Z0-9]*$", + "tokens": [ + "CLASS", + "PUBLIC", + "PRIVATE", + "TYPEDEF" + ] + }, + "type": "MemberName" + }, + { + "props": { + "ignoreExtern": true, + "format": "^[A-Z][A-z0-9_]*$", + "tokens": [ + "ENUM" + ] + }, + "type": "MemberName" + }, + { + "props": { + "maxPrivate": 50, + "maxPublic": 50, + "maxTotal": 50 + }, + "type": "MethodCount" + }, + { + "props": { + "max": 100 + }, + "type": "MethodLength" + }, + { + "props": { + "ignoreExtern": true, + "format": "^[_a-z][_a-zA-Z0-9]*$" + }, + "type": "MethodName" + }, + { + "props": { + "modifiers": [ + "MACRO", + "OVERRIDE", + "PUBLIC_PRIVATE", + "STATIC", + "INLINE", + "DYNAMIC" + ] + }, + "type": "ModifierOrder" + }, + { + "props": { + "minLength": 2, + "ignore": "^\\s+$", + "allowDuplicates": 2 + }, + "type": "MultipleStringLiterals" + }, + { + "type": "MultipleVariableDeclarations" + }, + { + "type": "NestedForDepth" + }, + { + "type": "NestedTryDepth" + }, + { + "props": { + "assignOpPolicy": "around", + "unaryOpPolicy": "none", + "ternaryOpPolicy": "around", + "arithmeticOpPolicy": "around", + "compareOpPolicy": "around", + "bitwiseOpPolicy": "around", + "boolOpPolicy": "around", + "intervalOpPolicy": "none", + "arrowPolicy": "around", + "functionArgPolicy": "around" + }, + "type": "OperatorWhitespace" + }, + { + "props": { + "tokens": [ + "=", + "+", + "-", + "*", + "/", + "%", + ">", + "<", + ">=", + "<=", + "==", + "!=", + "&", + "|", + "^", + "&&", + "||", + "<<", + ">>", + ">>>", + "+=", + "-=", + "*=", + "/=", + "%=", + "<<=", + ">>=", + ">>>=", + "|=", + "&=", + "^=", + "...", + "=>", + "++", + "--" + ], + "option": "eol" + }, + "type": "OperatorWrap" + }, + { + "props": { + "ignoreExtern": true, + "format": "^(_|[a-z][a-zA-Z0-9]*$)" + }, + "type": "ParameterName" + }, + { + "props": { + "max": 7, + "ignoreOverriddenMethods": false + }, + "type": "ParameterNumber" + }, + { + "props": { + "allowEmptyReturn": true, + "enforceReturnType": true + }, + "type": "Return" + }, + { + "props": { + "dotPolicy": "none", + "commaPolicy": "after", + "semicolonPolicy": "after" + }, + "type": "SeparatorWhitespace" + }, + { + "props": { + "tokens": [ + ",", + "." + ], + "option": "eol" + }, + "type": "SeparatorWrap" + }, + { + "type": "SimplifyBooleanExpression" + }, + { + "type": "SimplifyBooleanReturn" + }, + { + "props": { + "spaceIfCondition": true, + "spaceAroundBinop": true, + "spaceForLoop": true, + "ignoreRangeOperator": true, + "spaceWhileLoop": true, + "spaceCatch": true, + "spaceSwitchCase": true, + "noSpaceAroundUnop": true + }, + "type": "Spacing" + }, + { + "type": "TODOComment" + }, + { + "type": "TabForAligning" + }, + { + "props": { + "ignoreEnumAbstractValues": true + }, + "type": "Type" + }, + { + "props": { + "ignoreExtern": true, + "format": "^[A-Z]+[a-zA-Z0-9]*$" + }, + "type": "TypeName" + }, + { + "type": "UnnecessaryConstructor" + }, + { + "props": { + "tokens": [ + ",", + ";" + ] + }, + "type": "WhitespaceAfter" + }, + { + "props": { + "tokens": [ + "=", + "+", + "-", + "*", + "/", + "%", + ">", + "<", + ">=", + "<=", + "==", + "!=", + "&", + "|", + "^", + "&&", + "||", + "<<", + ">>", + ">>>", + "+=", + "-=", + "*=", + "/=", + "%=", + "<<=", + ">>=", + ">>>=", + "|=", + "&=", + "^=", + "=>" + ] + }, + "type": "WhitespaceAround" + }, + { + "type": "StringLiteral", + "props": { + "policy": "onlyDouble", + "allowException": true, + "severity": "WARNING" + } + } + ], + "exclude": { + "all": [ + "Sys" + ], + "Dynamic": [ + "checkstyle.Main", + "checkstyle.Checker", + "checkstyle.ChecksInfo", + "checkstyle.checks.Check", + "checkstyle.checks.Directive", + "checkstyle.checks.whitespace.SpacingCheck", + "checkstyle.checks.imports.UnusedImportCheck", + "TestMain", + "misc.ExtensionsTest", + "token.TokenTreeBuilderParsingTest" + ], + "MultipleStringLiterals": [ + "checks", + "token" + ], + "CyclomaticComplexity": [ + "checkstyle.checks.Check", + "checkstyle.utils.ExprUtils", + "checkstyle.utils.ComplexTypeUtils", + "checkstyle.checks.metrics.CyclomaticComplexityCheck", + "checkstyle.checks.block.LeftCurlyCheck", + "checkstyle.checks.block.RightCurlyCheck", + "checkstyle.checks.naming.MethodNameCheck", + "checkstyle.checks.type.ReturnCheck", + "checkstyle.checks.whitespace.OperatorWrapCheck", + "checkstyle.checks.whitespace.WhitespaceAfterCheck", + "checkstyle.checks.whitespace.WhitespaceAroundCheck", + "checkstyle.checks.block.EmptyBlockCheck", + "checkstyle.checks.whitespace.EmptyLinesCheck", + "checkstyle.token.walk.WalkStatement" + ], + "LeftCurly": [ + "checkstyle.checks.metrics.CyclomaticComplexityCheck" + ], + "RightCurly": [ + "checkstyle.checks.metrics.CyclomaticComplexityCheck" + ], + "MethodCount": [ + "checkstyle.token.TokenTreeBuilder" + ], + "MethodLength": [ + "checkstyle.checks.whitespace.WhitespaceAfterCheck", + "checkstyle.checks.whitespace.WhitespaceAroundCheck", + "checkstyle.checks.whitespace.EmptyLinesCheck", + "checkstyle.token.walk.WalkStatement" + ], + "NestedForDepth": [ + "TestMain" + ], + "MemberName": [ + "checkstyle.Main" + ] + } +} \ No newline at end of file diff --git a/src/Run.hx b/src/Run.hx index f230aa3..225378a 100644 --- a/src/Run.hx +++ b/src/Run.hx @@ -3,7 +3,6 @@ using StringTools; import as3hx.As3.Program; import as3hx.Config; import as3hx.Error; -import as3hx.ParserUtils; import as3hx.Writer; import sys.FileSystem; import sys.io.File; @@ -11,15 +10,15 @@ using haxe.io.Path; class Run { - static var errors : Array = new Array(); - static var warnings : Map> = new Map(); - static var cfg : as3hx.Config; + static var errors:Array = []; + static var warnings:Map> = new Map(); + static var cfg:as3hx.Config; static var writer:Writer; static var currentDstPath:String; - static var files:Array = new Array(); + static var files:Array = []; - - public static function main() { + public static function main():Void { + Sys.setCwd(Sys.args().pop()); cfg = new as3hx.Config(); if (cfg.useFullTyping) { writer = new Writer(cfg); @@ -99,14 +98,13 @@ class Run { static function parseFile(fileLocation:String, fileName:String, file:String):Program { var p = new as3hx.Parser(cfg); var content = File.getContent(file); - var program = p.parseString(content, fileLocation, fileName); - /*/try { + return try { p.parseString(content, fileLocation, fileName); } catch (e : Error) { #if macro File.stderr().writeString(file + ":" + p.tokenizer.line + ": " + errorString(e) + "\n"); #end - if(cfg.errorContinue) { + if (cfg.errorContinue) { errors.push("In " + file + "(" + p.tokenizer.line + ") : " + errorString(e)); null; } else { @@ -117,11 +115,10 @@ class Run { null; #end } - }//*/ - return program; + } } - static function errorString(e : Error) { + static function errorString(e : Error):String { return switch(e) { case EInvalidChar(c): "Invalid char '" + String.fromCharCode(c) + "' 0x" + StringTools.hex(c, 2); case EUnexpected(src): "Unexpected " + src; @@ -144,9 +141,9 @@ class Run { } } - static function postProcessor(?postProcessor:String = "", ?outFile:String = "") { + static function postProcessor(?postProcessor:String = "", ?outFile:String = ""):Void { if(postProcessor != "" && outFile != "") { - Sys.println('Running post-processor ' + postProcessor + ' on file: ' + outFile); + Sys.println("Running post-processor " + postProcessor + " on file: " + outFile); Sys.command(postProcessor, [outFile]); } } @@ -154,15 +151,15 @@ class Run { //if a .hx file with the same name as the .as file is found in the .as //file directory, then it is considered the expected output of the conversion //and is diffed against the actual output - static function verifyGeneratedFile(file:String, src:String, outFile:String) { + static function verifyGeneratedFile(file:String, src:String, outFile:String):Void { var test = src.addTrailingSlash() + Writer.properCase(file.substr(0, -3), true) + ".hx"; if (FileSystem.exists(test) && FileSystem.exists(outFile)) { Sys.println("expected HX file: " + test); var expectedFile = File.getContent(test); var generatedFile = File.getContent(outFile); if (generatedFile != expectedFile) { - Sys.println('Don\'t match generated file:' + outFile); - Sys.command('diff', [test, outFile]); + Sys.println("Don't match generated file:" + outFile); + Sys.command("diff", [test, outFile]); } } } diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index 58bb98c..31e703f 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -1,7 +1,7 @@ package as3hx; -import haxe.xml.Fast; +import haxe.xml.Access; import sys.FileSystem; import sys.io.File; import haxe.ds.StringMap; @@ -116,7 +116,6 @@ class Config { */ public var importTypes : StringMap; - /** source directory **/ public var src : Array; /** output directory **/ @@ -133,7 +132,7 @@ class Config { processImportPaths(); } - public function init() { + public function init():Void { var env = Sys.environment(); if (env.exists("AS3HX_CONFIG")) { cfgFile = env.get("AS3HX_CONFIG"); @@ -183,11 +182,11 @@ class Config { return s.substr(0, 1).toUpperCase() + s.substr(1); } - function processDefaultConfig() { + function processDefaultConfig():Void { fromXmlString(defaultConfig()); } - function processEnvConfig() { + function processEnvConfig():Void { // $HOME/.as3hx_config.xml or env if(cfgFile != null) { if(!FileSystem.exists(cfgFile)) { @@ -202,7 +201,7 @@ class Config { } } - function processLocalConfig() { + function processLocalConfig():Void { if(FileSystem.exists("./.as3hx_config.xml")) { fromXmlString(File.getContent("./.as3hx_config.xml")); } @@ -212,7 +211,7 @@ class Config { * Store fuly qualified names of Haxe files found * at provided directories */ - function processImportPaths() { + function processImportPaths():Void { importTypes = new StringMap(); for(path in importPaths) { processImportPath(path, "", importTypes); @@ -250,7 +249,7 @@ class Config { } } - public static function usage() { + public static function usage():Void { var println = Sys.println; println("Usage: as3hx [options] sourceDir [outdir]"); println(" Options:"); @@ -267,7 +266,7 @@ class Config { println(" outdir\t\t : defaults to './out'"); } - function processCommandLine() { + function processCommandLine():Void { var args = Sys.args().copy(); #if !munit if (args.length == 0) { @@ -277,10 +276,10 @@ class Config { #else if (args.length == 0) return; #end - var arg = ""; - while(true) { + var arg:String = null; + while (true) { arg = args.shift(); - switch(arg) { + switch (arg) { case "-help", "--help": usage(); Sys.exit(0); @@ -308,31 +307,30 @@ class Config { dictionaryToHash = true; case "-libPath", "--libPath": libPaths.push(args.shift()); - default: + case null: break; + case _ if (arg.charAt(0) == "-"): + Sys.println("Unknown argument: " + arg); + usage(); + Sys.exit(1); + case _ if (src.length == 0): + src.push(directory(arg)); + case _ if (dst.length == 0): + dst.push(directory(arg, Sys.getCwd() + "out")); } } - if(arg == null) { + if (dst.length == 0) { + dst.push(directory(arg, Sys.getCwd() + "out")); + } + if (src == null) { usage(); Sys.exit(1); } - var cwd = new Path(arg).toString(); - if (((StringTools.endsWith(cwd, "/") && cwd != "/") || StringTools.endsWith(cwd, "\\")) && !StringTools.endsWith(cwd, ":\\")) { - cwd = cwd.substr(0, cwd.length - 1); - } - if (FileSystem.exists(cwd) && FileSystem.isDirectory(cwd)) { - Sys.setCwd(cwd); - } - src.push(directory(arg)); - dst.push(directory(args.shift(), "./out")); - while (args.length > 1) { - src.push(directory(args.shift())); - dst.push(directory(args.shift(), "./out")); - } } - static var reabs = ~/^([a-z]:|\\\\|\/)/i; - static function directory(dir : String, alt = ".") { + static var reabs:EReg = ~/^([a-z]:|\\\\|\/)/i; + + static function directory(dir : String, alt = "."):String { if (dir == null) dir = alt; if(dir.endsWith("/") || dir.endsWith("\\")) @@ -353,12 +351,12 @@ class Config { } */ - public function fromXmlString(s:String) { + public function fromXmlString(s:String):Void { var x = Xml.parse(s); - fromXml(new Fast(x.firstElement())); + fromXml(new Access(x.firstElement())); } - public function fromXml(f:Fast) { + public function fromXml(f:Access):Void { for(el in f.elements) { switch(el.name) { case "indentChars": setCharField(el, " "); @@ -400,7 +398,7 @@ class Config { } } - function setBoolField(f:Fast, defaultVal:Bool) { + function setBoolField(f:Access, defaultVal:Bool):Void { var val = defaultVal; if(f.has.value) { var c = f.att.value.toLowerCase().charAt(0); @@ -409,7 +407,7 @@ class Config { Reflect.setField(this, f.name, val); } - function setCharField(f:Fast, defaultVal:String, constrain:Array = null) { + function setCharField(f:Access, defaultVal:String, constrain:Array = null):Void { if(constrain == null) constrain = []; var val = (f.has.value) ? f.att.value : defaultVal; if(constrain.length > 0) { @@ -421,7 +419,7 @@ class Config { Reflect.setField(this, f.name, unescape(val)); } - function setExcludeField(f:Fast, defaultExcludes:List) { + function setExcludeField(f:Access, defaultExcludes:List):Void { excludePaths = defaultExcludes; for (file in f.nodes.path) { if (file.has.value) { @@ -430,7 +428,7 @@ class Config { } } - function setLibPaths(f:Fast, defaultLibPaths:Array) { + function setLibPaths(f:Access, defaultLibPaths:Array):Void { libPaths = defaultLibPaths; for (dir in f.nodes.path) { if (dir.has.value) { @@ -439,7 +437,7 @@ class Config { } } - function setConditionalVars(f:Fast, defaultVars:List) { + function setConditionalVars(f:Access, defaultVars:List):Void { conditionalVars = defaultVars; for (conditionalVar in f.nodes.variable) { if (conditionalVar.has.value) { @@ -448,7 +446,7 @@ class Config { } } - function setImportPaths(f:Fast, defaultVars:Array) { + function setImportPaths(f:Access, defaultVars:Array):Void { importPaths = defaultVars; for (importPath in f.nodes.variable) { if (importPath.has.value) { @@ -457,7 +455,7 @@ class Config { } } - function setImportExclude(f:Fast, defaultVars:Array) { + function setImportExclude(f:Access, defaultVars:Array):Void { importExclude = defaultVars; for (importPath in f.nodes.variable) { if (importPath.has.value) { @@ -475,7 +473,7 @@ class Config { public static function isWindows() : Bool { var os = Sys.systemName(); - return (new EReg("window","i")).match(os); + return new EReg("window", "i").match(os); } static function escape(s:String):String { diff --git a/src/as3hx/ParserUtils.hx b/src/as3hx/ParserUtils.hx index 8bd83d4..7aab915 100644 --- a/src/as3hx/ParserUtils.hx +++ b/src/as3hx/ParserUtils.hx @@ -167,8 +167,7 @@ class ParserUtils { * In certain cases, a typedef will be generated * for a class attribute, for better type safety */ - public static function generateTypeIfNeeded(classVar : ClassField) - { + public static function generateTypeIfNeeded(classVar : ClassField) { //this only applies to static field attributes, as //they only define constants values if (!Lambda.has(classVar.kwds, "static")) { diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index 6babe16..24992e3 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -204,7 +204,7 @@ class Typer } } switch(t2) { - case "Object", "Dynamic", CommonImports.ObjectType, CommonImports.ObjectImport: + case "Dynamic", CommonImports.ObjectType, CommonImports.ObjectImport: switch(f) { case "hasOwnProperty": return "String->Bool"; } @@ -621,7 +621,7 @@ class Typer case "uint" : cfg.uintToInt ? "Int" : "UInt"; case "void" : "Void"; case "Function" : cfg.functionToDynamic ? "Dynamic" : c; - case "Object", CommonImports.ObjectType : isNativeGetSet ? "{}" : (cfg.useOpenFlTypes ? CommonImports.ObjectType : "Dynamic"); + case CommonImports.ObjectType : isNativeGetSet ? "{}" : (cfg.useOpenFlTypes ? CommonImports.ObjectType : "Dynamic"); case "XML" : cfg.useFastXML ? "FastXML" : "Xml"; case "XMLList" : cfg.useFastXML ? "FastXMLList" : "Iterator"; case "RegExp" : cfg.useCompat ? "as3hx.Compat.Regex" : "flash.utils.RegExp"; @@ -1271,6 +1271,10 @@ class Typer //classMap = new Map(); while (ic != null && ic.extend != null) { var packageString:String = parentPath.substring(0, parentPath.lastIndexOf(".")); + if (classPrograms[ic] == null) { + ic = null; + break; + } var path:String = getPathByType(ic.extend, ic, classPrograms[ic].pack, packageString); if (path != null) { parentPath = path; diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index c4f9e8e..a7c1bfb 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -4075,7 +4075,7 @@ class Writer return s != null && (s.indexOf("Dictionary") == 0 || s.indexOf("openfl.utils.Dictionary") == 0) && cfg.useOpenFlTypes; } - inline function isFunctionType(type:String):Bool { + function isFunctionType(type:String):Bool { if (type == "Function" || type == "haxe.Constraints.Function") return true; if (type == null) return false; var delimeters:Array = []; @@ -4124,7 +4124,7 @@ class Writer default: false; } - function addWarning(type:String, isError = false) { + function addWarning(type:String, isError = false):Void { warnings.set(type, isError); } diff --git a/test/e2e/mxml/First.mxml b/test/e2e/mxml/First.mxml new file mode 100644 index 0000000..deb73d0 --- /dev/null +++ b/test/e2e/mxml/First.mxml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/test/e2e/mxml/pack/Second.mxml b/test/e2e/mxml/pack/Second.mxml new file mode 100644 index 0000000..efc5f05 --- /dev/null +++ b/test/e2e/mxml/pack/Second.mxml @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/test/e2e/simple/Attr.hx b/test/e2e/simple/Attr.hx index 6cb7b0a..8c821e8 100644 --- a/test/e2e/simple/Attr.hx +++ b/test/e2e/simple/Attr.hx @@ -1,12 +1,11 @@ package test.package; -class Min -{ - private var testAttr : Int = 1; +class Min { - public function new() - { - var test : String = "hello"; - } -} + private var testAttr:Int = 1; + public function new() { + var test:String = 'hello'; + } + +} \ No newline at end of file diff --git a/test/e2e/simple/Dictionary.hx b/test/e2e/simple/Dictionary.hx index 4421e0b..6d5dfd2 100644 --- a/test/e2e/simple/Dictionary.hx +++ b/test/e2e/simple/Dictionary.hx @@ -1,13 +1,9 @@ -import flash.utils.Dictionary; +class Dict { -class Dict -{ + private var _dic:haxe.ds.ObjectMap = new haxe.ds.ObjectMap(); - private var _dic : Dictionary = new Dictionary(); - - public function new() - { - var dic : Dictionary = new Dictionary(); - } -} + public function new() { + var dic:haxe.ds.ObjectMap = new haxe.ds.ObjectMap(); + } +} \ No newline at end of file diff --git a/test/e2e/simple/ForLoop.hx b/test/e2e/simple/ForLoop.hx index 2fa753c..9317c9c 100644 --- a/test/e2e/simple/ForLoop.hx +++ b/test/e2e/simple/ForLoop.hx @@ -1,12 +1,9 @@ package test.package; -class ForLoop -{ - public function new() - { - for (i in 0...10){ +class ForLoop { - } - } -} + public function new() { + for (i in 0...10) {} + } +} \ No newline at end of file diff --git a/test/e2e/simple/Func.hx b/test/e2e/simple/Func.hx index b9c563c..becc93e 100644 --- a/test/e2e/simple/Func.hx +++ b/test/e2e/simple/Func.hx @@ -1,16 +1,13 @@ package test.package; -class Min -{ - private var testAttr : Int = 1; +class Min { - public function new() - { - var test : String = "hello"; - } + private var testAttr:Int = 1; - private function testFun(){ + public function new() { + var test:String = 'hello'; + } - } -} + private function testFun() {} +} \ No newline at end of file diff --git a/test/e2e/simple/Interface.hx b/test/e2e/simple/Interface.hx index e30b226..db5a717 100644 --- a/test/e2e/simple/Interface.hx +++ b/test/e2e/simple/Interface.hx @@ -1,7 +1,7 @@ package test.package; -interface Test -{ - function someFunc() : Void; -} +interface Test { + function someFunc():Void; + +} \ No newline at end of file diff --git a/test/e2e/simple/Min.hx b/test/e2e/simple/Min.hx index b0375ff..6180034 100644 --- a/test/e2e/simple/Min.hx +++ b/test/e2e/simple/Min.hx @@ -1,7 +1,5 @@ -class Min -{ - public function new() - { - } -} +class Min { + public function new() {} + +} \ No newline at end of file diff --git a/test/e2e/simple/Package.hx b/test/e2e/simple/Package.hx index 3c172ad..6a2096d 100644 --- a/test/e2e/simple/Package.hx +++ b/test/e2e/simple/Package.hx @@ -1,9 +1,7 @@ package test.package; -class Min -{ - public function new() - { - } -} +class Min { + public function new() {} + +} \ No newline at end of file diff --git a/test/e2e/simple/Var.hx b/test/e2e/simple/Var.hx index a464bfd..00b7e3c 100644 --- a/test/e2e/simple/Var.hx +++ b/test/e2e/simple/Var.hx @@ -1,10 +1,9 @@ package test.package; -class Min -{ - public function new() - { - var test : String = "hello"; - } -} +class Min { + public function new() { + var test:String = 'hello'; + } + +} \ No newline at end of file diff --git a/test/issues/Issue.as b/test/issues/Issue.as deleted file mode 100644 index 7a66d66..0000000 --- a/test/issues/Issue.as +++ /dev/null @@ -1,9 +0,0 @@ -package { - public class Issue103 { - public function Issue103() { - var string:String = ""; - var boolean:Boolean = true; - var number:Number = 10.1; - } - } -} \ No newline at end of file diff --git a/test/issues/Issue.hx b/test/issues/Issue.hx deleted file mode 100644 index 889d560..0000000 --- a/test/issues/Issue.hx +++ /dev/null @@ -1,10 +0,0 @@ - -class Issue103 -{ - public function new() - { - var string : String = ""; - var boolean : Bool = true; - var number : Float = 10.1; - } -} diff --git a/test/issues/Issue103.hx b/test/issues/Issue103.hx index 889d560..cdd8e9a 100644 --- a/test/issues/Issue103.hx +++ b/test/issues/Issue103.hx @@ -1,10 +1,9 @@ +class Issue103 { -class Issue103 -{ - public function new() - { - var string : String = ""; - var boolean : Bool = true; - var number : Float = 10.1; - } -} + public function new() { + var string:String = ''; + var boolean:Bool = true; + var number:Float = 10.1; + } + +} \ No newline at end of file diff --git a/test/issues/Issue112.hx b/test/issues/Issue112.hx index 3110979..f4610e4 100644 --- a/test/issues/Issue112.hx +++ b/test/issues/Issue112.hx @@ -1,15 +1,10 @@ +class Issue112 { -class Issue112 -{ - public function new() - { - var timeoutId : Int = as3hx.Compat.setTimeout(function(s : String) : Void - { - }, 1000, ["string"]); - as3hx.Compat.clearTimeout(timeoutId); - var intervalId : Int = as3hx.Compat.setInterval(function(s : String) : Void - { - }, 1000, ["string"]); - as3hx.Compat.clearInterval(intervalId); - } -} + public function new() { + var timeoutId:Int = as3hx.Compat.setTimeout(function(s:String):Void {}, 1000, ['string']); + as3hx.Compat.clearTimeout(timeoutId); + var intervalId:Int = as3hx.Compat.setInterval(function(s:String):Void {}, 1000, ['string']); + as3hx.Compat.clearInterval(intervalId); + } + +} \ No newline at end of file diff --git a/test/issues/Issue115.hx b/test/issues/Issue115.hx index a4a66df..1971242 100644 --- a/test/issues/Issue115.hx +++ b/test/issues/Issue115.hx @@ -1,43 +1,31 @@ +class Issue115 { -class Issue115 -{ - public function new() - { - if (true) - { - var i : Int = 1; - } - - if (true) - { - var i : Int = 1; - } - - if (true) - { - var i : Int = 1; - } - else - { - var i : Int = 1; - } - - if (true) - { - var i : Int = 1; - } - else - { - var i : Int = 1; - } - - if (true) - { - var i : Int = 1; - } - else - { - var i : Int = 1; - } - } -} + public function new() { + if (true) { + var i:Int = 1; + } + + if (true) { + var i:Int = 1; + } + + if (true) { + var i:Int = 1; + } else { + var i:Int = 1; + } + + if (true) { + var i:Int = 1; + } else { + var i:Int = 1; + } + + if (true) { + var i:Int = 1; + } else { + var i:Int = 1; + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue119_notUseCompat.hx b/test/issues/Issue119_notUseCompat.hx index e43a53d..196d8e3 100644 --- a/test/issues/Issue119_notUseCompat.hx +++ b/test/issues/Issue119_notUseCompat.hx @@ -1,13 +1,12 @@ import flash.system.Capabilities; +class Issue119 { -class Issue119 -{ - public function new() - { - var sPlatform : String = Capabilities.version.substr(0, 3); - var sDesktop : Bool = new flash.utils.RegExp('(WIN|MAC|LNX)', "").exec(sPlatform) != null; - - var ereg : flash.utils.RegExp = new flash.utils.RegExp('(WIN|MAC|LNX)', ""); - var sDesktop2 : Bool = ereg.exec(sPlatform) != null; - } -} + public function new() { + var sPlatform:String = Capabilities.version.substr(0, 3); + var sDesktop:Bool = new flash.utils.RegExp('(WIN|MAC|LNX)', '').exec(sPlatform) != null; + + var ereg:flash.utils.RegExp = new flash.utils.RegExp('(WIN|MAC|LNX)', ''); + var sDesktop2:Bool = ereg.exec(sPlatform) != null; + } + +} \ No newline at end of file diff --git a/test/issues/Issue119_useCompat.hx b/test/issues/Issue119_useCompat.hx index c200f8b..b82d3ad 100644 --- a/test/issues/Issue119_useCompat.hx +++ b/test/issues/Issue119_useCompat.hx @@ -1,13 +1,12 @@ import flash.system.Capabilities; +class Issue119 { -class Issue119 -{ - public function new() - { - var sPlatform : String = Capabilities.version.substr(0, 3); - var sDesktop : Bool = new as3hx.Compat.Regex('(WIN|MAC|LNX)', "").exec(sPlatform) != null; - - var ereg : as3hx.Compat.Regex = new as3hx.Compat.Regex('(WIN|MAC|LNX)', ""); - var sDesktop2 : Bool = ereg.exec(sPlatform) != null; - } -} + public function new() { + var sPlatform:String = Capabilities.version.substr(0, 3); + var sDesktop:Bool = new as3hx.Compat.Regex('(WIN|MAC|LNX)', '').exec(sPlatform) != null; + + var ereg:as3hx.Compat.Regex = new as3hx.Compat.Regex('(WIN|MAC|LNX)', ''); + var sDesktop2:Bool = ereg.exec(sPlatform) != null; + } + +} \ No newline at end of file diff --git a/test/issues/Issue120.hx b/test/issues/Issue120.hx index 99412d1..101845a 100644 --- a/test/issues/Issue120.hx +++ b/test/issues/Issue120.hx @@ -1,12 +1,12 @@ import haxe.Constraints.Function; -class Issue120 -{ - public function new() - { - var call : Function = trace; - var args : Array = []; - Reflect.callMethod(null, call, args); - Reflect.callMethod(null, call, [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); - } -} +class Issue120 { + + public function new() { + var call:Function = trace; + var args:Array = []; + Reflect.callMethod(null, call, args); + Reflect.callMethod(null, call, [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); + } + +} \ No newline at end of file diff --git a/test/issues/Issue121.hx b/test/issues/Issue121.hx index 30b50ba..a3f20dc 100644 --- a/test/issues/Issue121.hx +++ b/test/issues/Issue121.hx @@ -1,34 +1,26 @@ +class Issue121 { -class Issue121 -{ - public function new() - { - var o : Dynamic = { }; - if (Lambda.has(o, "some")) - { - Reflect.deleteField(o, "some"); - } - else - { - o = null; - } - - if (Lambda.has(o, 1)) - { - Reflect.deleteField(o, "1"); - } - } - - private var _eventListeners : Dynamic = { }; - public function removeEventListeners(type : String = null) : Void - { - if (type != null && _eventListeners != null) - { - Reflect.deleteField(_eventListeners, type); - } - else - { - _eventListeners = null; - } - } -} + public function new() { + var o:Dynamic = {}; + if (Lambda.has(o, 'some')) { + Reflect.deleteField(o, 'some'); + } else { + o = null; + } + + if (Lambda.has(o, 1)) { + Reflect.deleteField(o, '1'); + } + } + + private var _eventListeners:Dynamic = {}; + + public function removeEventListeners(type:String = null):Void { + if (type != null && _eventListeners != null) { + Reflect.deleteField(_eventListeners, type); + } else { + _eventListeners = null; + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue124.hx b/test/issues/Issue124.hx index f443870..0d35f53 100644 --- a/test/issues/Issue124.hx +++ b/test/issues/Issue124.hx @@ -1,22 +1,15 @@ -import flash.utils.Dictionary; +class Issue124 { -class Issue124 -{ - private var _eventListeners : Dictionary = new Dictionary(); - public function removeEventListeners(type : String = null) : Void - { - if (type != null && _eventListeners != null) - { - This is an intentional compilation error. See the README for handling the delete keyword - delete _eventListeners[type]; - } - else - { - _eventListeners = null; - } - } + private var _eventListeners:haxe.ds.ObjectMap = new haxe.ds.ObjectMap(); - public function new() - { - } -} + public function removeEventListeners(type:String = null):Void { + if (type != null && _eventListeners != null) { + _eventListeners.remove(type); + } else { + _eventListeners = null; + } + } + + public function new() {} + +} \ No newline at end of file diff --git a/test/issues/Issue128.hx b/test/issues/Issue128.hx index 9497e9e..fa3ff6e 100644 --- a/test/issues/Issue128.hx +++ b/test/issues/Issue128.hx @@ -1,13 +1,11 @@ +class Issue128 { -class Issue128 -{ - public function new() - { - var b : Bool; - var n : Float = 1; - if (b || (n != 0 && !Math.isNaN(n))) - { - trace(n); - } - } -} + public function new() { + var b:Bool; + var n:Float = 1; + if (b || (n != 0 && !Math.isNaN(n))) { + trace(n); + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue133.hx b/test/issues/Issue133.hx index 3d5af21..ae36c28 100644 --- a/test/issues/Issue133.hx +++ b/test/issues/Issue133.hx @@ -1,18 +1,15 @@ +class Issue133 { -class Issue133 -{ - public function new() - { - var max : Int = as3hx.Compat.INT_MAX; - if (max > as3hx.Compat.INT_MAX) - { - max = as3hx.Compat.INT_MAX; - } - - var min : Int = as3hx.Compat.INT_MIN; - if (min < as3hx.Compat.INT_MIN) - { - min = as3hx.Compat.INT_MIN; - } - } -} + public function new() { + var max:Int = as3hx.Compat.INT_MAX; + if (max > as3hx.Compat.INT_MAX) { + max = as3hx.Compat.INT_MAX; + } + + var min:Int = as3hx.Compat.INT_MIN; + if (min < as3hx.Compat.INT_MIN) { + min = as3hx.Compat.INT_MIN; + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue134.hx b/test/issues/Issue134.hx index 4afa400..a753046 100644 --- a/test/issues/Issue134.hx +++ b/test/issues/Issue134.hx @@ -1,22 +1,19 @@ import flash.errors.Error; -class Issue134 -{ - public function new() - { - throw new Error(); - } - - private function test() : Void - { - trace("Issue134"); - } - - private function test2() : Void - { - for (i in 0...10) - { - trace("Issue134"); - } - } -} +class Issue134 { + + public function new() { + throw new Error(); + } + + private function test():Void { + trace('Issue134'); + } + + private function test2():Void { + for (i in 0...10) { + trace('Issue134'); + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue139.hx b/test/issues/Issue139.hx index 3f97fa1..bde32bc 100644 --- a/test/issues/Issue139.hx +++ b/test/issues/Issue139.hx @@ -1,18 +1,15 @@ +class Issue139 { -class Issue139 -{ - public function new() - { - var max : Float = as3hx.Compat.FLOAT_MAX; - if (max > as3hx.Compat.FLOAT_MAX) - { - max = as3hx.Compat.FLOAT_MAX; - } - - var min : Float = as3hx.Compat.FLOAT_MIN; - if (min < as3hx.Compat.FLOAT_MIN) - { - min = as3hx.Compat.FLOAT_MIN; - } - } -} + public function new() { + var max:Float = as3hx.Compat.FLOAT_MAX; + if (max > as3hx.Compat.FLOAT_MAX) { + max = as3hx.Compat.FLOAT_MAX; + } + + var min:Float = as3hx.Compat.FLOAT_MIN; + if (min < as3hx.Compat.FLOAT_MIN) { + min = as3hx.Compat.FLOAT_MIN; + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue14.hx b/test/issues/Issue14.hx index 8641850..2a60396 100644 --- a/test/issues/Issue14.hx +++ b/test/issues/Issue14.hx @@ -1,11 +1,9 @@ +class Issue14 { -class Issue14 -{ - - private var _regEx : as3hx.Compat.Regex = new as3hx.Compat.Regex('[\\/]', "g"); - - public function new() - { - var regEx : as3hx.Compat.Regex = new as3hx.Compat.Regex('[\\/]', "g"); - } -} + private var _regEx:as3hx.Compat.Regex = new as3hx.Compat.Regex('[\\/]', 'g'); + + public function new() { + var regEx:as3hx.Compat.Regex = new as3hx.Compat.Regex('[\\/]', 'g'); + } + +} \ No newline at end of file diff --git a/test/issues/Issue142.hx b/test/issues/Issue142.hx index da03654..4acf1c1 100644 --- a/test/issues/Issue142.hx +++ b/test/issues/Issue142.hx @@ -1,15 +1,14 @@ import flash.display.Scene; import flash.display.Sprite; import flash.events.DataEvent; +class Issue142 { -class Issue142 -{ - public function new() - { - var sceneClass : Class = Type.getClass(Type.resolveClass("SceneType")); - var currentScene : Scene = try cast(Type.createInstance(sceneClass, []), Scene) catch(e:Dynamic) null; - - var d : Date = Date.now(); - var s : Sprite = new Sprite(); - } -} + public function new() { + var sceneClass:Class = Type.getClass(Type.resolveClass('SceneType')); + var currentScene:Scene = try cast(Type.createInstance(sceneClass, []), Scene) catch (e:Dynamic) null; + + var d:Date = Date.now(); + var s:Sprite = new Sprite(); + } + +} \ No newline at end of file diff --git a/test/issues/Issue143.hx b/test/issues/Issue143.hx index e66814c..6e0b0ee 100644 --- a/test/issues/Issue143.hx +++ b/test/issues/Issue143.hx @@ -1,8 +1,6 @@ import flash.display3D.Context3D; +class Issue143 { -class Issue143 -{ - public function new() - { - } -} + public function new() {} + +} \ No newline at end of file diff --git a/test/issues/Issue144.hx b/test/issues/Issue144.hx index 5a4199a..a4a55e2 100644 --- a/test/issues/Issue144.hx +++ b/test/issues/Issue144.hx @@ -1,17 +1,17 @@ import flash.events.TouchEvent; +class Issue144 { -class Issue144 -{ - private var multitouchEnabled : Bool; - private var types : Array = []; - public function new() - { - if (multitouchEnabled) - { - types.push(TouchEvent.TOUCH_BEGIN); - types.push(TouchEvent.TOUCH_MOVE); - types.push(TouchEvent.TOUCH_END); - - } - } -} + private var multitouchEnabled:Bool; + + private var types:Array = []; + + public function new() { + if (multitouchEnabled) { + types.push(TouchEvent.TOUCH_BEGIN); + types.push(TouchEvent.TOUCH_MOVE); + types.push(TouchEvent.TOUCH_END); + + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue148.hx b/test/issues/Issue148.hx index 3bcfceb..60e5dae 100644 --- a/test/issues/Issue148.hx +++ b/test/issues/Issue148.hx @@ -1,11 +1,7 @@ +class Issue148 { -class Issue148 -{ - public function new() - { - } - - public function enqueue(rawAssets : Array = null) : Void - { - } -} + public function new() {} + + public function enqueue(rawAssets:Array = null):Void {} + +} \ No newline at end of file diff --git a/test/issues/Issue15.hx b/test/issues/Issue15.hx index 4c50a5a..c450304 100644 --- a/test/issues/Issue15.hx +++ b/test/issues/Issue15.hx @@ -1,109 +1,87 @@ +class Issue15 { -class Issue15 -{ - - public function new() - { - var i : Int = 0; - if (i != 0) - { - trace(i); - } - ++i; - - if (true) - { - trace(""); - } - else - { - trace(""); - } - ++i; - - for (j in 0...10) - { - trace(""); - } - ++i; - - for (j in 0...10) - { - trace(""); - } - ++i; - - for (name in Reflect.fields({ })) - { - trace(""); - } - ++i; - - for (name in Reflect.fields({ })) - { - trace(""); - } - ++i; - - for (item/* AS3HX WARNING could not determine type for var: item exp: EObject([]) type: null */ in { }) - { - trace(""); - } - ++i; - - for (item/* AS3HX WARNING could not determine type for var: item exp: EObject([]) type: null */ in { }) - { - trace(""); - } - ++i; - - while (true) - { - trace(""); - } - ++i; - - while (true) - { - trace(""); - } - ++i; - - do - { - trace(""); - } - while ((true)); - ++i; - - do - { - trace(""); - } - while ((true)); - ++i; - - do - { - trace(""); - } - while ((true)); - ++i; - - switch (i) - { - case 1: - trace(""); - default: - } - ++i; - - switch (i) - { - case 1: - trace(""); - default: - } - ++i; - } -} + public function new() { + var i:Int = 0; + if (i != 0) { + trace(i); + } + ++i; + + if (true) { + trace(''); + } else { + trace(''); + } + ++i; + + for (j in 0...10) { + trace(''); + } + ++i; + + for (j in 0...10) { + trace(''); + } + ++i; + + for (name in Reflect.fields({})) { + trace(''); + } + ++i; + + for (name in Reflect.fields({})) { + trace(''); + } + ++i; + + for (item /* AS3HX WARNING could not determine type for var: item exp: EObject([]) type: null */ in {}) { + trace(''); + } + ++i; + + for (item /* AS3HX WARNING could not determine type for var: item exp: EObject([]) type: null */ in {}) { + trace(''); + } + ++i; + + while (true) { + trace(''); + } + ++i; + + while (true) { + trace(''); + } + ++i; + + do { + trace(''); + } while ((true)); + ++i; + + do { + trace(''); + } while ((true)); + ++i; + + do { + trace(''); + } while ((true)); + ++i; + + switch (i) { + case 1: + trace(''); + case _: + } + ++i; + + switch (i) { + case 1: + trace(''); + case _: + } + ++i; + } + +} \ No newline at end of file diff --git a/test/issues/Issue150.hx b/test/issues/Issue150.hx index caba124..572d6af 100644 --- a/test/issues/Issue150.hx +++ b/test/issues/Issue150.hx @@ -1,23 +1,22 @@ +class Issue150 { -class Issue150 -{ - public function new() - { - var fragmentShader : String = [ - tex("ft0", "v1", 1, _mapTexture, false), // read map texture - "sub ft1, ft0, fc0", // subtract 0.5 -> range [-0.5, 0.5] - "mul ft1.xy, ft1.xy, ft0.ww", // zero displacement when alpha == 0 - "m44 ft2, ft1, fc1", // multiply matrix with displacement values - "add ft3, v0, ft2", // add displacement values to texture coords - tex("oc", "ft3", 0, texture) // read input texture at displaced coords - ].join("\n"); - - var s1 : String = [1, 2, 3, 4, 5].join("\n"); - - var s2 : String = [1, - 2, 3, 4, 5 - ].join("\n"); - - var s2 : String = [1, 2, 3, /*comment*/ 4, 5].join("\n"); - } -} + public function new() { + var fragmentShader:String = [ + tex('ft0', 'v1', 1, _mapTexture, false), // read map texture + 'sub ft1, ft0, fc0', // subtract 0.5 -> range [-0.5, 0.5] + 'mul ft1.xy, ft1.xy, ft0.ww', // zero displacement when alpha == 0 + 'm44 ft2, ft1, fc1', // multiply matrix with displacement values + 'add ft3, v0, ft2', // add displacement values to texture coords + tex('oc', 'ft3', 0, texture) // read input texture at displaced coords + ].join('\n'); + + var s1:String = [1, 2, 3, 4, 5].join('\n'); + + var s2:String = [1, + 2, 3, 4, 5 + ].join('\n'); + + var s2:String = [1, 2, 3, /*comment*/ 4, 5].join('\n'); + } + +} \ No newline at end of file diff --git a/test/issues/Issue152.hx b/test/issues/Issue152.hx index 38d93a2..1f3b546 100644 --- a/test/issues/Issue152.hx +++ b/test/issues/Issue152.hx @@ -1,21 +1,21 @@ +class Issue152 { -class Issue152 -{ - private var vertexShader : Array; - public function new() - { - vertexShader.push( - 1 // add offset 1 - ); - vertexShader.push( - 2 // add offset 2 - ); - vertexShader.push( - 3 // add offset 3 - ); - vertexShader.push( - 4 - ); - - } -} + private var vertexShader:Array; + + public function new() { + vertexShader.push( + 1 // add offset 1 + ); + vertexShader.push( + 2 // add offset 2 + ); + vertexShader.push( + 3 // add offset 3 + ); + vertexShader.push( + 4 + ); + + } + +} \ No newline at end of file diff --git a/test/issues/Issue156.hx b/test/issues/Issue156.hx index b269f27..e151c2f 100644 --- a/test/issues/Issue156.hx +++ b/test/issues/Issue156.hx @@ -4,22 +4,19 @@ import flash.events.EventDispatcher; import flash.display.Sprite; /** Dispatched when a fatal error is encountered. The 'data' property contains an error string. */ -@:meta(Event(name="fatalError",type="starling.events.Event")) +@:meta(Event(name = 'fatalError', type = 'starling.events.Event')) +class Issue156 extends EventDispatcher { + + public function new() { + super(); + } -class Issue156 extends EventDispatcher -{ - public function new() - { - super(); - } } +class PrivateClass extends Sprite { -class PrivateClass extends Sprite -{ + public function new() { + super(); + } - public function new() - { - super(); - } } \ No newline at end of file diff --git a/test/issues/Issue158.hx b/test/issues/Issue158.hx index bdcdbe5..20dbf75 100644 --- a/test/issues/Issue158.hx +++ b/test/issues/Issue158.hx @@ -1,8 +1,7 @@ +class Issue158 { -class Issue158 -{ - public function new() - { - var cls : Class = Type.getClass(this); - } -} + public function new() { + var cls:Class = Type.getClass(this); + } + +} \ No newline at end of file diff --git a/test/issues/Issue162.hx b/test/issues/Issue162.hx index bf1d675..8f503bc 100644 --- a/test/issues/Issue162.hx +++ b/test/issues/Issue162.hx @@ -1,10 +1,9 @@ +class Issue162 { -class Issue162 -{ - public function new() - { - var s : String = "1"; - var i : Int = as3hx.Compat.parseInt(s); - var n : Float = as3hx.Compat.parseFloat(s); - } -} + public function new() { + var s:String = '1'; + var i:Int = as3hx.Compat.parseInt(s); + var n:Float = as3hx.Compat.parseFloat(s); + } + +} \ No newline at end of file diff --git a/test/issues/Issue164.hx b/test/issues/Issue164.hx index 0a2cdac..48b96f2 100644 --- a/test/issues/Issue164.hx +++ b/test/issues/Issue164.hx @@ -1,9 +1,8 @@ import flash.display.DisplayObject; +class Issue164 { -class Issue164 -{ - public function new(rootClass : Class) - { - var d : DisplayObject = try cast(Type.createInstance(rootClass, []), DisplayObject) catch(e:Dynamic) null; - } -} + public function new(rootClass:Class) { + var d:DisplayObject = try cast(Type.createInstance(rootClass, []), DisplayObject) catch (e:Dynamic) null; + } + +} \ No newline at end of file diff --git a/test/issues/Issue165.hx b/test/issues/Issue165.hx index b9302cc..693d513 100644 --- a/test/issues/Issue165.hx +++ b/test/issues/Issue165.hx @@ -1,11 +1,10 @@ +class Issue165 { -class Issue165 -{ - public function new() - { - var a : Array = []; - var b : Array = a.splice(0, a.length); - var c : Array = as3hx.Compat.arraySplice(a, 0, 0, [1, 2, 3, 4, 5]); - var d : Array = a.splice(0, 1); - } -} + public function new() { + var a:Array = []; + var b:Array = a.splice(0, a.length); + var c:Array = as3hx.Compat.arraySplice(a, 0, 0, [1, 2, 3, 4, 5]); + var d:Array = a.splice(0, 1); + } + +} \ No newline at end of file diff --git a/test/issues/Issue166.hx b/test/issues/Issue166.hx index b49cce9..185109a 100644 --- a/test/issues/Issue166.hx +++ b/test/issues/Issue166.hx @@ -1,9 +1,8 @@ +class Issue166 { -class Issue166 -{ - public function new() - { - var n : Float = 10.12873894504; - n = as3hx.Compat.toFixed(n, 5); - } -} + public function new() { + var n:Float = 10.12873894504; + n = as3hx.Compat.toFixed(n, 5); + } + +} \ No newline at end of file diff --git a/test/issues/Issue167.hx b/test/issues/Issue167.hx index 62e45e2..a4bcaa8 100644 --- a/test/issues/Issue167.hx +++ b/test/issues/Issue167.hx @@ -1,21 +1,20 @@ import flash.geom.Point; +class Issue167 { -class Issue167 -{ - public function new(p : Point = null) - { - p = (p != null) ? p : new Point(); - - var n : Float; - n = ((n != 0 && !Math.isNaN(n))) ? n : 1; - - var i : Int; - i = (i != 0) ? i : 1; - - var s : String; - s = (s != null) ? s : "string"; - - var b : Bool; - b = (b) ? b : true; - } -} + public function new(p:Point = null) { + p = (p != null) ? p : new Point(); + + var n:Float; + n = ((n != 0 && !Math.isNaN(n))) ? n : 1; + + var i:Int; + i = (i != 0) ? i : 1; + + var s:String; + s = (s != null) ? s : 'string'; + + var b:Bool; + b = (b) ? b : true; + } + +} \ No newline at end of file diff --git a/test/issues/Issue176.hx b/test/issues/Issue176.hx index 3f48215..1dbae18 100644 --- a/test/issues/Issue176.hx +++ b/test/issues/Issue176.hx @@ -1,10 +1,10 @@ import haxe.Constraints.Function; -class Issue176 -{ - public function new() - { - var call : Function = trace; - Reflect.callMethod(null, call, [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); - } -} +class Issue176 { + + public function new() { + var call:Function = trace; + Reflect.callMethod(null, call, [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); + } + +} \ No newline at end of file diff --git a/test/issues/Issue178.hx b/test/issues/Issue178.hx index 7d6b029..b2e5b4c 100644 --- a/test/issues/Issue178.hx +++ b/test/issues/Issue178.hx @@ -1,13 +1,11 @@ +class Issue178 { -class Issue178 -{ - public function new() - { - var i : Int = 0; - while (i < 10) - { - trace(i); - i += 2; - } - } -} + public function new() { + var i:Int = 0; + while (i < 10) { + trace(i); + i += 2; + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue184.hx b/test/issues/Issue184.hx index 4ef46f6..5959ceb 100644 --- a/test/issues/Issue184.hx +++ b/test/issues/Issue184.hx @@ -1,9 +1,8 @@ +class Issue184 { -class Issue184 -{ - public function new() - { - var a : Array = []; - a.insert(0, 1); - } -} + public function new() { + var a:Array = []; + a.insert(0, 1); + } + +} \ No newline at end of file diff --git a/test/issues/Issue185.hx b/test/issues/Issue185.hx index 874ccd6..1ec92f2 100644 --- a/test/issues/Issue185.hx +++ b/test/issues/Issue185.hx @@ -1,10 +1,9 @@ +class Issue185 { -class Issue185 -{ - public function new() - { - var a : Array = [1]; - var i : Int = as3hx.Compat.parseInt(a.splice(0, 1)[0]); - a.splice(1, 1)[0]; - } -} + public function new() { + var a:Array = [1]; + var i:Int = as3hx.Compat.parseInt(a.splice(0, 1)[0]); + a.splice(1, 1)[0]; + } + +} \ No newline at end of file diff --git a/test/issues/Issue187.hx b/test/issues/Issue187.hx index 327d8ba..2d9f067 100644 --- a/test/issues/Issue187.hx +++ b/test/issues/Issue187.hx @@ -1,25 +1,22 @@ import flash.geom.Matrix3D; import flash.geom.Vector3D; +class Issue187 { -class Issue187 -{ - private static var sPoint3D : Vector3D; - public function new() - { - } - - public static function createPerspectiveProjectionMatrix( - x : Float, y : Float, width : Float, height : Float, - stageWidth : Float = 0, stageHeight : Float = 0, cameraPos : Vector3D = null, - out : Matrix3D = null) : Matrix3D - { - if (cameraPos == null) - { - cameraPos = sPoint3D; - cameraPos.setTo( - stageWidth / 2, stageHeight / 2, // -> center of stage - stageWidth / Math.tan(0.5) * 0.5 - ); - } - } -} + private static var sPoint3D:Vector3D; + + public function new() {} + + public static function createPerspectiveProjectionMatrix( + x:Float, y:Float, width:Float, height:Float, + stageWidth:Float = 0, stageHeight:Float = 0, cameraPos:Vector3D = null, + out:Matrix3D = null):Matrix3D { + if (cameraPos == null) { + cameraPos = sPoint3D; + cameraPos.setTo( + stageWidth / 2, stageHeight / 2, // -> center of stage + stageWidth / Math.tan(0.5) * 0.5 + ); + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue192.hx b/test/issues/Issue192.hx index 49b1e30..31ec2c5 100644 --- a/test/issues/Issue192.hx +++ b/test/issues/Issue192.hx @@ -1,15 +1,14 @@ import haxe.Constraints.Function; -class Issue192 -{ - public function new() - { - var f : Function = test; - test(s); - } - - private function test(s : String) - { - trace(s); - } -} +class Issue192 { + + public function new() { + var f:Function = test; + test(s); + } + + private function test(s:String) { + trace(s); + } + +} \ No newline at end of file diff --git a/test/issues/Issue198.hx b/test/issues/Issue198.hx index 898e6a9..5b45dc2 100644 --- a/test/issues/Issue198.hx +++ b/test/issues/Issue198.hx @@ -1,9 +1,8 @@ +class Issue198 { -class Issue198 -{ - public function new() - { - var b : Bool; - b = b && true; - } -} + public function new() { + var b:Bool; + b = b && true; + } + +} \ No newline at end of file diff --git a/test/issues/Issue2.hx b/test/issues/Issue2.hx index 242c202..61fbdad 100644 --- a/test/issues/Issue2.hx +++ b/test/issues/Issue2.hx @@ -1,10 +1,9 @@ +class Issue2 { -class Issue2 -{ - public function new() - { - trace({ - name : "hello" - }); - } -} + public function new() { + trace({ + name: 'hello' + }); + } + +} \ No newline at end of file diff --git a/test/issues/Issue200.hx b/test/issues/Issue200.hx index d22ff09..c1f583e 100644 --- a/test/issues/Issue200.hx +++ b/test/issues/Issue200.hx @@ -1,9 +1,8 @@ +class Issue200 { -class Issue200 -{ - public function new() - { - Type.getClassName(Type.getClass(this)); - Type.getClassName(Issue200); - } -} + public function new() { + Type.getClassName(Type.getClass(this)); + Type.getClassName(Issue200); + } + +} \ No newline at end of file diff --git a/test/issues/Issue202.hx b/test/issues/Issue202.hx index 6676f43..fbb1bd5 100644 --- a/test/issues/Issue202.hx +++ b/test/issues/Issue202.hx @@ -1,10 +1,9 @@ +class Issue202 { -class Issue202 -{ - public function new() - { - var string : String = "She sells seashells by the seashore."; - string = new as3hx.Compat.Regex('sh', "gi").replace(string, "sch"); - trace(string); - } -} + public function new() { + var string:String = 'She sells seashells by the seashore.'; + string = new as3hx.Compat.Regex('sh', 'gi').replace(string, 'sch'); + trace(string); + } + +} \ No newline at end of file diff --git a/test/issues/Issue204.hx b/test/issues/Issue204.hx index 243c66f..d671945 100644 --- a/test/issues/Issue204.hx +++ b/test/issues/Issue204.hx @@ -1,22 +1,17 @@ import haxe.Constraints.Function; -class Issue204 -{ - public function new() - { - var i : Int; - var j : Int; - var test : Int->Float->Void = function(i : Int, n : Float) : Void - { - trace(i + n); - } - var f : Function = function() : Void - { - } - var i : Int = 10; - var n : Float = 0.1; - test(i, n); - } -} +class Issue204 { + public function new() { + var i:Int; + var j:Int; + var test:Int->Float->Void = function(i:Int, n:Float):Void { + trace(i + n); + } + var f:Function = function():Void {} + var i:Int = 10; + var n:Float = 0.1; + test(i, n); + } +} \ No newline at end of file diff --git a/test/issues/Issue205.hx b/test/issues/Issue205.hx index d9e203d..c2f3e1b 100644 --- a/test/issues/Issue205.hx +++ b/test/issues/Issue205.hx @@ -1,18 +1,16 @@ import haxe.Constraints.Function; -class Issue205 -{ - public function new() - { - var f : Function = test; - if (as3hx.Compat.getFunctionLength(f) == 1) - { - f(1); - } - } - - private function test(s : String) : Void - { - trace(s); - } -} +class Issue205 { + + public function new() { + var f:Function = test; + if (as3hx.Compat.getFunctionLength(f) == 1) { + f(1); + } + } + + private function test(s:String):Void { + trace(s); + } + +} \ No newline at end of file diff --git a/test/issues/Issue208.hx b/test/issues/Issue208.hx index 301fafe..cf80d56 100644 --- a/test/issues/Issue208.hx +++ b/test/issues/Issue208.hx @@ -1,32 +1,21 @@ import flash.errors.Error; -class Issue208 -{ - public function new() - { - try - { - var s : String = ""; - } - catch (e : Error) - { - trace(e); - } - - try - { - var s : String = ""; - } - catch (e : Error) - { - } - - try - { - var s : String = ""; - } - catch (e : Error) - { - } - } -} +class Issue208 { + + public function new() { + try { + var s:String = ''; + } catch (e:Error) { + trace(e); + } + + try { + var s:String = ''; + } catch (e:Error) {} + + try { + var s:String = ''; + } catch (e:Error) {} + } + +} \ No newline at end of file diff --git a/test/issues/Issue210.hx b/test/issues/Issue210.hx index 411d4b8..b12f7db 100644 --- a/test/issues/Issue210.hx +++ b/test/issues/Issue210.hx @@ -1,8 +1,7 @@ +class Issue210 { -class Issue210 -{ - public function new() - { - var n : Float = Math.NaN; - } -} + public function new() { + var n:Float = Math.NaN; + } + +} \ No newline at end of file diff --git a/test/issues/Issue213.hx b/test/issues/Issue213.hx index 68f04c7..9c8c3ec 100644 --- a/test/issues/Issue213.hx +++ b/test/issues/Issue213.hx @@ -1,20 +1,17 @@ import starling.utils.StringUtil; +class Issue213 { + + public function new() { + StringUtil.format('[VertexData format="{0}" numVertices={1}]', '', 1); + } -class Issue213 -{ - public function new() - { - StringUtil.format("[VertexData format=\"{0}\" numVertices={1}]", "", 1); - } } +class Foo { + public function new() { + StringTools.trim(' abc '); + StringTools.isSpace('', 0); + } -class Foo -{ - public function new() - { - StringTools.trim(" abc "); - StringTools.isSpace("", 0); - } -} +} \ No newline at end of file diff --git a/test/issues/Issue214.hx b/test/issues/Issue214.hx index 2050483..92b96a9 100644 --- a/test/issues/Issue214.hx +++ b/test/issues/Issue214.hx @@ -1,19 +1,15 @@ +class Issue214 { -class Issue214 -{ - public var test(never, set) : Bool; + public var test(never, set):Bool; - public function new() - { - } - - private function set_test(v : Bool) : Bool - { - if (!v) - { - return v; - } - trace(v); - return v; - } -} + public function new() {} + + private function set_test(v:Bool):Bool { + if (!v) { + return v; + } + trace(v); + return v; + } + +} \ No newline at end of file diff --git a/test/issues/Issue215.hx b/test/issues/Issue215.hx index ba981d3..d74bbeb 100644 --- a/test/issues/Issue215.hx +++ b/test/issues/Issue215.hx @@ -1,11 +1,11 @@ +class Issue215 { -class Issue215 -{ - private static var regex : as3hx.Compat.Regex = new as3hx.Compat.Regex('sh', "gi"); - public function new(string2 : String) - { - var string : String = "She sells seashells by the seashore."; - string = regex.replace(string, "sch"); - string = regex.replace(string2, "sch"); - } -} + private static var regex:as3hx.Compat.Regex = new as3hx.Compat.Regex('sh', 'gi'); + + public function new(string2:String) { + var string:String = 'She sells seashells by the seashore.'; + string = regex.replace(string, 'sch'); + string = regex.replace(string2, 'sch'); + } + +} \ No newline at end of file diff --git a/test/issues/Issue218.hx b/test/issues/Issue218.hx index bc9152c..cce0980 100644 --- a/test/issues/Issue218.hx +++ b/test/issues/Issue218.hx @@ -1,11 +1,10 @@ +class Issue218 { -class Issue218 -{ - public function new(sub : String, sub2 : Dynamic) - { - var string : String = "She sells seashells by the seashore."; - string = StringTools.replace(string, "sh", "sch"); - string = StringTools.replace(string, sub, "sch"); - string = StringTools.replace(string, Std.string(sub2), "sch"); - } -} + public function new(sub:String, sub2:Dynamic) { + var string:String = 'She sells seashells by the seashore.'; + string = StringTools.replace(string, 'sh', 'sch'); + string = StringTools.replace(string, sub, 'sch'); + string = StringTools.replace(string, Std.string(sub2), 'sch'); + } + +} \ No newline at end of file diff --git a/test/issues/Issue223.hx b/test/issues/Issue223.hx index 0583c6b..d590a52 100644 --- a/test/issues/Issue223.hx +++ b/test/issues/Issue223.hx @@ -1,9 +1,8 @@ +class Issue223 { -class Issue223 -{ - public function new() - { - var result : Float = Math.min(Math.min(Math.min(1, 2), 3), 4); - var result : Float = Math.max(Math.max(Math.max(1, 2), 3), 4); - } -} + public function new() { + var result:Float = Math.min(Math.min(Math.min(1, 2), 3), 4); + var result:Float = Math.max(Math.max(Math.max(1, 2), 3), 4); + } + +} \ No newline at end of file diff --git a/test/issues/Issue226.hx b/test/issues/Issue226.hx index d7bce8e..65bfa27 100644 --- a/test/issues/Issue226.hx +++ b/test/issues/Issue226.hx @@ -1,10 +1,9 @@ +class Issue226 { -class Issue226 -{ - public function new() - { - var dictionary : haxe.ds.ObjectMap = new haxe.ds.ObjectMap(); - dictionary.set("key", true); - dictionary.remove("key"); - } -} + public function new() { + var dictionary:haxe.ds.ObjectMap = new haxe.ds.ObjectMap(); + dictionary.set('key', true); + dictionary.remove('key'); + } + +} \ No newline at end of file diff --git a/test/issues/Issue228.hx b/test/issues/Issue228.hx index 72becc8..7ca02b1 100644 --- a/test/issues/Issue228.hx +++ b/test/issues/Issue228.hx @@ -1,9 +1,8 @@ +class Issue228 { -class Issue228 -{ - public function new() - { - var n : Float = Math.POSITIVE_INFINITY; - var n : Float = Math.NEGATIVE_INFINITY; - } -} + public function new() { + var n:Float = Math.POSITIVE_INFINITY; + var n:Float = Math.NEGATIVE_INFINITY; + } + +} \ No newline at end of file diff --git a/test/issues/Issue23.hx b/test/issues/Issue23.hx index 2554783..5b98d07 100644 --- a/test/issues/Issue23.hx +++ b/test/issues/Issue23.hx @@ -1,23 +1,21 @@ +class Issue23 { -class Issue23 -{ - - public function new(i : Int, n : Float, ss : String) - { - var a : Int = i; - var a2 : Int = i; - var a3 : Int = as3hx.Compat.parseInt(n); - var a4 : Int = as3hx.Compat.parseInt(s); - - var b : Float = n; - var b2 : Float = n; - var b3 : Float = i; - var b4 : Float = as3hx.Compat.parseFloat(s); - - var s : String = Std.string(n); - var s2 : String = ss; - var s3 : String = ss; - var s4 : String = Std.string(i); - var s5 : String = Std.string(i); - } -} + public function new(i:Int, n:Float, ss:String) { + var a:Int = i; + var a2:Int = i; + var a3:Int = as3hx.Compat.parseInt(n); + var a4:Int = as3hx.Compat.parseInt(s); + + var b:Float = n; + var b2:Float = n; + var b3:Float = i; + var b4:Float = as3hx.Compat.parseFloat(s); + + var s:String = Std.string(n); + var s2:String = ss; + var s3:String = ss; + var s4:String = Std.string(i); + var s5:String = Std.string(i); + } + +} \ No newline at end of file diff --git a/test/issues/Issue230.hx b/test/issues/Issue230.hx index df02fbc..af024f1 100644 --- a/test/issues/Issue230.hx +++ b/test/issues/Issue230.hx @@ -1,8 +1,7 @@ +class Issue230 { -class Issue230 -{ - public function new() - { - var d : haxe.ds.ObjectMap = new haxe.ds.ObjectMap(); - } -} + public function new() { + var d:haxe.ds.ObjectMap = new haxe.ds.ObjectMap(); + } + +} \ No newline at end of file diff --git a/test/issues/Issue234.hx b/test/issues/Issue234.hx index 7638b0f..6f35e07 100644 --- a/test/issues/Issue234.hx +++ b/test/issues/Issue234.hx @@ -1,9 +1,8 @@ import flash.display3D.Context3D; +class Issue234 { -class Issue234 -{ - public function new() - { - var supportsVideoTexture : Bool = Reflect.field(Context3D, "supportsVideoTexture"); - } -} + public function new() { + var supportsVideoTexture:Bool = Reflect.field(Context3D, 'supportsVideoTexture'); + } + +} \ No newline at end of file diff --git a/test/issues/Issue235.hx b/test/issues/Issue235.hx index d6c6ec4..d09bdec 100644 --- a/test/issues/Issue235.hx +++ b/test/issues/Issue235.hx @@ -1,15 +1,10 @@ +class Issue235 { -class Issue235 -{ - public function new() - { - var mask : Int; - var flag : Int; - if ((i & flag) == 0) - { - } - if ((i & flag) != 0) - { - } - } -} + public function new() { + var mask:Int; + var flag:Int; + if ((i & flag) == 0) {} + if ((i & flag) != 0) {} + } + +} \ No newline at end of file diff --git a/test/issues/Issue238.hx b/test/issues/Issue238.hx index 61ba94d..66e47ff 100644 --- a/test/issues/Issue238.hx +++ b/test/issues/Issue238.hx @@ -1,10 +1,9 @@ +class Issue238 { -class Issue238 -{ - public function new(x : Int, y : Int) - { - x = x & y; - x = x | y; - x = x ^ y; - } -} + public function new(x:Int, y:Int) { + x = x & y; + x = x | y; + x = x ^ y; + } + +} \ No newline at end of file diff --git a/test/issues/Issue24.hx b/test/issues/Issue24.hx index 371a565..7909520 100644 --- a/test/issues/Issue24.hx +++ b/test/issues/Issue24.hx @@ -1,47 +1,43 @@ +class Issue24 { -class Issue24 -{ - public function new(a : Int, b : Int, c : Int, n : Float) - { - c = a; - c = as3hx.Compat.parseInt(a / b); - c = as3hx.Compat.parseInt(n); - c = as3hx.Compat.parseInt(n - a); - c = as3hx.Compat.parseInt(n + a); - c = as3hx.Compat.parseInt(n * a); - c = as3hx.Compat.parseInt(n) << a; - c = as3hx.Compat.parseInt(n) >> a; - c = as3hx.Compat.parseInt(n) >>> a; - c = as3hx.Compat.parseInt(n) & a; - c = as3hx.Compat.parseInt(n) ^ a; - c = as3hx.Compat.parseInt(n) | a; - c = ~as3hx.Compat.parseInt(n); - c = as3hx.Compat.parseInt(n) | as3hx.Compat.parseInt(n); - - var i : Int = as3hx.Compat.parseInt(a / b); - var j : Int = as3hx.Compat.parseInt(n); - var k : Int = as3hx.Compat.parseInt(n - j); - var k : Int = as3hx.Compat.parseInt(n + j); - var k : Int = as3hx.Compat.parseInt(n * j); - var k : Int = as3hx.Compat.parseInt(n) << j; - var k : Int = as3hx.Compat.parseInt(n) >> j; - var k : Int = as3hx.Compat.parseInt(n) >>> j; - var k : Int = as3hx.Compat.parseInt(n) & j; - var k : Int = j & as3hx.Compat.parseInt(n); - var k : Int = as3hx.Compat.parseInt(n) ^ j; - var k : Int = j ^ as3hx.Compat.parseInt(n); - var k : Int = as3hx.Compat.parseInt(n) | j; - var k : Int = j | as3hx.Compat.parseInt(n); - var n2 : Float; - var k : Int = ~as3hx.Compat.parseInt(n2); - - if ((as3hx.Compat.parseInt(n) & as3hx.Compat.parseInt(n - 1)) == 0) - { - } - } - - public function getInt(n : Float) : Int - { - return as3hx.Compat.parseInt(n + 10); - } -} + public function new(a:Int, b:Int, c:Int, n:Float) { + c = a; + c = as3hx.Compat.parseInt(a / b); + c = as3hx.Compat.parseInt(n); + c = as3hx.Compat.parseInt(n - a); + c = as3hx.Compat.parseInt(n + a); + c = as3hx.Compat.parseInt(n * a); + c = as3hx.Compat.parseInt(n) << a; + c = as3hx.Compat.parseInt(n) >> a; + c = as3hx.Compat.parseInt(n) >>> a; + c = as3hx.Compat.parseInt(n) & a; + c = as3hx.Compat.parseInt(n) ^ a; + c = as3hx.Compat.parseInt(n) | a; + c = ~as3hx.Compat.parseInt(n); + c = as3hx.Compat.parseInt(n) | as3hx.Compat.parseInt(n); + + var i:Int = as3hx.Compat.parseInt(a / b); + var j:Int = as3hx.Compat.parseInt(n); + var k:Int = as3hx.Compat.parseInt(n - j); + var k:Int = as3hx.Compat.parseInt(n + j); + var k:Int = as3hx.Compat.parseInt(n * j); + var k:Int = as3hx.Compat.parseInt(n) << j; + var k:Int = as3hx.Compat.parseInt(n) >> j; + var k:Int = as3hx.Compat.parseInt(n) >>> j; + var k:Int = as3hx.Compat.parseInt(n) & j; + var k:Int = j & as3hx.Compat.parseInt(n); + var k:Int = as3hx.Compat.parseInt(n) ^ j; + var k:Int = j ^ as3hx.Compat.parseInt(n); + var k:Int = as3hx.Compat.parseInt(n) | j; + var k:Int = j | as3hx.Compat.parseInt(n); + var n2:Float; + var k:Int = ~as3hx.Compat.parseInt(n2); + + if ((as3hx.Compat.parseInt(n) & as3hx.Compat.parseInt(n - 1)) == 0) {} + } + + public function getInt(n:Float):Int { + return as3hx.Compat.parseInt(n + 10); + } + +} \ No newline at end of file diff --git a/test/issues/Issue241.hx b/test/issues/Issue241.hx index a5cbf0b..ed23731 100644 --- a/test/issues/Issue241.hx +++ b/test/issues/Issue241.hx @@ -1,9 +1,8 @@ +class Issue241 { -class Issue241 -{ - public function new() - { - var d : haxe.ds.ObjectMap = new haxe.ds.ObjectMap(); - trace(Std.is(d, haxe.ds.ObjectMap)); - } -} + public function new() { + var d:haxe.ds.ObjectMap = new haxe.ds.ObjectMap(); + trace(Std.is(d, haxe.ds.ObjectMap)); + } + +} \ No newline at end of file diff --git a/test/issues/Issue244.hx b/test/issues/Issue244.hx index 9ae3cb5..6a01ce8 100644 --- a/test/issues/Issue244.hx +++ b/test/issues/Issue244.hx @@ -1,16 +1,15 @@ +class Issue244 { -class Issue244 -{ - public function new(c : Dynamic) - { - var a : Dynamic = { }; - if (Reflect.field(a, Std.string(10)) == null) { - Reflect.setField(a, Std.string(10), {}); - } - var b : Dynamic = Reflect.field(a, Std.string(10)); - if (Reflect.field(a, Std.string(10)) == null) { - Reflect.setField(a, Std.string(10), {}); - } - c = Reflect.field(a, Std.string(10)); - } -} + public function new(c:Dynamic) { + var a:Dynamic = {}; + if (Reflect.field(a, Std.string(10)) == null) { + Reflect.setField(a, Std.string(10), {}); + } + var b:Dynamic = Reflect.field(a, Std.string(10)); + if (Reflect.field(a, Std.string(10)) == null) { + Reflect.setField(a, Std.string(10), {}); + } + c = Reflect.field(a, Std.string(10)); + } + +} \ No newline at end of file diff --git a/test/issues/Issue246.hx b/test/issues/Issue246.hx index 13b60d2..40f0090 100644 --- a/test/issues/Issue246.hx +++ b/test/issues/Issue246.hx @@ -1,19 +1,16 @@ +class Issue246 { -class Issue246 -{ - public var steps(never, set) : Int; + public var steps(never, set):Int; - public function new() - { - } - - private var _steps : Int = 8; - private function set_steps(val : Int) : Int - { - if (_steps == val) - { - return val; - } - return val; - } -} + public function new() {} + + private var _steps:Int = 8; + + private function set_steps(val:Int):Int { + if (_steps == val) { + return val; + } + return val; + } + +} \ No newline at end of file diff --git a/test/issues/Issue247.hx b/test/issues/Issue247.hx index 287ff1e..91aae17 100644 --- a/test/issues/Issue247.hx +++ b/test/issues/Issue247.hx @@ -1,11 +1,7 @@ +class Issue247 { -class Issue247 -{ - public function new(args : Array = null) - { - } - - public function test(args : Array = null) : Void - { - } -} + public function new(args:Array = null) {} + + public function test(args:Array = null):Void {} + +} \ No newline at end of file diff --git a/test/issues/Issue250.hx b/test/issues/Issue250.hx index 9c7213e..7f6a237 100644 --- a/test/issues/Issue250.hx +++ b/test/issues/Issue250.hx @@ -1,23 +1,19 @@ +class Issue250 { -class Issue250 -{ - - private static var globalStorage : Dynamic = {}; - - public function new() - { - var o : Dynamic = {}; - } - - private var localStorage : Dynamic = {}; - - private function onTest() : Void - { - var params : Dynamic = {}; - } - - private function getObject() : Dynamic - { - return {}; - } -} + private static var globalStorage:Dynamic = {}; + + public function new() { + var o:Dynamic = {}; + } + + private var localStorage:Dynamic = {}; + + private function onTest():Void { + var params:Dynamic = {}; + } + + private function getObject():Dynamic { + return {}; + } + +} \ No newline at end of file diff --git a/test/issues/Issue254.hx b/test/issues/Issue254.hx index 33f4440..bf7cfd2 100644 --- a/test/issues/Issue254.hx +++ b/test/issues/Issue254.hx @@ -1,16 +1,13 @@ +class Issue254 { -class Issue254 -{ - public function new() - { - if (true) - { - return; - } - - if (true) - { - return; - } - } -} + public function new() { + if (true) { + return; + } + + if (true) { + return; + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue255.hx b/test/issues/Issue255.hx index d584930..3622f39 100644 --- a/test/issues/Issue255.hx +++ b/test/issues/Issue255.hx @@ -1,8 +1,7 @@ +class Issue255 { -class Issue255 -{ - private var NORMAL(default, never) : Int = 0; - public function new() - { - } -} + private var NORMAL(default, never):Int = 0; + + public function new() {} + +} \ No newline at end of file diff --git a/test/issues/Issue257.hx b/test/issues/Issue257.hx index a0a9c6c..9b0074c 100644 --- a/test/issues/Issue257.hx +++ b/test/issues/Issue257.hx @@ -1,10 +1,9 @@ import flash.net.URLRequest; +class Issue257 { -class Issue257 -{ - public function new() - { - var req : URLRequest = new URLRequest("http://www.adobe.com/"); - flash.Lib.getURL(req, "_blank"); - } -} + public function new() { + var req:URLRequest = new URLRequest('http://www.adobe.com/'); + flash.Lib.getURL(req, '_blank'); + } + +} \ No newline at end of file diff --git a/test/issues/Issue26.hx b/test/issues/Issue26.hx index ab7c378..b8823d2 100644 --- a/test/issues/Issue26.hx +++ b/test/issues/Issue26.hx @@ -1,44 +1,33 @@ +class Issue26 { -class Issue26 -{ + public function new() {} - public function new() - { - } } +class Foo { + + @:allow() + private function foo():Void {} + + private function some():Void {} + + public function new() {} -class Foo -{ - @:allow() - private function foo() : Void - { - } - - private function some() : Void - { - } - - public function new() - { - } } -class Bar extends Foo -{ - @:allow() - override private function foo() : Void - { - super.foo(); - } - - override private function some() : Void - { - super.some(); - } - - public function new() - { - super(); - } +class Bar extends Foo { + + @:allow() + override private function foo():Void { + super.foo(); + } + + override private function some():Void { + super.some(); + } + + public function new() { + super(); + } + } \ No newline at end of file diff --git a/test/issues/Issue261.hx b/test/issues/Issue261.hx index 48d0fcb..f640293 100644 --- a/test/issues/Issue261.hx +++ b/test/issues/Issue261.hx @@ -1,9 +1,8 @@ +class Issue261 { -class Issue261 -{ - public function new() - { - var a : Array = [{ }]; - Reflect.setField(a[a.length - 1], "some", 10); - } -} + public function new() { + var a:Array = [{}]; + Reflect.setField(a[a.length - 1], 'some', 10); + } + +} \ No newline at end of file diff --git a/test/issues/Issue261_1.hx b/test/issues/Issue261_1.hx index 353451b..5c09717 100644 --- a/test/issues/Issue261_1.hx +++ b/test/issues/Issue261_1.hx @@ -1,13 +1,10 @@ +class Issue2611 { -class Issue2611 -{ - public function randomGen(param1 : Int) : Int - { - var _loc2_ : Int = Math.floor(Math.random() * param1); - return _loc2_; - } + public function randomGen(param1:Int):Int { + var _loc2_:Int = Math.floor(Math.random() * param1); + return _loc2_; + } - public function new() - { - } -} + public function new() {} + +} \ No newline at end of file diff --git a/test/issues/Issue261_2.hx b/test/issues/Issue261_2.hx index a45b074..7193082 100644 --- a/test/issues/Issue261_2.hx +++ b/test/issues/Issue261_2.hx @@ -1,12 +1,9 @@ +class Issue2612 { -class Issue2612 -{ - private function frame1() : Dynamic - { - gotoAndPlay((this.randomGen(48) + 1) * 4 + 1); - } + private function frame1():Dynamic { + gotoAndPlay((this.randomGen(48) + 1) * 4 + 1); + } - public function new() - { - } -} + public function new() {} + +} \ No newline at end of file diff --git a/test/issues/Issue264.hx b/test/issues/Issue264.hx index 568b2d5..b0b3035 100644 --- a/test/issues/Issue264.hx +++ b/test/issues/Issue264.hx @@ -1,25 +1,21 @@ +class Issue264 { -class Issue264 -{ - public function new() - { - var obj : Dynamic = {}; - var message : String; - - // error inside - if (Std.is(obj.error, Error)) - { - message = obj.error.message; - } - // error event inside - else if (Std.is(obj.error, ErrorEvent)) - { - message = obj.error.text; - } - // unknown - else - { - message = Std.string(obj.error); - } - } -} + public function new() { + var obj:Dynamic = {}; + var message:String; + + // error inside + if (Std.is(obj.error, Error)) { + message = obj.error.message; + } + // error event inside + else if (Std.is(obj.error, ErrorEvent)) { + message = obj.error.text; + } + // unknown + else { + message = Std.string(obj.error); + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue265.hx b/test/issues/Issue265.hx index de4828a..b4684ba 100644 --- a/test/issues/Issue265.hx +++ b/test/issues/Issue265.hx @@ -1,8 +1,7 @@ +class Issue265 { -class Issue265 -{ - public function new() - { - var color : Int = as3hx.Compat.parseInt("0xffffff", 16); - } -} + public function new() { + var color:Int = as3hx.Compat.parseInt('0xffffff', 16); + } + +} \ No newline at end of file diff --git a/test/issues/Issue27.hx b/test/issues/Issue27.hx index b6e3e10..d3c8c23 100644 --- a/test/issues/Issue27.hx +++ b/test/issues/Issue27.hx @@ -1,14 +1,12 @@ +class Issue27 { -class Issue27 -{ - public function new(condition : Bool) - { - if (condition) - { - trace(1); - } - - //some comment - trace(2); - } -} + public function new(condition:Bool) { + if (condition) { + trace(1); + } + + //some comment + trace(2); + } + +} \ No newline at end of file diff --git a/test/issues/Issue273.hx b/test/issues/Issue273.hx index ed36a5d..04f7bb2 100644 --- a/test/issues/Issue273.hx +++ b/test/issues/Issue273.hx @@ -1,30 +1,28 @@ +class Issue273 { -class Issue273 -{ - public function new() - { - var param1 = "j"; - switch (param1) - { - case "a": - return 1; - case "b": - return 2; - case "c": - return 3; - case "d": - return 4; - case "e": - return 5; - case "f": - return 6; - case "g": - return 7; - case "h": - return 8; - /* covers case "i": */ - default: - return 9; - } - } -} + public function new() { + var param1 = 'j'; + switch (param1) { + case 'a': + return 1; + case 'b': + return 2; + case 'c': + return 3; + case 'd': + return 4; + case 'e': + return 5; + case 'f': + return 6; + case 'g': + return 7; + case 'h': + return 8; + /* covers case 'i': */ + case _: + return 9; + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue274.hx b/test/issues/Issue274.hx index 8b03344..1faf53e 100644 --- a/test/issues/Issue274.hx +++ b/test/issues/Issue274.hx @@ -1,12 +1,11 @@ +class Issue274 { -class Issue274 -{ - public function new() - { - var a : Int = 1; - var b : Int = 1; - var c : Int = 1; - var e : Int = 1; - e += ((a > b || c > b)) ? 1 : 0; - } -} + public function new() { + var a:Int = 1; + var b:Int = 1; + var c:Int = 1; + var e:Int = 1; + e += ((a > b || c > b)) ? 1 : 0; + } + +} \ No newline at end of file diff --git a/test/issues/Issue275.hx b/test/issues/Issue275.hx index 7137a57..1c565f7 100644 --- a/test/issues/Issue275.hx +++ b/test/issues/Issue275.hx @@ -1,12 +1,11 @@ +class Issue275 { -class Issue275 -{ - public function new() - { - var a : Int = 1; - var b : Int = 1; - var c : Int = 1; - var d : Int = 1; - d += (a > b || c != 0) ? 1 : 0; - } -} + public function new() { + var a:Int = 1; + var b:Int = 1; + var c:Int = 1; + var d:Int = 1; + d += (a > b || c != 0) ? 1 : 0; + } + +} \ No newline at end of file diff --git a/test/issues/Issue277.hx b/test/issues/Issue277.hx index 6ba1e37..a3d5fa3 100644 --- a/test/issues/Issue277.hx +++ b/test/issues/Issue277.hx @@ -1,51 +1,29 @@ +class Issue277 { -class Issue277 -{ - public function new() - { - if (1) - { - a(); - } - else if (2) - { - b(); - } - else if (3) - { - c(); - } - else if (4) - { - d(); - } - else if (5) - { - e(); - } - else if (6) - { - f(); - } - else if (7) - { - g(); - } - else if (8) - { - h(); - } - else if (9) - { - i(); - } - else if (10) - { - j(); - } - else - { - k(); - } - } -} + public function new() { + if (1) { + a(); + } else if (2) { + b(); + } else if (3) { + c(); + } else if (4) { + d(); + } else if (5) { + e(); + } else if (6) { + f(); + } else if (7) { + g(); + } else if (8) { + h(); + } else if (9) { + i(); + } else if (10) { + j(); + } else { + k(); + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue28.hx b/test/issues/Issue28.hx index dc417e6..e0aa14f 100644 --- a/test/issues/Issue28.hx +++ b/test/issues/Issue28.hx @@ -1,34 +1,29 @@ +class Issue28 { -class Issue28 -{ - - private static var b : Bool = true; - private static var o : Dynamic = (b) ? { } : null; - - public function new() - { - var a : Int = 1; - var b : Int = 1; - var c : Int = 1; - var c : Int = (((a != 0 || b != 0) ? 1 : 0) && c != 0) ? 1 : 0; - } - - private function test(a : Array, b : Bool) : Int - { - return (a != null || b) ? 1 : 0; - } - - private function test2(a : Array, b : Bool) : Int - { - if ((a != null || b) ? true : false) - { - return 1; - } - return 0; - } - - private function test3(b : Bool, o : Dynamic) : Void - { - o = (b) ? { } : null; - } -} + private static var b:Bool = true; + + private static var o:Dynamic = (b) ? {} : null; + + public function new() { + var a:Int = 1; + var b:Int = 1; + var c:Int = 1; + var c:Int = (((a != 0 || b != 0) ? 1 : 0) && c != 0) ? 1 : 0; + } + + private function test(a:Array, b:Bool):Int { + return (a != null || b) ? 1 : 0; + } + + private function test2(a:Array, b:Bool):Int { + if ((a != null || b) ? true : false) { + return 1; + } + return 0; + } + + private function test3(b:Bool, o:Dynamic):Void { + o = (b) ? {} : null; + } + +} \ No newline at end of file diff --git a/test/issues/Issue285.hx b/test/issues/Issue285.hx index 8f7d967..1f3704b 100644 --- a/test/issues/Issue285.hx +++ b/test/issues/Issue285.hx @@ -1,13 +1,11 @@ +class Issue285 { -class Issue285 -{ - public function new() - { - var x : Int = 1; - var max : Int = 10; - while (x < max) - { - ++x; - } - } -} + public function new() { + var x:Int = 1; + var max:Int = 10; + while (x < max) { + ++x; + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue29.hx b/test/issues/Issue29.hx index 330d3bc..81fc1fb 100644 --- a/test/issues/Issue29.hx +++ b/test/issues/Issue29.hx @@ -1,14 +1,12 @@ +class Issue29 { -class Issue29 -{ - public function new() - { - var stuff : Array = []; - var i : Int = 0; - while (i < 10 || stuff[i] != null) - { - trace(i); - i++; - } - } -} + public function new() { + var stuff:Array = []; + var i:Int = 0; + while (i < 10 || stuff[i] != null) { + trace(i); + i++; + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue293.hx b/test/issues/Issue293.hx index efb8f64..42a8721 100644 --- a/test/issues/Issue293.hx +++ b/test/issues/Issue293.hx @@ -1,11 +1,9 @@ +class Issue293 { -class Issue293 -{ - public function new() - { - var i : Int = as3hx.Compat.setTimeout(function(args : Array = null) - { - trace(args); - }, (1 + 1) * 1000, [1, 2, 3]); - } -} + public function new() { + var i:Int = as3hx.Compat.setTimeout(function(args:Array = null) { + trace(args); + }, (1 + 1) * 1000, [1, 2, 3]); + } + +} \ No newline at end of file diff --git a/test/issues/Issue296.as b/test/issues/Issue296.as new file mode 100644 index 0000000..6c9a207 --- /dev/null +++ b/test/issues/Issue296.as @@ -0,0 +1,24 @@ +package { + public class Issue296 { + public function Issue296() { + var a:Array = [1, 2, 3]; + for(var i:int = 0; i < a.length; i++) { + trace(a.pop()); + } + for(var i:int = 0; i < a.pop(); i++) { + trace(i); + } + for(var i:int = 0; i < a.pop() + 10; i++) { + trace(i); + } + for(var i:int = 0; i < a.length; i++) { + if(i < 3) trace(a.pop()); + else continue; + } + for(var i:int = 0; i < a.length; i++) { + trace(a.pop()); + continue; + } + } + } +} \ No newline at end of file diff --git a/test/issues/Issue296.hx b/test/issues/Issue296.hx new file mode 100644 index 0000000..5e568f8 --- /dev/null +++ b/test/issues/Issue296.hx @@ -0,0 +1,38 @@ +class Issue296 { + + public function new() { + var a:Array = [1, 2, 3]; + var i:Int = 0; + while (i < a.length) { + trace(a.pop()); + i++; + } + var i:Int = 0; + while (i < a.pop()) { + trace(i); + i++; + } + var i:Int = 0; + while (i < a.pop() + 10) { + trace(i); + i++; + } + var i:Int = 0; + while (i < a.length) { + if (i < 3) { + trace(a.pop()); + } else { + i++; + continue; + } + i++; + } + var i:Int = 0; + while (i < a.length) { + trace(a.pop()); + i++; + continue; + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue296_1.as b/test/issues/Issue296_1.as new file mode 100644 index 0000000..59027f8 --- /dev/null +++ b/test/issues/Issue296_1.as @@ -0,0 +1,10 @@ +package { + public class Issue296 { + public function Issue296() { + function some(i:int):Boolean { return i < 10; } + for(var i:int = 0; some(i); i++) { + trace(a.pop()); + } + } + } +} \ No newline at end of file diff --git a/test/issues/Issue296_1.hx b/test/issues/Issue296_1.hx new file mode 100644 index 0000000..bf86d53 --- /dev/null +++ b/test/issues/Issue296_1.hx @@ -0,0 +1,14 @@ +class Issue296 { + + public function new() { + var some:Int->Bool = function(i:Int):Bool { + return i < 10; + } + var i:Int = 0; + while (some(i)) { + trace(a.pop()); + i++; + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue298.hx b/test/issues/Issue298.hx index 2e42f91..29608fe 100644 --- a/test/issues/Issue298.hx +++ b/test/issues/Issue298.hx @@ -1,8 +1,7 @@ +class Issue298 { -class Issue298 -{ - public function new() - { - var v : Float = 1.79E+308; - } -} + public function new() { + var v:Float = 1.79E+308; + } + +} \ No newline at end of file diff --git a/test/issues/Issue300.hx b/test/issues/Issue300.hx index b3341e7..0121b78 100644 --- a/test/issues/Issue300.hx +++ b/test/issues/Issue300.hx @@ -1,8 +1,7 @@ +class Issue300 { -class Issue300 -{ - public function new() - { - trace(as3hx.Compat.typeof(3)); - } -} + public function new() { + trace(as3hx.Compat.typeof(3)); + } + +} \ No newline at end of file diff --git a/test/issues/Issue302.hx b/test/issues/Issue302.hx index 87c62a5..d5fd5d5 100644 --- a/test/issues/Issue302.hx +++ b/test/issues/Issue302.hx @@ -1,7 +1,5 @@ +class Issue302 { -class Issue302 -{ - public function new(i : Int = 1) - { - } -} + public function new(i:Int = 1) {} + +} \ No newline at end of file diff --git a/test/issues/Issue303.hx b/test/issues/Issue303.hx index 0fc2be9..6eaffd5 100644 --- a/test/issues/Issue303.hx +++ b/test/issues/Issue303.hx @@ -1,7 +1,5 @@ +class Issue303 { -class Issue303 -{ - public function new(i : Int = 1000) - { - } -} + public function new(i:Int = 1000) {} + +} \ No newline at end of file diff --git a/test/issues/Issue314.hx b/test/issues/Issue314.hx index 35c2882..b23cb14 100644 --- a/test/issues/Issue314.hx +++ b/test/issues/Issue314.hx @@ -1,17 +1,15 @@ +class Issue314 { -class Issue314 -{ - public function new() - { - } - public function hide1(param1 : Dynamic) : Dynamic - { - Reflect.setField(this, Std.string(param1), false); - Reflect.field(this, Std.string(param1)).visible = false; - } - public function hide2(param1 : Dynamic) : Dynamic - { - Reflect.setField(this, Std.string(param1), "nothing"); - Reflect.field(this, Std.string(param1)).collision.currentObject = "nothing"; - } -} + public function new() {} + + public function hide1(param1:Dynamic):Dynamic { + Reflect.setField(this, Std.string(param1), false); + Reflect.field(this, Std.string(param1)).visible = false; + } + + public function hide2(param1:Dynamic):Dynamic { + Reflect.setField(this, Std.string(param1), 'nothing'); + Reflect.field(this, Std.string(param1)).collision.currentObject = 'nothing'; + } + +} \ No newline at end of file diff --git a/test/issues/Issue32.hx b/test/issues/Issue32.hx index 3429ab9..846fec5 100644 --- a/test/issues/Issue32.hx +++ b/test/issues/Issue32.hx @@ -1,13 +1,12 @@ +class Issue32 { -class Issue32 -{ - public function new() - { - var a : Array = []; - var b : Array = a.copy(); - var c : Array = a.concat([1, 2, 3, 4]); - var d : Array = []; - var e : Array = d.copy(); - var f : Array = d.concat([1, 2, 3, 4]); - } -} + public function new() { + var a:Array = []; + var b:Array = a.copy(); + var c:Array = a.concat([1, 2, 3, 4]); + var d:Array = []; + var e:Array = d.copy(); + var f:Array = d.concat([1, 2, 3, 4]); + } + +} \ No newline at end of file diff --git a/test/issues/Issue323.as b/test/issues/Issue323.as new file mode 100644 index 0000000..e98cbed --- /dev/null +++ b/test/issues/Issue323.as @@ -0,0 +1,12 @@ +package { + public class Issue323 { + private var friendsList:Vector.; + public function Issue323() { + for ( var i:int = 0; i < friendsList.length; i++ ) + { + if ( friendsList[i].bSelected ) + true; + } + } + } +} \ No newline at end of file diff --git a/test/issues/Issue323.hx b/test/issues/Issue323.hx new file mode 100644 index 0000000..f838616 --- /dev/null +++ b/test/issues/Issue323.hx @@ -0,0 +1,15 @@ +class Issue323 { + + private var friendsList:Array; + + public function new() { + var i:Int = 0; + while (i < friendsList.length) { + if (friendsList[i].bSelected) { + true; + } + i++; + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue36.hx b/test/issues/Issue36.hx index e4c366e..1019a78 100644 --- a/test/issues/Issue36.hx +++ b/test/issues/Issue36.hx @@ -1,9 +1,8 @@ +class Issue36 { -class Issue36 -{ - public function new() - { - var s : String = ""; - var c : String = s.charCodeAt(0); - } -} + public function new() { + var s:String = ''; + var c:String = s.charCodeAt(0); + } + +} \ No newline at end of file diff --git a/test/issues/Issue37.hx b/test/issues/Issue37.hx index 64fd94f..8e0074c 100644 --- a/test/issues/Issue37.hx +++ b/test/issues/Issue37.hx @@ -1,9 +1,8 @@ +class Issue37 { -class Issue37 -{ - public function new() - { - var s : String = "test"; - var xml : FastXML = FastXML.parse(s); - } -} + public function new() { + var s:String = 'test'; + var xml:FastXML = FastXML.parse(s); + } + +} \ No newline at end of file diff --git a/test/issues/Issue38.hx b/test/issues/Issue38.hx index b0ac77f..81ae54e 100644 --- a/test/issues/Issue38.hx +++ b/test/issues/Issue38.hx @@ -1,15 +1,13 @@ +class Issue38 { -class Issue38 -{ - public function new() - { - var a : String = ""; - switch (a) - { - case "a", "c": - trace("a"); - default: - trace("b"); - } - } -} + public function new() { + var a:String = ''; + switch (a) { + case 'a', 'c': + trace('a'); + case _: + trace('b'); + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue52.hx b/test/issues/Issue52.hx index 0517acc..ace0476 100644 --- a/test/issues/Issue52.hx +++ b/test/issues/Issue52.hx @@ -1,8 +1,7 @@ +class Issue52 { -class Issue52 -{ - private var i = 10; - public function new() - { - } -} + private var i = 10; + + public function new() {} + +} \ No newline at end of file diff --git a/test/issues/Issue53.hx b/test/issues/Issue53.hx index 35b365f..abf0f7d 100644 --- a/test/issues/Issue53.hx +++ b/test/issues/Issue53.hx @@ -1,13 +1,11 @@ +class Issue53 { -class Issue53 -{ - public function new() - { - } - private static var Issue53_static_initializer = { - Issue52; - Issue103; - true; - } + public function new() {} -} + private static var Issue53_static_initializer = { + Issue52; + Issue103; + true; + } + +} \ No newline at end of file diff --git a/test/issues/Issue54.hx b/test/issues/Issue54.hx index 119542e..e29d61f 100644 --- a/test/issues/Issue54.hx +++ b/test/issues/Issue54.hx @@ -1,8 +1,7 @@ +class Issue54 { -class Issue54 -{ - private var d : haxe.ds.ObjectMap = new haxe.ds.ObjectMap(); - public function new(d : haxe.ds.ObjectMap = null) - { - } -} + private var d:haxe.ds.ObjectMap = new haxe.ds.ObjectMap(); + + public function new(d:haxe.ds.ObjectMap = null) {} + +} \ No newline at end of file diff --git a/test/issues/Issue63.hx b/test/issues/Issue63.hx index bb713c3..376f9aa 100644 --- a/test/issues/Issue63.hx +++ b/test/issues/Issue63.hx @@ -1,12 +1,11 @@ import flash.utils.ByteArray; +class Issue63 { -class Issue63 -{ - public function new() - { - var a : Array = new Array(); - as3hx.Compat.setArrayLength(a, 10); - var bytes : ByteArray = new ByteArray(); - bytes.length = 0; - } -} + public function new() { + var a:Array = new Array(); + as3hx.Compat.setArrayLength(a, 10); + var bytes:ByteArray = new ByteArray(); + bytes.length = 0; + } + +} \ No newline at end of file diff --git a/test/issues/Issue64.hx b/test/issues/Issue64.hx index 68e0fed..a209fac 100644 --- a/test/issues/Issue64.hx +++ b/test/issues/Issue64.hx @@ -1,33 +1,27 @@ import flash.events.Event; +class Issue64 { + + public function new() { + var skeleton:Dynamic; + var timelines:Array; + var lastTime:Float; + var time:Float; + var events:Array; + var i:Int = 0; + var n:Int = timelines.length; + while (i < n) { + timelienes[i].apply(skeleton, lastTime, time, events, 1); + i++; + } + } -class Issue64 -{ - public function new() - { - var skeleton : Dynamic; - var timelines : Array; - var lastTime : Float; - var time : Float; - var events : Array; - var i : Int = 0; - var n : Int = timelines.length; - while (i < n) - { - timelienes[i].apply(skeleton, lastTime, time, events, 1); - i++; - } - } } +class Timeline { + + public function apply(object:Dynamic, lastTime:Float, time:Float, events:Array, number:Float):Void {} -class Timeline -{ - public function apply(object : Dynamic, lastTime : Float, time : Float, events : Array, number : Float) : Void - { - } + public function new() {} - public function new() - { - } } \ No newline at end of file diff --git a/test/issues/Issue65.hx b/test/issues/Issue65.hx index 6e78a27..ddfa8c2 100644 --- a/test/issues/Issue65.hx +++ b/test/issues/Issue65.hx @@ -1,16 +1,16 @@ +class Issue65 { -class Issue65 -{ - public function new() - { - var array : Array; - for (i in 0...array.length) - { - var current : Dynamic = array[i]; - if (current == null) - { - continue; - } - } - } -} + public function new() { + var array:Array; + var i:Int = 0; + while (i < array.length) { + var current:Dynamic = array[i]; + if (current == null) { + i++; + continue; + } + i++; + } + } + +} \ No newline at end of file diff --git a/test/issues/Issue66.hx b/test/issues/Issue66.hx index af36e6a..68b8362 100644 --- a/test/issues/Issue66.hx +++ b/test/issues/Issue66.hx @@ -1,12 +1,11 @@ +class Issue66 { -class Issue66 -{ - public function new() - { - var a : Int = 1; - var b : Int = as3hx.Compat.parseInt(10.5); - var c : Int = as3hx.Compat.parseInt(a / b); - var b : Float; - var d : Int = as3hx.Compat.parseInt(b); - } -} + public function new() { + var a:Int = 1; + var b:Int = as3hx.Compat.parseInt(10.5); + var c:Int = as3hx.Compat.parseInt(a / b); + var b:Float; + var d:Int = as3hx.Compat.parseInt(b); + } + +} \ No newline at end of file diff --git a/test/issues/Issue68.hx b/test/issues/Issue68.hx index 842d75a..7be3b2d 100644 --- a/test/issues/Issue68.hx +++ b/test/issues/Issue68.hx @@ -1,13 +1,12 @@ +class Issue68 { -class Issue68 -{ - public function new() - { - var a : Array = []; - var b : Array = a.copy(); - var c : Array = a.slice(0, 1); - var d : Array = []; - var e : Array = d.copy(); - var f : Array = d.slice(0, 1); - } -} + public function new() { + var a:Array = []; + var b:Array = a.copy(); + var c:Array = a.slice(0, 1); + var d:Array = []; + var e:Array = d.copy(); + var f:Array = d.slice(0, 1); + } + +} \ No newline at end of file diff --git a/test/issues/Issue69.hx b/test/issues/Issue69.hx index 585a58a..eaa0c9e 100644 --- a/test/issues/Issue69.hx +++ b/test/issues/Issue69.hx @@ -1,9 +1,8 @@ +class Issue69 { -class Issue69 -{ - public function new() - { - var s : String = ""; - var c : String = s.charAt(0); - } -} + public function new() { + var s:String = ''; + var c:String = s.charAt(0); + } + +} \ No newline at end of file diff --git a/test/issues/Issue70.hx b/test/issues/Issue70.hx index d209b73..91eee47 100644 --- a/test/issues/Issue70.hx +++ b/test/issues/Issue70.hx @@ -1,13 +1,11 @@ +class Issue70 { -class Issue70 -{ - public function new(i : Int = 10, args : Array = null) - { - trace(args); - } - - private function test(args : Array = null) : Void - { - trace(args); - } -} + public function new(i:Int = 10, args:Array = null) { + trace(args); + } + + private function test(args:Array = null):Void { + trace(args); + } + +} \ No newline at end of file diff --git a/test/issues/Issue71.hx b/test/issues/Issue71.hx index 9c50bc2..8e47534 100644 --- a/test/issues/Issue71.hx +++ b/test/issues/Issue71.hx @@ -1,19 +1,17 @@ +class Issue71 { -class Issue71 -{ - public function new() - { - __DOLLAR__test({ }); - var __DOLLAR__localVar : Dynamic = { - __DOLLAR__key : "value" - }; - } - - private var __DOLLAR__name : String; - - private function __DOLLAR__test(__DOLLAR__param : Dynamic) : Void - { - trace(__DOLLAR__param); - trace(__DOLLAR__name); - } -} + public function new() { + __DOLLAR__test({}); + var __DOLLAR__localVar:Dynamic = { + __DOLLAR__key: 'value' + }; + } + + private var __DOLLAR__name:String; + + private function __DOLLAR__test(__DOLLAR__param:Dynamic):Void { + trace(__DOLLAR__param); + trace(__DOLLAR__name); + } + +} \ No newline at end of file diff --git a/test/issues/Issue81.hx b/test/issues/Issue81.hx index cdd66b4..e93d82b 100644 --- a/test/issues/Issue81.hx +++ b/test/issues/Issue81.hx @@ -1,14 +1,11 @@ import flash.system.Security; +class Issue81 { -class Issue81 -{ + public function new() {} - public function new() - { - } - private static var Issue81_static_initializer = { - Security.allowDomain("*"); - true; - } + private static var Issue81_static_initializer = { + Security.allowDomain('*'); + true; + } -} +} \ No newline at end of file diff --git a/test/issues/Issue83.hx b/test/issues/Issue83.hx index 7d103cd..24edb36 100644 --- a/test/issues/Issue83.hx +++ b/test/issues/Issue83.hx @@ -1,9 +1,8 @@ +class Issue83 { -class Issue83 -{ - public function new() - { - var o : Dynamic = haxe.Json.parse(""); - var s : String = haxe.Json.stringify({ }); - } -} + public function new() { + var o:Dynamic = haxe.Json.parse(''); + var s:String = haxe.Json.stringify({}); + } + +} \ No newline at end of file diff --git a/test/issues/Issue85.hx b/test/issues/Issue85.hx index 258797a..5cd38d6 100644 --- a/test/issues/Issue85.hx +++ b/test/issues/Issue85.hx @@ -1,8 +1,7 @@ +class Issue85 { -class Issue85 -{ - public function new() - { - var i : Int = 1; - } -} + public function new() { + var i:Int = 1; + } + +} \ No newline at end of file diff --git a/test/issues/Issue87.hx b/test/issues/Issue87.hx index 01ffe9b..6e2a659 100644 --- a/test/issues/Issue87.hx +++ b/test/issues/Issue87.hx @@ -1,31 +1,27 @@ +class Issue87 { + + public function new() { + __DOLLAR__cast(''); + new PrivateClass().__DOLLAR__cast(''); + var __DOLLAR__cast:Int = as3hx.Compat.parseInt(10.0); + } + + private var __DOLLAR__cast:Int = as3hx.Compat.parseInt(10.0); + + private function __DOLLAR__cast(o:Dynamic):String { + return Std.string(o); + } -class Issue87 -{ - public function new() - { - __DOLLAR__cast(""); - new PrivateClass().__DOLLAR__cast(""); - var __DOLLAR__cast : Int = as3hx.Compat.parseInt(10.0); - } - - private var __DOLLAR__cast : Int = as3hx.Compat.parseInt(10.0); - - private function __DOLLAR__cast(o : Dynamic) : String - { - return Std.string(o); - } } +class PrivateClass { + + public function new(__DOLLAR__cast:Int) { + super(); + } + + public function __DOLLAR__cast(o:Dynamic):String { + return Std.string(o); + } -class PrivateClass -{ - public function new(__DOLLAR__cast : Int) - { - super(); - } - - public function __DOLLAR__cast(o : Dynamic) : String - { - return Std.string(o); - } } \ No newline at end of file diff --git a/test/issues/Issue89.hx b/test/issues/Issue89.hx index 9e267ec..6cf5234 100644 --- a/test/issues/Issue89.hx +++ b/test/issues/Issue89.hx @@ -1,16 +1,14 @@ +class Issue89 { -class Issue89 -{ - public function new() - { - var n : Float = getNaN(); - var v : Float = Math.NaN; - } - - private var n : Float = Math.NaN; - - private function getNaN() : Float - { - return Math.NaN; - } -} + public function new() { + var n:Float = getNaN(); + var v:Float = Math.NaN; + } + + private var n:Float = Math.NaN; + + private function getNaN():Float { + return Math.NaN; + } + +} \ No newline at end of file diff --git a/test/issues/Issue91.hx b/test/issues/Issue91.hx index f3f7d7e..2839593 100644 --- a/test/issues/Issue91.hx +++ b/test/issues/Issue91.hx @@ -1,9 +1,8 @@ +class Issue91 { -class Issue91 -{ - public function new() - { - var i : Int = 1; - var b : Bool = i != 0; - } -} + public function new() { + var i:Int = 1; + var b:Bool = i != 0; + } + +} \ No newline at end of file diff --git a/test/issues/Issue93.hx b/test/issues/Issue93.hx index fec7348..06461a4 100644 --- a/test/issues/Issue93.hx +++ b/test/issues/Issue93.hx @@ -1,10 +1,9 @@ +class Issue93 { -class Issue93 -{ - public function new() - { - trace([1, 2, 3, 4, 5, 6, 7, 8, 9, 0].join(",")); - var a : Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; - trace(a.join(",")); - } -} + public function new() { + trace([1, 2, 3, 4, 5, 6, 7, 8, 9, 0].join(',')); + var a:Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + trace(a.join(',')); + } + +} \ No newline at end of file diff --git a/test/issues/Issue94.hx b/test/issues/Issue94.hx index 0559291..66824e9 100644 --- a/test/issues/Issue94.hx +++ b/test/issues/Issue94.hx @@ -1,19 +1,18 @@ +class Issue94 { -class Issue94 -{ - public function new() - { - var a : Array = []; - a.push(1); - a.push(2); - a.push(3); - a.push(4); - a.push(5); - a.push(6); - a.push(7); - a.push(8); - a.push(9); - a.push(0); - - } -} + public function new() { + var a:Array = []; + a.push(1); + a.push(2); + a.push(3); + a.push(4); + a.push(5); + a.push(6); + a.push(7); + a.push(8); + a.push(9); + a.push(0); + + } + +} \ No newline at end of file diff --git a/test/issues/Issue95.hx b/test/issues/Issue95.hx index 3430ddb..8906f4a 100644 --- a/test/issues/Issue95.hx +++ b/test/issues/Issue95.hx @@ -1,19 +1,17 @@ - typedef ConfigsTypedef = { - var name : String; - var id : Int; + var name: String; + var id: Int; } -class Issue95 -{ - private static var _configs : Array = [ - { - name : "name", - id : 10 - } - ]; +class Issue95 { - public function new() - { - } -} + private static var _configs:Array = [ + { + name: 'name', + id: 10 + } + ]; + + public function new() {} + +} \ No newline at end of file diff --git a/test/issues/Issue96.hx b/test/issues/Issue96.hx index a737f4d..aa4aaec 100644 --- a/test/issues/Issue96.hx +++ b/test/issues/Issue96.hx @@ -1,9 +1,8 @@ +class Issue96 { -class Issue96 -{ - public function new() - { - var o : Dynamic = ""; - var s : String = (Std.is(o, String)) ? Std.string(o) : ""; - } -} + public function new() { + var o:Dynamic = ''; + var s:String = (Std.is(o, String)) ? Std.string(o) : ''; + } + +} \ No newline at end of file diff --git a/test/unit/TestSuite.hx b/test/unit/TestSuite.hx index 424d0c8..081c521 100644 --- a/test/unit/TestSuite.hx +++ b/test/unit/TestSuite.hx @@ -1,33 +1,31 @@ import massive.munit.TestSuite; -import as3hx.AS3HXTest; -import as3hx.CompatTest; +import ExampleTest; import as3hx.parsers.ExprParserTest; import as3hx.parsers.ImportParserTest; import as3hx.parsers.UseParserTest; +import as3hx.CompatTest; import as3hx.ParserUtilsTest; import as3hx.TokenizerTest; -import ExampleTest; +import as3hx.AS3HXTest; /** * Auto generated Test Suite for MassiveUnit. * Refer to munit command line tool for more information (haxelib run munit) */ - class TestSuite extends massive.munit.TestSuite -{ - +{ public function new() { super(); - add(as3hx.AS3HXTest); - add(as3hx.CompatTest); + add(ExampleTest); add(as3hx.parsers.ExprParserTest); add(as3hx.parsers.ImportParserTest); add(as3hx.parsers.UseParserTest); + add(as3hx.CompatTest); add(as3hx.ParserUtilsTest); add(as3hx.TokenizerTest); - add(ExampleTest); + add(as3hx.AS3HXTest); } } diff --git a/test/unit/as3hx/AS3HXTest.hx b/test/unit/as3hx/AS3HXTest.hx index 03fc7b0..ec7d7b5 100644 --- a/test/unit/as3hx/AS3HXTest.hx +++ b/test/unit/as3hx/AS3HXTest.hx @@ -24,6 +24,11 @@ class AS3HXTest { output = new BytesOutput(); } + @Before + public function setup() { + cfg.processDefaultConfig(); + } + @Test public function issue14() { generate("Issue14.as", "Issue14.hx"); @@ -571,6 +576,21 @@ class AS3HXTest { generate("Issue27.as", "Issue27.hx"); } + @Test("for(var i = 5; i < a.length; a.pop()) -> while(i < a.length)") + public function issue296() { + generate("Issue296.as", "Issue296.hx"); + } + + @Test("for(var i = 0; some(i); i++) -> while(i < some(i))") + public function issue296_1() { + generate("Issue296_1.as", "Issue296_1.hx"); + } + + @Test("https://github.com/HaxeFoundation/as3hx/issues/323") + public function issue323() { + generate("Issue323.as", "Issue323.hx"); + } + function generate(as3FileName:String, expectedHaxeFileName:String) { var issuesDirectory = FileSystem.absolutePath("test/issues"); var generatedDirectoryPath = '$issuesDirectory/generated'; diff --git a/test/unit/as3hx/CompatTest.hx b/test/unit/as3hx/CompatTest.hx index 024a3ba..dad1b51 100644 --- a/test/unit/as3hx/CompatTest.hx +++ b/test/unit/as3hx/CompatTest.hx @@ -28,7 +28,7 @@ class CompatTest @Test public function getFunctionLength() { Assert.areEqual(0, Compat.getFunctionLength(getFunctionLength)); - Assert.areEqual(3, Compat.getFunctionLength(Assert.areEqual)); + Assert.areEqual(4, Compat.getFunctionLength(Assert.areEqual)); } @Test diff --git a/test/unit/as3hx/parsers/ImportParserTest.hx b/test/unit/as3hx/parsers/ImportParserTest.hx index ce6e2e0..c9562fc 100644 --- a/test/unit/as3hx/parsers/ImportParserTest.hx +++ b/test/unit/as3hx/parsers/ImportParserTest.hx @@ -46,6 +46,8 @@ class ImportParserTest public function testDictionary():Void { var importParts = getImportParts('import flash.utils.Dictionary;'); + Assert.areEqual(importParts.length, 0); + var importParts = getImportParts('import flash.utils.Dictionary;', false); Assert.areEqual(importParts.length, 3); Assert.areEqual(importParts[0], 'flash'); Assert.areEqual(importParts[1], 'utils'); @@ -108,11 +110,12 @@ class ImportParserTest Assert.areEqual(importParts[0], '*'); } - function getImportParts(importString:String):Array + function getImportParts(importString:String, dictionaryToHash:Bool = true):Array { var tokenizer = new Tokenizer(new haxe.io.StringInput(importString)); Assert.areEqual(tokenizer.id(), 'import'); var cfg = new as3hx.Config(); + cfg.dictionaryToHash = dictionaryToHash; var importParts = ImportParser.parse(tokenizer, cfg); return importParts; } From 67a60189324013c01ee6e94126c9d65e9d539aa3 Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Sun, 7 Apr 2019 23:19:12 +0300 Subject: [PATCH 142/156] Fixes, change quotes, remove empty lines --- src/as3hx/Config.hx | 6 +- src/as3hx/Typer.hx | 46 ++--- src/as3hx/Writer.hx | 221 +++++++++++------------ src/as3hx/parsers/OverrideTypeComment.hx | 1 + test/e2e/simple/Min.hx | 2 - test/e2e/simple/Package.hx | 2 - test/issues/Issue133.hx | 8 +- test/issues/Issue15.hx | 4 +- test/issues/Issue156.hx | 4 - test/issues/Issue167.hx | 1 + test/issues/Issue234.hx | 3 +- test/issues/Issue296.hx | 23 +-- test/issues/Issue83.hx | 2 +- test/issues/Issue93.hx | 2 +- 14 files changed, 153 insertions(+), 172 deletions(-) diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index 31e703f..25ce0e6 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -494,10 +494,10 @@ class Config { return ' - + - - + + diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index 24992e3..c92f67c 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -1,4 +1,5 @@ package as3hx; + import as3hx.As3.ClassDef; import as3hx.As3.ClassField; import as3hx.As3.Expr; @@ -11,33 +12,33 @@ import as3hx.RebuildUtils.RebuildResult; /** * AS3 typing allows multiple equal variable type declarations in one method and opens new variable context only inside function, not in any {} block */ -class Typer -{ - public var classes(default,null) : Map> = new Map>(); - public var classDefs(default,null) : Map = new Map(); - public var classChildren(default,null):Map> = new Map>(); +class Typer { + + public var classes(default,null) : Map> = new Map>(); + public var classDefs(default,null) : Map = new Map(); + public var classChildren(default,null):Map> = new Map>(); public var currentPath(default, null):String = null; var cfg:Config; - var classesByPackages:Map> = new Map>(); - var parentStaticFields : Map = new Map(); - var funDefs : Map = new Map(); - var classPrograms : Map = new Map(); - var staticContext : Map = new Map(); - var context : Map = new Map(); - var contextStack : Array> = []; + var classesByPackages:Map> = new Map>(); + var parentStaticFields : Map = new Map(); + var funDefs : Map = new Map(); + var classPrograms : Map = new Map(); + var staticContext : Map = new Map(); + var context : Map = new Map(); + var contextStack : Array> = []; var functionStack : Array = []; var functionStackName : Array = []; var pack:String = null; - var importsMap : Map; - var classPacks:Map = new Map(); + var importsMap : Map; + var classPacks:Map = new Map(); var _hostClassRef:Reference = new Reference(); public function new(cfg:Config) { this.cfg = cfg; } - public function getContextClone(relativeLevel:Int = 0):Map { - var context:Map; + public function getContextClone(relativeLevel:Int = 0):Map { + var context:Map; if (relativeLevel < 0 && -relativeLevel <= contextStack.length) { context = contextStack[contextStack.length + relativeLevel]; } else { @@ -72,7 +73,7 @@ class Typer private function getQualifiedClassName(shortName:String):String { if (classes.exists(shortName)) return shortName; if (importsMap != null && importsMap.exists(shortName)) return importsMap.get(shortName); - return ''; + return ""; } public function getThisIdentType(ident:String):String { @@ -647,7 +648,7 @@ class Typer s; } case TComplex(e): return getExprType(e); // not confirmed - case TDictionary(k, v): (cfg.dictionaryToHash ? "haxe.ds.ObjectMap" : "Dictionary") + "<" + tstring(k) + "," + tstring(v) + ">"; + case TDictionary(k, v): (cfg.dictionaryToHash ? "haxe.ds.ObjectMap" : "Dictionary") + "<" + tstring(k) + ", " + tstring(v) + ">"; case TFunction(p): p.map(function(it) { var s:String = tstring(it); if (s != null && s.indexOf("->") != -1) { @@ -1184,7 +1185,7 @@ class Typer } private function unshiftIntoFunction(f:Function, toInsert:Array):Void { - var doInsert:Expr->Expr = null; + var doInsert:Expr -> Expr = null; doInsert = function(e) { if(e == null) return null; switch(e) { @@ -1209,7 +1210,6 @@ class Typer return tstring(a) == tstring(b); } - private function getClassPath(c:ClassDef):String { var pack:String = classPacks[c]; if (pack != null && pack.length > 0) { @@ -1230,7 +1230,7 @@ class Typer } } - public function getImportString(i : Array, hasClassName:Bool) { + public function getImportString(i : Array, hasClassName:Bool):String { if (i[0] == "flash") { i[0] = cfg.flashTopLevelPackage; return i.join("."); @@ -1262,8 +1262,8 @@ class Typer public function enterClass(path:String, c:ClassDef):Void { currentPath = path; //parentStaticFields = new Map(); - staticContext = new Map(); - var classMap:Map; + staticContext = new Map(); + var classMap:Map; classMap = classes.get(path); var ic:ClassDef = c; var parentPath:String = path; diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index a7c1bfb..5be87e8 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1,5 +1,6 @@ package as3hx; +import haxe.io.BytesOutput; import as3hx.As3; import as3hx.RebuildUtils.RebuildResult; import haxe.io.Output; @@ -172,7 +173,7 @@ class Writer inline function getColon():String return cfg.spacesOnTypeColon ? " : " : ":"; - function writeComments(comments : Array) { + function writeComments(comments : Array):Void { for(c in comments) { switch(c) { case null: @@ -201,19 +202,15 @@ class Writer } } - function writePackage(pack : Array) - { - if (pack.length > 0) - { + function writePackage(pack : Array):Void { + if (pack.length > 0) { writeLine("package " + properCaseA(pack,false).join(".") + ";"); writeNL(); } } - function writeImports(imports : Array>) - { - if (imports.length > 0) - { + function writeImports(imports : Array>):Void { + if (imports.length > 0) { for (i in imports) { writeImport(i); writeNL(); @@ -222,8 +219,7 @@ class Writer } } - function writeImport(i : Array) - { + function writeImport(i : Array):Void { var type = typer.getImportString(i, true); if (cfg.importExclude != null && cfg.importExclude.indexOf(type) != -1) { var short:String = type.substr(type.lastIndexOf(".") + 1); @@ -243,8 +239,7 @@ class Writer } } - function writeAdditionalImports(defPackage : Array, allTypes : Array, definedTypes : Array) - { + function writeAdditionalImports(defPackage : Array, allTypes : Array, definedTypes : Array):Void { // We don't want to import any type that is defined within // this file, so add each of those to the type import map // first. @@ -280,7 +275,7 @@ class Writer // Now look up each type import string in the type import // map. - var addnImports = new Array(); + var addnImports:Array = []; for(u in uniqueTypes.keys()) { if (typeImportMap.exists(u)) { var nu:String = typeImportMap.get(u); @@ -302,14 +297,12 @@ class Writer } } - function writeDefinitions(defs : Array) - { + function writeDefinitions(defs : Array):Void { for(d in defs) writeDefinition(d); } - function writeDefinition(def : Definition) - { + function writeDefinition(def : Definition):Void { switch(def) { case CDef(c): writeClassDef(c); @@ -318,7 +311,7 @@ class Writer } } - function writeMetaData(data:Array) { + function writeMetaData(data:Array):Void { if(data == null) return; @@ -352,8 +345,7 @@ class Writer } } - function writeClassDef(c : ClassDef) - { + function writeClassDef(c : ClassDef):Void { writeMetaData(c.meta); if (!generatedTypesWritten) { @@ -385,6 +377,7 @@ class Writer buf.add(" " + parents.join(" ")); buf.add(openb()); write(buf.toString()); + writeNL(); lvl++; var path:String = (pack.length > 0 ? pack.join(".") + "." : "") + c.name; @@ -394,6 +387,7 @@ class Writer // process properties writeProperties(c); + writeNL(); // process fields writeFields(c); @@ -410,8 +404,7 @@ class Writer } var propertyMap = new Map(); - function tryAddProperty(field:ClassField, f:Function):Void - { + function tryAddProperty(field:ClassField, f:Function):Void { var isGetter:Bool = this.isGetter(field.kwds); var isSetter:Bool = !isGetter && this.isSetter(field.kwds); if (isGetter || isSetter) @@ -444,8 +437,8 @@ class Writer } } } - function tryWritePropertyVar(field:ClassField, c:ClassDef):Void - { + + function tryWritePropertyVar(field:ClassField, c:ClassDef):Void { if (!propertyMap.exists(field.name)) return; @@ -488,8 +481,7 @@ class Writer } } - function writeProperties(c : ClassDef) - { + function writeProperties(c : ClassDef):Void { for (field in c.fields) { switch(field.kind) @@ -552,8 +544,7 @@ class Writer //} //} - function writeFields(c : ClassDef) - { + function writeFields(c : ClassDef):Void { if (c.isInterface) { for (field in c.fields) { writeField(field, c); @@ -562,12 +553,12 @@ class Writer } var constructor:Function = null; - var constructorFieldInits:Array = new Array(); + var constructorFieldInits:Array = []; var hasConstructor:Bool = false; var needConstructor:Bool = false; for (field in c.fields) { - switch(field.kind) { + switch (field.kind) { case FFun ( f ): if (!hasConstructor && field.name == c.name) { constructor = f; @@ -619,7 +610,6 @@ class Writer constructor.expr = EBlock(constructorFieldInits); } - for (field in c.fields) { writeField(field, c); } @@ -650,8 +640,7 @@ class Writer } } - function writeField(field : ClassField, c : ClassDef) - { + function writeField(field : ClassField, c : ClassDef):Void { var isGet : Bool = isGetter(field.kwds); var isSet : Bool = isSetter(field.kwds); var isFun : Bool = switch(field.kind) {case FFun(_): true; default: false;}; @@ -800,6 +789,7 @@ class Writer write(";"); case FFun( f ): + writeNL(); writeMetaData(field.meta); RebuildUtils.rebuild(f.expr, lookUpForNamespaces); if (field.name == c.name) @@ -885,8 +875,7 @@ class Writer * Return a new array containing all the conditional * compilation constants from the provided array */ - function getCondComp(exprs : Array) : Array - { + function getCondComp(exprs : Array) : Array { var condComps = []; for (expr in exprs) { @@ -903,8 +892,7 @@ class Writer * Return a new array containing all the conditional * compilation expressions from the provided array */ - function getECondComp(exprs : Array) : Array - { + function getECondComp(exprs : Array) : Array { var condComps = []; for (expr in exprs) { @@ -922,12 +910,10 @@ class Writer * contains a conditional compilation expr for the * condComp compilation constant */ - function hasCondComp(condComp : String, exprs : Array) : Bool - { - for (expr in exprs) - { + function hasCondComp(condComp : String, exprs : Array) : Bool { + for (expr in exprs) { switch (expr) { - case ECondComp(v,e,e2): + case ECondComp(v, e, e2): if (condComp == v) { return true; } @@ -941,8 +927,7 @@ class Writer * Write closing statement ("#end") for conditional * conpilation if any */ - function writeECondCompEnd(condComps : Array) : Void - { + function writeECondCompEnd(condComps : Array) : Void { for (i in 0...condComps.length) { writeNL(); writeIndent("#end"); @@ -952,8 +937,7 @@ class Writer } } - function writeArgs(args : Array<{ name : String, t : Null, val : Null, exprs : Array }>, varArgs:String = null, functionExpressions:Array) - { + function writeArgs(args : Array<{ name : String, t : Null, val : Null, exprs : Array }>, varArgs:String = null, functionExpressions:Array) { if(varArgs != null && !cfg.replaceVarArgsWithOptionalArguments) { var varArg = { name:varArgs, @@ -1039,7 +1023,7 @@ class Writer case ENL(_): //newline if (pendingComma) { pendingComma = false; - write(","); + write(", "); } writeNL(); writeIndent(); @@ -1082,7 +1066,7 @@ class Writer return fst; } - function writeConstructor(f:Function, isSubClass:Bool) { + function writeConstructor(f:Function, isSubClass:Bool):Void { //add super if missing, as it is mandatory in Haxe for subclasses if (isSubClass && !constructorHasSuper(f.expr)) { switch(f.expr) { @@ -1101,13 +1085,13 @@ class Writer es = new VarExprFix(cfg).apply(f, es, typer); } writeExpr(EBlock(es)); + writeNL(); } /** * Wether constructor method has a super() call */ - function constructorHasSuper(?expr : Expr) : Bool - { + function constructorHasSuper(?expr : Expr) : Bool { if (expr == null) return false; var hasSuper:Bool = false; function rebuildHasSuper(e:Expr):RebuildResult { @@ -1134,7 +1118,7 @@ class Writer return result; } - function writeFunction(f : Function, isGetter:Bool, isSetter:Bool, isNative:Bool, ?name : Null, ?ret : FunctionRet, ?meta:Array) { + function writeFunction(f : Function, isGetter:Bool, isSetter:Bool, isNative:Bool, ?name : Null, ?ret : FunctionRet, ?meta:Array):Void { var oldFunctionReturnType:T = functionReturnType; functionReturnType = f.ret.t; @@ -1162,8 +1146,8 @@ class Writer if (ret == null) ret = f.ret; writeFunctionReturn(ret, isGetter, isSetter, isNative); - var formatExpr:Expr->(Expr->Expr)->Expr = null; - var formatBlock:Array->(Expr->Expr)->Array = function(exprs, getResult) { + var formatExpr:Expr -> (Expr -> Expr) -> Expr = null; + var formatBlock:Array -> (Expr -> Expr) -> Array = function(exprs, getResult) { for(i in 0...exprs.length) { exprs[i] = formatExpr(exprs[i], getResult); } @@ -1186,11 +1170,11 @@ class Writer default: e; } } - if(isIntType(tstring(ret.t))) { + if (isIntType(tstring(ret.t))) { formatBlock(es, function(?e) return e != null && needCastToInt(e) ? getCastToIntExpr(e) : e); } // haxe setters must return the provided type - if(isSetter && !isNative && f.args.length == 1) { + if (isSetter && !isNative && f.args.length == 1) { var result = EIdent(f.args[0].name); formatBlock(es, function(e) { if (e != null) { @@ -1205,8 +1189,10 @@ class Writer if (cfg.fixLocalVariableDeclarations) { es = new VarExprFix(cfg).apply(f, es, typer); } - writeStartStatement(); + if (!isInterface) + writeStartStatement(); writeExpr(EBlock(es)); + writeNL(); functionReturnType = oldFunctionReturnType; } @@ -1214,14 +1200,14 @@ class Writer * Write the returned typed of a function and all * comments and newline until opening bracket */ - function writeFunctionReturn(ret:FunctionRet, isGetter : Bool, isSetter : Bool, isNative : Bool) { + function writeFunctionReturn(ret:FunctionRet, isGetter : Bool, isSetter : Bool, isNative : Bool):Void { //write return type if(isNative) { if(isGetter) writeVarType(ret.t, "{}", true); if(isSetter) writeVarType(null, "Void", true); } else - writeVarType(ret.t,null,false); + writeVarType(ret.t, null, false); //write comments after return type for (expr in ret.exprs) { @@ -1237,7 +1223,7 @@ class Writer write("/* " + p + " */"); } - inline function writeEReturn(?e:Expr) { + inline function writeEReturn(?e:Expr):Void { write("return"); if(e == null) return; write(" "); @@ -1248,7 +1234,7 @@ class Writer return isArrayType(etype) || isVectorType(etype) || isOpenFlDictionaryType(etype) || isMapType(etype) || isByteArrayType(etype); } - function writeEArray(e:Expr, index:Expr) { + function writeEArray(e:Expr, index:Expr):Void { //write("/* EArray ("+Std.string(e)+","+Std.string(index)+") " + Std.string(getExprType(e, true)) + " */ "); var old = inArrayAccess; inArrayAccess = true; @@ -1326,22 +1312,19 @@ class Writer } } - function writeLoop(incrs:Array, f:Void->Void) { + function writeLoop(incrs:Array, f:Void -> Void):Void { var old = loopIncrements; loopIncrements = incrs.slice(0); f(); loopIncrements = old; } - static function ucfirst(s : String) : String - { + static function ucfirst(s : String) : String { return s.substr(0, 1).toUpperCase() + s.substr(1); } - function writeVarType(?t : Null, ?alt : String, isNativeGetSet:Bool=false) - { - if (t == null) - { + function writeVarType(?t : Null, ?alt : String, isNativeGetSet:Bool = false):Void { + if (t == null) { if (alt != null) write(getColon() + alt); return; @@ -1353,7 +1336,7 @@ class Writer write(getColon() + s); } - function writeInits(c : ClassDef) { + function writeInits(c : ClassDef):Void { if(c.inits == null || c.inits.length == 0) return; writeNL(""); @@ -1372,10 +1355,8 @@ class Writer writeNL("}"); } - function getConst(c : Const) : String - { - return switch(c) - { + function getConst(c : Const) : String { + return switch(c) { case CInt(v), CFloat(v): v; case CString(s): quote(s); } @@ -1400,7 +1381,7 @@ class Writer } } - function writeModifiedIdent(s : String) { + function writeModifiedIdent(s : String):Void { s = typer.getModifiedIdent(s); write(s); } @@ -1413,7 +1394,7 @@ class Writer if(cfg.debugExpr) write(" /* " + Std.string(expr) + " */ "); if(expr == null) return None; var rv = Semi; - switch(expr) { + switch (expr) { case ETypedExpr(e, t): rv = writeETypedExpr(e, t); case EConst(c): write(getConst(c)); case EIdent(v): writeModifiedIdent(v); @@ -1512,14 +1493,14 @@ class Writer case ETry(e, catches): rv = writeETry(e, catches); case EObject(fl): if (fl.empty()) { - write("{ }"); + write("{}"); } else { writeNL("{"); lvl++; var length = fl.length; for (i in 0...length) { var field = fl[i]; - if (i > 0) writeNL(","); + if (i > 0) writeNL(", "); var field = fl[i]; writeIndent(prepareObjectFieldName(field.name) + (cfg.spacesOnTypeColon ? " : " : ": ")); writeExpr(field.e); @@ -1528,7 +1509,7 @@ class Writer writeNL(); writeIndent("}"); } - case ERegexp(str, opts): write('new ${getExprType(expr)}(' + eregQuote(str) + ', "' + opts + '")'); + case ERegexp(str, opts): write('new ${getExprType(expr)}(' + eregQuote(str) + ", '" + opts + "')"); case ENamespaceAccess(e, f): writeExpr(e); case ESwitch( e, cases, def): var newCases : Array = new Array(); @@ -1606,8 +1587,8 @@ class Writer writeMetaData(c.meta); //write commnent and newline before "case" write("case "); - for(i in 0...c.vals.length) { - write(i>0 ? ", " : ""); + for (i in 0...c.vals.length) { + write(i > 0 ? ", " : ""); writeExpr(c.vals[i]); } write(":"); @@ -1689,19 +1670,19 @@ class Writer case ECommented(s, b, t, ex): rv = writeECommented(s,b,t,ex); case EMeta(m): if (!cfg.convertFlexunit || !writeMunitMetadata(m)) { - write("@:meta("+m.name+"("); + write("@:meta(" + m.name + "("); var first = true; for(arg in m.args) { if(!first) - write(","); + write(", "); first = false; if(arg.name != null) - write(arg.name + "="); + write(arg.name + " = "); else - write("name="); + write("name = "); writeExpr(arg.val); } - writeNL("))"); + write("))"); } case ETypeof(e): switch(e) { @@ -1792,13 +1773,13 @@ class Writer return rv; } - function writeSwitchDefault(def:SwitchDefault) { + function writeSwitchDefault(def:SwitchDefault):Void { if(def.vals != null && def.vals.length > 0) { writeNL(); writeIndent(); write("/* covers case "); for (i in 0 ... def.vals.length) { - write(i>0 ? ", " : ""); + write(i > 0 ? ", " : ""); writeExpr(def.vals[i]); } write(":"); @@ -1818,7 +1799,7 @@ class Writer } } writeMetaData(newMeta); //write comment and newline before "default" - write("default:"); + write("case _:"); lvl++; for (i in 0...def.el.length) { @@ -1837,7 +1818,10 @@ class Writer //writeFinish(writeETypedExpr(ex, TPath([null]))); } lvl--; - write(closeb()); + if (e.length > 0) + write(closeb()); + else + write("}"); result = None; } else { write(";"); @@ -2028,7 +2012,7 @@ class Writer return result; } - inline function writeEParent(e:Expr) { + inline function writeEParent(e:Expr):Void { switch(e) { case EParent(e): writeExpr(e); default: @@ -2041,6 +2025,7 @@ class Writer function writeECall(fullExpr:Expr, expr:Expr, params:Array):BlockEnd { switch(expr) { case EField(expr, f): + trace('-----'); if ((f == "push" || f == "unshift") && params.length > 1 && (isArrayExpr(expr) || isVectorExpr(expr))) { if (f == "unshift") { params = params.copy(); @@ -2397,7 +2382,7 @@ class Writer } inline function writeEFor(inits:Array, conds:Array, incrs:Array, e:Expr):BlockEnd { - //Sys.println('inits: ${inits}; conds: ${conds}; incrs: ${incrs}'); + // Sys.println('inits: ${inits}; conds: ${conds}; incrs: ${incrs}'); for (i in 0...inits.length - 1) { var e:Expr = inits[i]; writeExpr(ENL(e)); @@ -2797,10 +2782,10 @@ class Writer } default: } - if((isIntType(type) || type == "UInt") && op == "!") { + if ((isIntType(type) || type == "UInt") && op == "!") { writeExpr(EBinop("!=", e, EConst(CInt("0")), false)); result = None; - } else if(prefix) { + } else if (prefix) { write(op); writeExpr(e); } else { @@ -2812,7 +2797,7 @@ class Writer inline function getToStringExpr(e:Expr):Expr return ECall(EField(EIdent("Std"), "string"), [e]); - function writeCastToInt(e:Expr) { + function writeCastToInt(e:Expr):Void { var type = getExprType(e); if(type != "Int") { e = getCastToIntExpr(e); @@ -2838,7 +2823,7 @@ class Writer return ECall(EField(EIdent("Std"), "parseInt"), [getToStringExpr(e)]); } - function writeCastToFloat(e:Expr) { + function writeCastToFloat(e:Expr):Void { var type = getExprType(e); if (type != "Float" && type != "Int") { e = getCastToFloatExpr(e); @@ -2989,7 +2974,7 @@ class Writer // return false; // }); // e1.(@user_id == 3) attribute search - function writeE4XFilterExpr(e1:Expr, e2:Expr) { + function writeE4XFilterExpr(e1:Expr, e2:Expr):Void { if(inE4XFilter) throw "Unexpected E4XFilter inside E4XFilter"; @@ -3060,11 +3045,11 @@ class Writer inline function writeENew(t : T, params : Array):Void { var writeParams = function() { var argTypes:Array = typer.getClassConstructorTypes(tstring(t)); - for(i in 0...params.length) { - if(i > 0) + for (i in 0...params.length) { + if (i > 0) write(", "); var param:Expr = params[i]; - switch(param) { + switch (param) { case EVector(t): param = EIdent("Vector"); default: @@ -3076,7 +3061,7 @@ class Writer } } } - switch(t) { + switch (t) { case TComplex(e): var pack:Array = typer.getPackString(e); if (pack != null) { @@ -3086,7 +3071,7 @@ class Writer } var isVariable:Bool = false; var handled = false; - switch(t) { + switch (t) { case TPath(p) if (p.length == 1 && typer.isVariable(p[0])): isVariable = true; default: } @@ -3141,9 +3126,7 @@ class Writer } if (!handled) { if (isObject) write("{}"); - else if (isDictionary) { - } - else write("new " + tstring(t) + "("); + else if (!isDictionary) write("new " + tstring(t) + "("); // prevent params when converting vector to array var out = switch(t) { case TVector(_): !cfg.vectorToArray; @@ -4030,7 +4013,7 @@ class Writer //if (validVariableNameEReg.match(name)) { //return name; //} else { - return '"' + name + '"'; + return "'" + name + "'"; //} } @@ -4130,12 +4113,12 @@ class Writer static function quote(s : String) : String { - return '"' + StringTools.replace(s, '"', '\\"') + '"'; + return "'" + StringTools.replace(s, "'", "\\'") + "'"; } static function eregQuote(s : String) : String { - return '"' + StringTools.replace(StringTools.replace(s, '\\', '\\\\'), '"', '\\"') + '"'; + return "'" + StringTools.replace(StringTools.replace(s, '\\', '\\\\'), "'", "\\'") + "'"; } function isOverride(kwds : Array) : Bool @@ -4215,8 +4198,7 @@ class Writer * Write an As3 package level function. As Haxe * does not have this, wrap it in a class definition */ - function writeFunctionDef(fDef : FunctionDef) - { + function writeFunctionDef(fDef : FunctionDef):Void { writeClassDef(wrapFuncDefInClassDef(fDef)); } @@ -4563,7 +4545,7 @@ class Writer } } - o = output; + o = new BytesOutput(); genTypes = program.genTypes; writeComments(program.header); writePackage(program.pack); @@ -4572,6 +4554,20 @@ class Writer generatedTypesWritten = false; writeDefinitions(program.defs); writeComments(program.footer); + + var rv = untyped o.getBytes().toString(); + rv = StringTools.trim(rv); + var lines:Array = rv.split('\n'); + var counter:Int = lines.length; + var prevEmpty:Bool = false; + for (line in lines) { + var s:String = StringTools.rtrim(line); + output.writeString(s); + if (--counter > 0 && (s != '' || !prevEmpty)) + output.writeString('\n'); + prevEmpty = s == ''; + } + return warnings; } @@ -4581,7 +4577,7 @@ class Writer * warning is affecting, so that the porter can more easily determine * the fix. */ - public static function showWarnings(allWarnings : Map>) { + public static function showWarnings(allWarnings : Map>):Void { var wke : Map> = new Map(); // warning->files for(filename in allWarnings.keys()) { for(errname in allWarnings.get(filename).keys()) { @@ -4613,7 +4609,7 @@ class Writer default: println("WARNING: " + warn); } for(f in a) - println("\t"+f); + println("\t" + f); } } } @@ -4656,4 +4652,5 @@ class Writer function (v:String) return v.length > 0 ? v.charAt(0).toUpperCase() + v.substr(1) : "" ).array().join(""); } + } \ No newline at end of file diff --git a/src/as3hx/parsers/OverrideTypeComment.hx b/src/as3hx/parsers/OverrideTypeComment.hx index e2a49e0..fc46049 100644 --- a/src/as3hx/parsers/OverrideTypeComment.hx +++ b/src/as3hx/parsers/OverrideTypeComment.hx @@ -1,4 +1,5 @@ package as3hx.parsers; + import as3hx.As3.T; import as3hx.Parser.Types; diff --git a/test/e2e/simple/Min.hx b/test/e2e/simple/Min.hx index 6180034..b4be5b6 100644 --- a/test/e2e/simple/Min.hx +++ b/test/e2e/simple/Min.hx @@ -1,5 +1,3 @@ class Min { - public function new() {} - } \ No newline at end of file diff --git a/test/e2e/simple/Package.hx b/test/e2e/simple/Package.hx index 6a2096d..7c8353c 100644 --- a/test/e2e/simple/Package.hx +++ b/test/e2e/simple/Package.hx @@ -2,6 +2,4 @@ package test.package; class Min { - public function new() {} - } \ No newline at end of file diff --git a/test/issues/Issue133.hx b/test/issues/Issue133.hx index ae36c28..baadf26 100644 --- a/test/issues/Issue133.hx +++ b/test/issues/Issue133.hx @@ -1,14 +1,14 @@ class Issue133 { public function new() { - var max:Int = as3hx.Compat.INT_MAX; + var max:Int = AS3.int(as3hx.Compat.INT_MAX); if (max > as3hx.Compat.INT_MAX) { - max = as3hx.Compat.INT_MAX; + max = AS3.int(as3hx.Compat.INT_MAX); } - var min:Int = as3hx.Compat.INT_MIN; + var min:Int = AS3.int(as3hx.Compat.INT_MIN); if (min < as3hx.Compat.INT_MIN) { - min = as3hx.Compat.INT_MIN; + min = AS3.int(as3hx.Compat.INT_MIN); } } diff --git a/test/issues/Issue15.hx b/test/issues/Issue15.hx index c450304..8edfc23 100644 --- a/test/issues/Issue15.hx +++ b/test/issues/Issue15.hx @@ -34,12 +34,12 @@ class Issue15 { } ++i; - for (item /* AS3HX WARNING could not determine type for var: item exp: EObject([]) type: null */ in {}) { + for (item in as3hx.Compat.each({})) { trace(''); } ++i; - for (item /* AS3HX WARNING could not determine type for var: item exp: EObject([]) type: null */ in {}) { + for (item in as3hx.Compat.each({})) { trace(''); } ++i; diff --git a/test/issues/Issue156.hx b/test/issues/Issue156.hx index e151c2f..94a5e46 100644 --- a/test/issues/Issue156.hx +++ b/test/issues/Issue156.hx @@ -15,8 +15,4 @@ class Issue156 extends EventDispatcher { class PrivateClass extends Sprite { - public function new() { - super(); - } - } \ No newline at end of file diff --git a/test/issues/Issue167.hx b/test/issues/Issue167.hx index a4bcaa8..b0441e9 100644 --- a/test/issues/Issue167.hx +++ b/test/issues/Issue167.hx @@ -1,4 +1,5 @@ import flash.geom.Point; + class Issue167 { public function new(p:Point = null) { diff --git a/test/issues/Issue234.hx b/test/issues/Issue234.hx index 6f35e07..91dca21 100644 --- a/test/issues/Issue234.hx +++ b/test/issues/Issue234.hx @@ -1,8 +1,9 @@ import flash.display3D.Context3D; + class Issue234 { public function new() { - var supportsVideoTexture:Bool = Reflect.field(Context3D, 'supportsVideoTexture'); + var supportsVideoTexture:Bool = Reflect.getProperty(Context3D, 'supportsVideoTexture') != null; } } \ No newline at end of file diff --git a/test/issues/Issue296.hx b/test/issues/Issue296.hx index 5e568f8..8e7964f 100644 --- a/test/issues/Issue296.hx +++ b/test/issues/Issue296.hx @@ -1,36 +1,25 @@ class Issue296 { public function new() { - var a:Array = [1, 2, 3]; - var i:Int = 0; - while (i < a.length) { + var a:Array = [1, 2, 3]; + for (i in 0...a.length) { trace(a.pop()); - i++; } - var i:Int = 0; - while (i < a.pop()) { + for (i in 0...a.pop()) { trace(i); - i++; } - var i:Int = 0; - while (i < a.pop() + 10) { + for (i in 0...a.pop() + 10) { trace(i); - i++; } - var i:Int = 0; - while (i < a.length) { + for (i in 0...a.length) { if (i < 3) { trace(a.pop()); } else { - i++; continue; } - i++; } - var i:Int = 0; - while (i < a.length) { + for (i in 0...a.length) { trace(a.pop()); - i++; continue; } } diff --git a/test/issues/Issue83.hx b/test/issues/Issue83.hx index 24edb36..0632225 100644 --- a/test/issues/Issue83.hx +++ b/test/issues/Issue83.hx @@ -2,7 +2,7 @@ class Issue83 { public function new() { var o:Dynamic = haxe.Json.parse(''); - var s:String = haxe.Json.stringify({}); + var s:String = Std.string(haxe.Json.stringify({})); } } \ No newline at end of file diff --git a/test/issues/Issue93.hx b/test/issues/Issue93.hx index 06461a4..d15b4b4 100644 --- a/test/issues/Issue93.hx +++ b/test/issues/Issue93.hx @@ -2,7 +2,7 @@ class Issue93 { public function new() { trace([1, 2, 3, 4, 5, 6, 7, 8, 9, 0].join(',')); - var a:Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + var a:Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; trace(a.join(',')); } From c6560e86d3bf0998df09a722decbe2df205bb371 Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Mon, 8 Apr 2019 03:13:12 +0300 Subject: [PATCH 143/156] disable fixLocalVariableDeclarations, fixes --- src/as3hx/Config.hx | 2 +- src/as3hx/ForLoopRebuild.hx | 20 ++++++++--------- src/as3hx/Writer.hx | 16 ++++++-------- src/as3hx/parsers/ExprParser.hx | 8 +++---- src/as3hx/parsers/FunctionParser.hx | 4 ++-- src/as3hx/parsers/StructureParser.hx | 33 ++++++++++++++-------------- 6 files changed, 40 insertions(+), 43 deletions(-) diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index 25ce0e6..c6dcd99 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -516,7 +516,7 @@ class Config { - + diff --git a/src/as3hx/ForLoopRebuild.hx b/src/as3hx/ForLoopRebuild.hx index 1272b1c..6c306de 100644 --- a/src/as3hx/ForLoopRebuild.hx +++ b/src/as3hx/ForLoopRebuild.hx @@ -1,4 +1,5 @@ package as3hx; + import as3hx.As3.Expr; import as3hx.RebuildUtils.RebuildResult; @@ -6,24 +7,21 @@ import as3hx.RebuildUtils.RebuildResult; * ... * @author xmi */ - - class LoopPosition { - public function new() { } + public function new() {} public var expr:Expr; public var num:Int; } -class ForLoopRebuild -{ - private var loopsListPerLoopVar:Map> = new Map>(); - private var loopsListPerLoopVarStack:Array>> = new Array>>(); - private var loopNumToReplace:Map = new Map(); +class ForLoopRebuild { + + private var loopsListPerLoopVar:Map> = new Map>(); + private var loopsListPerLoopVarStack:Array>> = []; + private var loopNumToReplace:Map = new Map(); private var forLoopNum:Int = 0; - public function new() { + public function new() {} - } private function rebuildLookUpPassArray(expressions:Array):Array { var needUpdate:Bool = false; var newExpressions:Array = []; @@ -66,7 +64,6 @@ class ForLoopRebuild return expressions; } - private function openBlockContext():Void { loopsListPerLoopVarStack.push(loopsListPerLoopVar); loopsListPerLoopVar = new Map>(); @@ -405,4 +402,5 @@ class ForLoopRebuild } return false; } + } \ No newline at end of file diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 5be87e8..dfbfa58 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -24,8 +24,8 @@ typedef CaseDef = { * @author Franco Ponticelli * @author Russell Weir */ -class Writer -{ +class Writer { + var lvl : Int; var o : Output; var cfg : Config; @@ -50,8 +50,7 @@ class Writer var typer:Typer; var dictionaries:DictionaryRebuild; - public function new(config:Config) - { + public function new(config:Config) { this.lvl = 0; this.cfg = config; this.varCount = 0; @@ -1337,13 +1336,13 @@ class Writer } function writeInits(c : ClassDef):Void { - if(c.inits == null || c.inits.length == 0) + if (c.inits == null || c.inits.length == 0) return; writeNL(""); writeIndent(); writeNL('private static var ${c.name}_static_initializer = {'); lvl++; - for(e in c.inits) { + for (e in c.inits) { writeIndent(); writeExpr(e); writeNL(";"); @@ -1391,8 +1390,8 @@ class Writer * @return if the block requires a terminating ; */ function writeExpr(?expr : Expr) : BlockEnd { - if(cfg.debugExpr) write(" /* " + Std.string(expr) + " */ "); - if(expr == null) return None; + if (cfg.debugExpr) write(" /* " + Std.string(expr) + " */ "); + if (expr == null) return None; var rv = Semi; switch (expr) { case ETypedExpr(e, t): rv = writeETypedExpr(e, t); @@ -2025,7 +2024,6 @@ class Writer function writeECall(fullExpr:Expr, expr:Expr, params:Array):BlockEnd { switch(expr) { case EField(expr, f): - trace('-----'); if ((f == "push" || f == "unshift") && params.length > 1 && (isArrayExpr(expr) || isVectorExpr(expr))) { if (f == "unshift") { params = params.copy(); diff --git a/src/as3hx/parsers/ExprParser.hx b/src/as3hx/parsers/ExprParser.hx index b6ad8b8..30774f2 100644 --- a/src/as3hx/parsers/ExprParser.hx +++ b/src/as3hx/parsers/ExprParser.hx @@ -17,12 +17,12 @@ class ExprParser { var tk = tokenizer.token(); Debug.dbgln("parseExpr(" + tk + ")", tokenizer.line); - switch( tk ) { + switch ( tk ) { case TSemicolon: return parseExpr(funcStart); case TId(id): var e = parseStructure(id); - if(e == null) + if (e == null) e = EIdent(ParserUtils.escapeName(id)); return switch(e) { case EIf(_,_,_) | EFor(_,_,_,_) | EForIn(_,_,_) | EForEach(_,_,_) | EWhile(_,_,_) | ESwitch(_,_,_): e; @@ -328,13 +328,13 @@ class ExprParser { var parseExpr = parse.bind(tokenizer, types, cfg); Debug.dbgln("parseFullExpr()", tokenizer.line); var e = parseExpr(false); - if( ParserUtils.opt(tokenizer, TColon) ) { + if ( ParserUtils.opt(tokenizer, TColon) ) { switch( e ) { case EIdent(l): e = ELabel(l); default: tokenizer.add(TColon); } } - if( !ParserUtils.opt(tokenizer, TComma) ) + if ( !ParserUtils.opt(tokenizer, TComma) ) tokenizer.end(); return e; } diff --git a/src/as3hx/parsers/FunctionParser.hx b/src/as3hx/parsers/FunctionParser.hx index 7395c1f..4ba9413 100644 --- a/src/as3hx/parsers/FunctionParser.hx +++ b/src/as3hx/parsers/FunctionParser.hx @@ -131,9 +131,9 @@ class FunctionParser { } } - if(tokenizer.peek() == TBrOpen) { + if (tokenizer.peek() == TBrOpen) { f.expr = parseExpr(true); - switch(ParserUtils.removeNewLineExpr(f.expr)) { + switch (ParserUtils.removeNewLineExpr(f.expr)) { case EObject(fl): if(fl.length == 0) { f.expr = EBlock([]); diff --git a/src/as3hx/parsers/StructureParser.hx b/src/as3hx/parsers/StructureParser.hx index 436afc7..c09fda3 100644 --- a/src/as3hx/parsers/StructureParser.hx +++ b/src/as3hx/parsers/StructureParser.hx @@ -30,8 +30,8 @@ class StructureParser { var e1 = parseExpr(false); e1 = f(e1); tokenizer.end(); - var elseExpr = if(ParserUtils.opt(tokenizer, TId("else"), true)) parseExpr(false) else null; - if(elseExpr != null) elseExpr = f(elseExpr); + var elseExpr = if (ParserUtils.opt(tokenizer, TId("else"), true)) parseExpr(false) else null; + if (elseExpr != null) elseExpr = f(elseExpr); switch(cond) { case ECondComp(v, e, e2): //corner case, the condition is an AS3 preprocessor @@ -44,15 +44,15 @@ class StructureParser { } case "var", "const": var vars = []; - while( true ) { + while ( true ) { var name = tokenizer.id(), t = null, val = null; name = ParserUtils.escapeName(name); - if( ParserUtils.opt(tokenizer, TColon) ) + if ( ParserUtils.opt(tokenizer, TColon) ) t = parseType(); - if( ParserUtils.opt(tokenizer, TOp("=")) ) + if ( ParserUtils.opt(tokenizer, TOp("=")) ) val = ETypedExpr(parseExpr(false), t); vars.push( { name : name, t : t, val : val } ); - if( !ParserUtils.opt(tokenizer, TComma) ) + if ( !ParserUtils.opt(tokenizer, TComma) ) break; } EVars(vars); @@ -63,10 +63,10 @@ class StructureParser { var e = parseExpr(false); EWhile(econd,e, false); case "for": - if( ParserUtils.opt(tokenizer, TId("each")) ) { + if ( ParserUtils.opt(tokenizer, TId("each")) ) { tokenizer.ensure(TPOpen); var ev = parseExpr(false); - switch(ev) { + switch (ev) { case EBinop(op, e1, e2, n): if(op == "in") { tokenizer.ensure(TPClose); @@ -126,7 +126,7 @@ class StructureParser { } EReturn(e); case "new": - if(ParserUtils.opt(tokenizer, TOp("<"))) { + if (ParserUtils.opt(tokenizer, TOp("<"))) { // o = new [a,b,c..] var t = parseType(); tokenizer.ensure(TOp(">")); @@ -221,7 +221,7 @@ class StructureParser { default: return null; } } - switch(call) { + switch (call) { case EIdent(v): var type = TPath([v]); types.seen.push(type); @@ -413,25 +413,25 @@ class StructureParser { } static function getParams(tokenizer:Tokenizer, parseExpr) { - return switch(tokenizer.token()) { + return switch (tokenizer.token()) { case TPOpen: var params = []; var parCount = 1; - while(parCount > 0) { + while (parCount > 0) { var t = tokenizer.token(); - switch(t) { + switch (t) { case TPOpen: parCount++; case TPClose: parCount--; if(params.length > 0) params[params.length - 1] = EParent(params[params.length - 1]); case TComma: - case TOp(op) if(params.length > 0): + case TOp(op) if (params.length > 0): params[params.length - 1] = ParserUtils.makeBinop(tokenizer, op, params[params.length - 1], parseExpr(false)); case _: tokenizer.add(t); - if(params.length < 2) params.push(parseExpr(false)); + if (params.length < 2) params.push(parseExpr(false)); else { - if(params.length == 2) params.push(EArrayDecl([])); + if (params.length == 2) params.push(EArrayDecl([])); switch(params[2]) { case EArrayDecl(e): e.push(parseExpr(false)); case _: @@ -443,4 +443,5 @@ class StructureParser { case _: null; } } + } From f550fc2208d3aa0e611ce11f31a1d124ebcb6ee7 Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Mon, 8 Apr 2019 04:05:59 +0300 Subject: [PATCH 144/156] useFullTyping, getQualifiedClassName fix --- src/as3hx/Config.hx | 2 +- src/as3hx/RebuildUtils.hx | 6 ++--- src/as3hx/Typer.hx | 13 +++++---- src/as3hx/Writer.hx | 55 ++++++++++++++++++--------------------- 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index c6dcd99..54525e3 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -502,7 +502,7 @@ class Config { - + diff --git a/src/as3hx/RebuildUtils.hx b/src/as3hx/RebuildUtils.hx index 2fa8293..d1d9b32 100644 --- a/src/as3hx/RebuildUtils.hx +++ b/src/as3hx/RebuildUtils.hx @@ -78,7 +78,7 @@ class RebuildUtils } } - public static function rebuild(e:Expr, rebuildMethod:Expr->RebuildResult):Expr { + public static function rebuild(e:Expr, rebuildMethod:Expr -> RebuildResult):Expr { if (e == null) return null; var r:RebuildResult = rebuildMethod(e); switch(r) { @@ -157,8 +157,8 @@ class RebuildUtils return false; } - private static function rebuildExprParams(e:Expr, rebuildMethod:Expr->RebuildResult):Expr { - switch(e) { + private static function rebuildExprParams(e:Expr, rebuildMethod:Expr -> RebuildResult):Expr { + switch (e) { case EFunction(f, name): var rexpr = rebuild(f.expr, rebuildMethod); if (rexpr == null) return null; diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index c92f67c..a6ad19f 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -175,7 +175,7 @@ class Typer { } public function getExprType(e:Expr, isFieldAccess:Bool = false):Null { - switch(e) { + switch (e) { case null: return null; case ETypedExpr(e2, t): return tstring(t); case EField(e2, f): @@ -204,7 +204,7 @@ class Typer { case "sort" : return "Function->Void"; } } - switch(t2) { + switch (t2) { case "Dynamic", CommonImports.ObjectType, CommonImports.ObjectImport: switch(f) { case "hasOwnProperty": return "String->Bool"; @@ -390,7 +390,7 @@ class Typer { } } case EIdent(s): - switch(s) { + switch (s) { case "as3hx.Compat": return "as3hx.Compat"; case "Std": return "Std"; case "true", "false": return "Bool"; @@ -1455,7 +1455,7 @@ class Typer { if (f.varArgs != null) { context.set(f.varArgs, "Array"); } - var localTyping:Map = new Map(); + var localTyping:Map = new Map(); function lookUpForTyping(expr:Expr):RebuildResult { switch(expr) { case EBinop("=", EIdent(v), e2, _): @@ -1641,11 +1641,10 @@ class Typer { inline function isStatic(c:ClassField):Bool return Lambda.has(c.kwds, "static"); - /** * Opens a new context for variable typing */ - function openContext(f:Function = null, name:String = null, cl:ClassDef = null) { + function openContext(f:Function = null, name:String = null, cl:ClassDef = null):Void { var c = new Map(); for(k in context.keys()) c.set(k, context.get(k)); @@ -1660,7 +1659,7 @@ class Typer { /** * Closes the current variable typing context */ - function closeContext() { + function closeContext():Void { context = contextStack.pop(); if (functionStack.length > 0) { functionStack.pop(); diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index dfbfa58..86765ad 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -654,7 +654,8 @@ class Writer { var namespaceMetadata:Array = null; if (isFun) { switch(field.kind) { - case FFun(f): typer.enterFunction(f, field.name, c); + case FFun(f): + typer.enterFunction(f, field.name, c); default: }; } @@ -2098,15 +2099,19 @@ class Writer { write(")"); case "getQualifiedClassName": var t:String = getExprType(params[0]); - if (isClassType(t)) { - writeExpr(ECall(EField(EIdent("Type"), "getClassName"), params)); - } else if (t == "Dynamic" || t == null) { - writeExpr(ECall(EField(EIdent("as3hx.Compat"), "getQualifiedClassName"), params)); - } else { // regular type - writeExpr(ECall(EField(EIdent("Type"), "getClassName"), [ECall(EField(EIdent("Type"), "getClass"), params)])); + switch (params[0]) { + case EIdent(v) if (v == t): + writeExpr(ECall(EField(EIdent("Type"), "getClassName"), params)); + case _: + if (isClassType(t)) { + writeExpr(ECall(EField(EIdent("Type"), "getClassName"), params)); + } else if (t == "Dynamic" || t == null) { + writeExpr(ECall(EField(EIdent("as3hx.Compat"), "getQualifiedClassName"), params)); + } else { // regular type + writeExpr(ECall(EField(EIdent("Type"), "getClassName"), [ECall(EField(EIdent("Type"), "getClass"), params)])); + } + //ECall(EField(EIdent("Type"), "getClassName"), [ECall(EField(EIdent("Type"), "getSuperClass"), [e])]); } - //ECall(EField(EIdent("Type"), "getClassName"), [ECall(EField(EIdent("Type"), "getSuperClass"), [e])]); - case "getQualifiedSuperclassName": var t:String = getExprType(params[0]); if (isClassType(t)) { @@ -4311,8 +4316,7 @@ class Writer { return out; } - function openb() : String - { + function openb() : String { if (cfg.bracesOnNewline) { var s:String = cfg.newlineChars + indent() + "{"; if (pendingTailComment != null) { @@ -4334,20 +4338,18 @@ class Writer { return s; } - function write(s : String) - { + function write(s : String):Void { //set line as dirty if string contains something other //than whitespace/indent if (!containsOnlyWhiteSpace(s) && s != cfg.indentChars) { lineIsDirty = true; } - o.writeString(s); } /** write Haxe "allow" metadata using current package */ - function writeAllow() { - write("@:allow("+properCaseA(this.pack,false).join(".")+")"); + function writeAllow():Void { + write("@:allow(" + properCaseA(this.pack, false).join(".") + ")"); writeNL(); writeIndent(); } @@ -4361,8 +4363,7 @@ class Writer { * comment written on dirty line (not first text on line), * add extra whitespace before and after comment */ - function writeComment(s : String, blockComment : Bool) - { + function writeComment(s : String, blockComment : Bool):Void { if (blockComment) { if (isHaxeCodeComment(s)) { write(s.substring(7, s.length - 2)); @@ -4380,15 +4381,12 @@ class Writer { } } - function writeIndent(s = "") - { + function writeIndent(s = ""):Void { write(indent() + s); } - function writeLine(s = "") - { + function writeLine(s = ""):Void { lineIsDirty = false; - if (pendingTailComment != null) { write(indent() + s + pendingTailComment + cfg.newlineChars); pendingTailComment = null; @@ -4397,18 +4395,17 @@ class Writer { } } - function writeNL(s = "") - { + function writeNL(s = ""):Void { write(s); if (pendingTailComment != null) { - write(pendingTailComment); + write(" " + pendingTailComment); pendingTailComment = null; } write(cfg.newlineChars); lineIsDirty = false; } - inline function writeStartStatement() { + inline function writeStartStatement():Void { if(cfg.bracesOnNewline) { writeNL(); writeIndent(); @@ -4417,7 +4414,7 @@ class Writer { } } - inline function writeCloseStatement() { + inline function writeCloseStatement():Void { if(cfg.bracesOnNewline) { write(")"); writeNL(); @@ -4427,7 +4424,7 @@ class Writer { } } - function writeFinish(cond:BlockEnd) { + function writeFinish(cond:BlockEnd):Void { switch(cond) { case None: case Semi: write(";"); From 3561d68af2aa69b9f9af408e59f2b24466f61b99 Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Wed, 10 Apr 2019 02:10:35 +0300 Subject: [PATCH 145/156] Fixes --- .gitignore | 3 +- src/as3hx/Typer.hx | 2 + src/as3hx/Writer.hx | 96 ++++++++++++++++++++++++++++------------- test/issues/Issue112.hx | 2 +- test/issues/Issue121.hx | 6 +-- test/issues/Issue142.hx | 5 ++- test/issues/Issue143.hx | 1 + test/issues/Issue144.hx | 4 +- test/issues/Issue150.hx | 12 +++--- test/issues/Issue152.hx | 6 +-- test/issues/Issue164.hx | 3 +- test/issues/Issue185.hx | 4 +- test/issues/Issue187.hx | 1 + test/issues/Issue192.hx | 2 +- test/issues/Issue214.hx | 3 +- test/issues/Issue215.hx | 2 +- test/issues/Issue23.hx | 4 +- test/issues/Issue24.hx | 60 +++++++++++++------------- test/issues/Issue257.hx | 1 + test/issues/Issue261.hx | 2 +- test/issues/Issue264.hx | 19 ++++---- test/issues/Issue28.hx | 1 - test/issues/Issue314.hx | 8 ++-- test/issues/Issue323.hx | 6 +-- test/issues/Issue63.hx | 3 +- test/issues/Issue64.as | 2 +- test/issues/Issue64.hx | 2 +- test/issues/Issue65.hx | 7 +-- test/issues/Issue66.hx | 8 ++-- test/issues/Issue69.hx | 2 +- test/issues/Issue71.hx | 2 +- test/issues/Issue81.hx | 3 +- test/issues/Issue87.hx | 6 +-- test/issues/Issue91.hx | 2 +- test/issues/Issue95.hx | 8 ++-- 35 files changed, 168 insertions(+), 130 deletions(-) diff --git a/.gitignore b/.gitignore index 0a1ddb5..a8b1367 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ run.n *.hxproj out/ *.iml -.idea \ No newline at end of file +.idea +.unittest/ \ No newline at end of file diff --git a/src/as3hx/Typer.hx b/src/as3hx/Typer.hx index a6ad19f..6bd4fd5 100644 --- a/src/as3hx/Typer.hx +++ b/src/as3hx/Typer.hx @@ -380,6 +380,8 @@ class Typer { return getExprType(params[1]); default: } + case EField(e, "splice"): + return 'Array'; // todo get array type default: } var t:String = getExprType(e); diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 86765ad..6b30452 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -33,6 +33,7 @@ class Writer { var loopIncrements : Array; var varCount : Int; // vars added for ESwitch or EFor initialization var isInterface : Bool; // set if current class is an interface + var isExtends : Bool; var inArrayAccess : Bool; var inEField : Bool; var inE4XFilter : Bool; @@ -367,7 +368,8 @@ class Writer { } var parents = []; - if (null != c.extend) { + isExtends = null != c.extend; + if (isExtends) { parents.push((isInterface ? "implements " : "extends ") + tstring(c.extend)); } for (i in c.implement) @@ -396,6 +398,7 @@ class Writer { writeInits(c); lvl--; + writeNL(); write(closeb()); //close conditional compilation block if needed @@ -813,11 +816,13 @@ class Writer { if( cfg.getterSetterStyle == "flash" || cfg.getterSetterStyle == "combined") { start(field.name, true); writeFunction(f, isGetter(field.kwds), isSetter(field.kwds), true, name, ret); + writeNL(); } // write haxe version if( cfg.getterSetterStyle == "haxe" || cfg.getterSetterStyle == "combined") { start(field.name, false); writeFunction(f, isGetter(field.kwds), isSetter(field.kwds), false, name, ret); + writeNL(); } if(cfg.getterSetterStyle == "combined") { writeNL("#end"); @@ -826,6 +831,7 @@ class Writer { } else { start(name, false); writeFunction(f, isGetter(field.kwds), isSetter(field.kwds), false, name, ret, field.meta); + writeNL(); } } @@ -1000,7 +1006,7 @@ class Writer { if(arg.val != null) { write(" = "); switch(tstring(t)) { - case "Int" if(needCastToInt(arg.val)): + case "Int" if (needCastToInt(arg.val)): switch(arg.val) { case EConst(_ => CFloat(f)): var index = f.indexOf('.'); @@ -1192,7 +1198,7 @@ class Writer { if (!isInterface) writeStartStatement(); writeExpr(EBlock(es)); - writeNL(); + // writeNL(); functionReturnType = oldFunctionReturnType; } @@ -1271,7 +1277,7 @@ class Writer { inLvalAssign = false; //oldInLVA = false; var isProxy:Bool = etype == "PropertyProxy" || etype == "feathers.core.PropertyProxy"; - var isRawData:Bool = etype == "Object" || etype == CommonImports.ObjectType || etype == CommonImports.ObjectImport; + var isRawData:Bool = false; //etype == "Object" || etype == CommonImports.ObjectType || etype == CommonImports.ObjectImport; if (isArrayType(etype) || isVectorType(etype) || isOpenFlDictionaryType(etype) || isMapType(etype) || isByteArrayType(etype) || isProxy || isRawData) { writeExpr(e); inArrayAccess = old; @@ -1404,6 +1410,9 @@ class Writer { case EField(e, f): rv = writeEField(expr, e, f); case EBinop(op, e1, e2, newLineAfterOp): rv = writeEBinop(op, e1, e2, newLineAfterOp); case EUnop(op, prefix, e): rv = writeEUnop(op, prefix, e); + case ECall(EIdent('super'), params): + if (isExtends) rv = writeECall(expr, EIdent('super'), params); + else return None; case ECall(e, params): rv = writeECall(expr, e, params); case EIf(cond, e1, e2): rv = writeEIf(cond, e1, e2); case ETernary(cond, e1, e2): writeETernarny(cond, e1, e2); @@ -1934,7 +1943,8 @@ class Writer { if (f == "length") { var type:String = getExprType(e); if (type == "Function" || type == "haxe.Constraints.Function") { - write("1 /*# of arguments of " + v + "*/"); + // write("1 /*# of arguments of " + v + "*/"); + write('as3hx.Compat.getFunctionLength(' + v + ')'); return None; } else if (type != null && isFunctionType(type)) { writeExpr(getCompatCallExpr("getFunctionLength", [e])); @@ -2074,7 +2084,7 @@ class Writer { case "Number": writeCastToFloat(params[0]); case "String": if (getExprType(params[0]) == "String") { - writeEParent(params[0]); + writeExpr(params[0]); } else { writeExpr(getToStringExpr(params[0])); } @@ -2145,7 +2155,7 @@ class Writer { case "int" | "uint": var t:String = getExprType(params[0]); if (t == "Int" || t == "UInt") { - writeEParent(params[0]); + writeExpr(params[0]); } else { writeExpr(getCastToIntExpr(params[0])); } @@ -2182,7 +2192,7 @@ class Writer { if (globalFunction != null) { //write(properCase(globalFunction, true) + "."); write(n.charAt(0).toUpperCase() + n.substr(1) + "."); - } else { + } else if (!typer.isExistingIdent(n)) { var type:String = typer.getExprType(expr); var className:String = type.substring(type.lastIndexOf(".") + 1); if (type != "Function" && type != "haxe.Constraints.Function" && type.indexOf("->") == -1 && (className.charAt(0) == className.charAt(0).toUpperCase())) { @@ -2255,8 +2265,8 @@ class Writer { write("if ("); lvl++; //extra indenting if condition on multiple lines var rb = rebuildIfExpr(cond); - if(rb != null) { - var f:Expr->Expr = null; + if (rb != null) { + var f:Expr -> Expr = null; f = function(e) return switch(e) { case EParent(e): f(e); default: e; @@ -2293,13 +2303,21 @@ class Writer { // if we find an EBlock([ENL(EIf(...))]) // after an `else` then we have an // `else if` statement - switch(e2) { + var haveExtra:Bool = false; + switch (e2) { case EBlock(e3): if (e3 != null && e3.length == 1) { var e4 = ParserUtils.removeNewLineExpr(e3[0]); var extraExpr:Expr = extractComments(e3[0]); - writeExpr(extraExpr); - switch(e4) { + if (extraExpr != null) switch (extraExpr) { + case ENL(ECommented(s, isBlock, isTail, e)): + haveExtra = true; + writeNL(s); + case _: + } + // writeExpr(extraExpr); + + switch (e4) { case EIf(_, _, _): // found single if statement after an else // replace parent `block` + `new line` with @@ -2319,12 +2337,16 @@ class Writer { } //writeNL(); if (elseif != null) { - //writeIndent(" else "); - write(" else "); + if (haveExtra) + writeIndent("else "); + else + write(" else "); result = writeExpr(elseif); } else { - //writeIndent(" else"); - write(" else"); + if (haveExtra) + writeIndent("else"); + else + write(" else"); writeStartStatement(); result = writeExpr(e2); } @@ -2587,10 +2609,17 @@ class Writer { writeExpr(e1); write(")"); case "Class": - //addWarning("as Class", true); - write("as3hx.Compat.castClass("); - writeExpr(e1); - write(")"); + switch (e1) { + case EField(ECall(_, _), 'constructor'): + write("Type.getClass("); + writeExpr(e1); + write(")"); + case _: + //addWarning("as Class", true); + write("as3hx.Compat.castClass("); + writeExpr(e1); + write(")"); + } case "Function": addWarning("as Function", false); write("cast "); @@ -3439,9 +3468,14 @@ class Writer { case "Int" | "UInt": EBinop("!=", e, EConst(CInt("0")), false); case "Float": - var lvalue = EBinop("!=", e, EConst(CInt("0")), false); - var rvalue = EUnop("!", true, ECall(EField(EIdent("Math"), "isNaN"), [e])); - EParent(EBinop("&&", lvalue, rvalue, false)); + switch (e) { + case ECall(_, _): + e; + case _: + var lvalue = EBinop("!=", e, EConst(CInt("0")), false); + var rvalue = EUnop("!", true, ECall(EField(EIdent("Math"), "isNaN"), [e])); + EParent(EBinop("&&", lvalue, rvalue, false)); + } default: EBinop("!=", e, EIdent("null"), false); } case EBinop(op, e2, e3, n): @@ -3876,7 +3910,7 @@ class Writer { } return changed ? EBinop(op, lvalue, rvalue, false) : null; } - if(isBitwiseAndAssignmetnOp(op)) return EBinop("=", lvalue, EBinop(op.charAt(0), lvalue, rvalue, false), false); + if (isBitwiseAndAssignmetnOp(op)) return EBinop("=", lvalue, EBinop(op.charAt(0), lvalue, rvalue, false), false); switch(op) { case "||=": var type = getExprType(lvalue); @@ -3886,7 +3920,7 @@ class Writer { case "Int" | "UInt" | "Float" | _: rebuildIfExpr(lvalue); } if (cond == null) cond = lvalue; - if(isDynamicType(type)) { + if (isDynamicType(type)) { cond = switch(cond) { case EBinop(op, e1, e2, false) if(op == "!="): EBinop("==", e1, e2, false); default: cond; @@ -3930,7 +3964,7 @@ class Writer { } } switch(rvalue) { - case EBinop(op,e1,e2,_) if(op == "||="): + case EBinop(op,e1,e2,_) if (op == "||="): writeExpr(rebuildBinopExpr(op, e1, e2)); writeNL(); writeIndent(); @@ -4398,7 +4432,10 @@ class Writer { function writeNL(s = ""):Void { write(s); if (pendingTailComment != null) { - write(" " + pendingTailComment); + if (s == "") + write(pendingTailComment); + else + write(" " + pendingTailComment); pendingTailComment = null; } write(cfg.newlineChars); @@ -4443,11 +4480,12 @@ class Writer { for(field in genType.fields) { writeNL(); writeIndent(cfg.indentChars); - write("var "+field.name + " : " + field.t + ";"); + write("var " + field.name + ": " + field.t + ";"); } writeNL(); write("}"); writeNL(); + writeNL(); } } diff --git a/test/issues/Issue112.hx b/test/issues/Issue112.hx index f4610e4..03be495 100644 --- a/test/issues/Issue112.hx +++ b/test/issues/Issue112.hx @@ -3,7 +3,7 @@ class Issue112 { public function new() { var timeoutId:Int = as3hx.Compat.setTimeout(function(s:String):Void {}, 1000, ['string']); as3hx.Compat.clearTimeout(timeoutId); - var intervalId:Int = as3hx.Compat.setInterval(function(s:String):Void {}, 1000, ['string']); + var intervalId:Int = AS3.int(as3hx.Compat.setInterval(function(s:String):Void {}, 1000, ['string'])); as3hx.Compat.clearInterval(intervalId); } diff --git a/test/issues/Issue121.hx b/test/issues/Issue121.hx index a3f20dc..9100b99 100644 --- a/test/issues/Issue121.hx +++ b/test/issues/Issue121.hx @@ -2,13 +2,13 @@ class Issue121 { public function new() { var o:Dynamic = {}; - if (Lambda.has(o, 'some')) { + if (Reflect.hasField(o, 'some')) { Reflect.deleteField(o, 'some'); } else { o = null; } - if (Lambda.has(o, 1)) { + if (Reflect.hasField(o, Std.string(1))) { Reflect.deleteField(o, '1'); } } @@ -16,7 +16,7 @@ class Issue121 { private var _eventListeners:Dynamic = {}; public function removeEventListeners(type:String = null):Void { - if (type != null && _eventListeners != null) { + if (type != null && AS3.as(_eventListeners, Bool)) { Reflect.deleteField(_eventListeners, type); } else { _eventListeners = null; diff --git a/test/issues/Issue142.hx b/test/issues/Issue142.hx index 4acf1c1..3306fb3 100644 --- a/test/issues/Issue142.hx +++ b/test/issues/Issue142.hx @@ -1,11 +1,12 @@ import flash.display.Scene; import flash.display.Sprite; import flash.events.DataEvent; + class Issue142 { public function new() { - var sceneClass:Class = Type.getClass(Type.resolveClass('SceneType')); - var currentScene:Scene = try cast(Type.createInstance(sceneClass, []), Scene) catch (e:Dynamic) null; + var sceneClass:Class = as3hx.Compat.castClass(Type.resolveClass('SceneType')); + var currentScene:Scene = AS3.as(Type.createInstance(sceneClass, []), Scene); var d:Date = Date.now(); var s:Sprite = new Sprite(); diff --git a/test/issues/Issue143.hx b/test/issues/Issue143.hx index 6e0b0ee..83b6588 100644 --- a/test/issues/Issue143.hx +++ b/test/issues/Issue143.hx @@ -1,4 +1,5 @@ import flash.display3D.Context3D; + class Issue143 { public function new() {} diff --git a/test/issues/Issue144.hx b/test/issues/Issue144.hx index a4a55e2..254caaf 100644 --- a/test/issues/Issue144.hx +++ b/test/issues/Issue144.hx @@ -1,8 +1,8 @@ import flash.events.TouchEvent; -class Issue144 { - private var multitouchEnabled:Bool; +class Issue144 { + private var multitouchEnabled:Bool = false; private var types:Array = []; public function new() { diff --git a/test/issues/Issue150.hx b/test/issues/Issue150.hx index 572d6af..9248f0a 100644 --- a/test/issues/Issue150.hx +++ b/test/issues/Issue150.hx @@ -2,12 +2,12 @@ class Issue150 { public function new() { var fragmentShader:String = [ - tex('ft0', 'v1', 1, _mapTexture, false), // read map texture - 'sub ft1, ft0, fc0', // subtract 0.5 -> range [-0.5, 0.5] - 'mul ft1.xy, ft1.xy, ft0.ww', // zero displacement when alpha == 0 - 'm44 ft2, ft1, fc1', // multiply matrix with displacement values - 'add ft3, v0, ft2', // add displacement values to texture coords - tex('oc', 'ft3', 0, texture) // read input texture at displaced coords + tex('ft0', 'v1', 1, _mapTexture, false), // read map texture + 'sub ft1, ft0, fc0', // subtract 0.5 -> range [-0.5, 0.5] + 'mul ft1.xy, ft1.xy, ft0.ww', // zero displacement when alpha == 0 + 'm44 ft2, ft1, fc1', // multiply matrix with displacement values + 'add ft3, v0, ft2', // add displacement values to texture coords + tex('oc', 'ft3', 0, texture)// read input texture at displaced coords ].join('\n'); var s1:String = [1, 2, 3, 4, 5].join('\n'); diff --git a/test/issues/Issue152.hx b/test/issues/Issue152.hx index 1f3b546..5a338af 100644 --- a/test/issues/Issue152.hx +++ b/test/issues/Issue152.hx @@ -4,13 +4,13 @@ class Issue152 { public function new() { vertexShader.push( - 1 // add offset 1 + 1// add offset 1 ); vertexShader.push( - 2 // add offset 2 + 2// add offset 2 ); vertexShader.push( - 3 // add offset 3 + 3// add offset 3 ); vertexShader.push( 4 diff --git a/test/issues/Issue164.hx b/test/issues/Issue164.hx index 48b96f2..d1c27e2 100644 --- a/test/issues/Issue164.hx +++ b/test/issues/Issue164.hx @@ -1,8 +1,9 @@ import flash.display.DisplayObject; + class Issue164 { public function new(rootClass:Class) { - var d:DisplayObject = try cast(Type.createInstance(rootClass, []), DisplayObject) catch (e:Dynamic) null; + var d:DisplayObject = AS3.as(Type.createInstance(rootClass, []), DisplayObject); } } \ No newline at end of file diff --git a/test/issues/Issue185.hx b/test/issues/Issue185.hx index 1ec92f2..52e1473 100644 --- a/test/issues/Issue185.hx +++ b/test/issues/Issue185.hx @@ -1,8 +1,8 @@ class Issue185 { public function new() { - var a:Array = [1]; - var i:Int = as3hx.Compat.parseInt(a.splice(0, 1)[0]); + var a:Array = [1]; + var i:Int = AS3.int(a.splice(0, 1)[0]); a.splice(1, 1)[0]; } diff --git a/test/issues/Issue187.hx b/test/issues/Issue187.hx index 2d9f067..8815a13 100644 --- a/test/issues/Issue187.hx +++ b/test/issues/Issue187.hx @@ -1,5 +1,6 @@ import flash.geom.Matrix3D; import flash.geom.Vector3D; + class Issue187 { private static var sPoint3D:Vector3D; diff --git a/test/issues/Issue192.hx b/test/issues/Issue192.hx index 31ec2c5..056e341 100644 --- a/test/issues/Issue192.hx +++ b/test/issues/Issue192.hx @@ -4,7 +4,7 @@ class Issue192 { public function new() { var f:Function = test; - test(s); + test(Std.string(s)); } private function test(s:String) { diff --git a/test/issues/Issue214.hx b/test/issues/Issue214.hx index 92b96a9..0b39062 100644 --- a/test/issues/Issue214.hx +++ b/test/issues/Issue214.hx @@ -1,9 +1,8 @@ class Issue214 { - public var test(never, set):Bool; - public function new() {} + public var test(never, set):Bool; private function set_test(v:Bool):Bool { if (!v) { return v; diff --git a/test/issues/Issue215.hx b/test/issues/Issue215.hx index d74bbeb..77e3874 100644 --- a/test/issues/Issue215.hx +++ b/test/issues/Issue215.hx @@ -1,6 +1,6 @@ class Issue215 { - private static var regex:as3hx.Compat.Regex = new as3hx.Compat.Regex('sh', 'gi'); + private static var regex(default, never):as3hx.Compat.Regex = new as3hx.Compat.Regex('sh', 'gi'); public function new(string2:String) { var string:String = 'She sells seashells by the seashore.'; diff --git a/test/issues/Issue23.hx b/test/issues/Issue23.hx index 5b98d07..88d7619 100644 --- a/test/issues/Issue23.hx +++ b/test/issues/Issue23.hx @@ -3,8 +3,8 @@ class Issue23 { public function new(i:Int, n:Float, ss:String) { var a:Int = i; var a2:Int = i; - var a3:Int = as3hx.Compat.parseInt(n); - var a4:Int = as3hx.Compat.parseInt(s); + var a3:Int = AS3.int(n); + var a4:Int = AS3.int(s); var b:Float = n; var b2:Float = n; diff --git a/test/issues/Issue24.hx b/test/issues/Issue24.hx index 7909520..8c95832 100644 --- a/test/issues/Issue24.hx +++ b/test/issues/Issue24.hx @@ -2,42 +2,42 @@ class Issue24 { public function new(a:Int, b:Int, c:Int, n:Float) { c = a; - c = as3hx.Compat.parseInt(a / b); - c = as3hx.Compat.parseInt(n); - c = as3hx.Compat.parseInt(n - a); - c = as3hx.Compat.parseInt(n + a); - c = as3hx.Compat.parseInt(n * a); - c = as3hx.Compat.parseInt(n) << a; - c = as3hx.Compat.parseInt(n) >> a; - c = as3hx.Compat.parseInt(n) >>> a; - c = as3hx.Compat.parseInt(n) & a; - c = as3hx.Compat.parseInt(n) ^ a; - c = as3hx.Compat.parseInt(n) | a; - c = ~as3hx.Compat.parseInt(n); - c = as3hx.Compat.parseInt(n) | as3hx.Compat.parseInt(n); + c = AS3.int(a / b); + c = AS3.int(n); + c = AS3.int(n - a); + c = AS3.int(n + a); + c = AS3.int(n * a); + c = AS3.int(n) << a; + c = AS3.int(n) >> a; + c = AS3.int(n) >>> a; + c = AS3.int(n) & a; + c = AS3.int(n) ^ a; + c = AS3.int(n) | a; + c = ~AS3.int(n); + c = AS3.int(n) | AS3.int(n); - var i:Int = as3hx.Compat.parseInt(a / b); - var j:Int = as3hx.Compat.parseInt(n); - var k:Int = as3hx.Compat.parseInt(n - j); - var k:Int = as3hx.Compat.parseInt(n + j); - var k:Int = as3hx.Compat.parseInt(n * j); - var k:Int = as3hx.Compat.parseInt(n) << j; - var k:Int = as3hx.Compat.parseInt(n) >> j; - var k:Int = as3hx.Compat.parseInt(n) >>> j; - var k:Int = as3hx.Compat.parseInt(n) & j; - var k:Int = j & as3hx.Compat.parseInt(n); - var k:Int = as3hx.Compat.parseInt(n) ^ j; - var k:Int = j ^ as3hx.Compat.parseInt(n); - var k:Int = as3hx.Compat.parseInt(n) | j; - var k:Int = j | as3hx.Compat.parseInt(n); + var i:Int = AS3.int(a / b); + var j:Int = AS3.int(n); + var k:Int = AS3.int(n - j); + var k:Int = AS3.int(n + j); + var k:Int = AS3.int(n * j); + var k:Int = AS3.int(n << j); + var k:Int = AS3.int(n >> j); + var k:Int = AS3.int(n >>> j); + var k:Int = AS3.int(AS3.int(n) & j); + var k:Int = AS3.int(j & AS3.int(n)); + var k:Int = AS3.int(n ^ j); + var k:Int = AS3.int(j ^ n); + var k:Int = AS3.int(n | j); + var k:Int = AS3.int(j | n); var n2:Float; - var k:Int = ~as3hx.Compat.parseInt(n2); + var k:Int = AS3.int(~n2); - if ((as3hx.Compat.parseInt(n) & as3hx.Compat.parseInt(n - 1)) == 0) {} + if ((AS3.int(n) & AS3.int(n - 1)) == 0) {} } public function getInt(n:Float):Int { - return as3hx.Compat.parseInt(n + 10); + return AS3.int(n + 10); } } \ No newline at end of file diff --git a/test/issues/Issue257.hx b/test/issues/Issue257.hx index 9b0074c..9d39690 100644 --- a/test/issues/Issue257.hx +++ b/test/issues/Issue257.hx @@ -1,4 +1,5 @@ import flash.net.URLRequest; + class Issue257 { public function new() { diff --git a/test/issues/Issue261.hx b/test/issues/Issue261.hx index f640293..9f80497 100644 --- a/test/issues/Issue261.hx +++ b/test/issues/Issue261.hx @@ -1,7 +1,7 @@ class Issue261 { public function new() { - var a:Array = [{}]; + var a:Array = cast [{}]; Reflect.setField(a[a.length - 1], 'some', 10); } diff --git a/test/issues/Issue264.hx b/test/issues/Issue264.hx index b0b3035..4e5440d 100644 --- a/test/issues/Issue264.hx +++ b/test/issues/Issue264.hx @@ -1,3 +1,5 @@ +import flash.errors.Error; + class Issue264 { public function new() { @@ -5,17 +7,16 @@ class Issue264 { var message:String; // error inside - if (Std.is(obj.error, Error)) { - message = obj.error.message; - } - // error event inside - else if (Std.is(obj.error, ErrorEvent)) { - message = obj.error.text; - } - // unknown + if (Std.is(Reflect.field(obj, 'error'), Error)) { + message = AS3.string(Reflect.field(Reflect.field(obj, 'error'), 'message')); + }// error event inside + else if (Std.is(Reflect.field(obj, 'error'), ErrorEvent)) { + message = AS3.string(Reflect.field(Reflect.field(obj, 'error'), 'text')); + }// unknown else { - message = Std.string(obj.error); + message = Std.string(Std.string(Reflect.field(obj, 'error'))); } + } } \ No newline at end of file diff --git a/test/issues/Issue28.hx b/test/issues/Issue28.hx index e0aa14f..3408727 100644 --- a/test/issues/Issue28.hx +++ b/test/issues/Issue28.hx @@ -1,7 +1,6 @@ class Issue28 { private static var b:Bool = true; - private static var o:Dynamic = (b) ? {} : null; public function new() { diff --git a/test/issues/Issue314.hx b/test/issues/Issue314.hx index b23cb14..d1d40b4 100644 --- a/test/issues/Issue314.hx +++ b/test/issues/Issue314.hx @@ -3,13 +3,13 @@ class Issue314 { public function new() {} public function hide1(param1:Dynamic):Dynamic { - Reflect.setField(this, Std.string(param1), false); - Reflect.field(this, Std.string(param1)).visible = false; + Reflect.setProperty(this, Std.string(param1), false); + Reflect.getProperty(this, Std.string(param1)).visible = false; } public function hide2(param1:Dynamic):Dynamic { - Reflect.setField(this, Std.string(param1), 'nothing'); - Reflect.field(this, Std.string(param1)).collision.currentObject = 'nothing'; + Reflect.setProperty(this, Std.string(param1), 'nothing'); + Reflect.getProperty(this, Std.string(param1)).collision.currentObject = 'nothing'; } } \ No newline at end of file diff --git a/test/issues/Issue323.hx b/test/issues/Issue323.hx index f838616..0198a81 100644 --- a/test/issues/Issue323.hx +++ b/test/issues/Issue323.hx @@ -3,12 +3,10 @@ class Issue323 { private var friendsList:Array; public function new() { - var i:Int = 0; - while (i < friendsList.length) { - if (friendsList[i].bSelected) { + for (i in 0...friendsList.length) { + if (AS3.as(Reflect.field(friendsList[i], 'bSelected'), Bool)) { true; } - i++; } } diff --git a/test/issues/Issue63.hx b/test/issues/Issue63.hx index 376f9aa..29330d4 100644 --- a/test/issues/Issue63.hx +++ b/test/issues/Issue63.hx @@ -1,10 +1,11 @@ import flash.utils.ByteArray; + class Issue63 { public function new() { var a:Array = new Array(); as3hx.Compat.setArrayLength(a, 10); - var bytes:ByteArray = new ByteArray(); + var bytes:ByteArray = as3hx.Compat.newByteArray(); bytes.length = 0; } diff --git a/test/issues/Issue64.as b/test/issues/Issue64.as index 0ad0b8d..d3fb1ab 100644 --- a/test/issues/Issue64.as +++ b/test/issues/Issue64.as @@ -8,7 +8,7 @@ package { var time:Number; var events:Vector.; for (var i:int = 0, n:int = timelines.length; i < n; i++) { - timelienes[i].apply(skeleton, lastTime, time, events, 1); + timelines[i].apply(skeleton, lastTime, time, events, 1); } } } diff --git a/test/issues/Issue64.hx b/test/issues/Issue64.hx index a209fac..520eca5 100644 --- a/test/issues/Issue64.hx +++ b/test/issues/Issue64.hx @@ -11,7 +11,7 @@ class Issue64 { var i:Int = 0; var n:Int = timelines.length; while (i < n) { - timelienes[i].apply(skeleton, lastTime, time, events, 1); + timelines[i].apply(skeleton, lastTime, time, events, 1); i++; } } diff --git a/test/issues/Issue65.hx b/test/issues/Issue65.hx index ddfa8c2..33408ca 100644 --- a/test/issues/Issue65.hx +++ b/test/issues/Issue65.hx @@ -2,14 +2,11 @@ class Issue65 { public function new() { var array:Array; - var i:Int = 0; - while (i < array.length) { + for (i in 0...array.length) { var current:Dynamic = array[i]; - if (current == null) { - i++; + if (!AS3.as(current, Bool)) { continue; } - i++; } } diff --git a/test/issues/Issue66.hx b/test/issues/Issue66.hx index 68b8362..6a4a61f 100644 --- a/test/issues/Issue66.hx +++ b/test/issues/Issue66.hx @@ -1,11 +1,11 @@ class Issue66 { public function new() { - var a:Int = 1; - var b:Int = as3hx.Compat.parseInt(10.5); - var c:Int = as3hx.Compat.parseInt(a / b); + var a:Int = AS3.int(1); + var b:Int = AS3.int(AS3.int(10.5)); + var c:Int = AS3.int(AS3.int(a / b)); var b:Float; - var d:Int = as3hx.Compat.parseInt(b); + var d:Int = AS3.int(AS3.int(b)); } } \ No newline at end of file diff --git a/test/issues/Issue69.hx b/test/issues/Issue69.hx index eaa0c9e..1573850 100644 --- a/test/issues/Issue69.hx +++ b/test/issues/Issue69.hx @@ -2,7 +2,7 @@ class Issue69 { public function new() { var s:String = ''; - var c:String = s.charAt(0); + var c:String = Std.string(s.charAt(0)); } } \ No newline at end of file diff --git a/test/issues/Issue71.hx b/test/issues/Issue71.hx index 8e47534..9c05b0c 100644 --- a/test/issues/Issue71.hx +++ b/test/issues/Issue71.hx @@ -3,7 +3,7 @@ class Issue71 { public function new() { __DOLLAR__test({}); var __DOLLAR__localVar:Dynamic = { - __DOLLAR__key: 'value' + '__DOLLAR__key': 'value' }; } diff --git a/test/issues/Issue81.hx b/test/issues/Issue81.hx index e93d82b..9363837 100644 --- a/test/issues/Issue81.hx +++ b/test/issues/Issue81.hx @@ -1,7 +1,6 @@ import flash.system.Security; -class Issue81 { - public function new() {} +class Issue81 { private static var Issue81_static_initializer = { Security.allowDomain('*'); diff --git a/test/issues/Issue87.hx b/test/issues/Issue87.hx index 6e2a659..3e65952 100644 --- a/test/issues/Issue87.hx +++ b/test/issues/Issue87.hx @@ -3,10 +3,10 @@ class Issue87 { public function new() { __DOLLAR__cast(''); new PrivateClass().__DOLLAR__cast(''); - var __DOLLAR__cast:Int = as3hx.Compat.parseInt(10.0); + var __DOLLAR__cast:Int = AS3.int(10.0); } - private var __DOLLAR__cast:Int = as3hx.Compat.parseInt(10.0); + private var __DOLLAR__cast:Int = AS3.int(10.0); private function __DOLLAR__cast(o:Dynamic):String { return Std.string(o); @@ -17,7 +17,7 @@ class Issue87 { class PrivateClass { public function new(__DOLLAR__cast:Int) { - super(); + } public function __DOLLAR__cast(o:Dynamic):String { diff --git a/test/issues/Issue91.hx b/test/issues/Issue91.hx index 2839593..566f8b4 100644 --- a/test/issues/Issue91.hx +++ b/test/issues/Issue91.hx @@ -2,7 +2,7 @@ class Issue91 { public function new() { var i:Int = 1; - var b:Bool = i != 0; + var b:Bool = i == 0; } } \ No newline at end of file diff --git a/test/issues/Issue95.hx b/test/issues/Issue95.hx index 8906f4a..dab0442 100644 --- a/test/issues/Issue95.hx +++ b/test/issues/Issue95.hx @@ -5,13 +5,11 @@ typedef ConfigsTypedef = { class Issue95 { - private static var _configs:Array = [ + private static var _configs:Array = cast [ { - name: 'name', - id: 10 + 'name': 'name', + 'id': 10 } ]; - public function new() {} - } \ No newline at end of file From a6e14c907d6c54dec198d3f6fb788bfd55287060 Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Thu, 11 Apr 2019 04:33:03 +0300 Subject: [PATCH 146/156] Finish fixing tests --- src/as3hx/Writer.hx | 61 +++++++++++++++++++++++++---------------- test/issues/Issue2.hx | 2 +- test/issues/Issue213.hx | 1 + test/issues/Issue246.hx | 3 +- test/issues/Issue26.hx | 2 -- test/issues/Issue323.hx | 1 - test/issues/Issue36.hx | 2 +- 7 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 6b30452..ddbda27 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1459,29 +1459,29 @@ class Writer { } return r; } - switch (e) { - case ENew(t, params): - //var c = params.copy(); - //c.unshift(EConst(CString(tstring(t) + ": "))); - var args:Array = [EConst(CString(tstring(t)))]; - if (params.length > 0) { - args.push(joinToString(params)); - } - writeExpr(ENew(TPath(["XError"]), args)); - case ECall(e1, params): - switch(e1) { - case EIdent(s): - var args:Array = [EConst(CString(s))]; - if (params.length > 0) { - args.push(joinToString(params)); - } - writeExpr(ENew(TPath(["XError"]), args)); - default: - writeExpr(e); - } - default: + // switch (e) { + // case ENew(t, params): + // //var c = params.copy(); + // //c.unshift(EConst(CString(tstring(t) + ": "))); + // var args:Array = [EConst(CString(tstring(t)))]; + // if (params.length > 0) { + // args.push(joinToString(params)); + // } + // writeExpr(ENew(TPath(["XError"]), args)); + // case ECall(e1, params): + // switch(e1) { + // case EIdent(s): + // var args:Array = [EConst(CString(s))]; + // if (params.length > 0) { + // args.push(joinToString(params)); + // } + // writeExpr(ENew(TPath(["XError"]), args)); + // default: + // writeExpr(e); + // } + // default: writeExpr(e); - } + // } //switch (e) { //case ENew(t, params): //var c = params.copy(); @@ -1866,8 +1866,21 @@ class Writer { } } function writeBlockLine(e:Expr):Void { - var fix = fixBlockLine(e); - writeFinish(writeExpr(fix == null ? e : fix)); + if (e != null) { + switch (e) { + case EConst(_): return; + case EIdent(_): return; + case ENL(e): + if (e != null) switch (e) { + case EConst(_): return; + case EIdent(_): return; + case _: + } + case _: + } + var fix = fixBlockLine(e); + writeFinish(writeExpr(fix == null ? e : fix)); + } } private var restrictedFieldArrayAccessConversion:Array = ["length", "split", "indexOf"]; diff --git a/test/issues/Issue2.hx b/test/issues/Issue2.hx index 61fbdad..d55b541 100644 --- a/test/issues/Issue2.hx +++ b/test/issues/Issue2.hx @@ -2,7 +2,7 @@ class Issue2 { public function new() { trace({ - name: 'hello' + 'name': 'hello' }); } diff --git a/test/issues/Issue213.hx b/test/issues/Issue213.hx index 9c8c3ec..c1bd85f 100644 --- a/test/issues/Issue213.hx +++ b/test/issues/Issue213.hx @@ -1,4 +1,5 @@ import starling.utils.StringUtil; + class Issue213 { public function new() { diff --git a/test/issues/Issue246.hx b/test/issues/Issue246.hx index 40f0090..586b75c 100644 --- a/test/issues/Issue246.hx +++ b/test/issues/Issue246.hx @@ -1,11 +1,10 @@ class Issue246 { - public var steps(never, set):Int; - public function new() {} private var _steps:Int = 8; + public var steps(never, set):Int; private function set_steps(val:Int):Int { if (_steps == val) { return val; diff --git a/test/issues/Issue26.hx b/test/issues/Issue26.hx index b8823d2..e4fcb2d 100644 --- a/test/issues/Issue26.hx +++ b/test/issues/Issue26.hx @@ -1,7 +1,5 @@ class Issue26 { - public function new() {} - } class Foo { diff --git a/test/issues/Issue323.hx b/test/issues/Issue323.hx index 0198a81..de82c1e 100644 --- a/test/issues/Issue323.hx +++ b/test/issues/Issue323.hx @@ -5,7 +5,6 @@ class Issue323 { public function new() { for (i in 0...friendsList.length) { if (AS3.as(Reflect.field(friendsList[i], 'bSelected'), Bool)) { - true; } } } diff --git a/test/issues/Issue36.hx b/test/issues/Issue36.hx index 1019a78..678b94f 100644 --- a/test/issues/Issue36.hx +++ b/test/issues/Issue36.hx @@ -2,7 +2,7 @@ class Issue36 { public function new() { var s:String = ''; - var c:String = s.charCodeAt(0); + var c:String = Std.string(s.charCodeAt(0)); } } \ No newline at end of file From 9ef8dd307bbe42359894a3704f523a1a488e3954 Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Mon, 15 Apr 2019 18:59:42 +0300 Subject: [PATCH 147/156] Unit tests --- src/as3hx/Config.hx | 2 +- test.hxml | 1 + test/unit/as3hx/AS3HXTest.hx | 12 ++++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index 54525e3..9ced8da 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -182,7 +182,7 @@ class Config { return s.substr(0, 1).toUpperCase() + s.substr(1); } - function processDefaultConfig():Void { + public function processDefaultConfig():Void { fromXmlString(defaultConfig()); } diff --git a/test.hxml b/test.hxml index b4b8fbd..3908436 100644 --- a/test.hxml +++ b/test.hxml @@ -41,6 +41,7 @@ -cp test/unit -neko build/neko_test.n +-lib test-adapter --next diff --git a/test/unit/as3hx/AS3HXTest.hx b/test/unit/as3hx/AS3HXTest.hx index ec7d7b5..002c7f1 100644 --- a/test/unit/as3hx/AS3HXTest.hx +++ b/test/unit/as3hx/AS3HXTest.hx @@ -598,10 +598,22 @@ class AS3HXTest { var content = File.getContent('$issuesDirectory/$as3FileName'); var program = parser.parseString(content, issuesDirectory, '$issuesDirectory/$as3FileName'); var fw = File.write('$generatedDirectoryPath/$expectedHaxeFileName', false); + if (cfg.useFullTyping) { + writer.register(program); + writer.prepareTyping(); + if (cfg.useOpenFlTypes) { + writer.refineTypes(program); + writer.applyRefinedTypes(program); + } + writer.finishTyping(); + } writer.process(program, fw); fw.close(); var expectedText = File.getContent('$issuesDirectory/$expectedHaxeFileName'); var actualText = File.getContent('$generatedDirectoryPath/$expectedHaxeFileName'); + if (expectedText != actualText) { + Sys.command("diff", ['$issuesDirectory/$expectedHaxeFileName', '$generatedDirectoryPath/$expectedHaxeFileName']); + } Assert.areEqual(expectedText, actualText); } } \ No newline at end of file From cf868b6bd00d539b2f22d94d8d34fdd19eff6248 Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Mon, 15 Apr 2019 20:52:07 +0300 Subject: [PATCH 148/156] Repair tests --- src/as3hx/Config.hx | 4 ++-- test/issues/Issue119_notUseCompat.hx | 3 ++- test/issues/Issue119_useCompat.hx | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index 9ced8da..a5d59eb 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -517,10 +517,10 @@ class Config { - + - + diff --git a/test/issues/Issue119_notUseCompat.hx b/test/issues/Issue119_notUseCompat.hx index 196d8e3..15dece9 100644 --- a/test/issues/Issue119_notUseCompat.hx +++ b/test/issues/Issue119_notUseCompat.hx @@ -1,8 +1,9 @@ import flash.system.Capabilities; + class Issue119 { public function new() { - var sPlatform:String = Capabilities.version.substr(0, 3); + var sPlatform:String = Std.string(Capabilities.version.substr(0, 3)); var sDesktop:Bool = new flash.utils.RegExp('(WIN|MAC|LNX)', '').exec(sPlatform) != null; var ereg:flash.utils.RegExp = new flash.utils.RegExp('(WIN|MAC|LNX)', ''); diff --git a/test/issues/Issue119_useCompat.hx b/test/issues/Issue119_useCompat.hx index b82d3ad..04d0afc 100644 --- a/test/issues/Issue119_useCompat.hx +++ b/test/issues/Issue119_useCompat.hx @@ -1,8 +1,9 @@ import flash.system.Capabilities; + class Issue119 { public function new() { - var sPlatform:String = Capabilities.version.substr(0, 3); + var sPlatform:String = Std.string(Capabilities.version.substr(0, 3)); var sDesktop:Bool = new as3hx.Compat.Regex('(WIN|MAC|LNX)', '').exec(sPlatform) != null; var ereg:as3hx.Compat.Regex = new as3hx.Compat.Regex('(WIN|MAC|LNX)', ''); From 81edfa3527b24fe296eb1f8da1a2aa67d3cb0a92 Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Mon, 15 Apr 2019 21:40:56 +0300 Subject: [PATCH 149/156] new..as --- src/as3hx/parsers/StructureParser.hx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/as3hx/parsers/StructureParser.hx b/src/as3hx/parsers/StructureParser.hx index c09fda3..d93a573 100644 --- a/src/as3hx/parsers/StructureParser.hx +++ b/src/as3hx/parsers/StructureParser.hx @@ -230,6 +230,10 @@ class StructureParser { var type = TVector(t); types.seen.push(type); return ENew(type, []); + case EBinop('as', EIdent(v), e2, nl): + var type = TPath([v]); + types.seen.push(type); + return EBinop('as', ENew(type, []), e2, nl); default: var result:Expr = extractFirstCall(call); if (firstCall != null) { From 08aa4715997fb681263a8bf5ed3cfa8bfd4eb782 Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Tue, 16 Apr 2019 01:23:35 +0300 Subject: [PATCH 150/156] convert style def and conditional compilation --- src/FileParser.hx | 8 +-- src/as3hx/Config.hx | 4 +- src/as3hx/Writer.hx | 2 +- src/as3hx/parsers/ProgramParser.hx | 104 ++++++++++++++++++++++------- 4 files changed, 88 insertions(+), 30 deletions(-) diff --git a/src/FileParser.hx b/src/FileParser.hx index 96eef74..9b65eae 100644 --- a/src/FileParser.hx +++ b/src/FileParser.hx @@ -17,16 +17,15 @@ class FileParser { if (this.fileExtension.indexOf(".") != 0) this.fileExtension = "." + fileExtension; } - public function parseDirectory(src:String, excludes:List, handler:String->String->String->String->Void, relativeDestination:String = "/"):Void { src = Path.normalize(src); relativeDestination = Path.normalize(relativeDestination); var subDirList = new Array(); - for(childName in FileSystem.readDirectory(src)) { + for (childName in FileSystem.readDirectory(src)) { var childPath = Path.addTrailingSlash(src) + childName; if (FileSystem.isDirectory(childPath)) { subDirList.push(childName); - } else if(StringTools.endsWith(childName, fileExtension) && !isExcludeFile(excludes, childPath)) { + } else if (StringTools.endsWith(childName, fileExtension) && !isExcludeFile(excludes, childPath)) { handler(src, childName, childPath, relativeDestination); } } @@ -35,8 +34,7 @@ class FileParser { } } - - static function isExcludeFile(excludes: List, file: String) { + static function isExcludeFile(excludes: List, file: String):Bool { var filePath:String = as3hx.Config.toPath(file); return Lambda.filter(excludes, function (path) { var excludePath:String = StringTools.replace(path, ".", "\\"); diff --git a/src/as3hx/Config.hx b/src/as3hx/Config.hx index a5d59eb..de1f015 100644 --- a/src/as3hx/Config.hx +++ b/src/as3hx/Config.hx @@ -514,7 +514,9 @@ class Config { - + + + diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index ddbda27..684d9c8 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -4567,7 +4567,7 @@ class Writer { imported.push(packWithDot + type.name); } - switch(program.defs[0]) { + if (program.defs.length > 0) switch (program.defs[0]) { case CDef(c): for (meta in c.meta) { switch (meta) { diff --git a/src/as3hx/parsers/ProgramParser.hx b/src/as3hx/parsers/ProgramParser.hx index 2ff9234..ea52011 100644 --- a/src/as3hx/parsers/ProgramParser.hx +++ b/src/as3hx/parsers/ProgramParser.hx @@ -22,15 +22,19 @@ class ProgramParser { // look for first 'package' var tk = tokenizer.token(); var a = ParserUtils.explodeComment(tk); + var closed = false; + var defs:Array = []; - for(t in a) { + for (t in a) { switch(t) { case TId(s): - if(s != "package") + // if (s == 'mx_internal') continue; + if (s != "package") { ParserUtils.unexpected(t); - if(ParserUtils.opt(tokenizer, TBrOpen)) - pack = [] - else { + } + if (ParserUtils.opt(tokenizer, TBrOpen)) { + pack = []; + } else { pack = parsePackageName(); tokenizer.ensure(TBrOpen); } @@ -38,16 +42,62 @@ class ProgramParser { if(t != null) throw "Assert error " + Tokenizer.tokenString(t); header.push(ECommented(s,b,false,null)); case TNL(t): header.push(ENL(null)); - default: ParserUtils.unexpected(t); + case TBkOpen: + var tdef = tokenizer.token(); + var cname = switch tdef { + case TId(s): s; + case _: throw 'error'; + } + var t = tokenizer.token(); + if (t != TPOpen) { + ParserUtils.unexpected(t); + continue; + } + + var cdef = new ClassDef(); + cdef.imports = []; + cdef.isInterface = false; + cdef.typeParams = null; + cdef.implement = []; + cdef.extend = null; + cdef.inits = []; + cdef.meta = []; + cdef.kwds = []; + cdef.name = cname; + cdef.fields = []; + while (true) { + var name = switch (tokenizer.token()) { + case TId(s): s; + case _: throw 'error'; + } + var op = tokenizer.token(); + var value = switch (tokenizer.token()) { + case TConst(s): s; + case _: throw 'error'; + } + var dm = tokenizer.token(); + cdef.fields.push({meta: [], kwds: ['public', 'static'], name: name, kind: FVar(TPath(['String']), EConst(value)), condVars: []}); + switch dm { + case TComma: + case _: break; + } + } + defs.push(CDef(cdef)); + var close = tokenizer.token(); + if (close != TBkClose) { + ParserUtils.unexpected(close); + continue; + } + closed = true; + default: + ParserUtils.unexpected(t); } } // parse package var imports = []; var inits : Array = []; - var defs = []; var meta : Array = []; - var closed = false; var inNamespace = false; var inCondBlock = false; var outsidePackage = false; @@ -55,7 +105,7 @@ class ProgramParser { var pf : Bool->Void = null; pf = function(included:Bool) { - while( true ) { + while ( true ) { var tk = tokenizer.token(); switch( tk ) { case TBrClose: // } @@ -73,10 +123,10 @@ class ProgramParser { continue; } case TBrOpen: // { - if(inNamespace) + if (inNamespace) continue; // private classes outside of first package {} - if( !closed ) { + if ( !closed ) { ParserUtils.unexpected(tk); } closed = false; @@ -194,36 +244,44 @@ class ProgramParser { } continue; default: - if(ParserUtils.opt(tokenizer, TNs)) { + if (ParserUtils.opt(tokenizer, TNs)) { var ns : String = id; var t = ParserUtils.uncomment(tokenizer.token()); - switch(t) { + switch (t) { case TId(id2): id = id2; default: ParserUtils.unexpected(t); } - if (Lambda.has(cfg.conditionalVars, ns + "::" + id)) { // this is a user supplied conditional compilation variable Debug.openDebug("conditional compilation: " + ns + "::" + id, tokenizer.line); // condVars.push(ns + "_" + id); - meta.push(ECondComp(ns + "_" + id, null, null)); inCondBlock = true; t = tokenizer.token(); - switch (t) { - case TBrOpen: - pf(false); - default: - tokenizer.add(t); + + var nt = tokenizer.token(); + switch (nt) { + case TNL(TId('import')): + tokenizer.add(nt); pf(false); + case _: + tokenizer.add(nt); + meta.push(ECondComp(ns + "_" + id, null, null)); + + switch (t) { + case TBrOpen, TNL(TBrOpen): + pf(false); + default: + tokenizer.add(t); + pf(false); + } } - // condVars.pop(); + // condVars.pop(); Debug.closeDebug("end conditional compilation: " + ns + "::" + id, tokenizer.line); continue; } else { ParserUtils.unexpected(t); } - } - else if(ParserUtils.opt(tokenizer, TSemicolon)) { + } else if (ParserUtils.opt(tokenizer, TSemicolon)) { // class names without an import statement used // for forcing compilation and linking. inits.push(EIdent(id)); From 225f72d84fed2a83b2ed8d4e1b88e80c4f4929cf Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Thu, 18 Apr 2019 11:51:18 +0300 Subject: [PATCH 151/156] Convert mxml files --- .gitignore | 1 + src/Run.hx | 60 +++++++++++++++++++++++++++++++++++++++++ test/issues/Issue119.hx | 13 +++++++++ 3 files changed, 74 insertions(+) create mode 100644 test/issues/Issue119.hx diff --git a/.gitignore b/.gitignore index a8b1367..3c2abe7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ bin/ build/ report/ +tmp/ test/issues/generated/ run.n *.hxproj diff --git a/src/Run.hx b/src/Run.hx index 225378a..02d42e9 100644 --- a/src/Run.hx +++ b/src/Run.hx @@ -16,6 +16,12 @@ class Run { static var writer:Writer; static var currentDstPath:String; static var files:Array = []; + static var mxmlRoot:String; + static var mxmlRel:String; + static var mxmlMain:String; + static var mxmlFiles:Array = []; + static var mxmlTmpPath:String = 'tmp/'; + static var mxmlGenPath:String = mxmlTmpPath + 'generated/'; public static function main():Void { Sys.setCwd(Sys.args().pop()); @@ -24,6 +30,7 @@ class Run { writer = new Writer(cfg); } var fileParser:FileParser = new FileParser(cfg, ".as"); + var mxmlParser:FileParser = new FileParser(cfg, ".mxml"); var libExcludes:List = new List(); for (libPath in cfg.libPaths) { if (libPath == null) { @@ -42,7 +49,20 @@ class Run { } currentDstPath = Path.removeTrailingSlashes(Path.normalize(dst)); fileParser.parseDirectory(src, cfg.excludePaths, parseSrcFile); + mxmlParser.parseDirectory(src, cfg.excludePaths, addMxmlToList); } + mxmlFiles.remove(mxmlMain); + Sys.command('mxmlc', [mxmlMain, '--output', mxmlTmpPath + 'tmp.swf', '--keep-generated-actionscript']); + var mxmls:Array = [for (f in mxmlFiles) f.substr(mxmlRoot.length + 1)]; + var map:Map = [for (e in mxmls) + mxmlGenPath + e.substr(0, -5) + '-generated.as' => e.split('/').pop().substr(0, -5) + '.as']; + cleanTmp(mxmlTmpPath, map); + renameTmp(mxmlTmpPath, map); + var prevDst:String = currentDstPath; + currentDstPath = currentDstPath + mxmlRel; + fileParser.parseDirectory(mxmlGenPath, cfg.excludePaths, parseSrcFile); + currentDstPath = prevDst; + //loop(cfg.src, cfg.dst, cfg.excludePaths); if (cfg.useFullTyping) { writer.prepareTyping(); @@ -67,6 +87,46 @@ class Run { for(i in errors) Sys.println(i); } + #if neko + if (Sys.systemName() == 'Linux') Sys.sleep(1); + #end + } + + static function cleanTmp(path:String, ignore:Map):Void { + for (element in FileSystem.readDirectory(path)) { + if (FileSystem.isDirectory(path + element)) { + cleanTmp(path + element + '/', ignore); + } else { + var file:String = path + element; + if (!ignore.exists(file)) { + trace('Delete: $file'); + FileSystem.deleteFile(file); + } + } + } + } + + static function renameTmp(path:String, map:Map):Void { + for (element in FileSystem.readDirectory(path)) { + if (FileSystem.isDirectory(path + element)) { + renameTmp(path + element + '/', map); + } else { + var file:String = path + element; + if (map.exists(file)) { + trace('Rename: $file => ' + path + map[file]); + FileSystem.rename(file, path + map[file]); + } + } + } + } + + static function addMxmlToList(fileLocation:String, fileName:String, file:String, relativeDestination:String):Void { + if (mxmlRoot == null || fileLocation.length < mxmlRoot.length) { + mxmlRoot = fileLocation; + mxmlMain = file; + mxmlRel = relativeDestination; + } + mxmlFiles.push(file); } static function parseLibFile(fileLocation:String, fileName:String, file:String, relativeDestination:String):Void { diff --git a/test/issues/Issue119.hx b/test/issues/Issue119.hx new file mode 100644 index 0000000..f24c232 --- /dev/null +++ b/test/issues/Issue119.hx @@ -0,0 +1,13 @@ +import flash.system.Capabilities; + +class Issue119 { + + public function new() { + var sPlatform:String = Capabilities.version.substr(0, 3); + var sDesktop:Bool = new as3hx.Compat.Regex('(WIN|MAC|LNX)', '').exec(sPlatform) != null; + + var ereg:as3hx.Compat.Regex = new as3hx.Compat.Regex('(WIN|MAC|LNX)', ''); + var sDesktop2:Bool = ereg.exec(sPlatform) != null; + } + +} \ No newline at end of file From 69698f9d7e729822950a8413d78110f0898145b2 Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Fri, 19 Apr 2019 14:45:39 +0300 Subject: [PATCH 152/156] mx_internal --- src/as3hx/ParserUtils.hx | 6 ++-- src/as3hx/Writer.hx | 41 +++++++++++++-------------- src/as3hx/parsers/ClassParser.hx | 2 +- src/as3hx/parsers/DefinitionParser.hx | 6 ++-- src/as3hx/parsers/ExprParser.hx | 2 ++ src/as3hx/parsers/ProgramParser.hx | 2 +- test/unit/TestSuite.hx | 16 +++++------ 7 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/as3hx/ParserUtils.hx b/src/as3hx/ParserUtils.hx index 7aab915..2d0d290 100644 --- a/src/as3hx/ParserUtils.hx +++ b/src/as3hx/ParserUtils.hx @@ -1,5 +1,6 @@ package as3hx; +import haxe.PosInfos; import as3hx.Tokenizer; import as3hx.Error; import as3hx.Parser; @@ -158,9 +159,8 @@ class ParserUtils { } } - public static function unexpected(tk:Token) : Dynamic { - throw EUnexpected(Tokenizer.tokenString(tk)); - return null; + public static function unexpected(tk:Token, ?pos:PosInfos) : Dynamic { + return throw EUnexpected(Tokenizer.tokenString(tk) + '(${pos.fileName}:${pos.lineNumber})'); } /** diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 684d9c8..661223d 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -620,11 +620,12 @@ class Writer { writeNL(); writeNL(); writeIndent(); + if (isMXInternal(c.kwds)) + write("@:ns('mx_internal')"); if (isInternal(c.kwds)) { writeAllow(); write("private "); - } - else { + } else { write("public "); } if (c.extend != null) { @@ -716,18 +717,19 @@ class Writer { //coner-case, constructor of internal AS3 class is set to private in //Haxe with a meta allowing access from same package - if(isConstructor && isInternal(c.kwds)) { - write("private "); + if (isMXInternal(field.kwds)) { + write("@:ns('mx_internal') "); } - else if(isPublic(field.kwds)) { + if (isConstructor && isInternal(c.kwds)) { + write("private "); + } else if(isPublic(field.kwds)) { if(!(isGet && cfg.forcePrivateGetter) //check if forced private getter && !(isSet && cfg.forcePrivateSetter)) //check if forced private setter write("public "); else if(!isInterface) { write("private "); } - } - else if(!isInterface) { + } else if(!isInterface) { write("private "); } //check wheter the field is an AS3 constants, which can be inlined in Haxe @@ -4186,38 +4188,35 @@ class Writer { return Lambda.has(kwds, "public"); } - function isPrivate(kwds : Array) : Bool - { + function isPrivate(kwds : Array) : Bool { return Lambda.has(kwds, "private"); } - function isInternal(kwds : Array) : Bool - { + function isInternal(kwds : Array) : Bool { return Lambda.has(kwds, "internal"); } - function isFinal(kwds : Array) : Bool - { + function isMXInternal(kwds : Array) : Bool { + return Lambda.has(kwds, "mx_internal"); + } + + function isFinal(kwds : Array) : Bool { return Lambda.has(kwds, "final"); } - function isProtected(kwds : Array) : Bool - { + function isProtected(kwds : Array) : Bool { return Lambda.has(kwds, "protected"); } - function isGetter(kwds : Array) : Bool - { + function isGetter(kwds : Array) : Bool { return Lambda.has(kwds, "get"); } - function isSetter(kwds : Array) : Bool - { + function isSetter(kwds : Array) : Bool { return Lambda.has(kwds, "set"); } - function isConst(kwds : Array) : Bool - { + function isConst(kwds : Array) : Bool { return Lambda.has(kwds, "const"); } diff --git a/src/as3hx/parsers/ClassParser.hx b/src/as3hx/parsers/ClassParser.hx index 61ae274..84bf51c 100644 --- a/src/as3hx/parsers/ClassParser.hx +++ b/src/as3hx/parsers/ClassParser.hx @@ -124,7 +124,7 @@ class ClassParser { switch( t ) { case TId(id): switch( id ) { - case "public", "static", "private", "protected", "override", "internal", "final": kwds.push(id); + case "public", "static", "private", "protected", "override", "internal", "final", "mx_internal": kwds.push(id); case "const": kwds.push(id); do { diff --git a/src/as3hx/parsers/DefinitionParser.hx b/src/as3hx/parsers/DefinitionParser.hx index 4e31c60..a1877d9 100644 --- a/src/as3hx/parsers/DefinitionParser.hx +++ b/src/as3hx/parsers/DefinitionParser.hx @@ -16,16 +16,16 @@ class DefinitionParser { while( true ) { var id = tokenizer.id(); switch( id ) { - case "public", "internal", "final", "dynamic": kwds.push(id); + case "public", "internal", "final", "dynamic", "mx_internal": kwds.push(id); case "use": parseUse(); continue; case "class": - var c = parseClass(path, filename, kwds,meta,false); + var c = parseClass(path, filename, kwds, meta, false); types.defd.push(c); return CDef(c); case "interface": - var c = parseClass(path, filename, kwds,meta,true); + var c = parseClass(path, filename, kwds, meta, true); types.defd.push(c); return CDef(c); case "function": diff --git a/src/as3hx/parsers/ExprParser.hx b/src/as3hx/parsers/ExprParser.hx index 30774f2..c69833e 100644 --- a/src/as3hx/parsers/ExprParser.hx +++ b/src/as3hx/parsers/ExprParser.hx @@ -165,6 +165,8 @@ class ExprParser { Debug.closeDebug("end conditional compilation: " + i + "::" + id, tokenizer.line); return ECondComp(i + "_" + id, e, null); } + } else if (i == 'mx_internal') { + return parseExprNext(ECommented('// ', true, false, EIdent(i + "::" + id)), 0); } else switch(tokenizer.peek()) { case TBrOpen: // functions inside a namespace return parseExprNext(ECommented("/* AS3HX WARNING namespace modifier " + i + "::"+id+" */", true, false, null), 0); diff --git a/src/as3hx/parsers/ProgramParser.hx b/src/as3hx/parsers/ProgramParser.hx index ea52011..f8b0cff 100644 --- a/src/as3hx/parsers/ProgramParser.hx +++ b/src/as3hx/parsers/ProgramParser.hx @@ -208,7 +208,7 @@ class ProgramParser { case "use": parseUse(); continue; - case "final", "public", "class", "internal", "interface", "dynamic", "function": + case "final", "public", "class", "internal", "interface", "dynamic", "function", "mx_internal": inNamespace = false; tokenizer.add(tk); var d = parseDefinition(path, filename, meta); diff --git a/test/unit/TestSuite.hx b/test/unit/TestSuite.hx index 081c521..1b32503 100644 --- a/test/unit/TestSuite.hx +++ b/test/unit/TestSuite.hx @@ -1,13 +1,13 @@ import massive.munit.TestSuite; import ExampleTest; -import as3hx.parsers.ExprParserTest; +import as3hx.TokenizerTest; import as3hx.parsers.ImportParserTest; +import as3hx.parsers.ExprParserTest; import as3hx.parsers.UseParserTest; -import as3hx.CompatTest; -import as3hx.ParserUtilsTest; -import as3hx.TokenizerTest; import as3hx.AS3HXTest; +import as3hx.ParserUtilsTest; +import as3hx.CompatTest; /** * Auto generated Test Suite for MassiveUnit. @@ -20,12 +20,12 @@ class TestSuite extends massive.munit.TestSuite super(); add(ExampleTest); - add(as3hx.parsers.ExprParserTest); + add(as3hx.TokenizerTest); add(as3hx.parsers.ImportParserTest); + add(as3hx.parsers.ExprParserTest); add(as3hx.parsers.UseParserTest); - add(as3hx.CompatTest); - add(as3hx.ParserUtilsTest); - add(as3hx.TokenizerTest); add(as3hx.AS3HXTest); + add(as3hx.ParserUtilsTest); + add(as3hx.CompatTest); } } From fcea09871dde314a784dd23f023b7ebec7f1a349 Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Mon, 22 Apr 2019 13:48:23 +0300 Subject: [PATCH 153/156] asconfig suppport, 0X int, xml double dot warning --- src/Run.hx | 46 ++++++++++++++++++++++++++++++++---------- src/as3hx/Tokenizer.hx | 2 +- src/as3hx/Writer.hx | 7 ++++++- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/Run.hx b/src/Run.hx index 02d42e9..1f62dd7 100644 --- a/src/Run.hx +++ b/src/Run.hx @@ -1,3 +1,4 @@ +import haxe.Json; using StringTools; import as3hx.As3.Program; @@ -51,17 +52,34 @@ class Run { fileParser.parseDirectory(src, cfg.excludePaths, parseSrcFile); mxmlParser.parseDirectory(src, cfg.excludePaths, addMxmlToList); } - mxmlFiles.remove(mxmlMain); - Sys.command('mxmlc', [mxmlMain, '--output', mxmlTmpPath + 'tmp.swf', '--keep-generated-actionscript']); - var mxmls:Array = [for (f in mxmlFiles) f.substr(mxmlRoot.length + 1)]; - var map:Map = [for (e in mxmls) - mxmlGenPath + e.substr(0, -5) + '-generated.as' => e.split('/').pop().substr(0, -5) + '.as']; - cleanTmp(mxmlTmpPath, map); - renameTmp(mxmlTmpPath, map); - var prevDst:String = currentDstPath; - currentDstPath = currentDstPath + mxmlRel; - fileParser.parseDirectory(mxmlGenPath, cfg.excludePaths, parseSrcFile); - currentDstPath = prevDst; + if (mxmlFiles.length > 1) { + mxmlFiles.remove(mxmlMain); + var asconfig:String = "asconfig.json"; + var r:Int = if (FileSystem.exists(asconfig)) { + var flex:String = Sys.getEnv("FLEX"); + if (flex == null) exit(1, "FLEX home not set!"); + var asc:String = File.getContent(asconfig); + if (asc.indexOf("keep-generated-actionscript") == -1) exit(1, "keep-generated-actionscript not set in asconfig.json"); + var json = Json.parse(asc); + var output:String = json.compilerOptions.output; + mxmlTmpPath = output.substr(0, output.lastIndexOf("/") + 1); + mxmlGenPath = mxmlTmpPath + "generated/"; + mxmlRoot = cfg.src[0]; + Sys.command("asconfigc", ["--sdk", flex]); + } else { + Sys.command("mxmlc", [mxmlMain, "--output", mxmlTmpPath + "tmp.swf", "--keep-generated-actionscript"]); + } + if (r != 0) exit(r); + var mxmls:Array = [for (f in mxmlFiles) f.substr(mxmlRoot.length + 1)]; + var map:Map = [for (e in mxmls) + mxmlGenPath + e.substr(0, -5) + "-generated.as" => e.split("/").pop().substr(0, -5) + ".as"]; + cleanTmp(mxmlTmpPath, map); + renameTmp(mxmlTmpPath, map); + var prevDst:String = currentDstPath; + currentDstPath = currentDstPath + mxmlRel; + fileParser.parseDirectory(mxmlGenPath, cfg.excludePaths, parseSrcFile); + currentDstPath = prevDst; + } //loop(cfg.src, cfg.dst, cfg.excludePaths); if (cfg.useFullTyping) { @@ -87,9 +105,15 @@ class Run { for(i in errors) Sys.println(i); } + exit(); + } + + static function exit(code:Int = 0, ?message:String):Void { + if (message != null) Sys.println(message); #if neko if (Sys.systemName() == 'Linux') Sys.sleep(1); #end + Sys.exit(code); } static function cleanTmp(path:String, ignore:Map):Void { diff --git a/src/as3hx/Tokenizer.hx b/src/as3hx/Tokenizer.hx index 149ba86..4690093 100644 --- a/src/as3hx/Tokenizer.hx +++ b/src/as3hx/Tokenizer.hx @@ -144,7 +144,7 @@ class Tokenizer { char = nextChar(); } switch( char ) { - case 'x'.code: + case 'x'.code, 'X'.code: if( buf.toString() == "0" ) { do { buf.addChar(char); diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 661223d..06557a3 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1660,7 +1660,12 @@ class Writer { addWarning("EE4X"); case EE4XFilter( e1, e2 ): // e1.(weight > 300) search - writeE4XFilterExpr(e1, e2); + try { + writeE4XFilterExpr(e1, e2); + } catch (e:String) { + writeComment("//" + e, true); + addWarning(e, true); + } case EE4XDescend( e1, e2 ): //write("/* " + e2 + " */"); writeExpr(e1); From 25942dae6e4f179aa415e04de4a3defac6d62f46 Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Mon, 22 Apr 2019 23:25:51 +0300 Subject: [PATCH 154/156] FLEX_HOME --- src/Run.hx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Run.hx b/src/Run.hx index 1f62dd7..33b845a 100644 --- a/src/Run.hx +++ b/src/Run.hx @@ -56,7 +56,8 @@ class Run { mxmlFiles.remove(mxmlMain); var asconfig:String = "asconfig.json"; var r:Int = if (FileSystem.exists(asconfig)) { - var flex:String = Sys.getEnv("FLEX"); + var flex:String = Sys.getEnv("FLEX_HOME"); + if (flex == null) flex = Sys.getEnv("FLEX"); if (flex == null) exit(1, "FLEX home not set!"); var asc:String = File.getContent(asconfig); if (asc.indexOf("keep-generated-actionscript") == -1) exit(1, "keep-generated-actionscript not set in asconfig.json"); From 5479fbdf68234041904a12d70c2bc37ad4c68c37 Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Wed, 1 May 2019 18:50:56 +0300 Subject: [PATCH 155/156] XML Comments --- src/FastXMLList.hx | 3 --- src/as3hx/Writer.hx | 25 ++++++++++++++++--- src/as3hx/parsers/ExprParser.hx | 11 ++++----- src/as3hx/parsers/XMLReader.hx | 34 +++++++++++++++++++------ test/e2e/src3/CommentedXML.as | 16 ++++++++++++ test/e2e/src3/CommentedXML.hx | 11 +++++++++ test/e2e/src3/Comments.hx | 44 +++++++++++++++++++++++++++++++++ 7 files changed, 125 insertions(+), 19 deletions(-) create mode 100644 test/e2e/src3/CommentedXML.as create mode 100644 test/e2e/src3/CommentedXML.hx create mode 100644 test/e2e/src3/Comments.hx diff --git a/src/FastXMLList.hx b/src/FastXMLList.hx index ccb7b29..5e492fa 100644 --- a/src/FastXMLList.hx +++ b/src/FastXMLList.hx @@ -43,13 +43,10 @@ class FastXMLList { return l.length; } - /** - * public function set(i:Int, v:FastXML) : FastXML { l[i] = v; return v; } - */ public function toString() : String { var s = ""; diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index 06557a3..dd2a879 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -1252,8 +1252,20 @@ class Writer { if(etype == "FastXML" || etype == "FastXMLList") { writeExpr(e); inArrayAccess = old; - write(".get("); + var oldInLVA = inLvalAssign; + inLvalAssign = false; + if (oldInLVA) { + write(".set("); + } else { + write(".get("); + } writeExpr(index); + if (oldInLVA) { + write(", "); + writeExpr(rvalue); + rvalue = null; + } + inLvalAssign = oldInLVA; write(")"); } else if(isMapType(etype)) { writeExpr(e); @@ -3094,7 +3106,7 @@ class Writer { } } - inline function writeENew(t : T, params : Array):Void { + function writeENew(t : T, params : Array):Void { var writeParams = function() { var argTypes:Array = typer.getClassConstructorTypes(tstring(t)); for (i in 0...params.length) { @@ -3178,7 +3190,14 @@ class Writer { } if (!handled) { if (isObject) write("{}"); - else if (!isDictionary) write("new " + tstring(t) + "("); + else if (!isDictionary) { + var ts = tstring(t); + if (ts == "FastXML") { + writeParams(); + return; + } + write("new " + ts + "("); + } // prevent params when converting vector to array var out = switch(t) { case TVector(_): !cfg.vectorToArray; diff --git a/src/as3hx/parsers/ExprParser.hx b/src/as3hx/parsers/ExprParser.hx index c69833e..7d1a3b8 100644 --- a/src/as3hx/parsers/ExprParser.hx +++ b/src/as3hx/parsers/ExprParser.hx @@ -112,7 +112,6 @@ class ExprParser { var parseExprList = parseList.bind(tokenizer, types, cfg); var parseType= TypeParser.parse.bind(tokenizer, types, cfg); var parseE4X = E4XParser.parse.bind(tokenizer, types, cfg); - var tk = tokenizer.token(); Debug.dbgln("parseExprNext("+e1+") ("+tk+")", tokenizer.line); switch( tk ) { @@ -344,21 +343,21 @@ class ExprParser { public static function parseList(tokenizer:Tokenizer, types:Types, cfg:Config, etk:Token) : Array { var parseExpr = parse.bind(tokenizer, types, cfg); Debug.dbgln("parseExprList()", tokenizer.line); - - var args = new Array(); + var args = []; var f = function(t) { - if(args.length == 0) return; - args[args.length-1] = ParserUtils.tailComment(args[args.length-1], t); + if (args.length == 0) return; + args[args.length - 1] = ParserUtils.tailComment(args[args.length - 1], t); } if (ParserUtils.opt(tokenizer, etk)) return args; var exprToToken = new Map(); - while(true) { + while (true) { var tk = tokenizer.token(); tokenizer.add(tk); var expr = parseExpr(false); exprToToken.set(expr, tk); args.push(expr); tk = tokenizer.token(); + switch(tk) { case TComma: var ntk = tokenizer.token(); diff --git a/src/as3hx/parsers/XMLReader.hx b/src/as3hx/parsers/XMLReader.hx index 30432f4..a5254b9 100644 --- a/src/as3hx/parsers/XMLReader.hx +++ b/src/as3hx/parsers/XMLReader.hx @@ -5,21 +5,43 @@ import as3hx.Error; class XMLReader { - public static function read(tokenizer:Tokenizer) { + public static function read(tokenizer:Tokenizer):String { Debug.dbgln("readXML()", tokenizer.line); var buf = new StringBuf(); var input = tokenizer.input; buf.addChar("<".code); buf.addChar(tokenizer.char); - //corner case : check wether this is a satndalone CDATA element //(not wrapped in XML element) var isCDATA = tokenizer.char == "!".code; - tokenizer.char = 0; + if (isCDATA) { + var end1 = input.readByte(); + var end2 = input.readByte(); + if (end1 == '['.code) { + if (end2 != 'C'.code) + throw EInvalidChar(end2); + end1 = ']'.code; + } else if (end1 == '-'.code) { + if (end2 != '-'.code) + throw EInvalidChar(end2); + } else { + throw EInvalidChar(end1); + } + var p1 = 0; + var p2 = 0; + while (true) { + var c = input.readByte(); + buf.addChar(c); + if (p1 == end1 && p2 == end1 && c == '>'.code) + return buf.toString(); + p1 = p2; + p2 = c; + } + } try { var prev = 0; - while(true) { + while (true) { var c = input.readByte(); if(c == "\n".code) tokenizer.line++; buf.addChar(c); @@ -28,9 +50,7 @@ class XMLReader { } if( prev == "/".code ) return buf.toString(); - if (isCDATA) - return buf.toString(); - while(true) { + while (true) { var c = input.readByte(); if(c == "\n".code) tokenizer.line++; if( c == "<".code ) { diff --git a/test/e2e/src3/CommentedXML.as b/test/e2e/src3/CommentedXML.as new file mode 100644 index 0000000..40374f9 --- /dev/null +++ b/test/e2e/src3/CommentedXML.as @@ -0,0 +1,16 @@ +package { + +public class CommentedXML { + + function CommentedXML():void + { + var libXML:XMLList = p.assetLibrary; + libXML.child[0] = new XML(); + libXML.child[1] = new XML(); + libXML.child[2] = new XML( ]]>); + project.appendChild(libXML); + } + +} + +} \ No newline at end of file diff --git a/test/e2e/src3/CommentedXML.hx b/test/e2e/src3/CommentedXML.hx new file mode 100644 index 0000000..2de925a --- /dev/null +++ b/test/e2e/src3/CommentedXML.hx @@ -0,0 +1,11 @@ +class CommentedXML { + + private function new() { + var libXML:FastXMLList = p.assetLibrary; + libXML.descendants('child').set(0, FastXML.parse('')); + libXML.descendants('child').set(1, FastXML.parse(' -->')); + libXML.descendants('child').set(2, FastXML.parse(' ]]>')); + project.appendChild(libXML); + } + +} \ No newline at end of file diff --git a/test/e2e/src3/Comments.hx b/test/e2e/src3/Comments.hx new file mode 100644 index 0000000..eb4580c --- /dev/null +++ b/test/e2e/src3/Comments.hx @@ -0,0 +1,44 @@ +/** +Package Comment +**/ + +/** + * Class Comment + **/ +class Comments { + + /** Function comment **/ + public static function blah():Void { + var a:Int = 1;// line comment + } + + /** Second **/ + public function memberFunc() {} + + private var i(get, set):Dynamic; + private function get_i():Dynamic { + return _i; + } + + private function set_i(v:Dynamic):Dynamic { + _i = v; + return v; + } + + private var j(get, set):Int; + private function get_j():Int { + return AS3.int(_j); + } + + private function set_j(v:Int):Int { + _i = v; + return v; + } + + public function new() {} + +} + +/** + * Trailing package comment + **/ \ No newline at end of file From 15788b25bfe44a2e55b1f78df6f2d6b1c80ebbb9 Mon Sep 17 00:00:00 2001 From: Alexander Gordeyko Date: Sat, 11 May 2019 18:13:32 +0300 Subject: [PATCH 156/156] AS3 default sort, xml fixes --- src/AS3.hx | 25 +++++++++++++++++++++++++ src/as3hx/Writer.hx | 4 +++- src/as3hx/parsers/XMLReader.hx | 2 ++ test/e2e/src3/CommentedXML.hx | 4 ++-- test/e2e/src3/EmptySort.as | 9 +++++++++ test/e2e/src3/GetXmlNS.as | 10 ++++++++++ test/e2e/src3/XmlIfAttr.as | 14 ++++++++++++++ 7 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 test/e2e/src3/EmptySort.as create mode 100644 test/e2e/src3/GetXmlNS.as create mode 100644 test/e2e/src3/XmlIfAttr.as diff --git a/src/AS3.hx b/src/AS3.hx index e5abcea..805f1ed 100644 --- a/src/AS3.hx +++ b/src/AS3.hx @@ -162,4 +162,29 @@ class AS3 { macro public static function int(e:ExprOf, ?base:ExprOf):ExprOf { return macro untyped ~~${e}; } + + public static function defaultSort(a:Dynamic, b:Dynamic):Int { + return if (Std.is(a, String)) + defaultStringSort(a, b); + else if (Std.is(a, Int)) + defaultIntSort(a, b); + else + throw 'Unsupported'; + } + + public static function defaultStringSort(a:String, b:String):Int { + var min:Int = Std.int(Math.min(a.length, b.length)); + a = a.toLowerCase(); + b = b.toLowerCase(); + for (i in 0...min) { + var r:Int = a.charCodeAt(i) - a.charCodeAt(i); + if (r != 0) return r; + } + return 0; + } + + public static function defaultIntSort(a:Int, b:Int):Int { + return a - b; + } + } \ No newline at end of file diff --git a/src/as3hx/Writer.hx b/src/as3hx/Writer.hx index dd2a879..fba8a46 100644 --- a/src/as3hx/Writer.hx +++ b/src/as3hx/Writer.hx @@ -3747,7 +3747,9 @@ class Writer { } else if (f == "sort") { if (isArrayExpr(e)) { - switch(params[0]) { + switch (params[0]) { + case null: + result = ECall(EField(e, "sort"), [EField(EIdent("AS3"), "defaultSort")]); case EField(e1, "RETURNINDEXEDARRAY"): switch(e1) { case EIdent("Array"): diff --git a/src/as3hx/parsers/XMLReader.hx b/src/as3hx/parsers/XMLReader.hx index a5254b9..3950c4e 100644 --- a/src/as3hx/parsers/XMLReader.hx +++ b/src/as3hx/parsers/XMLReader.hx @@ -18,6 +18,8 @@ class XMLReader { if (isCDATA) { var end1 = input.readByte(); var end2 = input.readByte(); + buf.addChar(end1); + buf.addChar(end2); if (end1 == '['.code) { if (end2 != 'C'.code) throw EInvalidChar(end2); diff --git a/test/e2e/src3/CommentedXML.hx b/test/e2e/src3/CommentedXML.hx index 2de925a..6170d58 100644 --- a/test/e2e/src3/CommentedXML.hx +++ b/test/e2e/src3/CommentedXML.hx @@ -3,8 +3,8 @@ class CommentedXML { private function new() { var libXML:FastXMLList = p.assetLibrary; libXML.descendants('child').set(0, FastXML.parse('')); - libXML.descendants('child').set(1, FastXML.parse(' -->')); - libXML.descendants('child').set(2, FastXML.parse(' ]]>')); + libXML.descendants('child').set(1, FastXML.parse('')); + libXML.descendants('child').set(2, FastXML.parse(' ]]>')); project.appendChild(libXML); } diff --git a/test/e2e/src3/EmptySort.as b/test/e2e/src3/EmptySort.as new file mode 100644 index 0000000..f078d62 --- /dev/null +++ b/test/e2e/src3/EmptySort.as @@ -0,0 +1,9 @@ +package { + public class EmptySort { + public function EmptySort() + { + var arr:Array = []; + arr.sort(); + } + } +} \ No newline at end of file diff --git a/test/e2e/src3/GetXmlNS.as b/test/e2e/src3/GetXmlNS.as new file mode 100644 index 0000000..7e0996d --- /dev/null +++ b/test/e2e/src3/GetXmlNS.as @@ -0,0 +1,10 @@ +package { + public class GetXmlNS { + public function GetXmlNS() { + var updateDescriptor:XML = new XML(); + var updateVersion = updateDescriptor.UPDATE_XMLNS_1_0::version; + var updateDescription = updateDescriptor.UPDATE_XMLNS_1_0::description; + // var updatePackageURL = updateDescriptor.UPDATE_XMLNS_1_0::urls.UPDATE_XMLNS_1_1::[installerType]; + } + } +} \ No newline at end of file diff --git a/test/e2e/src3/XmlIfAttr.as b/test/e2e/src3/XmlIfAttr.as new file mode 100644 index 0000000..6ace80e --- /dev/null +++ b/test/e2e/src3/XmlIfAttr.as @@ -0,0 +1,14 @@ +package { + public class XmlIfAttr { + // protected static var HAS_UNCOMPRESS:Boolean = describeType(123).factory.method.(@name == "uncompress").parameter.length() > 0; + protected static var HAS_UNCOMPRESS:Boolean = getUnc(); + public function XmlIfAttr() { + } + public static function getUnc():Boolean { + return describeType(123).factory.method.(@name == "uncompress").parameter.length() > 0; + } + public function describeType(v:Number):XML { + return ; + } + } +} \ No newline at end of file