diff --git a/src/cscompiler/ast/CSExpr.hx b/src/cscompiler/ast/CSExpr.hx index 2df80c3..89682ca 100644 --- a/src/cscompiler/ast/CSExpr.hx +++ b/src/cscompiler/ast/CSExpr.hx @@ -1,5 +1,6 @@ package cscompiler.ast; +import cscompiler.ast.CSTypePath; #if (macro || cs_runtime) import haxe.macro.Expr; @@ -11,7 +12,7 @@ import haxe.macro.Type; @:structInit class CSExpr { public var def(default, null): CSExprDef; - public var haxeExpr(default, null): Null; + public var haxeExpr(default, null): Null = null; public function new(def: CSExprDef, haxeExpr: Null = null) { this.def = def; @@ -41,15 +42,13 @@ enum CSExprDef { /** Binary operator `leftExpr op rightExpr`. **/ + // TODO Binop to CSBinop (because some operators are not supported by C#) CSBinop(op: Binop, leftExpr: CSExpr, rightExpr: CSExpr); /** Field access on `e` of name `fieldName`. - - TODO: - Replace `fieldName: String` with a custom `FieldAccess` type (`fieldAccess: CSFieldAccess`)? **/ - CSField(e: CSExpr, fieldName: String); + CSField(e: CSExpr, fieldAccess: CSFieldAccess); /** Reference to a module type `m`. @@ -58,7 +57,7 @@ enum CSExprDef { This is assuming static-access is only possible from a class in C#? Maybe this should be replaced with a `CSStaticVar(varData: CSVar, cls: CSClass)`. **/ - CSClassExpr(cls: CSClass); + CSClassExpr(cls: CSTypePath); /** Parentheses `(e)`. diff --git a/src/cscompiler/ast/CSFieldAccess.hx b/src/cscompiler/ast/CSFieldAccess.hx new file mode 100644 index 0000000..85ee0c0 --- /dev/null +++ b/src/cscompiler/ast/CSFieldAccess.hx @@ -0,0 +1,19 @@ +package cscompiler.ast; + +import cscompiler.ast.CSTypePath; + +enum CSFieldAccess { + + /** + Access of field `cf` on a class instance `c` with type parameters + `params`. + **/ + CSFInstance(c:CSTypePath, params:Array, cf:String); + + /** + Static access of a field `cf` on a class `c`. + Note that we accept type params here because it is valid in C# + **/ + CSFStatic(c:CSTypePath, params:Array, cf:String); + +} diff --git a/src/cscompiler/ast/CSStatement.hx b/src/cscompiler/ast/CSStatement.hx index de080b7..62f4c37 100644 --- a/src/cscompiler/ast/CSStatement.hx +++ b/src/cscompiler/ast/CSStatement.hx @@ -10,7 +10,7 @@ import haxe.macro.Type; @:structInit class CSStatement { public var def(default, null): CSStatementDef; - public var haxeExpr(default, null): Null; + public var haxeExpr(default, null): Null = null; public function new(def: CSStatementDef, haxeExpr: Null = null) { this.def = def; diff --git a/src/cscompiler/components/CSCompiler_Expr.hx b/src/cscompiler/components/CSCompiler_Expr.hx index b0b26a1..ed78e0d 100644 --- a/src/cscompiler/components/CSCompiler_Expr.hx +++ b/src/cscompiler/components/CSCompiler_Expr.hx @@ -67,7 +67,7 @@ class CSCompiler_Expr extends CSCompiler_Base { haxeExpr: expr, def: CSExprStatement({ haxeExpr: expr, - def: compileConstant(constant) + def: CSConst(compileConstant(constant)) }) } case TLocal(v): { @@ -95,11 +95,58 @@ class CSCompiler_Expr extends CSCompiler_Base { }) } case TBinop(op, e1, e2): { - result = binopToCS(op, e1, e2); + haxeExpr: expr, + def: CSExprStatement({ + haxeExpr: expr, + def: CSBinop( + op, + csStatementToExpr(_compileExpression(e1)), + csStatementToExpr(_compileExpression(e2)) + ) + }) } - case TField(e, fa): { - result = fieldAccessToCS(e, fa); + case TField(e, fa): + { + haxeExpr: expr, + def: CSExprStatement({ + haxeExpr: expr, + def: switch fa { + case FInstance(c, params, cf): + CSField( + csStatementToExpr(_compileExpression(e)), + CSFInstance( + compiler.typeComp.compileClassType(c.get()), + compiler.typeComp.compileTypeParams(params), + cf.get().name + ) + ); + case FStatic(c, cf): + CSField( + csStatementToExpr(_compileExpression(e)), + CSFStatic( + compiler.typeComp.compileClassType(c.get()), + // C# type inference should be able to infer generic types + // from arguments, but it also allows the types to be explicit. + // We might need that in some situation where inference is not enough? + [], + cf.get().name + ) + ); + case FAnon(cf): + // We rely on dynamic access to read anon fields, because for now, + // they will be backed with `haxe.lang.DynamicObject` anyway + compileDynamicGetField(expr, cf.get().name); + case FDynamic(s): + compileDynamicGetField(expr, s); + case FClosure(c, cf): + CSConst(CSNull); // TODO + case FEnum(e, ef): + CSConst(CSNull); // TODO + } + }) + //result = fieldAccessToCS(e, fa); } + /* case TTypeExpr(m): { result = compiler.compileModuleType(m); } @@ -307,13 +354,35 @@ class CSCompiler_Expr extends CSCompiler_Base { } /** - Generate an expression given a `Binop` and two typed expressions (from `TypedExprDef.TBinop`). + Generate a dynamic "getField" access **/ - function binopToCS(op: Binop, e1: TypedExpr, e2: TypedExpr): String { - var csExpr1 = _compileExpression(e1); - var csExpr2 = _compileExpression(e2); - final operatorStr = OperatorHelper.binopToString(op); - return csExpr1 + " " + operatorStr + " " + csExpr2; + function compileDynamicGetField(expr: TypedExpr, name: String): CSExprDef { + return CSCall( + { + haxeExpr: expr, + def: CSField( + { + haxeExpr: expr, + def: CSClassExpr("haxe.lang.Runtime") + }, + CSFStatic( + "haxe.lang.Runtime", + [], + "getField" + ) + ) + }, + [], + [ + { + haxeExpr: expr, + def: CSConst(CSString(name)) + } + // TODO + // add an integer argument used to retrieve fields names + // that are known at compile time in a faster way + ] + ); } /** diff --git a/src/cscompiler/components/CSCompiler_Type.hx b/src/cscompiler/components/CSCompiler_Type.hx index c40b8ec..71dc0c2 100644 --- a/src/cscompiler/components/CSCompiler_Type.hx +++ b/src/cscompiler/components/CSCompiler_Type.hx @@ -104,13 +104,13 @@ class CSCompiler_Type extends CSCompiler_Base { } - function compileClassType(classType:ClassType):CSTypePath { + public function compileClassType(classType:ClassType):CSTypePath { return compileClassName(classType, true); } - function compileTypeParams(params:Array):Array { + public function compileTypeParams(params:Array):Array { // TODO return [];