├── .gitignore ├── extraParams.hxml ├── test ├── macro.hxml ├── flash.hxml ├── js.hxml ├── cpp.hxml ├── neko.hxml ├── php.hxml ├── python.hxml ├── java.hxml ├── cs.hxml ├── each.hxml ├── erazor │ ├── Test.erazor │ ├── TestTemplate.hx │ ├── TestScriptBuilder.hx │ ├── TestSimpleMacro.hx │ ├── TestMacro.hx │ └── TestParser.hx └── TestAll.hx ├── run.bat ├── haxelib.xml ├── release.zip ├── demo.hxml ├── doc ├── html │ ├── images │ │ ├── alias.png │ │ ├── class.png │ │ ├── enum.png │ │ ├── hide.png │ │ ├── show.png │ │ ├── todo.png │ │ ├── alltypes.png │ │ ├── overview.png │ │ ├── package.png │ │ ├── typedef.png │ │ ├── bginherited.png │ │ ├── interface.png │ │ └── todobullet.png │ ├── chxdoc.js │ └── stylesheet.css └── doc.php.xml ├── test.hxml ├── bundle.sh ├── src ├── erazor │ ├── TBlock.hx │ ├── macro │ │ ├── HtmlTemplate.hx │ │ ├── SimpleTemplate.hx │ │ ├── Template.hx │ │ └── Build.hx │ ├── HtmlTemplate.hx │ ├── error │ │ └── ParserError.hx │ ├── ScriptBuilder.hx │ ├── Output.hx │ ├── Template.hx │ ├── hscript │ │ └── EnhancedInterp.hx │ └── Parser.hx └── demo │ └── Main.hx ├── release.bat ├── doc.bat ├── haxelib.json ├── doc.hxml ├── .travis.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | bin/* 2 | *.zip 3 | -------------------------------------------------------------------------------- /extraParams.hxml: -------------------------------------------------------------------------------- 1 | --macro keep('StringBuf') -------------------------------------------------------------------------------- /test/macro.hxml: -------------------------------------------------------------------------------- 1 | test/each.hxml 2 | --interp -------------------------------------------------------------------------------- /run.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | neko bin\erazor.n 3 | pause -------------------------------------------------------------------------------- /test/flash.hxml: -------------------------------------------------------------------------------- 1 | test/each.hxml 2 | -swf bin/TestAll.swf 3 | -------------------------------------------------------------------------------- /haxelib.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufront/erazor/master/haxelib.xml -------------------------------------------------------------------------------- /release.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufront/erazor/master/release.zip -------------------------------------------------------------------------------- /demo.hxml: -------------------------------------------------------------------------------- 1 | -cp src 2 | -lib hscript 3 | -main demo.Main 4 | -x bin/erazor.n 5 | -------------------------------------------------------------------------------- /test/js.hxml: -------------------------------------------------------------------------------- 1 | test/each.hxml 2 | -js bin/TestAll.js 3 | -cmd node bin/TestAll.js -------------------------------------------------------------------------------- /test/cpp.hxml: -------------------------------------------------------------------------------- 1 | test/each.hxml 2 | -cpp bin/TestAll 3 | -cmd bin/TestAll/TestAll 4 | -------------------------------------------------------------------------------- /test/neko.hxml: -------------------------------------------------------------------------------- 1 | test/each.hxml 2 | -neko bin/TestAll.n 3 | -cmd neko bin/TestAll.n 4 | -------------------------------------------------------------------------------- /test/php.hxml: -------------------------------------------------------------------------------- 1 | test/each.hxml 2 | -php bin/TestAll 3 | -cmd php bin/TestAll/index.php 4 | -------------------------------------------------------------------------------- /test/python.hxml: -------------------------------------------------------------------------------- 1 | test/each.hxml 2 | -python bin/TestAll.py 3 | -cmd python3 bin/TestAll.py -------------------------------------------------------------------------------- /test/java.hxml: -------------------------------------------------------------------------------- 1 | test/each.hxml 2 | -java bin/TestAll 3 | -cmd java -jar bin/TestAll/TestAll.jar 4 | -------------------------------------------------------------------------------- /doc/html/images/alias.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufront/erazor/master/doc/html/images/alias.png -------------------------------------------------------------------------------- /doc/html/images/class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufront/erazor/master/doc/html/images/class.png -------------------------------------------------------------------------------- /doc/html/images/enum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufront/erazor/master/doc/html/images/enum.png -------------------------------------------------------------------------------- /doc/html/images/hide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufront/erazor/master/doc/html/images/hide.png -------------------------------------------------------------------------------- /doc/html/images/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufront/erazor/master/doc/html/images/show.png -------------------------------------------------------------------------------- /doc/html/images/todo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufront/erazor/master/doc/html/images/todo.png -------------------------------------------------------------------------------- /test/cs.hxml: -------------------------------------------------------------------------------- 1 | test/each.hxml 2 | -cs bin/TestAll 3 | -cmd mono --debug bin/TestAll/bin/TestAll.exe 4 | -------------------------------------------------------------------------------- /doc/html/images/alltypes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufront/erazor/master/doc/html/images/alltypes.png -------------------------------------------------------------------------------- /doc/html/images/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufront/erazor/master/doc/html/images/overview.png -------------------------------------------------------------------------------- /doc/html/images/package.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufront/erazor/master/doc/html/images/package.png -------------------------------------------------------------------------------- /doc/html/images/typedef.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufront/erazor/master/doc/html/images/typedef.png -------------------------------------------------------------------------------- /doc/html/images/bginherited.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufront/erazor/master/doc/html/images/bginherited.png -------------------------------------------------------------------------------- /doc/html/images/interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufront/erazor/master/doc/html/images/interface.png -------------------------------------------------------------------------------- /doc/html/images/todobullet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufront/erazor/master/doc/html/images/todobullet.png -------------------------------------------------------------------------------- /test/each.hxml: -------------------------------------------------------------------------------- 1 | extraParams.hxml 2 | -main TestAll 3 | -cp test 4 | -cp src 5 | -lib utest 6 | -lib hscript 7 | -------------------------------------------------------------------------------- /test/erazor/Test.erazor: -------------------------------------------------------------------------------- 1 | @for(u in users){@if(u.name == 'Boris'){@u.name}else if(u.name == 'Doris'){@u.name}else{@u.name}
} -------------------------------------------------------------------------------- /test.hxml: -------------------------------------------------------------------------------- 1 | --next test/flash.hxml 2 | --next test/js.hxml 3 | --next test/php.hxml 4 | --next test/neko.hxml 5 | --next test/cpp.hxml 6 | --next test/java.hxml 7 | --next test/cs.hxml -------------------------------------------------------------------------------- /bundle.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | libname='erazor' 4 | rm -f "${libname}.zip" 5 | zip -r "${libname}.zip" haxelib.json src README.md 6 | echo "Saved as ${libname}.zip, please do a git-tag" 7 | -------------------------------------------------------------------------------- /src/erazor/TBlock.hx: -------------------------------------------------------------------------------- 1 | package erazor; 2 | 3 | enum TBlock 4 | { 5 | // Pure text 6 | literal(s : String); 7 | 8 | // Code 9 | codeBlock(s : String); 10 | 11 | // Code that should be printed immediately 12 | printBlock(s : String); 13 | } -------------------------------------------------------------------------------- /release.bat: -------------------------------------------------------------------------------- 1 | haxe doc.hxml 2 | rmdir /S /Q release 3 | rmdir release.zip 4 | mkdir release 5 | xcopy src release /S 6 | xcopy haxelib.xml release 7 | xcopy haxedoc.xml release 8 | cd release 9 | 7z a -tzip ..\release.zip * 10 | cd .. 11 | rmdir /S /Q release 12 | haxelib submit release.zip 13 | pause -------------------------------------------------------------------------------- /src/erazor/macro/HtmlTemplate.hx: -------------------------------------------------------------------------------- 1 | package erazor.macro; 2 | 3 | import erazor.Output; 4 | 5 | @:abstractTemplate class HtmlTemplate extends Template 6 | { 7 | 8 | override public function escape(str:String):String 9 | { 10 | return StringTools.htmlEscape(str, true); 11 | } 12 | 13 | public function raw(str : Dynamic) 14 | { 15 | return new SafeString(Std.string(str)); 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /doc.bat: -------------------------------------------------------------------------------- 1 | cd doc 2 | chxdoc.exe -f flash -f haxe -f neko -f php -f test --installTemplate=true --showPrivateClasses=false --showPrivateTypedefs=false --showPrivateEnums=false --showPrivateMethods=false --showPrivateVars=false --generateTodoFile=true --showTodoTags=true --ignoreRoot=true --title=erazor doc.neko.xml,neko doc.php.xml,php doc.f9.xml,flash9 doc.f8.xml,flash8 doc.f7.xml,flash7 doc.f6.xml,flash6 doc.cpp.xml,cpp 3 | cd .. 4 | PAUSE -------------------------------------------------------------------------------- /src/erazor/macro/SimpleTemplate.hx: -------------------------------------------------------------------------------- 1 | package erazor.macro; 2 | 3 | /** 4 | * SimpleTemplate preserves the legacy erazor.macro.Template behaviour, by promoting a 'data' variable 5 | * @author waneck 6 | */ 7 | @:abstractTemplate class SimpleTemplate extends Template 8 | { 9 | @:promote public var data:T; 10 | 11 | public function setData(newData:T):SimpleTemplate 12 | { 13 | this.data = newData; 14 | return this; 15 | } 16 | } -------------------------------------------------------------------------------- /haxelib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "erazor", 3 | "license": "BSD", 4 | "classPath": "src", 5 | "tags": ["cross","template"], 6 | "description": "A haXe implementation of the MVC 3 Razor template engine", 7 | "contributors": ["jason","fponticelli","waneck","ciscoheat","andyli"], 8 | "releasenote": "Bug fix release", 9 | "version": "1.0.2", 10 | "url": "http://github.com/ufront/erazor", 11 | "dependencies": { 12 | "hscript": "" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/TestAll.hx: -------------------------------------------------------------------------------- 1 | import utest.ui.Report; 2 | class TestAll 3 | { 4 | static function main() 5 | { 6 | var runner = new utest.Runner(); 7 | 8 | runner.addCase(new erazor.TestParser()); 9 | runner.addCase(new erazor.TestMacro()); 10 | runner.addCase(new erazor.TestSimpleMacro()); 11 | runner.addCase(new erazor.TestScriptBuilder()); 12 | runner.addCase(new erazor.TestTemplate()); 13 | 14 | var report = Report.create(runner); 15 | runner.run(); 16 | } 17 | } -------------------------------------------------------------------------------- /src/erazor/HtmlTemplate.hx: -------------------------------------------------------------------------------- 1 | package erazor; 2 | import erazor.Template.PropertyObject; 3 | import erazor.Output; 4 | 5 | class HtmlTemplate extends Template 6 | { 7 | 8 | public function new(template : String) 9 | { 10 | super(template); 11 | addHelper("raw", raw); 12 | } 13 | 14 | override public function escape(str : String) : String 15 | { 16 | return StringTools.htmlEscape(str, true); 17 | } 18 | 19 | private static function raw(str : Dynamic) 20 | { 21 | return new SafeString(Std.string(str)); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/erazor/macro/Template.hx: -------------------------------------------------------------------------------- 1 | package erazor.macro; 2 | 3 | /** 4 | * This is the macro Template class. In order to have a Template executed, you should extend it and add either 5 | * 6 | * @:template("inline template here @someVar") 7 | * or 8 | * @:includeTemplate("path/to/template") 9 | * 10 | * @author Waneck 11 | */ 12 | 13 | @:autoBuild(erazor.macro.Build.buildTemplate()) 14 | class Template 15 | { 16 | public function new() 17 | { 18 | 19 | } 20 | 21 | public function escape(str : String) : String 22 | { 23 | return str; 24 | } 25 | 26 | public function execute():String 27 | { 28 | return null; 29 | } 30 | } -------------------------------------------------------------------------------- /src/erazor/error/ParserError.hx: -------------------------------------------------------------------------------- 1 | package erazor.error; 2 | 3 | /** 4 | * ... 5 | * @author Waneck 6 | */ 7 | 8 | class ParserError 9 | { 10 | public var msg(default, null):String; 11 | public var pos(default, null):Int; 12 | public var excerpt(default, null):String; 13 | 14 | public function new(msg, pos, ?excerpt) 15 | { 16 | this.msg = msg; 17 | this.pos = pos; 18 | this.excerpt = excerpt; 19 | } 20 | 21 | public function toString() 22 | { 23 | var excerpt = this.excerpt; 24 | if (excerpt != null) 25 | { 26 | var nl = excerpt.indexOf("\n"); 27 | if (nl != -1) 28 | excerpt = excerpt.substr(0, nl); 29 | } 30 | 31 | return msg + " @ " + pos + (excerpt != null ? (" ( \"" + excerpt + "\" )") : ""); 32 | } 33 | } -------------------------------------------------------------------------------- /src/erazor/ScriptBuilder.hx: -------------------------------------------------------------------------------- 1 | package erazor; 2 | 3 | class ScriptBuilder 4 | { 5 | private var context : String; 6 | 7 | public function new(context : String) 8 | { 9 | this.context = context; 10 | } 11 | 12 | public function build(blocks : Array) : String 13 | { 14 | var buffer = new StringBuf(); 15 | 16 | for(block in blocks) 17 | { 18 | buffer.add(blockToString(block)); 19 | } 20 | return buffer.toString(); 21 | } 22 | 23 | public function blockToString(block : TBlock) : String 24 | { 25 | switch(block) 26 | { 27 | case literal(s): 28 | return context + ".add('" + StringTools.replace(s, "'", "\\'") + "');\n"; 29 | 30 | case codeBlock(s): 31 | return s + "\n"; 32 | 33 | case printBlock(s): 34 | return context + ".unsafeAdd(" + s + ");\n"; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /doc.hxml: -------------------------------------------------------------------------------- 1 | # Neko 2 | -neko _ 3 | -cp src 4 | -xml doc/doc.neko.xml 5 | -lib hscript 6 | --no-output 7 | --macro include('erazor', true, null, ['src']) 8 | #--macro include("", true) 9 | --next 10 | # PHP 11 | -php _ 12 | -cp src 13 | -xml doc/doc.php.xml 14 | --no-output 15 | -lib hscript 16 | --macro include('erazor', true, null, ['src']) 17 | --next 18 | # CPP 19 | -cpp _ 20 | -cp src 21 | -xml doc/doc.cpp.xml 22 | --no-output 23 | -lib hscript 24 | --macro include('erazor', true, null, ['src']) 25 | --next 26 | # F9 27 | -swf9 _ 28 | -cp src 29 | -xml doc/doc.f9.xml 30 | --no-output 31 | -lib hscript 32 | --macro include('erazor', true, null, ['src']) 33 | --next 34 | # Other Flash 35 | -swf _ 36 | -cp src 37 | -swf-version 8 38 | -xml doc/doc.f8.xml 39 | --no-output 40 | -lib hscript 41 | --macro include('erazor', true, null, ['src']) 42 | --next 43 | -swf _ 44 | -swf-version 7 45 | -cp src 46 | -xml doc/doc.f7.xml 47 | --no-output 48 | -lib hscript 49 | --macro include('erazor', true, null, ['src']) 50 | --next 51 | -swf _ 52 | -swf-version 6 53 | -cp src 54 | -xml doc/doc.f6.xml 55 | --no-output 56 | -lib hscript 57 | --macro include('erazor', true, null, ['src']) 58 | --next 59 | # JS 60 | -js _ 61 | -cp src 62 | -xml doc/doc.js.xml 63 | -lib hscript 64 | --macro include('erazor', true, null, ['src']) 65 | # --no-output 66 | 67 | # HAXEDOC.XML 68 | -cmd del _ 69 | -cmd copy doc\doc.js.xml haxedoc.xml 70 | -cmd PAUSE -------------------------------------------------------------------------------- /src/erazor/Output.hx: -------------------------------------------------------------------------------- 1 | package erazor; 2 | 3 | class TString { 4 | 5 | public var s : String; 6 | 7 | public function new( str ){ 8 | this.s = str; 9 | } 10 | 11 | @:keep 12 | public function toString() { 13 | return s; 14 | } 15 | 16 | } 17 | 18 | typedef SafeString = TString; 19 | 20 | class UnsafeString extends TString { 21 | 22 | public dynamic function escape( str ){ 23 | return StringTools.htmlEscape( str, true ); 24 | } 25 | 26 | public override function new( s , escapeMethod = null ){ 27 | super( s ); 28 | if( escapeMethod != null ) 29 | escape = escapeMethod; 30 | } 31 | 32 | @:keep 33 | public override function toString(){ 34 | return escape( s ); 35 | } 36 | } 37 | 38 | 39 | @:keep class Output extends StringBuf { 40 | 41 | public function new( escapeMethod = null ){ 42 | if( escapeMethod != null ) escape = escapeMethod; 43 | super(); 44 | } 45 | 46 | public dynamic function escape( str : String ) : String { 47 | return str; 48 | } 49 | 50 | public function unsafeAdd( str : Dynamic ){ 51 | var val = if( Std.is( str , TString ) ){ 52 | str.toString(); 53 | }else{ 54 | escape( Std.string( str ) ); 55 | } 56 | 57 | add(val); 58 | } 59 | 60 | public static function safe( str : String ) { 61 | return new SafeString( str ); 62 | } 63 | 64 | public static function unsafe( str : String ) { 65 | return new UnsafeString( str ); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: haxe 2 | 3 | haxe: 4 | - development 5 | - 3.2.1 6 | 7 | os: 8 | - linux 9 | - osx 10 | 11 | sudo: false 12 | addons: 13 | apt: 14 | packages: 15 | # Python 16 | - python3 17 | # PHP 18 | - php5-cli 19 | # C# 20 | - mono-devel 21 | - mono-mcs 22 | 23 | install: 24 | # os-specific config 25 | - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then 26 | brew update; 27 | brew install mono; 28 | brew install python3; 29 | fi 30 | # Install haxelibs 31 | - if [ "${TRAVIS_HAXE_VERSION}" = "development" ]; then 32 | haxelib git hxcpp https://github.com/HaxeFoundation/hxcpp.git; 33 | pushd $(haxelib path hxcpp | head -1); 34 | pushd tools/hxcpp; haxe compile.hxml; popd; 35 | pushd project; neko build.n; popd; 36 | popd; 37 | else 38 | haxelib install hxcpp; 39 | fi 40 | - haxelib install hxjava 41 | - haxelib install hxcs 42 | - yes | haxelib install test/each.hxml 43 | - haxelib list 44 | 45 | script: 46 | - haxe test/macro.hxml 47 | - haxe test/neko.hxml 48 | - haxe test/js.hxml 49 | - haxe test/java.hxml 50 | - haxe test/cs.hxml 51 | - haxe test/flash.hxml 52 | - haxe test/cpp.hxml; 53 | # php target of haxe 3.2.1 has issue with Reflect, fixed in https://github.com/HaxeFoundation/haxe/pull/4921 54 | # also, a weird bug forces us to use "-debug", see https://github.com/HaxeFoundation/haxe/issues/4924 55 | - if [ "${TRAVIS_HAXE_VERSION}" != "3.2.1" ]; then 56 | haxe test/php.hxml -debug; 57 | fi -------------------------------------------------------------------------------- /src/demo/Main.hx: -------------------------------------------------------------------------------- 1 | package demo; 2 | 3 | class Main 4 | { 5 | static var TEMPLATE = "@{ 6 | function ucwords(s) { 7 | var r = ''; 8 | var arr = s.split(' '); 9 | for (v in arr) 10 | r += v.substr(0, 1).toUpperCase() + v.substr(1, v.length-1) + ' '; 11 | return r; 12 | }; 13 | sortArray(list); 14 | } 15 | @{ line = '--='; } 16 | @(line + '=--') 17 | @ucwords(title) 18 | @(line + '=--') 19 | 20 | @content.substr(0, 40)... 21 | 22 | @for(item in list) { 23 | * @if(item.sex == 'f') {Ms.} else {Mr.} @item.name 24 | } 25 | "; 26 | static function main() 27 | { 28 | var h = { 29 | title : 'erazor - the template system for haxe', 30 | content : 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In ullamcorper felis non libero blandit facilisis. In hac habitasse platea dictumst', 31 | list : [ 32 | { sex : 'm', name : 'Boris' }, 33 | { sex : 'f', name : 'Doris' }, 34 | { sex : 'm', name : 'John' }, 35 | { sex : 'f', name : 'Jane' }, 36 | ], 37 | repeat : function(v, l) { 38 | return StringTools.lpad('', v, l); 39 | }, 40 | sortArray : function(arr) { 41 | arr.sort(function(a, b) { 42 | if (a.name == b.name) 43 | return 0; 44 | else if (a.name < b.name) 45 | return -1 46 | else 47 | return 1; 48 | }); 49 | } 50 | }; 51 | 52 | var template = new erazor.Template(TEMPLATE); 53 | #if php 54 | php.Lib.print(template.execute(h)); 55 | #elseif neko 56 | neko.Lib.print(template.execute(h)); 57 | #elseif cpp 58 | cpp.Lib.print(template.execute(h)); 59 | #else 60 | trace(template.execute(h)); 61 | #end 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /doc/html/chxdoc.js: -------------------------------------------------------------------------------- 1 | 2 | function showInherited(name, visibile) { 3 | //if IE 4 | // document.styleSheets[0].rules 5 | var r = document.styleSheets[0].cssRules; 6 | if(r == undefined) { 7 | document.styleSheets[0].addRule(".hideInherited" + name, visibile ? "display:inline" : "display:none"); 8 | document.styleSheets[0].addRule(".showInherited" + name, visibile ? "display:none" : "display:inline"); 9 | } 10 | else { 11 | for (var i = 0; i < r.length; i++) { 12 | if (r[i].selectorText == ".hideInherited" + name) 13 | r[i].style.display = visibile ? "inline" : "none"; 14 | if (r[i].selectorText == ".showInherited" + name) 15 | r[i].style.display = visibile ? "none" : "inline"; 16 | } 17 | } 18 | 19 | setCookie( 20 | "showInherited" + name, 21 | visibile ? "true" : "false", 22 | 10000, 23 | "/", 24 | document.location.domain); 25 | } 26 | 27 | function initShowInherited() { 28 | showInherited("Var", getCookie("showInheritedVar") == "true"); 29 | showInherited("Method", getCookie("showInheritedMethod") == "true"); 30 | } 31 | 32 | function setCookie(name, value, days, path, domain, secure) { 33 | var endDate=new Date(); 34 | endDate.setDate(endDate.getDate() + days); 35 | 36 | document.cookie = 37 | name + "=" + escape(value) + 38 | ((days==null) ? "" : ";expires=" + endDate.toGMTString()) + 39 | ((path) ? "; path=" + path : "") + 40 | ((domain) ? "; domain=" + domain : "") + 41 | ((secure) ? "; secure" : ""); 42 | } 43 | 44 | function getCookie(name) { 45 | if (document.cookie.length>0) { 46 | begin=document.cookie.indexOf(name + "="); 47 | if (begin != -1) { 48 | begin = begin + name.length + 1; 49 | end = document.cookie.indexOf(";",begin); 50 | if(end==-1) 51 | end=document.cookie.length; 52 | return unescape(document.cookie.substring(begin,end)); 53 | } 54 | } 55 | return ""; 56 | } 57 | 58 | function isIE() { 59 | if(navigator.appName.indexOf("Microsoft") != -1) 60 | return true; 61 | return false; 62 | } 63 | 64 | initShowInherited(); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Erazor Templating Engine 2 | ======================== 3 | 4 | [![Build Status](https://travis-ci.org/ufront/erazor.svg?branch=master)](https://travis-ci.org/ufront/erazor) 5 | 6 | More details coming soon. Feel free to send a pull request adding some examples and instructions to this readme! 7 | 8 | ### Installation 9 | 10 | haxelib install erazor 11 | 12 | ### Basic Usage 13 | 14 | #### Simple variables 15 | ```haxe 16 | var s = new Template("Hello, @name!").execute({name:"World"}); 17 | // "Hello, World!" 18 | ``` 19 | 20 | #### Function call 21 | ```haxe 22 | var s = new Template("Hello, @getName()!").execute({getName:function() return "World"}); 23 | // "Hello, World!" 24 | ``` 25 | 26 | #### Condition 27 | ```haxe 28 | var s = new Template("@if(success){done!}else{fail!}").execute({success:true}); 29 | // "done!" 30 | ``` 31 | 32 | #### For loop 33 | ```haxe 34 | var s = new Template("@for(name in names){Hello, @name! }").execute({names:["Peter","Clare","Sandra"]}); 35 | // "Hello, Peter! Hello, Clare! Hello, Sandra! " 36 | ``` 37 | 38 | #### Code blocks 39 | 40 | Use `@{ }` to wrap some hscript codes. Don't forget the semicolon (;) at the end. With this you can declare some variables for later use. 41 | ```haxe 42 | var s = new Template("@{var p = "Hello, World!";}@p").execute(); 43 | // "Hello, World!" 44 | ``` 45 | 46 | ... can somebody send a pull request with some more examples? Thanks! 47 | 48 | 49 | ### License 50 | 51 | BSD. 52 | 53 | ### Contributing 54 | 55 | Many Haxe developers have used erazor, but it has not been clear which fork on Github is the "official" version, with different forks having different fixes and patches applied. 56 | 57 | This repository has been created so that there is a central place to contribute, so pull requests, bug reports, and documentation are all welcome! 58 | 59 | If you would like direct commit access, send at least one good pull request and we'll let you in! 60 | (If you are one of the major contributors already, just ask me: jason@ufront.net) 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/erazor/Template.hx: -------------------------------------------------------------------------------- 1 | package erazor; 2 | 3 | import hscript.Interp; 4 | import erazor.hscript.EnhancedInterp; 5 | #if haxe3 6 | import haxe.ds.StringMap in Hash; 7 | #end 8 | 9 | /** 10 | * Can be any object with properties or a Hash. 11 | */ 12 | typedef PropertyObject = Dynamic; 13 | 14 | class Template 15 | { 16 | private var template : String; 17 | 18 | public var variables(default, null) : Hash; 19 | 20 | public var helpers : Hash; 21 | 22 | var parsedBlocks:Array; 23 | var script:String; 24 | var parser:hscript.Parser; 25 | var program:hscript.Expr; 26 | 27 | public function new(template : String) 28 | { 29 | this.template = template; 30 | this.helpers = new Hash(); 31 | 32 | // Parse the template into TBlocks for the HTemplateParser 33 | parsedBlocks = new Parser().parse(template); 34 | 35 | // Make a hscript with the buffer as context. 36 | script = new ScriptBuilder('__b__').build(parsedBlocks); 37 | 38 | // Make hscript parse and interpret the script. 39 | parser = new hscript.Parser(); 40 | program = parser.parseString(script); 41 | } 42 | 43 | public dynamic function escape(str : String) : String 44 | { 45 | return str; 46 | } 47 | 48 | public function addHelper(name : String, helper : Dynamic) : Void 49 | { 50 | helpers.set(name, helper); 51 | } 52 | 53 | public function execute(?content : PropertyObject) : String 54 | { 55 | var buffer = new Output(escape); 56 | 57 | var interp = new EnhancedInterp(); 58 | 59 | variables = interp.variables; 60 | 61 | var bufferStack = []; 62 | 63 | setInterpreterVars(interp, helpers); 64 | setInterpreterVars(interp, content); 65 | 66 | interp.variables.set('__b__', buffer); // Connect the buffer to the script 67 | interp.variables.set('__string_buf__', function(current) { 68 | bufferStack.push(current); 69 | return new StringBuf(); 70 | }); 71 | 72 | interp.variables.set('__restore_buf__', function() { 73 | return bufferStack.pop(); 74 | }); 75 | 76 | interp.execute(program); 77 | 78 | // The buffer now holds the output. 79 | return buffer.toString(); 80 | } 81 | 82 | private function setInterpreterVars(interp : Interp, content : PropertyObject) : Void 83 | { 84 | if(Std.is(content, Hash)) 85 | { 86 | var hash : Hash = cast content; 87 | 88 | for(field in hash.keys()) 89 | { 90 | interp.variables.set(field, hash.get(field)); 91 | } 92 | } 93 | else 94 | { 95 | if (content != null) 96 | for(field in Reflect.fields(content)) 97 | { 98 | interp.variables.set(field, Reflect.field(content, field)); 99 | } 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /src/erazor/hscript/EnhancedInterp.hx: -------------------------------------------------------------------------------- 1 | package erazor.hscript; 2 | 3 | import hscript.Expr; 4 | import hscript.Interp; 5 | 6 | class EnhancedInterp extends Interp 7 | { 8 | #if flash9 9 | static var re = ~/(\d+)[^0-9]+\d+[^0-9]*$/; 10 | #elseif php 11 | static var re = ~/^[^0-9]+(\d+)/; 12 | #end 13 | override public function new(){ 14 | super(); 15 | //require StringBuf's add field 16 | var add = new StringBuf().add; 17 | } 18 | override function call( o : Dynamic, f : Dynamic, args : Array ) : Dynamic { 19 | #if php 20 | while (true) 21 | { 22 | try 23 | { 24 | return Reflect.callMethod(o,f,args); 25 | } catch (e : String) { 26 | if (e.substr(0, 16) != "Missing argument") 27 | php.Lib.rethrow(e); 28 | var expected = args.length + 1; 29 | if (re.match(e)) 30 | expected = Std.parseInt(re.matched(1)); 31 | if (expected > 15) // guard value 32 | throw "invalid number of arguments"; 33 | else if (expected < args.length) 34 | args = args.slice(0, expected); 35 | else while (expected > args.length) 36 | args.push(null); 37 | } 38 | } 39 | return null; 40 | #elseif js 41 | args = args.concat([null, null, null, null, null]); 42 | return Reflect.callMethod(o, f, args); 43 | #elseif neko 44 | var n : Int = untyped __dollar__nargs(f); 45 | while(args.length < n) 46 | args.push(null); 47 | return Reflect.callMethod(o,f,args); 48 | #elseif flash9 49 | while (true) 50 | { 51 | try 52 | { 53 | return Reflect.callMethod(o,f,args); 54 | } catch (e : flash.errors.Error) { 55 | var expected = re.match(e.message) ? Std.parseInt(re.matched(1)) : args.length + 1; 56 | if (expected > 15) // guard value 57 | throw "invalid number of arguments"; 58 | else if (expected < args.length) 59 | args = args.slice(0, expected); 60 | else while (expected > args.length) 61 | args.push(null); 62 | } 63 | } 64 | return null; 65 | #else 66 | return Reflect.callMethod(o,f,args); 67 | #end 68 | } 69 | #if php 70 | override public function expr( e : Expr ) : Dynamic { 71 | switch( e ) { 72 | case EFunction(params,fexpr,name,ret): 73 | var capturedLocals = duplicate(locals); 74 | var me = this; 75 | var f = function(args:Array) { 76 | var old = me.locals; 77 | me.locals = me.duplicate(capturedLocals); 78 | for( i in 0...params.length ) 79 | me.locals.set(params[i].name,{ r : args[i] }); 80 | var r = null; 81 | try { 82 | r = me.exprReturn(fexpr); 83 | } catch( e : Dynamic ) { 84 | me.locals = old; 85 | throw e; 86 | } 87 | me.locals = old; 88 | return r; 89 | }; 90 | var f = Reflect.makeVarArgs(f); 91 | if( name != null ) 92 | variables.set(name,f); 93 | return f; 94 | default: 95 | return super.expr(e); 96 | } 97 | return null; 98 | } 99 | #end 100 | } 101 | -------------------------------------------------------------------------------- /test/erazor/TestTemplate.hx: -------------------------------------------------------------------------------- 1 | package erazor; 2 | 3 | import utest.Assert; 4 | import erazor.Output; 5 | #if haxe3 6 | import haxe.ds.StringMap in Hash; 7 | #end 8 | 9 | using erazor.Output; 10 | 11 | class TestTemplate 12 | { 13 | var template : Template; 14 | 15 | public function new(){} 16 | 17 | public function test_If_basic_vars_are_parsed_correctly() 18 | { 19 | template = new Template('Hello @name'); 20 | Assert.equals('Hello Boris', template.execute( { name: 'Boris' } )); 21 | } 22 | 23 | public function test_If_basic_vars_are_parsed_correctly_with_hash() 24 | { 25 | var vars = new Hash(); 26 | vars.set('name', 'Boris'); 27 | 28 | template = new Template('Hello @name'); 29 | Assert.equals('Hello Boris', template.execute(vars)); 30 | } 31 | 32 | public function test_If_basic_vars_are_parsed_correctly_with_whitespace() 33 | { 34 | template = new Template(" Hello @name \n "); 35 | Assert.equals(" Hello Boris \n ", template.execute( { name: 'Boris' } )); 36 | } 37 | 38 | public function test_If_keyword_vars_are_parsed_correctly() 39 | { 40 | template = new Template("@for(i in numbers){@(i)-}"); 41 | Assert.equals("1-2-3-4-5-", template.execute( { numbers: [1, 2, 3, 4, 5] } )); 42 | 43 | template = new Template("@for(u in users){@if(u.name == 'Boris'){@u.name}else if(u.name == 'Doris'){@u.name}else{@u.name}
}"); 44 | Assert.equals("Boris
Doris
Someone else
", template.execute({ 45 | users: [{name: 'Boris'}, {name: 'Doris'}, {name: 'Someone else'}] 46 | })); 47 | 48 | template = new Template("@{ a = 10; }@while(--a > 0){@a}"); 49 | Assert.equals("987654321", template.execute()); 50 | 51 | template = new Template("@{var a = 9; var b = '9'; while(--a > 0){b += a;} }@b"); 52 | Assert.equals("987654321", template.execute()); 53 | } 54 | 55 | public function test_If_HtmlTemplate_strings_are_escaped() 56 | { 57 | template = new HtmlTemplate("@text"); 58 | Assert.equals("< > & " '", template.execute( { text: "< > & \" '" } )); 59 | 60 | template = new HtmlTemplate("@for(u in users){
@u
}"); 61 | Assert.equals("
admin
<script>
", template.execute( { users: ["admin","'); 31 | Assert.same([TBlock.literal('')], output); 32 | } 33 | 34 | public function test_If_escaped_blocks_are_parsed_correctly() 35 | { 36 | var output = parser.parse('normal@@email.com'); 37 | Assert.same([TBlock.literal("normal@email.com")], output); 38 | 39 | output = parser.parse('AtTheEnd@'); 40 | Assert.same([TBlock.literal('AtTheEnd@')], output); 41 | 42 | output = parser.parse('more@@than@@one'); 43 | Assert.same([TBlock.literal('more@than@one')], output); 44 | 45 | output = parser.parse('@@@@{hello}'); 46 | Assert.same([TBlock.literal('@@{hello}')], output); 47 | } 48 | 49 | public function test_If_printblocks_are_parsed_correctly() 50 | { 51 | var output : Array; 52 | 53 | // Simple substitution 54 | output = parser.parse('Hello @name'); 55 | Assert.same([TBlock.literal("Hello "), TBlock.printBlock("name")], output); 56 | 57 | // String substitution 58 | output = parser.parse('Hello@(name)abc'); 59 | Assert.same([TBlock.literal("Hello"), TBlock.printBlock('name'), TBlock.literal("abc")], output); 60 | 61 | output = parser.parse('Hello @("Boris")'); 62 | Assert.same([TBlock.literal("Hello "), TBlock.printBlock('"Boris"')], output); 63 | 64 | // String substitution with escaped quotation marks 65 | output = parser.parse('Hello @(a + "A \\" string.")'); 66 | Assert.same([TBlock.literal("Hello "), TBlock.printBlock('a + "A \\" string."')], output); 67 | 68 | output = parser.parse("Hello @(a + 'A \\' string.')"); 69 | Assert.same([TBlock.literal("Hello "), TBlock.printBlock("a + 'A \\' string.'")], output); 70 | 71 | output = parser.parse('@("\'Mixing\'")'); 72 | Assert.same([TBlock.printBlock("\"'Mixing'\"")], output); 73 | 74 | // Braces around var 75 | output = parser.parse('Hello {@name}'); 76 | Assert.same([TBlock.literal("Hello {"), TBlock.printBlock('name'), TBlock.literal('}')], output); 77 | 78 | // Concatenated vars with space between start/end of block 79 | output = parser.parse('@( user.firstname + " " + user.lastname )'); 80 | Assert.same([TBlock.printBlock('user.firstname + " " + user.lastname')], output); 81 | } 82 | 83 | public function test_If_codeblocks_are_parsed_correctly() 84 | { 85 | // Single codeblock 86 | var output = parser.parse('Test: @{a = 0; Lib.print("Evil Bracke}"); }'); 87 | Assert.same([ 88 | TBlock.literal("Test: "), 89 | TBlock.codeBlock('a = 0; Lib.print("Evil Bracke}");') 90 | ], output); 91 | 92 | // Nested codeblock 93 | var output = parser.parse('@{ a = 0; if(b == 2) { Lib.print("Ok"); }}'); 94 | Assert.same([ 95 | TBlock.codeBlock('a = 0; if(b == 2) { Lib.print("Ok"); }') 96 | ], output); 97 | 98 | // @ in codeblock 99 | var output = parser.parse('@{ a = 0; if(b == 2) { Lib.print("a@b"); }}'); 100 | Assert.same([ 101 | TBlock.codeBlock('a = 0; if(b == 2) { Lib.print("a@b"); }') 102 | ], output); 103 | } 104 | 105 | public function test_More_complicated_variables() 106 | { 107 | var output : Array; 108 | 109 | output = parser.parse('@custom(0, 10, "test(")'); 110 | Assert.same([TBlock.printBlock('custom(0, 10, "test(")')], output); 111 | 112 | output = parser.parse('@test[a+1]'); 113 | Assert.same([TBlock.printBlock("test[a+1]")], output); 114 | 115 | output = parser.parse('@test.users[user.id]'); 116 | Assert.same([TBlock.printBlock('test.users[user.id]')], output); 117 | 118 | output = parser.parse('@test.user.id'); 119 | Assert.same([TBlock.printBlock('test.user.id')], output); 120 | 121 | output = parser.parse('@getFunction()()'); 122 | Assert.same([TBlock.printBlock('getFunction()()')], output); 123 | } 124 | 125 | public function test_If_keyword_blocks_are_parsed_correctly() 126 | { 127 | // if 128 | var output = parser.parse('Test: @if(a == 0) { Zero }'); 129 | Assert.same([TBlock.literal("Test: "), TBlock.codeBlock("if(a == 0) {"), TBlock.literal(' Zero '), TBlock.codeBlock("}")], output); 130 | 131 | // nested if 132 | var output = parser.parse('@if(a) { @if(b) { Ok }}'); 133 | Assert.same([ 134 | TBlock.codeBlock("if(a) {"), 135 | TBlock.literal(' '), 136 | TBlock.codeBlock("if(b) {"), 137 | TBlock.literal(' Ok '), 138 | TBlock.codeBlock('}'), 139 | TBlock.codeBlock('}') 140 | ], output); 141 | 142 | // if/else if/else spaced out 143 | var output = parser.parse('@if (a == 0) { Zero } else if (a == 1 && b == 2) { One } else { Above }'); 144 | Assert.same([ 145 | TBlock.codeBlock("if (a == 0) {"), 146 | TBlock.literal(' Zero '), 147 | TBlock.codeBlock("} else if (a == 1 && b == 2) {"), 148 | TBlock.literal(' One '), 149 | TBlock.codeBlock('} else {'), 150 | TBlock.literal(' Above '), 151 | TBlock.codeBlock('}') 152 | ], output); 153 | 154 | // if/else if/else with some space between braces 155 | output = parser.parse('@if (a == 0) { Zero }else if(a == 1 && b == 2) {One} else{ Above }'); 156 | Assert.same([ 157 | TBlock.codeBlock("if (a == 0) {"), 158 | TBlock.literal(' Zero '), 159 | TBlock.codeBlock("}else if(a == 1 && b == 2) {"), 160 | TBlock.literal('One'), 161 | TBlock.codeBlock('} else{'), 162 | TBlock.literal(' Above '), 163 | TBlock.codeBlock('}') 164 | ], output); 165 | 166 | // if/else if/else with no space between braces 167 | output = parser.parse('@if(a == 0){Zero}else if(a == 1 && b == 2){One}else{Above}'); 168 | Assert.same([ 169 | TBlock.codeBlock("if(a == 0){"), 170 | TBlock.literal('Zero'), 171 | TBlock.codeBlock("}else if(a == 1 && b == 2){"), 172 | TBlock.literal('One'), 173 | TBlock.codeBlock('}else{'), 174 | TBlock.literal('Above'), 175 | TBlock.codeBlock('}') 176 | ], output); 177 | 178 | // for 179 | output = parser.parse('@for (u in users) { @u.name
}'); 180 | Assert.same([ 181 | TBlock.codeBlock("for (u in users) {"), 182 | TBlock.literal(' '), 183 | TBlock.printBlock('u.name'), 184 | TBlock.literal('
'), 185 | TBlock.codeBlock('}') 186 | ], output); 187 | 188 | // for IntIterator 189 | output = parser.parse('@for (i in 0...3) { @i
}'); 190 | Assert.same([ 191 | TBlock.codeBlock("for (i in 0...3) {"), 192 | TBlock.literal(' '), 193 | TBlock.printBlock('i'), 194 | TBlock.literal('
'), 195 | TBlock.codeBlock('}') 196 | ], output); 197 | 198 | // while 199 | output = parser.parse('@while( a > 0 ) { @{a--;} }'); 200 | Assert.same([ 201 | TBlock.codeBlock("while( a > 0 ) {"), 202 | TBlock.literal(' '), 203 | TBlock.codeBlock('a--;'), 204 | TBlock.literal(' '), 205 | TBlock.codeBlock('}') 206 | ], output); 207 | } 208 | 209 | public function test_If_parsing_exceptions_are_thrown() 210 | { 211 | var self = this; 212 | 213 | // Unclosed tags 214 | Assert.raises(function() { 215 | self.parser.parse('@if (incompleted == true)'); 216 | }, ParserError); 217 | 218 | Assert.raises(function() { 219 | self.parser.parse('@{unclosed{{'); 220 | }, ParserError); 221 | 222 | Assert.raises(function() { 223 | self.parser.parse("@if(a == 'Oops)}"); 224 | }, ParserError); 225 | 226 | //non-paired brackets 227 | 228 | Assert.raises(function() { 229 | self.parser.parse("@if(true){{}"); 230 | }, ParserError); 231 | 232 | Assert.raises(function() { 233 | self.parser.parse("@if(true){}}"); 234 | }, ParserError); 235 | } 236 | 237 | public function test_If_paired_brackets_are_parsed_correctly() 238 | { 239 | var output; 240 | 241 | output = parser.parse('@if(true){ {} }'); 242 | Assert.same([ 243 | TBlock.codeBlock("if(true){"), 244 | TBlock.literal(' {} '), 245 | TBlock.codeBlock('}') 246 | ], output); 247 | 248 | output = parser.parse('@for(i in 0...3){ {{}{{}}} }'); 249 | Assert.same([ 250 | TBlock.codeBlock("for(i in 0...3){"), 251 | TBlock.literal(' {{}{{}}} '), 252 | TBlock.codeBlock('}') 253 | ], output); 254 | } 255 | } -------------------------------------------------------------------------------- /src/erazor/macro/Build.hx: -------------------------------------------------------------------------------- 1 | package erazor.macro; 2 | import erazor.error.ParserError; 3 | import erazor.Output; 4 | import erazor.Parser; 5 | import erazor.ScriptBuilder; 6 | import haxe.ds.StringMap; 7 | import haxe.ds.StringMap; 8 | import haxe.macro.Context; 9 | import haxe.macro.Expr; 10 | import haxe.macro.ExprTools; 11 | import haxe.macro.Type; 12 | import sys.FileSystem; 13 | import sys.io.File; 14 | 15 | using Lambda; 16 | 17 | typedef PosInfo = 18 | { 19 | file:String, 20 | max:Int, 21 | min:Int 22 | } 23 | 24 | class Build 25 | { 26 | static function buildTemplate():Array 27 | { 28 | #if display 29 | return null; 30 | #else 31 | var cls = Context.getLocalClass().get(); 32 | 33 | //is it the first template extension? 34 | var isFirst = true; 35 | if (cls.superClass.t.toString() != "erazor.macro.Template") 36 | { 37 | isFirst = false; 38 | } 39 | 40 | var params = cls.superClass.params[0]; 41 | 42 | var fields = Context.getBuildFields(); 43 | 44 | var isAbstract = false; 45 | for (meta in cls.meta.get()) 46 | { 47 | switch(meta.name) 48 | { 49 | case ":template", "template": 50 | var s = getString(meta.params[0]); 51 | var pos = Context.getPosInfos(meta.params[0].pos); 52 | pos.min++; 53 | pos.max--; 54 | return build(s, Context.makePosition(pos), fields); 55 | case ":includeTemplate", "includeTemplate": 56 | var srcLocation = Context.resolvePath(cls.module.split(".").join("/") + ".hx"); 57 | var path = srcLocation.split("/"); 58 | path.pop(); 59 | 60 | var templatePath = getString(meta.params[0]); 61 | path.push(templatePath); 62 | templatePath = path.join("/"); 63 | 64 | if (! FileSystem.exists(templatePath)) throw new Error("File " + templatePath + " not found.", meta.params[0].pos); 65 | 66 | Context.registerModuleDependency(Context.getLocalClass().get().module, templatePath); 67 | var contents = File.getContent(templatePath); 68 | var pos = Context.makePosition( { min:0, max:contents.length, file:templatePath } ); 69 | 70 | return build(contents, pos, fields); 71 | case 'abstractTemplate', ':abstractTemplate': isAbstract = true; 72 | } 73 | } 74 | 75 | if (isFirst && !isAbstract) 76 | throw new Error("No :template meta or :includeTemplate meta were found", cls.pos); 77 | 78 | return fields; 79 | #end 80 | } 81 | 82 | #if !display 83 | public static function getString(e:Expr, ?acceptIdent = false, ?throwExceptions = true):Null 84 | { 85 | var ret = switch(e.expr) 86 | { 87 | case EConst(c): 88 | switch(c) 89 | { 90 | case CString(s): s; 91 | case CIdent(s): if (acceptIdent) s; else null; 92 | default: null; 93 | } 94 | default: null; 95 | } 96 | if (throwExceptions && ret == null) 97 | throw new Error("String type was expected", e.pos); 98 | return ret; 99 | } 100 | 101 | static function build(template:String, pos:Null, fields:Array):Array 102 | { 103 | if (pos == null) 104 | { 105 | pos = Context.currentPos(); 106 | } 107 | 108 | // Parse the template into TBlocks for the HTemplateParser 109 | var parsedBlocks = null; 110 | try 111 | { 112 | parsedBlocks = new Parser().parseWithPosition(template); 113 | } 114 | 115 | //if a ParserError is found, bubble up but add the correct macro position to it. 116 | catch (e:ParserError) 117 | { 118 | var pos = Context.getPosInfos(pos); 119 | pos.min += e.pos; 120 | throw new Error("Parser error: \"" + e.toString() + "\"", Context.makePosition(pos)); 121 | } 122 | 123 | var buildedBlocks = new StringBuf(); 124 | buildedBlocks.add("{"); 125 | var builder = new ScriptBuilder('__b__'); 126 | for (block in parsedBlocks) 127 | { 128 | //we'll include a no-op so we can distinguish the blocks. 129 | buildedBlocks.add("__blockbegin__;\n"); 130 | buildedBlocks.add(builder.blockToString(block.block)); 131 | } 132 | buildedBlocks.add("}"); 133 | 134 | var posInfo = Context.getPosInfos(pos); 135 | var min = posInfo.min; 136 | var blockPos = parsedBlocks.map(function(block) return { file:posInfo.file, min:min + block.start, max:min + block.start + block.length } ).array(); 137 | blockPos.reverse(); 138 | 139 | // Make a hscript with the buffer as context. 140 | var script = buildedBlocks.toString(); 141 | 142 | var file = "_internal_"; 143 | 144 | var declaredVars = [for (v in ["this","null","true","false","trace","__b__","super"]) v => true], promotedField = null; 145 | for (f in fields) 146 | { 147 | declaredVars.set(f.name, true); 148 | if (f.meta.exists(function(m) return m.name == "promote" || m.name == ":promote")) 149 | { 150 | if (promotedField == null) 151 | promotedField = f.name; 152 | else 153 | Context.error("Only one promoted field is allowed, but '" + promotedField +"' and '" + f.name + "' were declared", f.pos); 154 | } 155 | } 156 | 157 | //now add all declaredVars from superclasses 158 | var shouldLookSuper = promotedField == null; 159 | function loop(c:Ref, isFirst:Bool) 160 | { 161 | var c = c.get(); 162 | if (!isFirst && shouldLookSuper) 163 | { 164 | shouldLookSuper = c.meta.has("abstractTemplate") || c.meta.has(":abstractTemplate"); 165 | } 166 | 167 | for (f in c.fields.get()) 168 | { 169 | if (shouldLookSuper && (f.meta.has(':promote') || f.meta.has('promote'))) 170 | { 171 | promotedField = f.name; 172 | shouldLookSuper = false; 173 | } else { 174 | declaredVars.set(f.name, true); 175 | } 176 | } 177 | 178 | var sc = c.superClass; 179 | if (sc != null) 180 | { 181 | loop(sc.t, false); 182 | } 183 | } 184 | loop(Context.getLocalClass(), true); 185 | 186 | // Call macro string -> macro parser 187 | var expr = Context.parseInlineString(script, Context.makePosition( { min:0, max:script.length, file:file } )); 188 | expr = new MacroBuildMap(blockPos, promotedField, declaredVars).map(expr); 189 | 190 | #if erazor_macro_debug 191 | file = haxe.io.Path.withoutExtension(posInfo.file) + "_" + Context.getLocalClass().toString().split(".").pop() + "_debug.erazor"; 192 | 193 | var w = File.write(file, false); 194 | var str = ExprTools.toString(expr); 195 | w.writeString(str); 196 | w.close(); 197 | 198 | expr = Context.parseInlineString(str, Context.makePosition( { min:0, max:str.length, file: file } )); 199 | #end 200 | 201 | var executeBlock = []; 202 | 203 | executeBlock.push(macro var __b__ = new erazor.Output(escape)); 204 | executeBlock.push(expr); 205 | executeBlock.push(macro return __b__.toString()); 206 | 207 | //return new execute() field 208 | fields.push({ 209 | name:"execute", 210 | doc:null, 211 | access:[APublic, AOverride], 212 | kind:FFun({ 213 | args:[], 214 | ret:null, 215 | expr:{expr:EBlock(executeBlock), pos:pos}, 216 | params:[] 217 | }), 218 | pos:pos, 219 | meta:[] 220 | }); 221 | 222 | return fields; 223 | } 224 | } 225 | 226 | class MacroBuildMap 227 | { 228 | var info:PosInfo; 229 | var carry:Int; 230 | var blockPos:Array; 231 | var promotedField:Null; 232 | 233 | var declaredVars:Array>; 234 | 235 | public function new(blockPos, promotedField:String, declaredVars) 236 | { 237 | this.carry = 0; 238 | this.blockPos = blockPos; 239 | this.declaredVars = [ declaredVars ]; 240 | if (promotedField != null) 241 | this.promotedField = { expr: EConst(CIdent(promotedField)), pos: Context.currentPos() }; 242 | } 243 | 244 | function lookupVar(name:String) 245 | { 246 | for (v in declaredVars) 247 | if (v.exists(name)) 248 | return true; 249 | return false; 250 | } 251 | 252 | function pos(lastPos:Position) 253 | { 254 | var info = info; 255 | var pos = Context.getPosInfos(lastPos); 256 | var len = pos.max - pos.min; 257 | 258 | var min = pos.min - carry; 259 | var ret = Context.makePosition( { file: info.file, min:min, max:min + len } ); 260 | 261 | return ret; 262 | } 263 | 264 | public function map(e:Expr):Expr 265 | { 266 | if (e == null) return null; 267 | return switch(e.expr) 268 | { 269 | case EConst(CIdent("__blockbegin__")): 270 | var info = blockPos.pop(); 271 | var pos = Context.getPosInfos(e.pos); 272 | this.info = info; 273 | 274 | carry = pos.max - info.min - 3; 275 | {expr:EConst(CIdent("null")), pos:e.pos }; 276 | case EConst(CIdent(s)) if (promotedField == null || (s.charCodeAt(0) >= 'A'.code && s.charCodeAt(0) <= 'Z'.code) || lookupVar(s)): 277 | {expr:EConst(CIdent(s)), pos:pos(e.pos) }; 278 | case EConst(CIdent(s)): 279 | {expr:EField(promotedField, s), pos:pos(e.pos) } 280 | //we need to check if we find the expression __b__.add() 281 | //in order to not mess with the positions 282 | case ECall(e1 = macro __b__.add, params): //behold the beauty of pattern matching! 283 | var p = Context.getPosInfos(e1.pos); 284 | carry += (p.max - p.min) + 2; 285 | 286 | var ret = { expr:ECall(macro __b__.add, params.map(map)), pos:e.pos }; 287 | carry += 3; 288 | ret; 289 | case EVars(vars): 290 | for (v in vars) 291 | addVar(v.name); 292 | var ret = ExprTools.map(e, map); 293 | ret.pos = pos(ret.pos); 294 | ret; 295 | case EFunction(name, f): 296 | if (name != null) 297 | addVar(name); 298 | pushStack([ for (arg in f.args) arg.name => true ]); 299 | var ret = ExprTools.map(e, map); 300 | ret.pos = pos(ret.pos); 301 | popStack(); 302 | ret; 303 | case EBlock(_): 304 | pushStack(); 305 | var ret = ExprTools.map(e, map); 306 | ret.pos = pos(ret.pos); 307 | popStack(); 308 | ret; 309 | case EField(e1, f) if (promotedField != null): 310 | //check all fields first 311 | var hasTypeFields = f.charCodeAt(0) >= 'A'.code && f.charCodeAt(0) <= 'Z'.code; 312 | function checkField(e:Expr) 313 | { 314 | switch(e.expr) 315 | { 316 | case EField(_, f) | EConst(CIdent(f)) if (f.charCodeAt(0) >= 'A'.code && f.charCodeAt(0) <= 'Z'.code): 317 | hasTypeFields = true; 318 | ExprTools.iter(e, checkField); 319 | case EParenthesis(_), EField(_, _): //continue looking 320 | ExprTools.iter(e, checkField); 321 | case EConst(CIdent(_)): 322 | default: //stop looking; isn't a type field 323 | hasTypeFields = false; 324 | } 325 | } 326 | checkField(e1); 327 | if (hasTypeFields) 328 | { 329 | var old = this.promotedField; 330 | this.promotedField = null; 331 | var ret = ExprTools.map(e, map); 332 | ret.pos = pos(ret.pos); 333 | this.promotedField = old; 334 | ret; 335 | } else { 336 | var ret = ExprTools.map(e, map); 337 | ret.pos = pos(ret.pos); 338 | ret; 339 | } 340 | case ESwitch(e1, cases, edef): 341 | cases = cases.map(function(c) { 342 | pushStack(); 343 | for (v in c.values) addIdents(v); 344 | var ret = { 345 | values: c.values, 346 | guard: map(c.guard), 347 | expr: map(c.expr) 348 | }; 349 | popStack(); 350 | return ret; 351 | }); 352 | { expr: ESwitch(map(e1), cases, map(edef)), pos: pos(e.pos) }; 353 | case ETry(e1, catches): 354 | catches = catches.map(function(c) { 355 | pushStack([c.name => true]); 356 | var ret = { type: c.type, name:c.name, expr: map(c.expr) }; 357 | popStack(); 358 | return ret; 359 | }); 360 | { expr: ETry(map(e1), catches), pos: pos(e.pos) }; 361 | #if (haxe_ver >= 4) 362 | case EFor( { expr: EBinop(OpIn, e1, _) }, _): 363 | #else 364 | case EFor( { expr: EIn(e1, _) }, _): 365 | #end 366 | pushStack(); 367 | addIdents(e1); 368 | var ret = ExprTools.map(e, map); 369 | popStack(); 370 | ret.pos = pos(ret.pos); 371 | return ret; 372 | default: 373 | var ret = ExprTools.map(e, map); 374 | ret.pos = pos(ret.pos); 375 | return ret; 376 | } 377 | } 378 | 379 | function addIdents(e:Expr) 380 | { 381 | switch(e.expr) 382 | { 383 | case EConst(CIdent(s)) if (s.charCodeAt(0) < 'A'.code || s.charCodeAt(0) > 'Z'.code): addVar(s); 384 | default: ExprTools.iter(e, addIdents); 385 | } 386 | } 387 | 388 | function addVar(v:String) 389 | { 390 | declaredVars[declaredVars.length - 1].set(v, true); 391 | } 392 | 393 | function pushStack(?map) 394 | { 395 | if (map == null) map = new StringMap(); 396 | declaredVars.push(map); 397 | } 398 | 399 | function popStack() 400 | { 401 | declaredVars.pop(); 402 | } 403 | } 404 | #end 405 | -------------------------------------------------------------------------------- /src/erazor/Parser.hx: -------------------------------------------------------------------------------- 1 | package erazor; 2 | import erazor.error.ParserError; 3 | 4 | private typedef Block = { 5 | var block : TBlock; 6 | var start : Int; 7 | var length : Int; 8 | } 9 | 10 | private enum ParseContext { 11 | literal; 12 | code; 13 | } 14 | 15 | private enum ParseResult { 16 | keepGoing; 17 | doneIncludeCurrent; 18 | doneSkipCurrent; 19 | } 20 | 21 | class Parser 22 | { 23 | private static inline var at = '@'; 24 | 25 | private var condMatch : EReg; 26 | private var inConditionalMatch : EReg; 27 | //private var variableMatch : EReg; 28 | private var variableChar : EReg; 29 | 30 | // State variables for the parser 31 | private var context : ParseContext; 32 | private var bracketStack : Array; 33 | private var conditionalStack : Int; 34 | 35 | private var pos : Int; 36 | 37 | private static var bracketMismatch = "Bracket mismatch! Inside template, non-paired brackets, '{' or '}', should be replaced by @{'{'} and @{'}'}."; 38 | 39 | function parseScriptPart(template : String, startBrace : String, endBrace : String) : String 40 | { 41 | var insideSingleQuote = false; 42 | var insideDoubleQuote = false; 43 | 44 | // If startbrace is empty, assume we are in the script already. 45 | var stack = (startBrace == '') ? 1 : 0; 46 | var i = -1; 47 | 48 | while(++i < template.length) 49 | { 50 | var char = template.charAt(i); 51 | 52 | if(!insideDoubleQuote && !insideSingleQuote) 53 | { 54 | if (char == startBrace) 55 | { 56 | ++stack; 57 | } else if (char == endBrace) { 58 | --stack; 59 | 60 | if(stack == 0) 61 | return template.substr(0, i+1); 62 | if (stack < 0) 63 | throw new ParserError( 'Unbalanced braces for block: ', pos, template.substr(0, 100) ); 64 | } else if (char == '"') { 65 | insideDoubleQuote = true; 66 | } else if (char == "'") { 67 | insideSingleQuote = true; 68 | } 69 | } 70 | else if(insideDoubleQuote && char == '"' && template.charAt(i-1) != '\\') 71 | { 72 | insideDoubleQuote = false; 73 | } 74 | else if(insideSingleQuote && char == "'" && template.charAt(i-1) != '\\') 75 | { 76 | insideSingleQuote = false; 77 | } 78 | } 79 | 80 | //trace(startBrace); trace(endBrace); 81 | throw new ParserError( 'Failed to find a closing delimiter for the script block: ', this.pos, template.substr(0, 100) ); 82 | } 83 | 84 | function parseContext(template : String) : ParseContext 85 | { 86 | // If a single @ is found, go into code context. 87 | if (peek(template) == Parser.at && peek(template, 1) != Parser.at) 88 | return ParseContext.code; 89 | 90 | // Same if we're inside a conditional and a } is found. 91 | if (conditionalStack > 0 && peek(template) == '}') 92 | switch(bracketStack[bracketStack.length - 1]) { 93 | case code: return ParseContext.code; 94 | default: 95 | } 96 | 97 | // Otherwise parse pure text. 98 | return ParseContext.literal; 99 | } 100 | 101 | function accept(template : String, acceptor : String -> Bool, throwAtEnd : Bool) 102 | { 103 | return parseString(template, function(chr : String) { 104 | return acceptor(chr) ? ParseResult.keepGoing : ParseResult.doneSkipCurrent; 105 | }, throwAtEnd); 106 | } 107 | 108 | function isIdentifier(char : String, first = true) 109 | { 110 | return first 111 | ? (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || char == '_' 112 | : (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9') || char == '_'; 113 | } 114 | 115 | function acceptIdentifier(template : String) 116 | { 117 | var first = true; 118 | var self = this; 119 | 120 | return accept(template, function(chr : String) { 121 | var status = self.isIdentifier(chr, first); 122 | first = false; 123 | return status; 124 | }, false); 125 | } 126 | 127 | function acceptBracket(template : String, bracket : String) 128 | { 129 | return parseScriptPart(template, bracket, bracket == '(' ? ')' : ']'); 130 | } 131 | 132 | /** 133 | * Main block parse method, called from parse(). 134 | */ 135 | function parseBlock(template : String) : Block 136 | { 137 | //trace(">>> " + (template.length > 30 ? template.substr(0, 30) + '...' : template)); 138 | return (context == ParseContext.code) ? parseCodeBlock(template) : parseLiteral(template); 139 | } 140 | 141 | function parseConditional(template : String) : Block 142 | { 143 | var str = parseScriptPart(template, '', '{'); 144 | return { block: TBlock.codeBlock(str.substr(1)), length: str.length, start:this.pos }; 145 | } 146 | 147 | function peek(template : String, offset = 0) 148 | { 149 | return template.length > offset ? template.charAt(offset) : null; 150 | } 151 | 152 | function parseVariable(template : String) : Block 153 | { 154 | var output = ""; 155 | var char : String = null; 156 | var part : String = null; 157 | 158 | // Remove @ 159 | template = template.substr(1); 160 | 161 | do 162 | { 163 | // Parse identifier 164 | part = acceptIdentifier(template); 165 | template = template.substr(part.length); 166 | 167 | output += part; 168 | char = peek(template); 169 | 170 | // Look for brackets 171 | while (char == '(' || char == '[') 172 | { 173 | part = acceptBracket(template, char); 174 | template = template.substr(part.length); 175 | 176 | output += part; 177 | char = peek(template); 178 | } 179 | 180 | // Look for . and if the char after that is an identifier 181 | if (char == '.' && isIdentifier(peek(template, 1))) 182 | { 183 | template = template.substr(1); 184 | 185 | output += '.'; 186 | } 187 | else 188 | { 189 | break; 190 | } 191 | } while (char != null); 192 | 193 | return { block: TBlock.printBlock(output), length: output.length + 1, start:this.pos }; 194 | } 195 | 196 | function parseVariableChar(char : String) : ParseResult 197 | { 198 | return (variableChar.match(char)#if macro && variableChar.matchedPos().pos == 0 #end) ? ParseResult.keepGoing : ParseResult.doneSkipCurrent; 199 | } 200 | 201 | function parseCodeBlock(template : String) : Block 202 | { 203 | // Test if at end of a conditional 204 | if (bracketStack.length > 0 && peek(template) == '}') 205 | { 206 | // It may not be an end, just a continuation (else if, else) 207 | if (inConditionalMatch.match(template) #if macro && inConditionalMatch.matchedPos().pos == 0 #end) 208 | { 209 | var str = parseScriptPart(template, '', '{'); 210 | return { block: TBlock.codeBlock(str), length: str.length, start:this.pos }; 211 | } 212 | 213 | if (switch (bracketStack.pop()) { 214 | case code: --conditionalStack < 0; 215 | default: true; 216 | }) throw new ParserError( bracketMismatch, this.pos ); 217 | 218 | return { block: TBlock.codeBlock('}'), length: 1, start:this.pos }; 219 | } 220 | 221 | // Test for conditional code block 222 | if (condMatch.match(template) #if macro && condMatch.matchedPos().pos == 0 #end) 223 | { 224 | bracketStack.push(code); 225 | ++conditionalStack; 226 | 227 | return parseConditional(template); 228 | } 229 | 230 | // Test for variable like @name 231 | if (peek(template) == '@' && isIdentifier(peek(template, 1))) 232 | return parseVariable(template); 233 | 234 | // Test for code or print block @{ or @( 235 | var startBrace = peek(template, 1); 236 | var endBrace = (startBrace == '{') ? '}' : ')'; 237 | 238 | var str = parseScriptPart(template.substr(1), startBrace, endBrace); 239 | var noBraces = StringTools.trim(str.substr(1, str.length - 2)); 240 | 241 | if(startBrace == '{') 242 | return { block: TBlock.codeBlock(noBraces), length: str.length + 1, start:this.pos }; 243 | else // ( 244 | return { block: TBlock.printBlock(noBraces), length: str.length + 1, start:this.pos }; 245 | } 246 | 247 | private function parseString(str : String, modifier : String -> ParseResult, throwAtEnd : Bool) : String 248 | { 249 | var insideSingleQuote = false; 250 | var insideDoubleQuote = false; 251 | 252 | var i = -1; 253 | while(++i < str.length) 254 | { 255 | var char = str.charAt(i); 256 | 257 | if(!insideDoubleQuote && !insideSingleQuote) 258 | { 259 | switch(modifier(char)) 260 | { 261 | case ParseResult.doneIncludeCurrent: 262 | return str.substr(0, i + 1); 263 | 264 | case ParseResult.doneSkipCurrent: 265 | return str.substr(0, i); 266 | 267 | case ParseResult.keepGoing: 268 | // Just do as he says! 269 | } 270 | 271 | if (char == '"') 272 | insideDoubleQuote = true; 273 | else if (char == "'") 274 | insideSingleQuote = true; 275 | } 276 | else if(insideDoubleQuote && char == '"' && str.charAt(i-1) != '\\') 277 | { 278 | insideDoubleQuote = false; 279 | } 280 | else if(insideSingleQuote && char == "'" && str.charAt(i-1) != '\\') 281 | { 282 | insideSingleQuote = false; 283 | } 284 | } 285 | 286 | if(throwAtEnd) 287 | throw new ParserError( 'Failed to find a closing delimiter: ', this.pos, str.substr(0, 100) ); 288 | 289 | return str; 290 | } 291 | 292 | function parseLiteral(template : String) : Block 293 | { 294 | var len = template.length; 295 | var i = -1; 296 | 297 | while (++i < len) { 298 | var char = template.charAt(i); 299 | switch(char) { 300 | case Parser.at: 301 | // Test for escaped @ 302 | if (len > i + 1 && template.charAt(i + 1) != Parser.at) { 303 | return { 304 | block: TBlock.literal(escapeLiteral(template.substr(0, i))), 305 | length: i, 306 | start: this.pos 307 | }; 308 | } 309 | ++i; 310 | case '}': 311 | if (bracketStack.length > 0) { 312 | switch (bracketStack[bracketStack.length - 1]) { 313 | case code: 314 | return { 315 | block: TBlock.literal(escapeLiteral(template.substr(0, i))), 316 | length: i, 317 | start:this.pos 318 | }; 319 | case literal: 320 | bracketStack.pop(); 321 | } 322 | } else { 323 | throw new ParserError( bracketMismatch, this.pos ); 324 | } 325 | case '{': 326 | bracketStack.push(literal); 327 | } 328 | } 329 | 330 | return { 331 | block: TBlock.literal(escapeLiteral(template)), 332 | length: len, 333 | start: this.pos 334 | }; 335 | } 336 | 337 | function escapeLiteral(input : String) : String 338 | { 339 | return StringTools.replace(input, Parser.at + Parser.at, Parser.at); 340 | } 341 | 342 | /** 343 | * Takes a template string as input and returns an AST made of TBlock instances. 344 | * @param template 345 | * @return 346 | */ 347 | public function parse(template : String) : Array 348 | { 349 | this.pos = 0; 350 | 351 | var output = new Array(); 352 | bracketStack = []; 353 | conditionalStack = 0; 354 | 355 | while (template != '') 356 | { 357 | context = parseContext(template); 358 | var block = parseBlock(template); 359 | 360 | if(block.block != null) 361 | output.push(block.block); 362 | 363 | template = template.substr(block.length); 364 | this.pos += block.length; 365 | } 366 | 367 | if (bracketStack.length != 0) throw new ParserError( bracketMismatch, this.pos ); 368 | 369 | return output; 370 | } 371 | 372 | public function parseWithPosition(template:String) : Array 373 | { 374 | this.pos = 0; 375 | 376 | var output = new Array(); 377 | bracketStack = []; 378 | conditionalStack = 0; 379 | 380 | while (template != '') 381 | { 382 | context = parseContext(template); 383 | var block = parseBlock(template); 384 | 385 | if(block.block != null) 386 | output.push(block); 387 | 388 | template = template.substr(block.length); 389 | this.pos += block.length; 390 | } 391 | 392 | if (bracketStack.length != 0) throw new ParserError( bracketMismatch, this.pos ); 393 | 394 | return output; 395 | } 396 | 397 | // Constructor must be put at end of class to prevent intellisense problems with regexps 398 | public function new() 399 | { 400 | // Some are quite simple, could be made with string functions instead for speed 401 | #if macro 402 | condMatch = ~/^@(if|for|while)[^A-Za-z0-9]/; 403 | inConditionalMatch = ~/^(}[ \t\r\n]*else if[^A-Za-z0-9]|}[ \t\r\n]*else[ \t\r\n]*{)/; 404 | //variableMatch = ~/^@[_A-Za-z][\w\.]*([\(\[])?/; 405 | variableChar = ~/^[_A-Za-z0-9\.]$/; 406 | #else 407 | condMatch = ~/^@(?:if|for|while)\b/; 408 | inConditionalMatch = ~/^(?:\}[\s\r\n]*else if\b|\}[\s\r\n]*else[\s\r\n]*\{)/; 409 | //variableMatch = ~/^@[_A-Za-z][\w\.]*([\(\[])?/; 410 | variableChar = ~/^[_\w\.]$/; 411 | #end 412 | } 413 | } 414 | -------------------------------------------------------------------------------- /doc/doc.php.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | An abstract type that represents an Enum. 4 | See [Type] for the haXe Reflection API. 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | Returns either a copy or a reference of the current bytes. 134 | Once called, the buffer can no longer be used. 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | An Input is an abstract reader. See other classes in the [haxe.io] package 188 | for several possible implementations. 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | Encode an URL by using the standard format. 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | Decode an URL using the standard format. 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | Escape HTML special characters of the string. 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | Unescape HTML special characters of the string. 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | Tells if the string [s] starts with the string [start]. 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | Tells if the string [s] ends with the string [end]. 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | Tells if the character in the string [s] at position [pos] is a space. 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | Removes spaces at the left of the String [s]. 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | Removes spaces at the right of the String [s]. 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | Removes spaces at the beginning and the end of the String [s]. 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | Pad the string [s] by appending [c] at its right until it reach [l] characters. 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | Pad the string [s] by appending [c] at its left until it reach [l] characters. 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | Replace all occurences of the string [sub] in the string [s] by the string [by]. 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | Encode a number into a hexadecimal representation, with an optional number of zeros for left padding. 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | Provides a fast native string charCodeAt access. Since the EOF value might vary depending on the platforms, always test with StringTools.isEOF. 337 | Only guaranteed to work if index in [0,s.length] range. Might not work with strings containing \0 char. 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | The StringTools class contains some extra functionalities for [String] 346 | manipulation. It's stored in a different class in order to prevent 347 | the standard [String] of being bloated and thus increasing the size of 348 | each application using it. 349 | 350 | 351 | 352 | 353 | 354 | * Can be any object with properties or a Hash. 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | Tells if an object has a field set. This doesn't take into account the object prototype (class methods). 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | Returns the field of an object, or null if [o] is not an object or doesn't have this field. 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | Set an object field value. 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | Call a method with the given object and arguments. 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | Returns the list of fields of an object, excluding its prototype (class methods). 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | Tells if a value is a function or not. 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | Generic comparison function, does not work for methods, see [compareMethods] 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | Compare two methods closures. Returns true if it's the same method of the same instance. 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | Tells if a value is an object or not. 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | Delete an object field. 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | Make a copy of the fields of an object. 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | Transform a function taking an array of arguments into a function that can 494 | be called with any number of arguments. 495 | 496 | 497 | 498 | The Reflect API is a way to manipulate values dynamicly through an 499 | abstract interface in an untyped manner. Use with care. 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 |
575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | This is an API that can be used by macros implementations. 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | Adds the representation of any value to the string buffer. 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | Adds a part of a string to the string buffer. 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | Adds a character to the string buffer. 726 | 727 | 728 | 729 | 730 | 731 | Returns the content of the string buffer. 732 | The buffer is not emptied by this operation. 733 | 734 | 735 | 736 | 737 | A String buffer is an efficient way to build a big string by 738 | appending small elements together. 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 |
901 | 902 | 903 | 904 |
905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | 939 | 940 | 941 | 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | Compare two Int32 in unsigned mode. 969 | 970 | 971 |
972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | activate JSON compatiblity 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | allow types declarations 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | 1066 | 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | 1080 | 1081 | 1082 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | 1095 | 1096 | 1097 | 1098 | 1099 | 1100 | 1101 | 1102 | 1103 | 1104 | 1105 | 1106 | 1107 | 1108 | 1109 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | 1127 | 1128 | 1129 | 1130 | 1131 | 1132 | 1133 | 1134 | 1135 | 1136 | 1137 | 1138 | 1139 | 1140 | 1141 | 1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | 1149 | 1150 | 1151 | 1152 | 1153 | 1154 | 1155 | 1156 | 1157 | 1158 | 1159 | 1160 | 1161 | 1162 | 1163 | 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | 1170 | 1171 | 1172 | 1173 | 1174 | 1175 | 1176 | 1177 | 1178 | 1179 | 1180 | 1181 | 1182 | 1183 | 1184 | 1185 | 1186 | 1187 | 1188 | 1189 | 1190 | 1191 | 1192 | 1193 | 1194 | 1195 | 1196 | 1197 | 1198 | 1199 | 1200 | 1201 | 1202 | 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 1210 | 1211 | 1212 | 1213 | 1214 | 1215 | 1216 | 1217 | 1218 | 1219 | 1220 | 1221 | 1222 | 1223 | 1224 | 1225 | 1226 | 1227 | 1228 | 1229 | 1230 | 1231 | 1232 | 1233 | 1234 | 1235 | 1236 | 1237 | 1238 | 1239 | 1240 | 1241 | 1242 | 1243 | 1244 | 1245 | 1246 | 1247 | 1248 | 1249 | 1250 | 1251 | 1252 | 1253 | 1254 | 1255 | 1256 | 1257 | 1258 | 1259 | 1260 | 1261 | 1262 | 1263 | 1264 | 1265 | 1266 | 1267 | 1268 | 1269 | 1270 | 1271 | 1272 | 1273 | 1274 | 1275 | 1276 | 1277 | 1278 | 1279 | 1280 | 1281 | 1282 | 1283 | 1284 | 1285 | 1286 | 1287 | 1288 | 1289 | 1290 | 1291 | 1292 | 1293 | 1294 | 1295 | 1296 | 1297 | 1298 | 1299 | 1300 | 1301 | 1302 | 1303 | 1304 | 1305 | 1306 | 1307 | 1308 | 1309 | 1310 | 1311 | 1312 | 1313 | 1314 | 1315 | 1316 | 1317 | 1318 | 1319 | 1320 | 1321 | 1322 | 1323 | 1324 | 1325 | 1326 | 1327 | 1328 | 1329 | 1330 | 1331 | 1332 | 1333 | 1334 | 1335 | 1336 | 1337 | 1338 | 1339 | 1340 | 1341 | 1342 | 1343 | 1344 | 1345 | 1346 | 1347 | 1348 | 1349 | 1350 | 1351 | 1352 | 1353 | 1354 | 1355 | 1356 | 1357 | 1358 | 1359 | 1360 | 1361 | 1362 | 1363 | 1364 | 1365 | 1366 | 1367 | 1368 | 1369 | 1370 | 1371 | 1372 | 1373 | 1374 | 1375 | 1376 | 1377 | 1378 | 1379 | 1380 | 1381 | 1382 | 1383 | 1384 | 1385 | 1386 | This error can be used to handle or produce compilation errors in macros. 1387 | 1388 | 1389 | 1390 | 1391 | 1392 | 1393 | 1394 | 1395 | 1396 | 1397 | 1398 | 1399 | 1400 | 1401 | 1402 | 1403 | 1404 | 1405 | 1406 | 1407 | 1408 | 1409 | 1410 | 1411 | 1412 | 1413 | 1414 | 1415 | 1416 | 1417 | 1418 | 1419 | 1420 | 1421 | 1422 | 1423 | 1424 | 1425 | 1426 | 1427 | 1428 | 1429 | 1430 | 1431 | 1432 | 1433 | 1434 | 1435 | 1436 | 1437 | 1438 | 1439 | 1440 | 1441 | 1442 | 1443 | 1444 | 1445 | 1446 | 1447 | 1448 | 1449 | 1450 | 1451 | 1452 | 1453 | 1454 | 1455 | 1456 | 1457 | 1458 | 1459 | 1460 | 1461 | 1462 | 1463 | 1464 | 1465 | 1466 | 1467 | 1468 | 1469 | 1470 | 1471 | 1472 | 1473 | 1474 | 1475 | 1476 | 1477 | 1478 | 1479 | 1480 | 1481 | 1482 | 1483 | 1484 | 1485 | 1486 | 1487 | 1488 | 1489 | Inform that we are about to write at least a specified number of bytes. 1490 | The underlying implementation can allocate proper working space depending 1491 | on this information, or simply ignore it. This is not a mandatory call 1492 | but a tip and is only used in some specific cases. 1493 | 1494 | 1495 | 1496 | 1497 | 1498 | 1499 | 1500 | 1501 | 1502 | 1503 | 1504 | 1505 | An Output is an abstract write. A specific output implementation will only 1506 | have to override the [writeChar] and maybe the [write], [flush] and [close] 1507 | methods. See [File.write] and [String.write] for two ways of creating an 1508 | Output. 1509 | 1510 | 1511 | 1512 | 1513 | 1514 | 1515 | 1516 | 1517 | 1518 | 1519 | 1520 | 1521 | 1522 | 1523 | 1524 | 1525 | 1526 | 1527 | 1528 | 1529 | 1530 | 1531 | 1532 | 1533 | 1534 | 1535 | 1536 | 1537 | 1538 | 1539 | 1540 | 1541 | 1542 | 1543 | 1544 | 1545 | 1546 | 1547 | 1548 | 1549 | 1550 | 1551 | 1552 | 1553 | 1554 | 1555 | 1556 | 1557 | 1558 | 1559 | 1560 | 1561 | 1562 | 1563 | 1564 | 1565 | 1566 | 1567 | 1568 | 1569 | 1570 | 1571 | Returns true if the iterator has other items, false otherwise. 1572 | 1573 | 1574 | 1575 | 1576 | 1577 | Moves to the next item of the iterator. 1578 | 1579 | 1580 | 1581 | 1582 | 1583 | 1584 | 1585 | 1586 | 1590 | 1591 | 1592 | Integer iterator. Used for interval implementation. 1593 | 1594 | 1595 | 1596 | An integer value is outside its allowed range 1597 | An operation on Bytes is outside of its valid range 1598 | 1599 | 1600 | Other errors 1601 | 1602 | The IO is set into nonblocking mode and some data cannot be read or written 1603 | 1604 | The possible IO errors that can occur 1605 | 1606 | 1607 | 1608 | 1609 | 1610 | 1611 | 1612 | 1613 | 1614 | 1615 | 1616 | Tells if a value v is of the type t. 1617 | 1618 | 1619 | 1620 | 1621 | 1622 | 1623 | 1624 | 1625 | Convert any value to a String 1626 | 1627 | 1628 | 1629 | 1630 | 1631 | 1632 | 1633 | 1634 | Convert a Float to an Int, rounded down. 1635 | 1636 | 1637 | 1638 | 1639 | 1640 | 1641 | 1642 | 1643 | Convert a String to an Int, parsing different possible representations. Returns [null] if could not be parsed. 1644 | 1645 | 1646 | 1647 | 1648 | 1649 | 1650 | 1651 | 1652 | Convert a String to a Float, parsing different possible reprensations. 1653 | 1654 | 1655 | 1656 | 1657 | 1658 | 1659 | 1660 | 1661 | Return a random integer between 0 included and x excluded. 1662 | 1663 | 1664 | 1665 | The Std class provides standard methods for manipulating basic types. 1666 | 1667 | 1668 | 1669 | The standard Void type. Only [null] values can be of the type [Void]. 1670 | 1671 | 1672 | The standard Float type, this is a double-precision IEEE 64bit float. 1673 | 1674 | 1675 | 1676 | 1677 | The standard Int type. Its precision depends on the platform. 1678 | 1679 | 1680 | 1681 | 1682 | 1683 | [Null] can be useful in two cases. In order to document some methods 1684 | that accepts or can return a [null] value, or for the Flash9 compiler and AS3 1685 | generator to distinguish between base values that can be null and others that 1686 | can't. 1687 | 1688 | 1689 | 1690 | 1691 | 1692 | 1693 | The standard Boolean type is represented as an enum with two choices. 1694 | 1695 | 1696 | 1697 | Dynamic is an internal compiler type which has special behavior. 1698 | See the haXe language reference for more informations. 1699 | 1700 | 1701 | 1702 | 1703 | 1704 | 1705 | 1706 | An Iterator is a structure that permits to list a given container 1707 | values. It can be used by your own data structures. See the haXe 1708 | documentation for more informations. 1709 | 1710 | 1711 | 1712 | 1713 | 1714 | An Iterable is a data structure which has an iterator() method. 1715 | See [Lambda] for generic functions on iterable structures. 1716 | 1717 | 1718 | 1719 | ArrayAccess is used to indicate a class that can be accessed using brackets. 1720 | The type parameter represent the type of the elements stored. 1721 | 1722 | 1723 | 1724 | 1725 | This method is not public to not induce haXe users to use it ;) 1726 | Use iterator() instead. 1727 | The return type would be Aggregator that is unusable in haXe 1728 | 1729 | 1730 | 1731 | 1732 | 1733 | 1734 | 1735 | 1736 | 1737 | 1738 | 1739 | 1740 | 1741 | 1742 | Print the specified value on the default output. 1743 | 1744 | 1745 | 1746 | 1747 | 1748 | 1749 | 1750 | 1751 | Print the specified value on the default output followed by a newline character. 1752 | 1753 | 1754 | 1755 | 1756 | 1757 | 1758 | 1759 | 1760 | 1761 | 1762 | 1763 | 1764 | Serialize using native PHP serialization. This will return a Binary string that can be 1765 | stored for long term usage. 1766 | 1767 | 1768 | 1769 | 1770 | 1771 | 1772 | 1773 | 1774 | Unserialize a string using native PHP serialization. See [serialize]. 1775 | 1776 | 1777 | 1778 | 1779 | 1780 | 1781 | 1782 | 1783 | 1784 | 1785 | 1786 | 1787 | 1788 | 1789 | 1790 | 1791 | 1792 | 1793 | 1794 | 1795 | 1796 | 1797 | 1798 | 1799 | 1800 | 1801 | 1802 | 1803 | 1804 | 1805 | 1806 | 1807 | 1808 | For neko compatibility only. 1809 | 1810 | 1811 | 1812 | 1813 | 1814 | 1815 | 1816 | 1817 | 1818 | 1819 | 1820 | 1821 | 1822 | 1823 | 1824 | * Loads types defined in the specified directory. 1825 | 1826 | 1827 | 1828 | 1829 | 1830 | 1831 | 1832 | 1833 | 1834 | 1835 | 1836 | 1837 | 1838 | 1839 | 1840 | 1841 | 1842 | 1843 | 1844 | 1845 | 1846 | Returns the class of a value or [null] if this value is not a Class instance. 1847 | 1848 | 1849 | 1850 | 1851 | 1852 | 1853 | 1854 | 1855 | Returns the enum of a value or [null] if this value is not an Enum instance. 1856 | 1857 | 1858 | 1859 | 1860 | 1861 | 1862 | 1863 | 1864 | Returns the super-class of a class, or null if no super class. 1865 | 1866 | 1867 | 1868 | 1869 | 1870 | 1871 | 1872 | 1873 | Returns the complete name of a class. 1874 | 1875 | 1876 | 1877 | 1878 | 1879 | 1880 | 1881 | 1882 | Returns the complete name of an enum. 1883 | 1884 | 1885 | 1886 | 1887 | 1888 | 1889 | 1890 | 1891 | Evaluates a class from a name. The class must have been compiled 1892 | to be accessible. 1893 | 1894 | 1895 | 1896 | 1897 | 1898 | 1899 | 1900 | 1901 | Evaluates an enum from a name. The enum must have been compiled 1902 | to be accessible. 1903 | 1904 | 1905 | 1906 | 1907 | 1908 | 1909 | 1910 | 1911 | 1912 | Creates an instance of the given class with the list of constructor arguments. 1913 | 1914 | 1915 | 1916 | 1917 | 1918 | 1919 | 1920 | 1921 | Similar to [Reflect.createInstance] excepts that the constructor is not called. 1922 | This enables you to create an instance without any side-effect. 1923 | 1924 | 1925 | 1926 | 1927 | 1928 | 1929 | 1930 | 1931 | 1932 | 1933 | Create an instance of an enum by using a constructor name and parameters. 1934 | 1935 | 1936 | 1937 | 1938 | 1939 | 1940 | 1941 | 1942 | 1943 | 1944 | Create an instance of an enum by using a constructor index and parameters. 1945 | 1946 | 1947 | 1948 | 1949 | 1950 | 1951 | 1952 | 1953 | Returns the list of instance fields. 1954 | 1955 | 1956 | 1957 | 1958 | 1959 | 1960 | 1961 | 1962 | Returns the list of a class static fields. 1963 | 1964 | 1965 | 1966 | 1967 | 1968 | 1969 | 1970 | 1971 | Returns all the available constructor names for an enum. 1972 | 1973 | 1974 | 1975 | 1976 | 1977 | 1978 | 1979 | 1980 | Returns the runtime type of a value. 1981 | 1982 | 1983 | 1984 | 1985 | 1986 | 1987 | 1988 | 1989 | 1990 | Recursively compare two enums constructors and parameters. 1991 | 1992 | 1993 | 1994 | 1995 | 1996 | 1997 | 1998 | 1999 | Returns the constructor of an enum 2000 | 2001 | 2002 | 2003 | 2004 | 2005 | 2006 | 2007 | 2008 | Returns the parameters of an enum 2009 | 2010 | 2011 | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 | Returns the index of the constructor of an enum 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | 2026 | Returns the list of all enum values that don't take any parameter. 2027 | 2028 | 2029 | 2030 | The haXe Reflection API enables you to retreive informations about any value, 2031 | Classes and Enums at runtime. 2032 | 2033 | 2034 | 2035 | 2036 | 2037 | 2038 | This exception is raised when reading while data is no longer available in the [Input]. 2039 | 2040 | 2041 | 2042 | 2043 | 2044 | 2045 | 2046 | 2047 | 2048 | 2049 | 2050 | 2051 | 2052 | 2053 | 2054 | 2055 | 2056 | Tells if the regular expression matches the String. 2057 | Updates the internal state accordingly. 2058 | 2059 | 2060 | 2061 | 2062 | 2063 | 2064 | 2065 | 2066 | Returns a matched group or throw an expection if there 2067 | is no such group. If [n = 0], the whole matched substring 2068 | is returned. 2069 | 2070 | 2071 | 2072 | 2073 | 2074 | Returns the part of the string that was as the left of 2075 | of the matched substring. 2076 | 2077 | 2078 | 2079 | 2080 | 2081 | Returns the part of the string that was at the right of 2082 | of the matched substring. 2083 | 2084 | 2085 | 2086 | 2087 | 2088 | 2089 | 2090 | 2091 | Returns the position of the matched substring within the 2092 | original matched string. 2093 | 2094 | 2095 | 2096 | 2097 | 2098 | 2099 | 2100 | 2101 | Split a string by using the regular expression to match 2102 | the separators. 2103 | 2104 | 2105 | 2106 | 2107 | 2108 | 2109 | 2110 | 2111 | 2112 | Replaces a pattern by another string. The [by] format can 2113 | contains [$1] to [$9] that will correspond to groups matched 2114 | while replacing. [$$] means the [$] character. 2115 | 2116 | 2117 | 2118 | 2119 | 2120 | 2121 | 2122 | 2123 | 2124 | 2125 | 2126 | 2127 | For each occurence of the pattern in the string [s], the function [f] is called and 2128 | can return the string that needs to be replaced. All occurences are matched anyway, 2129 | and setting the [g] flag might cause some incorrect behavior on some platforms. 2130 | 2131 | 2132 | 2133 | 2134 | 2135 | 2136 | 2137 | 2138 | Regular expressions are a way to find regular patterns into 2139 | Strings. Have a look at the tutorial on haXe website to learn 2140 | how to use them. 2141 | 2142 | 2143 | 2144 | 2145 | 2146 | 2147 | 2148 | 2149 | 2150 | 2151 | 2152 | 2153 | 2154 | 2155 | 2156 | 2157 | 2158 | 2159 | 2160 | 2161 | 2162 | 2163 | 2164 | 2165 | 2166 | 2167 | 2168 | 2169 | 2170 | 2171 | 2172 | 2173 | 2174 | 2175 | 2176 | 2177 | 2178 | 2179 | 2180 | Add an element at the head of the list. 2181 | 2182 | 2183 | 2184 | 2185 | 2186 | Returns the first element of the list, or null 2187 | if the list is empty. 2188 | 2189 | 2190 | 2191 | 2192 | 2193 | Removes the first element of the list and 2194 | returns it or simply returns null if the 2195 | list is empty. 2196 | 2197 | 2198 | 2199 | 2200 | 2201 | Tells if a list is empty. 2202 | 2203 | 2204 | 2205 | 2206 | 2207 | 2208 | 2209 | 2210 | Remove the first element that is [== v] from the list. 2211 | Returns [true] if an element was removed, [false] otherwise. 2212 | 2213 | 2214 | 2215 | 2216 | 2217 | Returns an iterator on the elements of the list. 2218 | 2219 | 2220 | 2221 | 2222 | 2223 | Returns a displayable representation of the String. 2224 | 2225 | 2226 | 2227 | 2228 | 2229 | Creates a new empty list. 2230 | 2231 | 2232 | 2233 | A linked-list of elements. A different class is created for each container used in platforms where it matters 2234 | 2235 | 2236 | 2237 | An abstract type that represents a Class. 2238 | See [Type] for the haXe Reflection API. 2239 | 2240 | 2241 | 2242 | 2243 | 2244 | 2245 | 2246 | 2247 | 2248 | The number of characters in the String. 2249 | 2250 | 2251 | 2252 | 2253 | 2254 | Returns an String where all characters have been uppercased. 2255 | 2256 | 2257 | 2258 | 2259 | 2260 | Returns an String where all characters have been lowercased. 2261 | 2262 | 2263 | 2264 | 2265 | 2266 | 2267 | 2268 | 2269 | Returns the character at the given position. 2270 | Returns the empty String if outside of String bounds. 2271 | 2272 | 2273 | 2274 | 2275 | 2276 | 2277 | 2278 | 2279 | Returns the character code at the given position. 2280 | Returns [null] if outside of String bounds. 2281 | 2282 | 2283 | 2284 | 2285 | 2286 | 2287 | 2288 | 2289 | 2290 | Returns the index of first occurence of [value] 2291 | Returns [1-1] if [value] is not found. 2292 | The optional [startIndex] parameter allows you to specify at which character to start searching. 2293 | The position returned is still relative to the beginning of the string. 2294 | 2295 | 2296 | 2297 | 2298 | 2299 | 2300 | 2301 | 2302 | 2303 | Similar to [indexOf] but returns the latest index. 2304 | 2305 | 2306 | 2307 | 2308 | 2309 | 2310 | 2311 | 2312 | Split the string using the specified delimiter. 2313 | 2314 | 2315 | 2316 | 2317 | 2318 | 2319 | 2320 | 2321 | 2322 | Returns a part of the String, taking [len] characters starting from [pos]. 2323 | If [len] is not specified, it takes all the remaining characters. 2324 | 2325 | 2326 | 2327 | 2328 | 2329 | Returns the String itself. 2330 | 2331 | 2332 | 2333 | 2334 | 2335 | 2336 | 2337 | 2338 | Creates a copy from a given String. 2339 | 2340 | 2341 | 2342 | The basic String class. 2343 | 2344 | 2345 | 2346 | 2347 | 2348 | 2349 | 2350 | 2351 | 2352 | 2353 | 2354 | 2355 | 2356 | 2357 | 2358 | 2359 | 2360 | 2361 | 2362 | 2363 | 2364 | 2365 | The length of the Array 2366 | 2367 | 2368 | 2369 | 2370 | 2371 | 2372 | 2373 | 2374 | Returns a new Array by appending [a] to [this]. 2375 | 2376 | 2377 | 2378 | 2379 | 2380 | 2381 | 2382 | 2383 | Returns a representation of an array with [sep] for separating each element. 2384 | 2385 | 2386 | 2387 | 2388 | 2389 | Removes the last element of the array and returns it. 2390 | 2391 | 2392 | 2393 | 2394 | 2395 | 2396 | 2397 | 2398 | Adds the element [x] at the end of the array. 2399 | 2400 | 2401 | 2402 | 2403 | 2404 | Reverse the order of elements of the Array. 2405 | 2406 | 2407 | 2408 | 2409 | 2410 | Removes the first element and returns it. 2411 | 2412 | 2413 | 2414 | 2415 | 2416 | 2417 | 2418 | 2419 | 2420 | Copies the range of the array starting at [pos] up to, 2421 | but not including, [end]. Both [pos] and [end] can be 2422 | negative to count from the end: -1 is the last item in 2423 | the array. 2424 | 2425 | 2426 | 2427 | 2428 | 2429 | 2430 | 2431 | 2432 | 2433 | 2434 | 2435 | 0] if [x > y] 2438 | and [<0] if [x < y]. 2439 | ]]> 2440 | 2441 | 2442 | 2443 | 2444 | 2445 | 2446 | 2447 | 2448 | Removes [len] elements starting from [pos] an returns them. 2449 | 2450 | 2451 | 2452 | 2453 | 2454 | Returns a displayable representation of the Array content. 2455 | 2456 | 2457 | 2458 | 2459 | 2460 | 2461 | 2462 | 2463 | Adds the element [x] at the start of the array. 2464 | 2465 | 2466 | 2467 | 2468 | 2469 | 2470 | 2471 | 2472 | 2473 | Inserts the element [x] at the position [pos]. 2474 | All elements after [pos] are moved one index ahead. 2475 | 2476 | 2477 | 2478 | 2479 | 2480 | 2481 | 2482 | 2483 | Removes the first occurence of [x]. 2484 | Returns false if [x] was not present. 2485 | Elements are compared by using standard equality. 2486 | 2487 | 2488 | 2489 | 2490 | 2491 | Returns a copy of the Array. The values are not 2492 | copied, only the Array structure. 2493 | 2494 | 2495 | 2496 | 2497 | 2498 | Returns an iterator of the Array values. 2499 | 2500 | 2501 | 2502 | 2503 | 2504 | Creates a new Array. 2505 | 2506 | 2507 | 2508 | An Array is a storage for values. You can access it using indexes or 2509 | with its API. On the server side, it's often better to use a [List] which 2510 | is less memory and CPU consuming, unless you really need indexed access. 2511 | 2512 | 2513 | 2514 | 2515 | 2516 | 2517 | 2518 | 2519 | 2520 | Returns the metadata that were declared for the given type (class or enum) 2521 | 2522 | 2523 | 2524 | 2525 | 2526 | 2527 | 2528 | 2529 | Returns the metadata that were declared for the given class fields or enum constructors 2530 | 2531 | 2532 | 2533 | 2534 | 2535 | 2536 | 2537 | 2538 | Returns the metadata that were declared for the given class static fields 2539 | 2540 | 2541 | 2542 | An api to access classes and enums metadata at runtime. 2543 | 2544 | 2545 | 2546 | 2547 | 2548 | 2549 | 2550 | 2551 | 2552 | 2553 | 2554 | 2555 | 2556 | 2557 | 2558 | 2559 | 2560 | 2561 | 2562 | 2563 | 2564 | 2565 | 2566 | 2567 | 2568 | 2569 | 2570 | 2571 | 2572 | 2573 | 2574 | 2575 | 2576 | 2577 | 2578 | 2579 | 2580 | 2581 | 2582 | 2583 | 2584 | 2585 | 2586 | 2587 | 2588 | 2589 | 2590 | 2591 | 2592 | 2593 | 2594 | 2595 | 2596 | 2597 | 2598 | 2599 | 2600 | 2601 | 2602 | 2603 | 2604 | 2605 | 2606 | * Main block parse method, called from parse(). 2607 | 2608 | 2609 | 2610 | 2611 | 2612 | 2613 | 2614 | 2615 | 2616 | 2617 | 2618 | 2619 | 2620 | 2621 | 2622 | 2623 | 2624 | 2625 | 2626 | 2627 | 2628 | 2629 | 2630 | 2631 | 2632 | 2633 | 2634 | 2635 | 2636 | 2637 | 2638 | 2639 | 2640 | 2641 | 2642 | 2643 | 2644 | 2645 | 2646 | 2647 | 2648 | 2649 | 2650 | 2651 | 2652 | 2653 | * Takes a template string as input and returns an AST made of TBlock instances. 2654 | * @param template 2655 | * @return 2656 | 2657 | 2658 | 2659 | 2660 | 2661 | 2662 | 2663 | 2664 | 2665 | 2666 | 2667 | 2668 | 2669 | 2670 | 2671 | 2672 | 2673 | 2674 | 2675 | 2676 | 2677 | 2678 | <__toString public="1" set="method"> 2679 | 2680 | 2681 | 2682 | 2683 | 2684 | 2685 | 2686 | 2687 | 2688 | 2689 | 2690 | 2691 | 2692 | 2693 | 2694 | 2695 | 2696 | Set a value for the given key. 2697 | 2698 | 2699 | 2700 | 2701 | 2702 | 2703 | 2704 | 2705 | Get a value for the given key. 2706 | 2707 | 2708 | 2709 | 2710 | 2711 | 2712 | 2713 | 2714 | Tells if a value exists for the given key. 2715 | In particular, it's useful to tells if a key has 2716 | a [null] value versus no value. 2717 | 2718 | 2719 | 2720 | 2721 | 2722 | 2723 | 2724 | 2725 | Removes a hashtable entry. Returns [true] if 2726 | there was such entry. 2727 | 2728 | 2729 | 2730 | 2731 | 2732 | Returns an iterator of all keys in the hashtable. 2733 | 2734 | 2735 | 2736 | 2737 | 2738 | Returns an iterator of all values in the hashtable. 2739 | 2740 | 2741 | 2742 | 2743 | 2744 | Returns an displayable representation of the hashtable content. 2745 | 2746 | 2747 | 2748 | 2749 | 2750 | Implement IteratorAggregate for native php iteration 2751 | 2752 | 2753 | 2754 | 2755 | Hashtable over a set of elements, using [String] as keys. 2756 | Other kind of keys are not possible on all platforms since they 2757 | can't always be implemented efficiently. 2758 | 2759 | 2760 | --------------------------------------------------------------------------------