Latest Changes

Differences between version EMPTY and #20119

0a1,250
> C와 같은 언어에서는 사용자가 문법을 간단히 정의할 수 있도록 해주는 ''#define''같은 기능이 있습니다. 그것들은 pseudo-code-generation(가상 코드 생성)를 수행하는데 유용하고 언어의 문법을 수정하도록 해주는 반면, 다른 개발자가 읽기힘든 코드를 만듭니다.
> 
> Haxe 매크로 시스템은 Haxe 문법을 수정하지 않으면서 컴파일 도중 코드생성을 해주는 강력한 기능입니다.
> 
> ====== Macro functions ======
> 
> 매크로는 컴파일 도중에 실행되는데, 값을 반환하는 대신에 컴파일 될 Haxe코드 조각을 반환하는 것이 매크로의 원리입니다.
> 
> ''@:macro'' [[/manual/metadata]]를 사용하는 매크로 함수로 정의하면 됩니다.
> 
> 아래는 빌드 날짜를 컴파일하는 매크로 예제입니다. 매크로는 컴파일 도중에 실행된다는 점을 유의해야합니다. 따라서 프로그램이 실행되는 '현재 날짜'가 아니라, 출판될 때의 날짜가 출력됩니다.
> 
> <code haxe>
> import haxe.macro.Context;
> class Test {
> 	@:macro public static function getBuildDate() {
> 		var date = Date.now().toString();
> 		return Context.makeExpr(date, Context.currentPos());
> 	}
> 	static function main() {
> 		trace(getBuildDate());
> 	}
> }
> </code>
> 
> 모든 매크로 함수는 그 매크로 호출를 대체할 코드블록에 상응하는 //표현식(expression)//을 반환해야 하므로, ''date'' 변수에 저장된 String //값//을 그에 상응하는 string-표현식으로 변환할 필요가 있습니다. ''Context.makeExpr''이 그 역할을 합니다.
> 
> 모든 표현식은 (에러 출력과 디버깅을 목적으로) 그것이 선언된 파일과 행을 알려주는 //위치(position)//가 필요합니다. 이 예제에서는 ''Context.currentPos()'' 위치가 ''getBuildDate()'' 매크로 호출의 위치입니다.
> 
> //You cannot have platform specific imports in a file that has @:macro, unless you use some #if !macro ... #end wrappers around them.   So put your macros in a specific macro class and do not try to create them next to your regular code unless you sure your not using platform specific code which I guess is quite rare, so simpler to always keep them separate.//
> 
> ===== Macro Reification =====
> 
> 물론 간단한 값을 표현식으로 전환하는 것보다 더 많은 것을 할 수 있습니다. ''macro'' reification을 사용하면, 표현식을 생성하고 다룰 수 있습니다 : 
> 
> <code haxe>
> import haxe.macro.Expr;
> class Test {
> 	@:macro public static function repeat(cond:Expr,e:Expr) : Expr {
> 		return macro while( $cond ) trace($e);
> 	}
> 	static function main() {
> 		var x = 0;
> 		repeat(x < 10, x++);
> 	}
> }
> </code>
> 
> 이 매크로는 ''while( x < 10 ) trace(x++)'' 과 같은 코드를 생성할 것 입니다.
> 
> 
> A few explanations :
> 
>   * 매크로 ''repeat''는 //표현식//를 인자로 가져오므로, 연산이 되지 않은 표현식의 형태로 받습니다. 이 표현식은 유효한 Haxe 문법이어야 하며, 선언되지 않은 변수/타입 등등을 참조할 수 있습니다.
>   * 그 다음에 이런 표현식을 조작하고(아래를 보시길), 어떤 wrapping code에 의해 재사용합니다.
>   * ''macro'' 키워드는 표현식을, 실행에 필효한 코드가 아니라 표현식을 생성할 코드로 다루게 됩니다. It will also replace all $-prefixed identifiers by the corresponding variable.
> 
> 
> ===== Reification Escaping =====
> 
> **new in haxe 3.0**
> 
> ''macro'' reification를 사용할 때, 표현식에 어떤 값을 주입하기 원한다면, 몇가지 방법이 있습니다.
>        * ''${value}''를 사용하면, 그 지점의 표현식을 동일한 값으로 바꿉니다. The value needs to be an actual ''haxe.macro.Expr''
> 
> <code haxe>
> 	var v = macro "Hello";
> 	var e = macro ${v}.toLowerCase();
> 	// is the same as :
> 	var e = macro "Hello".toLowerCase();
> </code>
> 
> 	* In some case where the value can only be an identifier and not an expression, ''$ident''' is replaced by the value of the identifier :
> 
> With ''var'':
> <code haxe>
> 	var myVar = "i";
> 	var e = macro var $myVar = 0;
> 	// is the same as :
> 	var e = macro var i = 0;
> </code>
> 
> With field :
> <code haxe>
> 	var myField = "f";
> 	var e = macro o.$myField;
> 	// is the same as :
> 	var e = macro o.f;
> </code>
> 
> With object fields :
> <code haxe>
> 	var myField = "f";
> 	var e = macro { $myField : 0 };
> 	// is the same as :
> 	var e = macro { f : 0 };
> </code>
> 
> 	* Using ''$i{ident}'', will create an identifier which value is ''ident''
> <code haxe>
> 	var varName = "myVar";
> 	var e = macro $i{varName}++;
> 	// is the same as :
> 	var e = macro myVar++;
> </code>
> 	* Using ''$v{value}'' will tranform the value into the corresponding expression, in a similar way to ''Context.makeExpr'' :
> <code haxe>
> 	var myStr = "some string";
> 	var e = macro $v{myStr};
> 	// is the same as :
> 	var e = macro "some string";
> </code>
> And for a more complex case :
> <code haxe>
> 	var o = { x : 5 * 20 };
> 	var e = macro $v{o};
> 	// is the same as :
> 	var e = macro { x : 100 };
> </code>
> 	* Using ''$a{exprs}'', will substitute the expression Array in a ''{..}'' block, a ''[ ... ]'' constant array or a call parameters :
> <code haxe>
> 	var args = [macro "sub", macro 3];
> 	var e = macro "Hello".toLowerCase($a{args});
> 	// is the same as :
> 	var e = macro "Hello".toLowerCase("sub",3);
> </code>
> 
> ===== Creating Expressions =====
> 
> As we see in the two last examples, we have several ways of creating expressions :
> 	* using ''Context.makeExpr'' to convert a //value// into the corresponding expression, that - when run - will produce the same value
> 	* using ''macro'' to convert some Haxe code into an expression
> 	* expressions can also be created "by-hand", since they are just plain Haxe enums :
> 
> <code haxe>
> // manual creation by using enums :
> var e : Expr = {
> 	expr : EConst(CString("Hello World")), 
> 	pos : Context.currentPos()
> };
> // is actually the same as :
> var e : Expr = macro "Hello World !";
> </code>
> 
> ===== Manipulating expressions =====
> 
> Since expressions are just a small structure with a position and an enum, you can easily match them.
> 
> For instance the following example make sure that the expression passed as argument is a constant String, and generates a string constant based on the file content :
> 
> <code haxe>
> import haxe.macro.Expr;
> import haxe.macro.Context;
> class Test {
> 	@:macro static function getFileContent( fileName : Expr ) {
> 		var fileStr = null;
> 		switch( fileName.expr ) {
> 		case EConst(c):
> 			switch( c ) {
> 			case CString(s): fileStr = s;
> 			default:
> 			}
> 		default:
> 		};
> 		if( fileStr == null )
> 			Context.error("Constant string expected",fileName.pos);
> 		return Context.makeExpr(sys.io.File.getContent(fileStr),fileName.pos);
> 	}
> 	static function main() {
> 		trace(getFileContent("myFile.txt"));
> 	}
> }
> </code>
> 
> Please note that since macro execute at compile-time, the following example will not work :
> 
> <code haxe>
> var file = "myFile.txt";
> getFileContent(file);
> </code>
> 
> Because it that case the macro ''fileName'' argument expression will be the identifier ''file'', and there is no way to know its value without actually running the code, which is not possible since the code might use some platform-specific API that the macro compiler cannot emulate.
> 
> ===== Constant arguments =====
> 
> The above example can be greatly simplified by telling that your macro only accept constant strings :
> 
> <code haxe>
> @:macro static function getFileContent( fileName : String ) {
> 	var content = sys.io.File.getContent(fileName);
> 	return Context.makeExpr(content,Context.currentPos());
> }
> </code>
> 
> Again - same as above - you will have to pass a constant expression, it cannot be a value of type ''String''.
> 
> The following types are supported for constant arguments :
> 	* Int, Bool, String, Float
> 	* arrays of constants
> 	* structures of constants
> 	* null value
> 
> ===== Context API and macro Context =====
> 
> The [[/api/haxe/macro/Context]] class gives you access to a lot of informations, such as compilation parameters, but also the ability to load type or even create new classes.
> 
> The Context API operates on the "application context", which is the unit in which the compilation of your code occurs. There is another context which is the "macro context" which compiles and run the macro code. Please note that these two contexts are separated.
> 
> For instance, if you compile a Javascript file :
> 	* the application context will contain your Haxe/Javascript code, it will have access to the Javascript API
> 	* the macro context will contain your macro code (the classes in which @:macro methods are declared) and it will not be able to access the Javascript API. It can however access the [[/api/sys]] API, the [[/api|sys]] package and the [[/api/neko]] API as well. It can still interact and modify the application context by using the [[/api/haxe/macro/Context]] class.
> 
> It is important to understand that some code sometimes get compiled twice : once inside the application context and once inside the macro context.
> 
> In general, it is recommended to completely separate your macro code (classes contaiting @:macro statements) from your application code, in order to prevent expected issues due to some code being included in the wrong context.
> 
> ===== Type Reification =====
> 
> It is possible to use ''macro : Type'' to build a type instead of an expression.
> 
> Type reification also support escaping (see below).
> 
> The following example will declare a new typed variable when called :
> 
> <code haxe>
> import haxe.macro.Expr;
> class Test {
> 	@:macro static function decl( vname : String ) {
> 		var str : ComplexType = macro : String;
> 		var arr : ComplexType = macro : Array<Array<$str>>;
> 		return macro var $vname : $arr = [];
> 	}
> 	#if !macro
> 	static function main() {
> 		decl("table");
> 		trace(table);
> 	}
> 	#end
> }
> </code>
> 
> Please note that in that case we need to make sure that the ''main()'' code is not compiled as part of the macro context.
> 
> ====== Building types ======
> 
> You can also generate and manipulate types declarations content with macros, see [[build]]
> 
> ====== Advanced Features ======
> 
> Read on to know if you want to learn every bit about Haxe macro possibilities : [[advanced]]
\ No newline at end of file

	
Ver Date Entry Lg User Action
#20122 2014-05-24 12:52:26 com/libs/cocktail/cocktail_web_app_demo en codam View | Diff
#20121 2014-05-22 20:00:15 doc/libraries en Confidant View | Diff
#20120 2014-05-22 19:49:58 doc/libraries en Confidant View | Diff
#20119 2014-05-22 11:25:38 manual/macros kr papapang View | Diff
#20118 2014-05-22 11:25:38 manual/macros kr papapang Set title to macros (매크로)
#20117 2014-05-22 07:16:17 doc/glossary en vitalyo View | Diff
#20116 2014-05-21 19:35:43 doc/libraries en Confidant View | Diff
#20115 2014-05-21 15:17:54 doc/libraries en Confidant View | Diff
#20114 2014-05-21 15:16:44 doc/libraries en Confidant View | Diff
#20113 2014-05-21 13:13:34 ref/callback en Simn View | Diff
#20112 2014-05-20 19:48:30 doc/libraries en Confidant View | Diff
#20111 2014-05-20 19:47:59 doc/libraries en Confidant View | Diff
#20110 2014-05-20 19:18:18 doc/libraries en Confidant View | Diff
#20109 2014-05-17 18:07:43 ref/callback en galundin View | Diff
#20108 2014-05-17 18:05:56 ref/callback en galundin View | Diff
#20107 2014-05-17 17:51:30 ref/callback en galundin View | Diff
#20106 2014-05-11 22:04:20 ref/oop en Chax0 View | Diff
#20105 2014-05-11 22:02:31 ref/oop en Chax0 View | Diff
#20104 2014-05-09 04:42:48 doc/java/lwjgl en JLM View | Diff
#20103 2014-05-08 13:52:07 doc/java/lwjgl en JLM View | Diff

Previous | Next