Bladeren bron

{platform}.Syntax modules (#6849)

* python.Syntax.code()

* python.Syntax.construct()

* renamed `js.Syntax.new_` to `construct`

* minor

* TestSynatxModule

* [python] replace Syntax.newInstance usages with Syntax.construct

* fixed Syntax.construct() for python and php

* Syntax.field()
Alexander Kuzmenko 7 jaren geleden
bovenliggende
commit
6191e3c9a3

+ 1 - 1
src/generators/genjs.ml

@@ -892,7 +892,7 @@ and gen_value ctx e =
 
 and gen_syntax ctx meth args pos =
 	match meth, args with
-	| "new_", cl :: params ->
+	| "construct", cl :: params ->
 		spr ctx "new ";
 		begin
 			match cl.eexpr with

+ 6 - 2
src/generators/genphp7.ml

@@ -2384,7 +2384,7 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 				| "nativeClassName" -> self#write_expr_syntax_native_class_name args
 				| "foreach" -> self#write_expr_syntax_foreach args
 				| "construct" -> self#write_expr_syntax_construct args
-				| "getField" -> self#write_expr_syntax_get_field args
+				| "field" | "getField" -> self#write_expr_syntax_get_field args
 				| "setField" -> self#write_expr_syntax_set_field args
 				| "getStaticField" -> self#write_expr_syntax_get_static_field args
 				| "setStaticField" -> self#write_expr_syntax_set_static_field args
@@ -2403,7 +2403,7 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 				| [] -> fail self#pos __POS__
 				| { eexpr = TConst (TString php) } :: args ->
 					Codegen.interpolate_code ctx php args self#write self#write_expr self#pos
-				| _ -> ctx.error "First argument of php.Syntax.php() must be a constant string." self#pos
+				| _ -> ctx.error "First argument of php.Syntax.code() must be a constant string." self#pos
 		(**
 			Writes error suppression operator (for `php.Syntax.suppress()`)
 		*)
@@ -2512,6 +2512,10 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 			in
 			self#write "new ";
 			self#write_expr class_expr;
+			(match follow class_expr.etype with
+				| TInst ({ cl_path = ([], "String") }, _) -> ()
+				| _ -> self#write "->phpClassName"
+			);
 			self#write "(";
 			write_args self#write (fun e -> self#write_expr e) args;
 			self#write ")"

+ 16 - 3
src/generators/genpy.ml

@@ -1526,7 +1526,8 @@ module Printer = struct
 			| "super",_ ->
 				let s_el = (print_call_args pctx e1 el) in
 				Printf.sprintf "super().__init__(%s)" s_el
-			| ("python_Syntax._pythonCode"),[({ eexpr = TConst (TString code) } as ecode); {eexpr = TArrayDecl tl}] ->
+			| ("python_Syntax._pythonCode"),[({ eexpr = TConst (TString code) } as ecode); {eexpr = TArrayDecl tl}]
+			| ("python_Syntax.code"),({ eexpr = TConst (TString code) } as ecode) :: tl ->
 				let buf = Buffer.create 0 in
 				let interpolate () =
 					Codegen.interpolate_code pctx.pc_com code tl (Buffer.add_string buf) (fun e -> Buffer.add_string buf (print_expr pctx e)) ecode.epos
@@ -1537,6 +1538,12 @@ module Printer = struct
 				Buffer.contents buf
 			| ("python_Syntax._pythonCode"), [e] ->
 				print_expr pctx e
+			| ("python_Syntax.code"), [e] ->
+				(match e.eexpr with
+					| TConst (TString py) -> ()
+					| _ -> pctx.pc_com.error "First argument of python.Syntax.code() must be a constant string." e1.epos
+				);
+				print_expr pctx e
 			| "python_Syntax._callNamedUntyped",el ->
 				let res,fields = match List.rev el with
 					| {eexpr = TObjectDecl fields} :: el ->
@@ -1580,8 +1587,14 @@ module Printer = struct
 				Printf.sprintf "%s = %s" (print_expr pctx e0) (print_expr pctx e1)
 			| "python_Syntax.arraySet",[e1;e2;e3] ->
 				Printf.sprintf "%s[%s] = %s" (print_expr pctx e1) (print_expr pctx e2) (print_expr pctx e3)
-			| "python_Syntax._newInstance", e1 :: [{eexpr = TArrayDecl el}] ->
-				Printf.sprintf "%s(%s)" (print_expr pctx e1) (print_exprs pctx ", " el)
+			| "python_Syntax._newInstance", e1 :: [{eexpr = TArrayDecl el}]
+			| "python_Syntax.construct", e1 :: el ->
+				let cls =
+					match e1.eexpr with
+						| TConst (TString class_name) -> class_name
+						| _ -> print_expr pctx e1
+				in
+				Printf.sprintf "%s(%s)" cls (print_exprs pctx ", " el)
 			| "python_Syntax.opPow", [e1;e2] ->
 				Printf.sprintf "(%s ** %s)" (print_expr pctx e1) (print_expr pctx e2)
  			| "python_Syntax._foreach",[e1;e2;e3] ->

+ 1 - 1
std/haxe/Int32.hx

@@ -243,7 +243,7 @@ abstract Int32(Int) from Int to Int {
 		// we might be on 64-bit php, so sign extend from 32-bit
 		return (x << extraBits) >> extraBits;
 		#elseif python
-		return python.Syntax.pythonCode("{0} % {1}", (x + python.Syntax.opPow(2, 31)), python.Syntax.opPow(2, 32)) - python.Syntax.opPow(2, 31);
+		return (python.Syntax.code("{0} % {1}", (x + python.Syntax.opPow(2, 31)), python.Syntax.opPow(2, 32)):Int) - python.Syntax.opPow(2, 31);
 		#elseif lua
 		return lua.Boot.clamp(x);
 		#else

+ 2 - 2
std/haxe/ds/Vector.hx

@@ -65,7 +65,7 @@ abstract Vector<T>(VectorData<T>) {
 		#elseif neko
 			this = untyped __dollar__amake(length);
 		#elseif js
-			this = js.Syntax.new_(Array, length);
+			this = js.Syntax.construct(Array, length);
 		#elseif cs
 			this = new cs.NativeArray(length);
 		#elseif java
@@ -73,7 +73,7 @@ abstract Vector<T>(VectorData<T>) {
 		#elseif cpp
 			this = NativeArray.create(length);
 		#elseif python
-			this = python.Syntax.pythonCode("[{0}]*{1}", null, length);
+			this = python.Syntax.code("[{0}]*{1}", null, length);
 		#elseif lua
 			this = untyped __lua_table__({length:length});
 		#elseif eval

+ 2 - 2
std/haxe/io/Bytes.hx

@@ -86,7 +86,7 @@ class Bytes {
 		#elseif cs
 		cs.system.Array.Copy(src.b, srcpos, b, pos, len);
 		#elseif python
-		python.Syntax.pythonCode("self.b[{0}:{0}+{1}] = src.b[srcpos:srcpos+{1}]", pos, len);
+		python.Syntax.code("self.b[{0}:{0}+{1}] = src.b[srcpos:srcpos+{1}]", pos, len);
 		#elseif cpp
 		b.blit(pos, src.b, srcpos, len);
 		#else
@@ -366,7 +366,7 @@ class Bytes {
 			return new String(b, pos, len, "UTF-8")
 		catch (e:Dynamic) throw e;
 		#elseif python
-		return python.Syntax.pythonCode("self.b[{0}:{0}+{1}].decode('UTF-8','replace')", pos, len);
+		return python.Syntax.code("self.b[{0}:{0}+{1}].decode('UTF-8','replace')", pos, len);
 		#elseif lua
 		var begin = cast(Math.min(pos,b.length),Int);
 		var end = cast(Math.min(pos+len,b.length),Int);

+ 1 - 1
std/js/Browser.hx

@@ -104,7 +104,7 @@ class Browser {
 			return new XMLHttpRequest();
 		}
 		if( untyped __js__("typeof ActiveXObject") != "undefined" ) {
-			return js.Syntax.new_("ActiveXObject","Microsoft.XMLHTTP");
+			return js.Syntax.construct("ActiveXObject","Microsoft.XMLHTTP");
 		}
 		throw "Unable to create XMLHttpRequest object.";
 	}

+ 8 - 1
std/js/Syntax.hx

@@ -27,7 +27,7 @@ extern class Syntax {
 		Generate `new cl(...args)` expression.
 	**/
 	@:overload(function(cl:String, args:Rest<Dynamic>):Dynamic {})
-	static function new_<T>(cl:Class<T>, args:Rest<Dynamic>):T;
+	static function construct<T>(cl:Class<T>, args:Rest<Dynamic>):T;
 
 	/**
 		Generate `v instanceof cl` expression.
@@ -54,4 +54,11 @@ extern class Syntax {
 	**/
 	@:overload(function(o:Dynamic, f:Int):Bool {})
 	static function delete(o:Dynamic, f:String):Bool;
+
+	/**
+		Generate `o[f]` expression
+	*/
+	static inline function field(o:Dynamic, f:String):Dynamic {
+		return code('{0}[{1}]', o, f);
+	}
 }

+ 2 - 2
std/js/_std/Date.hx

@@ -36,11 +36,11 @@
 	}
 
 	@:pure static inline function now() : Date {
-		return js.Syntax.new_(Date);
+		return js.Syntax.construct(Date);
 	}
 
 	@:pure static inline function fromTime( t : Float ) : Date {
-		return js.Syntax.new_(Date, t);
+		return js.Syntax.construct(Date, t);
 	}
 
 	@:pure static inline function fromString( s : String ) : Date {

+ 1 - 1
std/js/_std/HxOverrides.hx

@@ -40,7 +40,7 @@ class HxOverrides {
 		switch( s.length ) {
 		case 8: // hh:mm:ss
 			var k = s.split(":");
-			var d = js.Syntax.new_(Date);
+			var d = js.Syntax.construct(Date);
 			(cast d)[cast "setTime"](0);
 			(cast d)[cast "setUTCHours"](k[0]);
 			(cast d)[cast "setUTCMinutes"](k[1]);

+ 15 - 15
std/js/_std/Type.hx

@@ -85,35 +85,35 @@ enum ValueType {
 	public static function createInstance<T>( cl : Class<T>, args : Array<Dynamic> ) : T {
 		switch( args.length ) {
 		case 0:
-			return js.Syntax.new_(cl);
+			return js.Syntax.construct(cl);
 		case 1:
-			return js.Syntax.new_(cl,args[0]);
+			return js.Syntax.construct(cl,args[0]);
 		case 2:
-			return js.Syntax.new_(cl,args[0],args[1]);
+			return js.Syntax.construct(cl,args[0],args[1]);
 		case 3:
-			return js.Syntax.new_(cl,args[0],args[1],args[2]);
+			return js.Syntax.construct(cl,args[0],args[1],args[2]);
 		case 4:
-			return js.Syntax.new_(cl,args[0],args[1],args[2],args[3]);
+			return js.Syntax.construct(cl,args[0],args[1],args[2],args[3]);
 		case 5:
-			return js.Syntax.new_(cl,args[0],args[1],args[2],args[3],args[4]);
+			return js.Syntax.construct(cl,args[0],args[1],args[2],args[3],args[4]);
 		case 6:
-			return js.Syntax.new_(cl,args[0],args[1],args[2],args[3],args[4],args[5]);
+			return js.Syntax.construct(cl,args[0],args[1],args[2],args[3],args[4],args[5]);
 		case 7:
-			return js.Syntax.new_(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
+			return js.Syntax.construct(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
 		case 8:
-			return js.Syntax.new_(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
+			return js.Syntax.construct(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
 		case 9:
-			return js.Syntax.new_(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
+			return js.Syntax.construct(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
 		case 10:
-			return js.Syntax.new_(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
+			return js.Syntax.construct(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]);
 		case 11:
-			return js.Syntax.new_(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
+			return js.Syntax.construct(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]);
 		case 12:
-			return js.Syntax.new_(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11]);
+			return js.Syntax.construct(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11]);
 		case 13:
-			return js.Syntax.new_(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12]);
+			return js.Syntax.construct(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12]);
 		case 14:
-			return js.Syntax.new_(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13]);
+			return js.Syntax.construct(cl,args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10],args[11],args[12],args[13]);
 		default:
 			throw "Too many arguments";
 		}

+ 4 - 4
std/php/Boot.hx

@@ -350,7 +350,7 @@ class Boot {
 				return value.__toString();
 			}
 			if (Std.is(value, StdClass)) {
-				if (Global.isset(Syntax.getField(value, 'toString')) && value.toString.is_callable()) {
+				if (Global.isset(Syntax.field(value, 'toString')) && value.toString.is_callable()) {
 					return value.toString();
 				}
 				var result = new NativeIndexedArray<String>();
@@ -519,7 +519,7 @@ class Boot {
 		if(Global.is_string(value)) {
 			value = @:privateAccess new HxDynamicStr(value);
 		}
-		return Syntax.getField(value, field);
+		return Syntax.field(value, field);
 	}
 
 	public static function dynamicString( str:String ) : HxDynamicStr {
@@ -813,7 +813,7 @@ private class HxAnon extends StdClass {
 
 	@:phpMagic
 	function __call( name:String, args:NativeArray ) : Dynamic {
-		var method = Syntax.getField(this, name);
+		var method = Syntax.field(this, name);
 		Syntax.keepVar(method);
 		return method(Syntax.splat(args));
 	}
@@ -856,7 +856,7 @@ private class HxClosure {
 		}
 		if (Std.is(eThis, StdClass)) {
 			if (Std.is(eThis, HxAnon)) {
-				return Syntax.getField(eThis, func);
+				return Syntax.field(eThis, func);
 			}
 		}
 		return Syntax.arrayDecl(eThis, func);

+ 2 - 2
std/php/Lib.hx

@@ -156,10 +156,10 @@ class Lib {
 			var obj = result;
 			while(parts.length > 1) {
 				var pack = parts.shift();
-				if(Syntax.getField(obj, pack) == null) {
+				if(Syntax.field(obj, pack) == null) {
 					Syntax.setField(obj, pack, {});
 				}
-				obj = Syntax.getField(obj, pack);
+				obj = Syntax.field(obj, pack);
 			}
 			Syntax.setField(obj, parts[0], Boot.getClass(phpName));
 		});

+ 17 - 3
std/php/Syntax.hx

@@ -23,13 +23,13 @@ extern class Syntax {
         var_dump($a, $b);
         ```
     **/
-    static function code(php:String, args:Rest<Dynamic>):Dynamic;
+    static function code(code:String, args:Rest<Dynamic>):Dynamic;
 
     /**
         The same as `code()`, but adds dereferencing
         when required to workaround "cannot use temporary expression in write context" php error.
     **/
-    static function codeDeref(php:String, args:Rest<Dynamic>):Dynamic;
+    static function codeDeref(code:String, args:Rest<Dynamic>):Dynamic;
 
     /**
         Generates `$left <=> $right`
@@ -101,6 +101,13 @@ extern class Syntax {
         return code('({0} ** {1})', left, right);
     }
 
+    /**
+        Generates `$left % $right`
+    **/
+    static inline function mod( left:Float, right:Float ) : Int {
+        return code('({0} % {1})', left, right);
+    }
+
     /**
         Generates `$left ?: $right`
     **/
@@ -189,11 +196,18 @@ extern class Syntax {
     /**
         Generates `new $className($arg1, ...$argN)`
     **/
-    static function construct( className:AsVar<String>, args:Rest<Dynamic>) : Dynamic;
+    @:overload(function(className:AsVar<String>, args:Rest<Dynamic>):Dynamic {})
+    static function construct<T>( cls:AsVar<Class<T>>, args:Rest<Dynamic>) : T;
+
+    /**
+        Generates instance field access for reading on `object`
+    **/
+    static function field<T>( object:AsVar<T>, fieldName:AsVar<String> ) : Dynamic;
 
     /**
         Generates instance field access for reading on `object`
     **/
+    @:deprecated("php.Syntax.getFiled() is deprecated. Use php.Syntax.field() instead.")
     static function getField<T>( object:AsVar<T>, fieldName:AsVar<String> ) : Dynamic;
 
     /**

+ 4 - 4
std/php/_std/Reflect.hx

@@ -43,12 +43,12 @@ using php.Global;
 
 	public static function field( o : Dynamic, field : String ) : Dynamic {
 		if (o.is_string()) {
-			return Syntax.getField(Boot.dynamicString(o), field);
+			return Syntax.field(Boot.dynamicString(o), field);
 		}
 		if (!o.is_object()) return null;
 
 		if (o.property_exists(field)) {
-			return Syntax.getField(o, field);
+			return Syntax.field(o, field);
 		}
 		if (o.method_exists(field)) {
 			return Boot.closure(o, field);
@@ -60,7 +60,7 @@ using php.Global;
 				return Global.constant('$phpClassName::$field');
 			}
 			if (Global.property_exists(phpClassName, field)) {
-				return Syntax.getField(o, field);
+				return Syntax.field(o, field);
 			}
 			if (Global.method_exists(phpClassName, field)) {
 				return Boot.closure(phpClassName, field);
@@ -152,7 +152,7 @@ using php.Global;
 
 	public static function deleteField( o : Dynamic, field : String ) : Bool {
 		if (hasField(o, field)) {
-			Global.unset(Syntax.getField(o, field));
+			Global.unset(Syntax.field(o, field));
 			return true;
 		} else {
 			return false;

+ 6 - 6
std/python/Boot.hx

@@ -48,11 +48,11 @@ class Boot {
 	]);
 
 	inline static function arrayJoin <T>(x:Array<T>, sep:String):String {
-		return Syntax.field(sep, "join")(Syntax.pythonCode("[{0}(x1,'') for x1 in {1}]", python.Boot.toString1, x));
+		return Syntax.field(sep, "join")(Syntax.code("[{0}(x1,'') for x1 in {1}]", python.Boot.toString1, x));
 	}
 
 	inline static function safeJoin (x:Array<String>, sep:String):String {
-		return Syntax.field(sep, "join")(Syntax.pythonCode("[x1 for x1 in {0}]", x));
+		return Syntax.field(sep, "join")(Syntax.code("[x1 for x1 in {0}]", x));
 	}
 
 	inline static function isPyBool(o:Dynamic):Bool {
@@ -254,15 +254,15 @@ class Boot {
 				var keys = Syntax.callField(d, "keys");
 				var handler = unhandleKeywords;
 
-				Syntax.pythonCode("for k in keys:");
-				Syntax.pythonCode("    a.append(handler(k))");
+				Syntax.code("for k in keys:");
+				Syntax.code("    a.append(handler(k))");
 			}
 			else if (UBuiltins.hasattr(o, "__dict__")) {
 				var a = [];
 				var d = Syntax.field(o, "__dict__");
 				var keys1  = Syntax.callField(d, "keys");
-				Syntax.pythonCode("for k in keys1:");
-				Syntax.pythonCode("    a.append(k)");
+				Syntax.code("for k in keys1:");
+				Syntax.code("    a.append(k)");
 
 			}
 		}

+ 16 - 3
std/python/Syntax.hx

@@ -27,6 +27,8 @@ import haxe.macro.Context;
 import haxe.macro.ExprTools;
 #end
 
+import haxe.extern.Rest;
+
 @:noPackageRestrict
 extern class Syntax {
 
@@ -35,17 +37,23 @@ extern class Syntax {
 	#end
 
 	@:noUsing macro public static function importModule (module:String):haxe.macro.Expr {
-		return macro ($self.pythonCode($v{"import " + module}):Void);
+		return macro ($self.code($v{"import " + module}):Void);
 	}
 
 	@:noUsing macro public static function importAs (module:String, className : String):haxe.macro.Expr {
 		var n = className.split(".").join("_");
 		var e = "import " + module + " as " + n;
 
-		return macro ($self.pythonCode($v{e}):Void);
+		return macro ($self.code($v{e}):Void);
 	}
 
+	#if !macro
+	@:overload(function(className:String, args:Rest<Dynamic>):Dynamic {})
+	static function construct<T>(cls:Class<T>, args:Rest<Dynamic>):T;
+	#end
+
 	@:noUsing
+	@:deprecated("python.Syntax.newInstance() is deprecated. Use python.Syntax.construct() instead.")
 	macro public static function newInstance (c:Expr, params:Array<Expr>):haxe.macro.Expr {
 		return macro $self._newInstance($c, $a{params});
 	}
@@ -64,7 +72,12 @@ extern class Syntax {
 	@:noUsing
 	public static function assign(a:Dynamic, b:Dynamic):Void { }
 
+	#if !macro
+	public static function code(code:String, args:Rest<Dynamic>):Dynamic;
+	#end
+
 	@:noUsing
+	@:deprecated("python.Syntax.pythonCode() is deprecated. Use python.Syntax.code() instead.")
 	macro public static function pythonCode(b:ExprOf<String>, rest:Array<Expr>):Expr {
 		if (rest == null) rest = [];
 		return macro @:pos(Context.currentPos()) untyped $self._pythonCode($b, $a{rest});
@@ -120,7 +133,7 @@ extern class Syntax {
 
 		var e = "from " + from + " import " + module + " as " + n;
 
-		return macro ($self.pythonCode($v{e}):Void);
+		return macro ($self.code($v{e}):Void);
 	}
 
 	@:noUsing

+ 1 - 1
std/python/_std/Type.hx

@@ -113,7 +113,7 @@ enum ValueType {
 
 	public static inline function createInstance<T>( cl : Class<T>, args : Array<Dynamic> ) : T
 	{
-		return Syntax.newInstance(cl, Syntax.varArgs(args));
+		return Syntax.construct(cl, Syntax.varArgs(args));
 	}
 
 	public static function createEmptyInstance<T>( cl : Class<T> ) : T

+ 3 - 3
std/python/_std/sys/net/Socket.hx

@@ -48,7 +48,7 @@ private class SocketInput extends haxe.io.Input {
         }
         if( r.length == 0 )
             throw new haxe.io.Eof();
-        return python.Syntax.pythonCode("r[0]");
+        return python.Syntax.code("r[0]");
     }
 
     public override function readBytes( buf : haxe.io.Bytes, pos : Int, len : Int ) : Int {
@@ -84,7 +84,7 @@ private class SocketOutput extends haxe.io.Output {
 
     public override function writeByte( c : Int ) {
         try {
-            __s.send(python.Syntax.pythonCode('bytes([c])'),0);
+            __s.send(python.Syntax.code('bytes([c])'),0);
         } catch( e : BlockingIOError ) {
                 throw Blocked;
         }
@@ -93,7 +93,7 @@ private class SocketOutput extends haxe.io.Output {
     public override function writeBytes( buf : haxe.io.Bytes, pos : Int, len : Int) : Int {
         try {
             var data    = buf.getData();
-            var payload = python.Syntax.pythonCode("data[{0}:{0}+{1}]", pos, len);
+            var payload = python.Syntax.code("data[{0}:{0}+{1}]", pos, len);
             var r = __s.send(payload,0);
             return r;
         } catch( e : BlockingIOError ) {

+ 5 - 5
std/python/internal/HxOverrides.hx

@@ -23,7 +23,7 @@ package python.internal;
 
 import python.Syntax;
 
-import python.Syntax.pythonCode in py;
+import python.Syntax.code in py;
 
 @:noDoc
 @:native("HxOverrides")
@@ -44,7 +44,7 @@ class HxOverrides {
 	@:ifFeature("dynamic_binop_==", "dynamic_binop_!=")
 	static function eq( a:Dynamic, b:Dynamic ) : Bool {
 		if (Boot.isArray(a) || Boot.isArray(b)) {
-			return Syntax.pythonCode('a is b');
+			return Syntax.code('a is b');
 		}
 		return Syntax.binop(a, "==", b);
 	}
@@ -137,16 +137,16 @@ class HxOverrides {
 
 	@:ifFeature("binop_>>>")
 	static public function rshift(val:Int, n:Int) {
-		return Syntax.binop(Syntax.binop(val, "%", Syntax.pythonCode("0x100000000")), ">>", n);
+		return Syntax.binop(Syntax.binop(val, "%", Syntax.code("0x100000000")), ">>", n);
 	}
 
 	@:ifFeature("binop_%")
 	static public function modf(a:Float, b:Float) {
-		return Syntax.pythonCode("float('nan') if (b == 0.0) else a % b if a >= 0 else -(-a % b)");
+		return Syntax.code("float('nan') if (b == 0.0) else a % b if a >= 0 else -(-a % b)");
 	}
 	@:ifFeature("binop_%")
 	static public function mod(a:Int, b:Int) {
-		return Syntax.pythonCode("a % b if a >= 0 else -(-a % b)");
+		return Syntax.code("a % b if a >= 0 else -(-a % b)");
 	}
 
 	@:ifFeature("dynamic_array_read")

+ 2 - 2
std/python/internal/Internal.hx

@@ -78,7 +78,7 @@ class Internal {
 	}
 
 	macro public static function classRegistry ():Expr {
-		return macro (untyped __define_feature__($v{"python." + _classes}, python.Syntax.pythonCode($v{_classes})) : python.Dict<String, Class<Dynamic>>);
+		return macro (untyped __define_feature__($v{"python." + _classes}, python.Syntax.code($v{_classes})) : python.Dict<String, Class<Dynamic>>);
 	}
 
 	macro public static function callFieldPrefixed (o:Expr, x:String, params:Array<Expr>):Expr {
@@ -107,7 +107,7 @@ class Internal {
 	}
 
 	macro public static function pythonCodePrefixed (x:String):Expr {
-		return macro python.Syntax.pythonCode($v{_prefix + x});
+		return macro python.Syntax.code($v{_prefix + x});
 	}
 
 	macro public static function hasClassName (o:Expr):Expr {

+ 5 - 2
tests/runci/targets/Python.hx

@@ -19,8 +19,11 @@ class Python {
 					infoMsg('pypy3 has already been installed.');
 				} else {
 					var pypyVersion = "pypy3-2.4.0-linux64";
-					runCommand("wget", ['https://bitbucket.org/pypy/pypy/downloads/${pypyVersion}.tar.bz2'], true);
-					runCommand("tar", ["-xf", '${pypyVersion}.tar.bz2']);
+					var file = '${pypyVersion}.tar.bz2';
+					if(!FileSystem.exists(file)) {
+						runCommand("wget", ['https://bitbucket.org/pypy/pypy/downloads/$file'], true);
+					}
+					runCommand("tar", ["-xf", file]);
 					pypy = FileSystem.fullPath('${pypyVersion}/bin/pypy3');
 				}
 				runCommand(pypy, ["-V"]);

+ 1 - 0
tests/unit/src/unit/TestMain.hx

@@ -64,6 +64,7 @@ class TestMain {
 			new TestGeneric(),
 			new TestArrowFunctions(),
 			new TestCasts(),
+			new TestSyntaxModule(),
 			#if !no_pattern_matching
 			new TestMatch(),
 			#end

+ 6 - 6
tests/unit/src/unit/TestPython.hx

@@ -350,18 +350,18 @@ class TestPython extends Test {
 
 	function testPythonCodeStringInterpolation () {
 		var z = 1;
-		var a = (Syntax.pythonCode('[{0}, {1}]', z, 2):Array<Int>);
+		var a = (Syntax.code('[{0}, {1}]', z, 2):Array<Int>);
 
 		eq(a[0], z);
 		eq(a[1], 2);
 
 		function test2 (x:Int) {
 			x += 1;
-			return (Syntax.pythonCode("{0}", x):Int);
+			return (Syntax.code("{0}", x):Int);
 		}
 
 		function test3 (x:Int) {
-			return (Syntax.pythonCode('[{0}]', x):Array<Int>);
+			return (Syntax.code('[{0}]', x):Array<Int>);
 		}
 
 		var x = 1;
@@ -370,15 +370,15 @@ class TestPython extends Test {
 		eq(1, x);
 		eq(1, test3(1)[0]);
 
-		eq("foo1bar", Syntax.pythonCode("'foo' + str({0}) + 'bar'", x));
+		eq("foo1bar", Syntax.code("'foo' + str({0}) + 'bar'", x));
 
 
 		function test4a (x:Int) {
-			return (Syntax.pythonCode("[{0}][0]", x+x):Int);
+			return (Syntax.code("[{0}][0]", x+x):Int);
 		}
 
 		function test4b (x:Int):String {
-			return Syntax.pythonCode('[{0}][0]', (function () return Std.string(x+x))() );
+			return Syntax.code('[{0}][0]', (function () return Std.string(x+x))() );
 		}
 
 		eq(2, test4a(1));

+ 49 - 0
tests/unit/src/unit/TestSyntaxModule.hx

@@ -0,0 +1,49 @@
+package unit;
+
+#if js
+import js.Syntax;
+#elseif php
+import php.Syntax;
+#elseif python
+import python.Syntax;
+#end
+
+class TestSyntaxModule extends Test {
+#if (php || js || python)
+	function testCode() {
+		var i1 = 1;
+		var i2 = 2;
+		var result = Syntax.code('{0} + {1}', i1, i2);
+		eq(i1 + i2, result);
+	}
+
+	function testField() {
+		var o = {field:'hello'};
+		var value = Syntax.field(o, 'field');
+		eq(o.field, value);
+	}
+
+	function testConstruct() {
+		var className:String =
+			#if php "\\unit\\_TestSyntaxModule\\Construct";
+			#elseif js
+				#if js_unflatten "unit._TestSyntaxModule.Construct";
+				#else "unit__$TestSyntaxModule_Construct";
+				#end
+			#elseif python "unit__TestSyntaxModule_Construct";
+			#end
+		var a:Construct = Syntax.construct(className, 10);
+		t(Std.is(a, Construct));
+		eq(10, a.value);
+
+		var b = Syntax.construct(Construct, 10);
+		t(Std.is(b, Construct));
+		eq(10, b.value);
+	}
+#end
+}
+
+private class Construct {
+	public var value:Int;
+	public function new(arg:Int) value = arg;
+}