Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70b11ec7ad | ||
|
|
f2944e0bae | ||
|
|
fdec33d086 | ||
|
|
0702074469 | ||
|
|
6d5cbf6974 | ||
|
|
5429a3a4d4 | ||
|
|
c124076279 | ||
|
|
0d1d811d2c | ||
|
|
8c04831339 | ||
|
|
4a8b2690aa | ||
|
|
e2bc716ea7 | ||
|
|
6c5987f9af | ||
|
|
1e79880c72 | ||
|
|
f62d891c63 | ||
|
|
930cb8853c | ||
|
|
22104ff64e | ||
|
|
17564441b5 | ||
|
|
a9140a4403 | ||
|
|
ce47ca0a8a | ||
|
|
852fee170e | ||
|
|
8463e99d13 | ||
|
|
3c016b73ee | ||
|
|
8d4173b0be | ||
|
|
502f043804 | ||
|
|
f8571fb175 | ||
|
|
7209aa8880 | ||
|
|
1a4a1217ae | ||
|
|
139c360feb | ||
|
|
be1afbdb5c | ||
|
|
8a7e8c8d7d | ||
|
|
931f79dacb | ||
|
|
261e6ee78e | ||
|
|
9eaddcdafb | ||
|
|
b8ede1a3e7 | ||
|
|
bbaacd5d28 | ||
|
|
60ed5fdfe2 | ||
|
|
512f88c63e | ||
|
|
50c01b2cfb | ||
|
|
27d3f889b5 | ||
|
|
140a9918c0 | ||
|
|
fc6a30b684 | ||
|
|
deb0ae8b8e | ||
|
|
1425479569 |
+4
-2
@@ -20,8 +20,6 @@ addons:
|
||||
- g++-multilib
|
||||
# Python
|
||||
- python3
|
||||
# PHP
|
||||
- php5-cli
|
||||
# C#
|
||||
- mono-devel
|
||||
- mono-mcs
|
||||
@@ -34,10 +32,13 @@ install:
|
||||
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then
|
||||
export DISPLAY=:99.0;
|
||||
export AUDIODEV=null;
|
||||
phpenv global 7.0;
|
||||
elif [ "${TRAVIS_OS_NAME}" = "osx" ]; then
|
||||
brew update;
|
||||
brew install mono;
|
||||
brew install python3;
|
||||
brew tap homebrew/homebrew-php;
|
||||
brew install php71;
|
||||
fi
|
||||
# Download and setup a standalone flash player debugger
|
||||
- haxe flash/install.hxml
|
||||
@@ -53,6 +54,7 @@ install:
|
||||
fi
|
||||
- haxelib install hxjava
|
||||
- haxelib install hxcs
|
||||
- haxelib install hx3compat
|
||||
- haxelib dev hscript .
|
||||
- haxelib list
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (C)2008-2017 Haxe Foundation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
@@ -64,6 +64,8 @@ You can use `parser.allowJSON` to allow JSON data.
|
||||
|
||||
You can use `parser.allowTypes` to parse types for local vars, exceptions, function args and return types. Types are ignored by the interpreter.
|
||||
|
||||
You can use `parser.allowMetadata` to parse metadata before expressions on in anonymous types. Metadata are ignored by the interpreter.
|
||||
|
||||
You can use `new hscript.Macro(pos).convert(ast)` to convert an hscript AST to a Haxe macros one.
|
||||
|
||||
Limitations
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import haxe.ds.EnumValueMap;
|
||||
import haxe.ds.Option;
|
||||
import hscript.Macro;
|
||||
import hscript.Tools;
|
||||
import hscript.Async;
|
||||
import hscript.Printer;
|
||||
import haxe.unit.*;
|
||||
|
||||
class Test extends TestCase {
|
||||
@@ -97,7 +100,7 @@ class Test extends TestCase {
|
||||
assertScript("/**/0", 0);
|
||||
assertScript("x=1;x*=-2", -2);
|
||||
}
|
||||
|
||||
|
||||
function testMap():Void {
|
||||
var objKey = { ok:true };
|
||||
var vars = {
|
||||
@@ -110,7 +113,7 @@ class Test extends TestCase {
|
||||
stringIntMap: ["foo" => 100]
|
||||
}
|
||||
vars.enumMap.set(vars.enumKey, "ok");
|
||||
|
||||
|
||||
assertScript('stringMap["foo"]', "Foo", vars);
|
||||
assertScript('intMap[100]', "one hundred", vars);
|
||||
assertScript('objMap[objKey]', "ok", vars);
|
||||
|
||||
+4
-3
@@ -18,9 +18,10 @@ install:
|
||||
# Download and setup a standalone flash player debugger
|
||||
- haxe flash/install.hxml
|
||||
# Install project dependencies
|
||||
- haxelib install hxcpp > log.txt || type log.txt && cmd /C exit 1
|
||||
- haxelib install hxjava > log.txt || type log.txt && cmd /C exit 1
|
||||
- haxelib install hxcs > log.txt || type log.txt && cmd /C exit 1
|
||||
- haxelib install hxcpp > log.txt || type log.txt && cmd /C exit 1
|
||||
- haxelib install hxjava > log.txt || type log.txt && cmd /C exit 1
|
||||
- haxelib install hxcs > log.txt || type log.txt && cmd /C exit 1
|
||||
- haxelib install hx3compat > log.txt || type log.txt && cmd /C exit 1
|
||||
- haxelib dev hscript .
|
||||
- haxelib list
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
-main Test
|
||||
-dce no
|
||||
-lib hx3compat
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
"url": "https://github.com/HaxeFoundation/hscript",
|
||||
"license": "MIT",
|
||||
"description": "Haxe Script is a scripting engine for a subset of the Haxe language",
|
||||
"version": "2.1.0",
|
||||
"releasenote": "added metadata support",
|
||||
"version": "2.2.0",
|
||||
"releasenote": "",
|
||||
"contributors": ["ncannasse"]
|
||||
}
|
||||
@@ -0,0 +1,494 @@
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
import hscript.Expr;
|
||||
|
||||
class Async {
|
||||
|
||||
var varNames : Array<String>;
|
||||
var currentFun : String;
|
||||
var currentLoop : Expr;
|
||||
var currentBreak : Expr -> Expr;
|
||||
var uid = 0;
|
||||
|
||||
static var nullExpr : Expr = #if hscriptPos { e : null, pmin : 0, pmax : 0, origin : "<null>", line : 0 } #else null #end;
|
||||
static var nullId = mk(EIdent("null"), nullExpr);
|
||||
|
||||
inline static function expr( e : Expr ) {
|
||||
return #if hscriptPos e.e #else e #end;
|
||||
}
|
||||
|
||||
inline static function mk( e, inf : Expr ) : Expr {
|
||||
return #if hscriptPos { e : e, pmin : inf.pmin, pmax : inf.pmax, origin : inf.origin, line : inf.line } #else e #end;
|
||||
}
|
||||
|
||||
/**
|
||||
Convert a script into asynchronous one.
|
||||
- calls such as foo(a,b,c) are translated to a_foo(function(r) ...rest, a,b,c) where r is the result value
|
||||
- object access such obj.bar(a,b,c) are translated to obj.a_bar(function(r) ...rest, a, b, c)
|
||||
- @async expr will execute the expression but continue without waiting for it to finish
|
||||
- @split [ e1, e2, e3 ] is transformed to split(function(_) ...rest, [e1, e2, e3]) which
|
||||
should execute asynchronously all expressions - until they return - before continuing the execution
|
||||
- for(i in v) block; loops are translated to the following:
|
||||
var _i = makeIterator(v);
|
||||
function _loop() {
|
||||
if( !_i.hasNext() ) return;
|
||||
var v = _i.next();
|
||||
block(function(_) _loop());
|
||||
}
|
||||
_loop()
|
||||
- while loops are translated similar to for loops
|
||||
- break and continue are correctly handled
|
||||
- you can use @sync <expr> to disable async transformation in some code parts (for performance reason)
|
||||
- a few expressions are still not supported (complex calls, try/catch, and a few others)
|
||||
|
||||
In these examples ...rest represents the continuation of execution of the script after the expression
|
||||
**/
|
||||
public static function toAsync( e : Expr, topLevelSync = false ) {
|
||||
var a = new Async();
|
||||
return a.build(e, topLevelSync);
|
||||
}
|
||||
|
||||
public function build( e : Expr, topLevelSync = false ) {
|
||||
if( topLevelSync ) {
|
||||
return buildSync(e,null);
|
||||
} else {
|
||||
var nothing = ignore();
|
||||
return new Async().toCps(e, nothing, nothing);
|
||||
}
|
||||
}
|
||||
|
||||
function buildSync( e : Expr, exit : Expr ) : Expr {
|
||||
switch( expr(e) ) {
|
||||
case EFunction(_):
|
||||
return toCps(e, null, null);
|
||||
case EBlock(el):
|
||||
var v = saveVars();
|
||||
for( e in el )
|
||||
switch( expr(e) ) {
|
||||
case EFunction(_, _, name, _) if( name != null ): varNames.push(name);
|
||||
default:
|
||||
}
|
||||
var e = block([for(e in el) buildSync(e,exit)], e);
|
||||
restoreVars(v);
|
||||
return e;
|
||||
case EMeta("async", _, e):
|
||||
return toCps(e, ignore(), ignore());
|
||||
case EBreak if( currentBreak != null ):
|
||||
return currentBreak(e);
|
||||
case EContinue if( currentLoop != null ):
|
||||
return block([call(currentLoop, [nullId], e), mk(EReturn(),e)],e);
|
||||
case EFor(_), EWhile(_):
|
||||
var oldLoop = currentLoop, oldBreak = currentBreak;
|
||||
currentLoop = null;
|
||||
currentBreak = null;
|
||||
e = Tools.map(e, buildSync.bind(_, exit));
|
||||
currentLoop = oldLoop;
|
||||
currentBreak = oldBreak;
|
||||
return e;
|
||||
case EReturn(eret) if( exit != null ):
|
||||
return block([call(exit,[eret == null ? nullId : eret], e), mk(EReturn(),e)], e);
|
||||
default:
|
||||
return Tools.map(e, buildSync.bind(_, exit));
|
||||
}
|
||||
}
|
||||
|
||||
public function new() {
|
||||
varNames = [];
|
||||
}
|
||||
|
||||
function ignore(?e) : Expr {
|
||||
var inf = e == null ? nullExpr : e;
|
||||
return fun("_", block(e == null ? [] : [e],inf));
|
||||
}
|
||||
|
||||
inline function ident(str, e) {
|
||||
return mk(EIdent(str), e);
|
||||
}
|
||||
|
||||
inline function fun(arg:String, e, ?name) {
|
||||
return mk(EFunction([{ name : arg, t : null }], e, name), e);
|
||||
}
|
||||
|
||||
inline function funs(arg:Array<String>, e, ?name) {
|
||||
return mk(EFunction([for( a in arg ) { name : a, t : null }], e, name), e);
|
||||
}
|
||||
|
||||
inline function block(arr, e) {
|
||||
return mk(EBlock(arr), e);
|
||||
}
|
||||
|
||||
inline function field(e, f, inf) {
|
||||
return mk(EField(e, f), inf);
|
||||
}
|
||||
|
||||
inline function binop(op, e1, e2, inf) {
|
||||
return mk(EBinop(op, e1, e2), inf);
|
||||
}
|
||||
|
||||
inline function call(e, args, inf) {
|
||||
return mk(ECall(e, args), inf);
|
||||
}
|
||||
|
||||
function retNull(e) : Expr {
|
||||
return call(e, [nullId],e);
|
||||
}
|
||||
|
||||
function makeCall( ecall, args : Array<Expr>, rest : Expr, exit, sync = false ) {
|
||||
var names = [for( i in 0...args.length ) "_a"+uid++];
|
||||
var rargs = [for( i in 0...args.length ) ident(names[i],ecall)];
|
||||
if( !sync )
|
||||
rargs.unshift(rest);
|
||||
var rest = mk(sync ? ECall(rest,[call(ecall, rargs,ecall)]) : ECall(ecall, rargs), ecall);
|
||||
var i = args.length - 1;
|
||||
while( i >= 0 ) {
|
||||
rest = toCps(args[i], fun(names[i], rest), exit);
|
||||
i--;
|
||||
}
|
||||
return rest;
|
||||
}
|
||||
|
||||
var syncFlag : Bool;
|
||||
|
||||
function isSync( e : Expr ) {
|
||||
syncFlag = true;
|
||||
checkSync(e);
|
||||
return syncFlag;
|
||||
}
|
||||
|
||||
function checkSync( e : Expr ) {
|
||||
if( !syncFlag )
|
||||
return;
|
||||
switch( expr(e) ) {
|
||||
case ECall(_), EFunction(_):
|
||||
syncFlag = false;
|
||||
case EMeta("sync" | "async", _, _):
|
||||
// isolated from the sync part
|
||||
default:
|
||||
Tools.iter(e, checkSync);
|
||||
}
|
||||
}
|
||||
|
||||
function saveVars() {
|
||||
return varNames.length;
|
||||
}
|
||||
|
||||
function restoreVars(k) {
|
||||
while( varNames.length > k ) varNames.pop();
|
||||
}
|
||||
|
||||
public function toCps( e : Expr, rest : Expr, exit : Expr ) : Expr {
|
||||
if( isSync(e) )
|
||||
return call(rest, [buildSync(e, exit)],e);
|
||||
switch( expr(e) ) {
|
||||
case EBlock(el):
|
||||
var el = el.copy();
|
||||
var vold = saveVars();
|
||||
// local recursion
|
||||
for( e in el )
|
||||
switch( expr(e) ) {
|
||||
case EFunction(_, _, name, null): varNames.push(name);
|
||||
default:
|
||||
}
|
||||
while( el.length > 0 ) {
|
||||
var e = toCps(el.pop(), rest, exit);
|
||||
rest = ignore(e);
|
||||
}
|
||||
restoreVars(vold);
|
||||
return retNull(rest);
|
||||
case EFunction(args, body, name, t):
|
||||
var vold = saveVars();
|
||||
if( name != null )
|
||||
varNames.push(name);
|
||||
for( a in args )
|
||||
varNames.push(a.name);
|
||||
args.unshift( { name : "_onEnd", t : null } );
|
||||
var frest = ident("_onEnd",e);
|
||||
var oldFun = currentFun;
|
||||
currentFun = name;
|
||||
var body = toCps(body, frest, frest);
|
||||
var f = mk(EFunction(args, body, name, t),e);
|
||||
restoreVars(vold);
|
||||
return rest == null ? f : call(rest, [f],e);
|
||||
case EParent(e):
|
||||
return mk(EParent(toCps(e, rest, exit)),e);
|
||||
case EMeta("sync", _, e):
|
||||
return call(rest,[buildSync(e,exit)],e);
|
||||
case EMeta("async", _, e):
|
||||
var nothing = ignore();
|
||||
return block([toCps(e,nothing,nothing),retNull(rest)],e);
|
||||
case EMeta("split", _, e):
|
||||
var args = switch( expr(e) ) { case EArrayDecl(el): el; default: throw "@split expression should be an array"; };
|
||||
var args = [for( a in args ) fun("_rest", toCps(block([a],a), ident("_rest",a), exit))];
|
||||
return call(ident("split",e), [rest, mk(EArrayDecl(args),e)],e);
|
||||
case ECall(expr(_) => EIdent(i), args):
|
||||
return makeCall( ident( varNames.indexOf(i) < 0 ? "a_" + i : i,e) , args, rest, exit);
|
||||
case ECall(expr(_) => EField(e, f), args):
|
||||
return makeCall(field(e,"a_"+f,e), args, rest, exit);
|
||||
case EFor(v, eit, eloop):
|
||||
var id = ++uid;
|
||||
var it = ident("_i" + id,e);
|
||||
var oldLoop = currentLoop, oldBreak = currentBreak;
|
||||
var loop = ident("_loop" + id,e);
|
||||
currentLoop = loop;
|
||||
currentBreak = function(inf) return block([call(rest, [nullId], inf), mk(EReturn(),inf)], inf);
|
||||
var efor = block([
|
||||
mk(EVar("_i" + id, call(ident("makeIterator",eit),[eit],eit)),eit),
|
||||
fun("_", block([
|
||||
mk(EIf(mk(EUnop("!", true, call( field(it, "hasNext", it), [], it)),it), currentBreak(it)),it),
|
||||
mk(EVar(v, call(field(it, "next",it), [], it)), it),
|
||||
toCps(eloop, loop, exit),
|
||||
], it),"_loop" + id),
|
||||
call(loop, [nullId], e),
|
||||
], e);
|
||||
currentLoop = oldLoop;
|
||||
currentBreak = oldBreak;
|
||||
return efor;
|
||||
case EUnop(op = "!", prefix, eop):
|
||||
return toCps(eop, fun("_r",call(rest, [mk(EUnop(op, prefix, ident("_r",e)),e)], e)), exit);
|
||||
case EBinop(op, e1, e2):
|
||||
switch( op ) {
|
||||
case "=", "+=", "-=", "/=", "*=", "%=", "&=", "|=", "^=":
|
||||
switch( expr(e1) ) {
|
||||
case EIdent(_):
|
||||
var id = "_r" + uid++;
|
||||
return toCps(e2, fun(id, call(rest, [binop(op, e1, ident(id,e1),e1)], e1)), exit);
|
||||
case EField(ef1, f):
|
||||
var id1 = "_r" + uid++;
|
||||
var id2 = "_r" + uid++;
|
||||
return toCps(ef1, fun(id1, toCps(e2, fun(id2, call(rest, [binop(op, field(ident(id1, e1), f, ef1), ident(id2, e2), e)], e)), exit)), exit);
|
||||
case EArray(earr, eindex):
|
||||
var idArr = "_r" + uid++;
|
||||
var idIndex = "_r" + uid++;
|
||||
var idVal = "_r" + uid++;
|
||||
return toCps(earr,fun(idArr, toCps(eindex, fun(idIndex, toCps(e2,
|
||||
fun(idVal, call(rest, [binop(op, mk(EArray(ident(idArr,earr), ident(idIndex,eindex)),e1), ident(idVal,e1), e)], e))
|
||||
, exit)), exit)),exit);
|
||||
default:
|
||||
throw "assert " + e1;
|
||||
}
|
||||
case "||":
|
||||
var id1 = "_r" + uid++;
|
||||
var id2 = "_r" + uid++;
|
||||
return toCps(e1, fun(id1, mk(EIf(binop("==", ident(id1,e1), ident("true",e1), e1),call(rest,[ident("true",e1)],e1),toCps(e2, rest, exit)),e)), exit);
|
||||
case "&&":
|
||||
var id1 = "_r" + uid++;
|
||||
var id2 = "_r" + uid++;
|
||||
return toCps(e1, fun(id1, mk(EIf(binop("!=", ident(id1,e1), ident("true",e1), e1),call(rest,[ident("false",e1)],e1),toCps(e2, rest, exit)),e)), exit);
|
||||
default:
|
||||
var id1 = "_r" + uid++;
|
||||
var id2 = "_r" + uid++;
|
||||
return toCps(e1, fun(id1, toCps(e2, fun(id2, call(rest, [binop(op, ident(id1,e1), ident(id2,e2), e)], e)), exit)), exit);
|
||||
}
|
||||
case EIf(cond, e1, e2), ETernary(cond, e1, e2):
|
||||
return toCps(cond, fun("_c", mk(EIf(ident("_c",cond), toCps(e1, rest, exit), e2 == null ? retNull(rest) : toCps(e2, rest, exit)),e)), exit);
|
||||
case EWhile(cond, ewh):
|
||||
var id = ++uid;
|
||||
var loop = ident("_loop" + id, cond);
|
||||
var oldLoop = currentLoop, oldBreak = currentBreak;
|
||||
currentLoop = loop;
|
||||
currentBreak = function(e) return block([call(rest, [nullId], e), mk(EReturn(),e)],e);
|
||||
var ewhile = block([
|
||||
fun("_r",
|
||||
toCps(cond, fun("_c", mk(EIf(ident("_c", cond), toCps(ewh, loop, exit), call(rest, [nullId], cond)),cond)), exit)
|
||||
, "_loop"+id),
|
||||
call(loop, [nullId], cond),
|
||||
],e);
|
||||
currentLoop = oldLoop;
|
||||
currentBreak = oldBreak;
|
||||
return ewhile;
|
||||
case EReturn(eret):
|
||||
return eret == null ? call(exit, [nullId], e) : toCps(eret, exit, exit);
|
||||
case EObject(fields):
|
||||
var id = "_o" + uid++;
|
||||
var rest = call(rest, [ident(id,e)], e);
|
||||
fields.reverse();
|
||||
for( f in fields )
|
||||
rest = toCps(f.e, fun("_r", block([
|
||||
binop("=", mk(EField(ident(id,f.e), f.name),f.e), ident("_r",f.e), f.e),
|
||||
rest,
|
||||
],f.e)),exit);
|
||||
return block([
|
||||
mk(EVar(id, mk(EObject([]),e)),e),
|
||||
rest,
|
||||
],e);
|
||||
case EArrayDecl(el):
|
||||
var id = "_a" + uid++;
|
||||
var rest = call(rest, [ident(id,e)], e);
|
||||
var i = el.length - 1;
|
||||
while( i >= 0 ) {
|
||||
var e = el[i];
|
||||
rest = toCps(e, fun("_r", block([
|
||||
binop("=", mk(EArray(ident(id,e), mk(EConst(CInt(i)),e)),e), ident("_r",e), e),
|
||||
rest,
|
||||
],e)), exit);
|
||||
i--;
|
||||
}
|
||||
return block([
|
||||
mk(EVar(id, mk(EArrayDecl([]),e)),e),
|
||||
rest,
|
||||
],e);
|
||||
case EArray(earr, eindex):
|
||||
var id1 = "_r" + uid++;
|
||||
var id2 = "_r" + uid++;
|
||||
return toCps(earr, fun(id1, toCps(eindex, fun(id2, call(rest, [mk(EArray(ident(id1,e), ident(id2,e)),e)], e)), exit)), exit);
|
||||
case EVar(v, t, ev):
|
||||
if( ev == null )
|
||||
return block([e, call(rest, [nullId],e)], e);
|
||||
return block([
|
||||
mk(EVar(v, t),e),
|
||||
toCps(ev, fun("_r", block([binop("=", ident(v,e), ident("_r",e), e), call(rest,[nullId],e)], e)), exit),
|
||||
],e);
|
||||
case EConst(_), EIdent(_), EUnop(_), EField(_):
|
||||
return call(rest, [e], e);
|
||||
case ENew(cl, args):
|
||||
var names = [for( i in 0...args.length ) "_a"+uid++];
|
||||
var rargs = [for( i in 0...args.length ) ident(names[i], args[i])];
|
||||
var rest = call(rest,[mk(ENew(cl, rargs),e)],e);
|
||||
var i = args.length - 1;
|
||||
while( i >= 0 ) {
|
||||
rest = toCps(args[i], fun(names[i], rest), exit);
|
||||
i--;
|
||||
}
|
||||
return rest;
|
||||
case EBreak:
|
||||
if( currentBreak == null ) throw "Break outside loop";
|
||||
return currentBreak(e);
|
||||
case EContinue:
|
||||
if( currentLoop == null ) throw "Continue outside loop";
|
||||
return block([call(currentLoop, [nullId], e), mk(EReturn(),e)], e);
|
||||
case ESwitch(v, cases, def):
|
||||
var cases = [for( c in cases ) { values : c.values, expr : toCps(c.expr, rest, exit) } ];
|
||||
return toCps(v, mk(EFunction([ { name : "_c", t : null } ], mk(ESwitch(ident("_c",v), cases, def == null ? retNull(rest) : toCps(def, rest, exit)),e)),e), exit );
|
||||
case EThrow(v):
|
||||
return toCps(v, mk(EFunction([ { name : "_v", t : null } ], mk(EThrow(v),v)), v), exit);
|
||||
//case EDoWhile(_), ETry(_), ECall(_):
|
||||
default:
|
||||
throw "Unsupported async expression " + Printer.toString(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class AsyncInterp extends Interp {
|
||||
|
||||
public function setContext( api : Dynamic ) {
|
||||
|
||||
var funs = new Array();
|
||||
for( v in variables.keys() )
|
||||
if( Reflect.isFunction(variables.get(v)) )
|
||||
funs.push({ v : v, obj : null });
|
||||
|
||||
variables.set("split", split);
|
||||
variables.set("makeIterator", makeIterator);
|
||||
|
||||
var c = Type.getClass(api);
|
||||
for( f in (c == null ? Reflect.fields(api) : Type.getInstanceFields(c)) ) {
|
||||
var fv = Reflect.field(api, f);
|
||||
if( !Reflect.isFunction(fv) ) continue;
|
||||
if( f.charCodeAt(0) == "_".code ) f = f.substr(1);
|
||||
variables.set(f, fv);
|
||||
// create the async wrapper if doesn't exists
|
||||
if( f.substr(0, 2) != "a_" )
|
||||
funs.push({ v : f, obj : api });
|
||||
}
|
||||
|
||||
for( v in funs ) {
|
||||
if( variables.exists("a_" + v.v) ) continue;
|
||||
var fv : Dynamic = variables.get(v.v);
|
||||
var obj = v.obj;
|
||||
variables.set("a_" + v.v, Reflect.makeVarArgs(function(args:Array<Dynamic>) {
|
||||
var onEnd = args.shift();
|
||||
onEnd(Reflect.callMethod(obj, fv, args));
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
public function hasMethod( name : String ) {
|
||||
var v = variables.get(name);
|
||||
return v != null && Reflect.isFunction(v);
|
||||
}
|
||||
|
||||
public function callValue( value : Dynamic, args : Array<Dynamic>, ?onResult : Dynamic -> Void, ?vthis : {} ) {
|
||||
var oldThis = variables.get("this");
|
||||
if( vthis != null )
|
||||
variables.set("this", vthis);
|
||||
if( onResult == null )
|
||||
onResult = function(_) {};
|
||||
args.unshift(onResult);
|
||||
Reflect.callMethod(null, value, args);
|
||||
variables.set("this", oldThis);
|
||||
}
|
||||
|
||||
public function callAsync( id : String, args, ?onResult, ?vthis : {} ) {
|
||||
var v = variables.get(id);
|
||||
if( v == null )
|
||||
throw "Missing function " + id + "()";
|
||||
callValue(v, args, onResult, vthis);
|
||||
}
|
||||
|
||||
function split( rest : Dynamic -> Void, args : Array<Dynamic> ) {
|
||||
if( args.length == 0 )
|
||||
rest(null);
|
||||
else {
|
||||
var count = args.length;
|
||||
function next(_) {
|
||||
if( --count == 0 ) rest(null);
|
||||
}
|
||||
for( a in args )
|
||||
a(next);
|
||||
}
|
||||
}
|
||||
|
||||
override function fcall( o : Dynamic, f : String, args : Array<Dynamic> ) : Dynamic {
|
||||
var m = Reflect.field(o, f);
|
||||
if( m == null ) {
|
||||
if( f.substr(0, 2) == "a_" ) {
|
||||
m = Reflect.field(o, f.substr(2));
|
||||
// fallback on sync version
|
||||
if( m != null ) {
|
||||
var onEnd = args.shift();
|
||||
onEnd(call(o, m, args));
|
||||
return null;
|
||||
}
|
||||
// fallback on generic script
|
||||
m = Reflect.field(o, "scriptCall");
|
||||
if( m != null ) {
|
||||
call(o, m, [args.shift(), f.substr(2), args]);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
// fallback on generic script
|
||||
m = Reflect.field(o, "scriptCall");
|
||||
if( m != null ) {
|
||||
var result : Dynamic = null;
|
||||
call(o, m, [function(r) result = r, f, args]);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
error(ECustom(o + " has no method " + f));
|
||||
}
|
||||
return call(o, m, args);
|
||||
}
|
||||
|
||||
}
|
||||
+27
-20
@@ -1,26 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Nicolas Cannasse
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
import hscript.Expr;
|
||||
@@ -247,6 +244,11 @@ class Bytes {
|
||||
}
|
||||
bout.addByte(255);
|
||||
if( def == null ) bout.addByte(255) else doEncode(def);
|
||||
case EMeta(name,args,e):
|
||||
doEncodeString(name);
|
||||
bout.addByte(args == null ? 0 : args.length + 1);
|
||||
if( args != null ) for( e in args ) doEncode(e);
|
||||
doEncode(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,6 +368,11 @@ class Bytes {
|
||||
case 24:
|
||||
var cond = doDecode();
|
||||
EDoWhile(cond,doDecode());
|
||||
case 25:
|
||||
var name = doDecodeString();
|
||||
var count = bin.get(pin++);
|
||||
var args = count == 0 ? null : [for( i in 0...count - 1 ) doDecode()];
|
||||
EMeta(name, args, doDecode());
|
||||
case 255:
|
||||
null;
|
||||
default:
|
||||
|
||||
+81
-53
@@ -1,26 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Nicolas Cannasse
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
|
||||
@@ -73,7 +70,7 @@ enum Expr {
|
||||
EMeta( name : String, args : Array<Expr>, e : Expr );
|
||||
}
|
||||
|
||||
typedef Argument = { name : String, ?t : CType, ?opt : Bool };
|
||||
typedef Argument = { name : String, ?t : CType, ?opt : Bool, ?value : Expr };
|
||||
|
||||
typedef Metadata = Array<{ name : String, params : Array<Expr> }>;
|
||||
|
||||
@@ -98,39 +95,8 @@ class Error {
|
||||
this.origin = origin;
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
private function errorDefToString(): String {
|
||||
switch (e) {
|
||||
case EInvalidChar(c):
|
||||
return "Invalid character: '"+String.fromCharCode(c)+"' ("+c+")";
|
||||
|
||||
case EUnexpected(s):
|
||||
return "Unexpected token: \""+s+"\"";
|
||||
|
||||
case EUnterminatedString:
|
||||
return "Unterminated string";
|
||||
|
||||
case EUnterminatedComment:
|
||||
return "Unterminated comment";
|
||||
|
||||
case EUnknownVariable(v):
|
||||
return "Unknown variable: "+v;
|
||||
|
||||
case EInvalidIterator(v):
|
||||
return "Invalid iterator: "+v;
|
||||
|
||||
case EInvalidOp(op):
|
||||
return "Invalid operator: "+op;
|
||||
|
||||
case EInvalidAccess(f):
|
||||
return "Invalid access to field "+f;
|
||||
}
|
||||
}
|
||||
|
||||
public function toString(): String {
|
||||
var message = errorDefToString();
|
||||
message = origin + ":" + line + ": " + message;
|
||||
return message;
|
||||
return Printer.errorToString(this);
|
||||
}
|
||||
}
|
||||
enum ErrorDef {
|
||||
@@ -141,8 +107,70 @@ enum Error {
|
||||
EUnexpected( s : String );
|
||||
EUnterminatedString;
|
||||
EUnterminatedComment;
|
||||
EInvalidPreprocessor( msg : String );
|
||||
EUnknownVariable( v : String );
|
||||
EInvalidIterator( v : String );
|
||||
EInvalidOp( op : String );
|
||||
EInvalidAccess( f : String );
|
||||
ECustom( msg : String );
|
||||
}
|
||||
|
||||
|
||||
enum ModuleDecl {
|
||||
DPackage( path : Array<String> );
|
||||
DImport( path : Array<String>, ?everything : Bool );
|
||||
DClass( c : ClassDecl );
|
||||
DTypedef( c : TypeDecl );
|
||||
}
|
||||
|
||||
typedef ModuleType = {
|
||||
var name : String;
|
||||
var params : {}; // TODO : not yet parsed
|
||||
var meta : Metadata;
|
||||
var isPrivate : Bool;
|
||||
}
|
||||
|
||||
typedef ClassDecl = {> ModuleType,
|
||||
var extend : Null<CType>;
|
||||
var implement : Array<CType>;
|
||||
var fields : Array<FieldDecl>;
|
||||
var isExtern : Bool;
|
||||
}
|
||||
|
||||
typedef TypeDecl = {> ModuleType,
|
||||
var t : CType;
|
||||
}
|
||||
|
||||
typedef FieldDecl = {
|
||||
var name : String;
|
||||
var meta : Metadata;
|
||||
var kind : FieldKind;
|
||||
var access : Array<FieldAccess>;
|
||||
}
|
||||
|
||||
enum FieldAccess {
|
||||
APublic;
|
||||
APrivate;
|
||||
AInline;
|
||||
AOverride;
|
||||
AStatic;
|
||||
AMacro;
|
||||
}
|
||||
|
||||
enum FieldKind {
|
||||
KFunction( f : FunctionDecl );
|
||||
KVar( v : VarDecl );
|
||||
}
|
||||
|
||||
typedef FunctionDecl = {
|
||||
var args : Array<Argument>;
|
||||
var expr : Expr;
|
||||
var ret : Null<CType>;
|
||||
}
|
||||
|
||||
typedef VarDecl = {
|
||||
var get : Null<String>;
|
||||
var set : Null<String>;
|
||||
var expr : Null<Expr>;
|
||||
var type : Null<CType>;
|
||||
}
|
||||
|
||||
+44
-32
@@ -1,26 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Nicolas Cannasse
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
import haxe.PosInfos;
|
||||
@@ -29,7 +26,7 @@ import hscript.Expr;
|
||||
private enum Stop {
|
||||
SBreak;
|
||||
SContinue;
|
||||
SReturn( v : Dynamic );
|
||||
SReturn;
|
||||
}
|
||||
|
||||
class Interp {
|
||||
@@ -47,6 +44,7 @@ class Interp {
|
||||
var depth : Int;
|
||||
var inTry : Bool;
|
||||
var declared : Array<{ n : String, old : { r : Dynamic } }>;
|
||||
var returnValue : Dynamic;
|
||||
|
||||
#if hscriptPos
|
||||
var curExpr : Expr;
|
||||
@@ -64,7 +62,12 @@ class Interp {
|
||||
variables.set("null",null);
|
||||
variables.set("true",true);
|
||||
variables.set("false",false);
|
||||
variables.set("trace",function(e) haxe.Log.trace(Std.string(e), posInfos()));
|
||||
variables.set("trace", Reflect.makeVarArgs(function(el) {
|
||||
var inf = posInfos();
|
||||
var v = el.shift();
|
||||
if( el.length > 0 ) inf.customParams = el;
|
||||
haxe.Log.trace(Std.string(v), inf);
|
||||
}));
|
||||
initOps();
|
||||
}
|
||||
|
||||
@@ -250,7 +253,10 @@ class Interp {
|
||||
switch( e ) {
|
||||
case SBreak: throw "Invalid break";
|
||||
case SContinue: throw "Invalid continue";
|
||||
case SReturn(v): return v;
|
||||
case SReturn:
|
||||
var v = returnValue;
|
||||
returnValue = null;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -282,13 +288,18 @@ class Interp {
|
||||
#end
|
||||
}
|
||||
|
||||
inline function error(e : #if hscriptPos ErrorDef #else Error #end ) : Dynamic {
|
||||
#if hscriptPos
|
||||
throw new Error(e, curExpr.pmin, curExpr.pmax, curExpr.origin, curExpr.line);
|
||||
inline function error(e : #if hscriptPos ErrorDef #else Error #end, rethrow=false ) : Dynamic {
|
||||
#if hscriptPos var e = new Error(e, curExpr.pmin, curExpr.pmax, curExpr.origin, curExpr.line); #end
|
||||
if( rethrow ) this.rethrow(e) else throw e;
|
||||
return null;
|
||||
}
|
||||
|
||||
inline function rethrow( e : Dynamic ) {
|
||||
#if hl
|
||||
hl.Api.rethrow(e);
|
||||
#else
|
||||
throw e;
|
||||
#end
|
||||
return null;
|
||||
}
|
||||
|
||||
function resolve( id : String ) : Dynamic {
|
||||
@@ -385,7 +396,8 @@ class Interp {
|
||||
case EContinue:
|
||||
throw SContinue;
|
||||
case EReturn(e):
|
||||
throw SReturn((e == null)?null:expr(e));
|
||||
returnValue = e == null ? null : expr(e);
|
||||
throw SReturn;
|
||||
case EFunction(params,fexpr,name,_):
|
||||
var capturedLocals = duplicate(locals);
|
||||
var me = this;
|
||||
@@ -575,7 +587,7 @@ class Interp {
|
||||
switch(err) {
|
||||
case SContinue:
|
||||
case SBreak: break;
|
||||
case SReturn(_): throw err;
|
||||
case SReturn: throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -592,7 +604,7 @@ class Interp {
|
||||
switch(err) {
|
||||
case SContinue:
|
||||
case SBreak: break;
|
||||
case SReturn(_): throw err;
|
||||
case SReturn: throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -600,7 +612,7 @@ class Interp {
|
||||
}
|
||||
|
||||
function makeIterator( v : Dynamic ) : Iterator<Dynamic> {
|
||||
#if ((flash && !flash9) || php)
|
||||
#if ((flash && !flash9) || (php && !php7 && haxe_ver < '4.0.0'))
|
||||
if ( v.iterator != null ) v = v.iterator();
|
||||
#else
|
||||
try v = v.iterator() catch( e : Dynamic ) {};
|
||||
@@ -621,7 +633,7 @@ class Interp {
|
||||
switch( err ) {
|
||||
case SContinue:
|
||||
case SBreak: break;
|
||||
case SReturn(_): throw err;
|
||||
case SReturn: throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+33
-29
@@ -1,26 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Nicolas Cannasse
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
import hscript.Expr.Error;
|
||||
@@ -79,6 +76,9 @@ class Macro {
|
||||
#if haxe3
|
||||
case OpArrow: "=>";
|
||||
#end
|
||||
#if (haxe_ver >= 4)
|
||||
case OpIn: "in";
|
||||
#end
|
||||
};
|
||||
binops.set(str, op);
|
||||
if( assign )
|
||||
@@ -129,8 +129,10 @@ class Macro {
|
||||
TFunction(map(args,convertType), convertType(ret));
|
||||
case CTAnon(fields):
|
||||
var tf = [];
|
||||
for( f in fields )
|
||||
tf.push( { name : f.name, meta : [], doc : null, access : [], kind : FVar(convertType(f.t),null), pos : p } );
|
||||
for( f in fields ) {
|
||||
var meta = f.meta == null ? [] : [for( m in f.meta ) { name : m.name, params : m.params == null ? [] : [for( e in m.params ) convert(e)], pos : p }];
|
||||
tf.push( { name : f.name, meta : meta, doc : null, access : [], kind : FVar(convertType(f.t), null), pos : p } );
|
||||
}
|
||||
TAnonymous(tf);
|
||||
};
|
||||
}
|
||||
@@ -182,14 +184,16 @@ class Macro {
|
||||
EWhile(convert(c), convert(e), true);
|
||||
case EDoWhile(c, e):
|
||||
EWhile(convert(c), convert(e), false);
|
||||
#if (haxe_211 || haxe3)
|
||||
case EFor(v, it, efor):
|
||||
var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
|
||||
EFor({ expr : EIn({ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
|
||||
#else
|
||||
case EFor(v, it, e):
|
||||
EFor(v, convert(it), convert(e));
|
||||
#end
|
||||
#if (haxe_ver >= 4)
|
||||
var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
|
||||
EFor({ expr : EBinop(OpIn,{ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
|
||||
#elseif (haxe_211 || haxe3)
|
||||
var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
|
||||
EFor({ expr : EIn({ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
|
||||
#else
|
||||
EFor(v, convert(it), convert(efor));
|
||||
#end
|
||||
case EBreak:
|
||||
EBreak;
|
||||
case EContinue:
|
||||
|
||||
+493
-116
@@ -1,26 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Nicolas Cannasse
|
||||
* All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
import hscript.Expr;
|
||||
@@ -42,6 +39,7 @@ enum Token {
|
||||
TQuestion;
|
||||
TDoubleDot;
|
||||
TMeta( s : String );
|
||||
TPrepro( s : String );
|
||||
}
|
||||
|
||||
class Parser {
|
||||
@@ -60,6 +58,11 @@ class Parser {
|
||||
public var unops : Hash<Bool>; // true if allow postfix
|
||||
#end
|
||||
|
||||
/**
|
||||
allows to check for #if / #else in code
|
||||
**/
|
||||
public var preprocesorValues : Map<String,Dynamic> = new Map();
|
||||
|
||||
/**
|
||||
activate JSON compatiblity
|
||||
**/
|
||||
@@ -150,13 +153,9 @@ class Parser {
|
||||
error(EInvalidChar(c), readPos, readPos);
|
||||
}
|
||||
|
||||
public function parseString( s : String, ?origin : String = "hscript" ) {
|
||||
uid = 0;
|
||||
return parse( new haxe.io.StringInput(s), origin );
|
||||
}
|
||||
|
||||
public function parse( s : haxe.io.Input, ?origin : String = "hscript" ) {
|
||||
line = 1;
|
||||
function initParser( origin ) {
|
||||
// line=1 - don't reset line : it might be set manualy
|
||||
preprocStack = [];
|
||||
#if hscriptPos
|
||||
this.origin = origin;
|
||||
readPos = 0;
|
||||
@@ -169,19 +168,28 @@ class Parser {
|
||||
tokens = new haxe.FastList<Token>();
|
||||
#end
|
||||
char = -1;
|
||||
input = s;
|
||||
ops = new Array();
|
||||
idents = new Array();
|
||||
uid = 0;
|
||||
for( i in 0...opChars.length )
|
||||
ops[opChars.charCodeAt(i)] = true;
|
||||
for( i in 0...identChars.length )
|
||||
idents[identChars.charCodeAt(i)] = true;
|
||||
}
|
||||
|
||||
public function parseString( s : String, ?origin : String = "hscript" ) {
|
||||
return parse( new haxe.io.StringInput(s), origin );
|
||||
}
|
||||
|
||||
public function parse( s : haxe.io.Input, ?origin : String = "hscript" ) {
|
||||
initParser(origin);
|
||||
input = s;
|
||||
var a = new Array();
|
||||
while( true ) {
|
||||
var tk = token();
|
||||
if( tk == TEof ) break;
|
||||
push(tk);
|
||||
a.push(parseFullExpr());
|
||||
parseFullExpr(a);
|
||||
}
|
||||
return if( a.length == 1 ) a[0] else mk(EBlock(a),0);
|
||||
}
|
||||
@@ -206,6 +214,19 @@ class Parser {
|
||||
if( t != tk ) unexpected(t);
|
||||
}
|
||||
|
||||
inline function ensureToken(tk) {
|
||||
var t = token();
|
||||
if( !Type.enumEq(t,tk) ) unexpected(t);
|
||||
}
|
||||
|
||||
function maybe(tk) {
|
||||
var t = token();
|
||||
if( Type.enumEq(t, tk) )
|
||||
return true;
|
||||
push(t);
|
||||
return false;
|
||||
}
|
||||
|
||||
function getIdent() {
|
||||
var tk = token();
|
||||
switch( tk ) {
|
||||
@@ -255,7 +276,7 @@ class Parser {
|
||||
return switch( expr(e) ) {
|
||||
case EBlock(_), EObject(_), ESwitch(_): true;
|
||||
case EFunction(_,e,_,_): isBlock(e);
|
||||
case EVar(_,_,e): e != null && isBlock(e);
|
||||
case EVar(_, t, e): e != null ? isBlock(e) : t != null ? t.match(CTAnon(_)) : false;
|
||||
case EIf(_,e1,e2): if( e2 != null ) isBlock(e2) else isBlock(e1);
|
||||
case EBinop(_,_,e): isBlock(e);
|
||||
case EUnop(_,prefix,e): !prefix && isBlock(e);
|
||||
@@ -264,20 +285,29 @@ class Parser {
|
||||
case EFor(_,_,e): isBlock(e);
|
||||
case EReturn(e): e != null && isBlock(e);
|
||||
case ETry(_, _, _, e): isBlock(e);
|
||||
case EMeta(_, _, e): isBlock(e);
|
||||
default: false;
|
||||
}
|
||||
}
|
||||
|
||||
function parseFullExpr() {
|
||||
function parseFullExpr( exprs : Array<Expr> ) {
|
||||
var e = parseExpr();
|
||||
exprs.push(e);
|
||||
|
||||
var tk = token();
|
||||
// this is a hack to support var a,b,c; with a single EVar
|
||||
while( tk == TComma && expr(e).match(EVar(_)) ) {
|
||||
e = parseStructure("var"); // next variable
|
||||
exprs.push(e);
|
||||
tk = token();
|
||||
}
|
||||
|
||||
if( tk != TSemicolon && tk != TEof ) {
|
||||
if( isBlock(e) )
|
||||
push(tk);
|
||||
else
|
||||
unexpected(tk);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
function parseObject(p1) {
|
||||
@@ -367,7 +397,7 @@ class Parser {
|
||||
}
|
||||
var a = new Array();
|
||||
while( true ) {
|
||||
a.push(parseFullExpr());
|
||||
parseFullExpr(a);
|
||||
tk = token();
|
||||
if( tk == TBrClose )
|
||||
break;
|
||||
@@ -375,8 +405,19 @@ class Parser {
|
||||
}
|
||||
return mk(EBlock(a),p1);
|
||||
case TOp(op):
|
||||
if( unops.exists(op) )
|
||||
return makeUnop(op,parseExpr());
|
||||
if( unops.exists(op) ) {
|
||||
var start = tokenMin;
|
||||
var e = parseExpr();
|
||||
if( op == "-" )
|
||||
switch( expr(e) ) {
|
||||
case EConst(CInt(i)):
|
||||
return mk(EConst(CInt(-i)), start, pmax(e));
|
||||
case EConst(CFloat(f)):
|
||||
return mk(EConst(CFloat(-f)), start, pmax(e));
|
||||
default:
|
||||
}
|
||||
return makeUnop(op,e);
|
||||
}
|
||||
return unexpected(tk);
|
||||
case TBkOpen:
|
||||
var a = new Array();
|
||||
@@ -533,8 +574,7 @@ class Parser {
|
||||
case "for":
|
||||
ensure(TPOpen);
|
||||
var vname = getIdent();
|
||||
var tk = token();
|
||||
if( !Type.enumEq(tk,TId("in")) ) unexpected(tk);
|
||||
ensureToken(TId("in"));
|
||||
var eiter = parseExpr();
|
||||
ensure(TPClose);
|
||||
var e = parseExpr();
|
||||
@@ -542,6 +582,9 @@ class Parser {
|
||||
case "break": mk(EBreak);
|
||||
case "continue": mk(EContinue);
|
||||
case "else": unexpected(TId(id));
|
||||
case "inline":
|
||||
if( !maybe(TId("function")) ) unexpected(TId("inline"));
|
||||
return parseStructure("function");
|
||||
case "function":
|
||||
var tk = token();
|
||||
var name = null;
|
||||
@@ -549,51 +592,8 @@ class Parser {
|
||||
case TId(id): name = id;
|
||||
default: push(tk);
|
||||
}
|
||||
ensure(TPOpen);
|
||||
var args = new Array();
|
||||
tk = token();
|
||||
if( tk != TPClose ) {
|
||||
var done = false;
|
||||
while( !done ) {
|
||||
var name = null, opt = false;
|
||||
switch( tk ) {
|
||||
case TQuestion:
|
||||
opt = true;
|
||||
tk = token();
|
||||
default:
|
||||
}
|
||||
switch( tk ) {
|
||||
case TId(id): name = id;
|
||||
default: unexpected(tk);
|
||||
}
|
||||
tk = token();
|
||||
var arg : Argument = { name : name };
|
||||
args.push(arg);
|
||||
if( opt ) arg.opt = true;
|
||||
if( tk == TDoubleDot && allowTypes ) {
|
||||
arg.t = parseType();
|
||||
tk = token();
|
||||
}
|
||||
switch( tk ) {
|
||||
case TComma:
|
||||
tk = token();
|
||||
case TPClose:
|
||||
done = true;
|
||||
default:
|
||||
unexpected(tk);
|
||||
}
|
||||
}
|
||||
}
|
||||
var ret = null;
|
||||
if( allowTypes ) {
|
||||
tk = token();
|
||||
if( tk != TDoubleDot )
|
||||
push(tk);
|
||||
else
|
||||
ret = parseType();
|
||||
}
|
||||
var body = parseExpr();
|
||||
mk(EFunction(args, body, name, ret),p1,pmax(body));
|
||||
var inf = parseFunctionDecl();
|
||||
mk(EFunction(inf.args, inf.body, name, inf.ret),p1,pmax(inf.body));
|
||||
case "return":
|
||||
var tk = token();
|
||||
push(tk);
|
||||
@@ -621,18 +621,15 @@ class Parser {
|
||||
mk(EThrow(e),p1,pmax(e));
|
||||
case "try":
|
||||
var e = parseExpr();
|
||||
var tk = token();
|
||||
if( !Type.enumEq(tk, TId("catch")) ) unexpected(tk);
|
||||
ensureToken(TId("catch"));
|
||||
ensure(TPOpen);
|
||||
var vname = getIdent();
|
||||
ensure(TDoubleDot);
|
||||
var t = null;
|
||||
if( allowTypes )
|
||||
t = parseType();
|
||||
else {
|
||||
tk = token();
|
||||
if( !Type.enumEq(tk, TId("Dynamic")) ) unexpected(tk);
|
||||
}
|
||||
else
|
||||
ensureToken(TId("Dynamic"));
|
||||
ensure(TPClose);
|
||||
var ec = parseExpr();
|
||||
mk(ETry(e, vname, t, ec), p1, pmax(ec));
|
||||
@@ -667,7 +664,7 @@ class Parser {
|
||||
case TId("case"), TId("default"), TBrClose:
|
||||
break;
|
||||
default:
|
||||
exprs.push(parseFullExpr());
|
||||
parseFullExpr(exprs);
|
||||
}
|
||||
}
|
||||
c.expr = if( exprs.length == 1)
|
||||
@@ -687,7 +684,7 @@ class Parser {
|
||||
case TId("case"), TId("default"), TBrClose:
|
||||
break;
|
||||
default:
|
||||
exprs.push(parseFullExpr());
|
||||
parseFullExpr(exprs);
|
||||
}
|
||||
}
|
||||
def = if( exprs.length == 1)
|
||||
@@ -740,18 +737,76 @@ class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
function parseFunctionDecl() {
|
||||
ensure(TPOpen);
|
||||
var args = new Array();
|
||||
var tk = token();
|
||||
if( tk != TPClose ) {
|
||||
var done = false;
|
||||
while( !done ) {
|
||||
var name = null, opt = false;
|
||||
switch( tk ) {
|
||||
case TQuestion:
|
||||
opt = true;
|
||||
tk = token();
|
||||
default:
|
||||
}
|
||||
switch( tk ) {
|
||||
case TId(id): name = id;
|
||||
default: unexpected(tk);
|
||||
}
|
||||
var arg : Argument = { name : name };
|
||||
args.push(arg);
|
||||
if( opt ) arg.opt = true;
|
||||
if( allowTypes ) {
|
||||
if( maybe(TDoubleDot) )
|
||||
arg.t = parseType();
|
||||
if( maybe(TOp("=")) )
|
||||
arg.value = parseExpr();
|
||||
}
|
||||
tk = token();
|
||||
switch( tk ) {
|
||||
case TComma:
|
||||
tk = token();
|
||||
case TPClose:
|
||||
done = true;
|
||||
default:
|
||||
unexpected(tk);
|
||||
}
|
||||
}
|
||||
}
|
||||
var ret = null;
|
||||
if( allowTypes ) {
|
||||
tk = token();
|
||||
if( tk != TDoubleDot )
|
||||
push(tk);
|
||||
else
|
||||
ret = parseType();
|
||||
}
|
||||
return { args : args, ret : ret, body : parseExpr() };
|
||||
}
|
||||
|
||||
function parsePath() {
|
||||
var path = [getIdent()];
|
||||
while( true ) {
|
||||
var t = token();
|
||||
if( t != TDot ) {
|
||||
push(t);
|
||||
break;
|
||||
}
|
||||
path.push(getIdent());
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
function parseType() : CType {
|
||||
var t = token();
|
||||
switch( t ) {
|
||||
case TId(v):
|
||||
var path = [v];
|
||||
while( true ) {
|
||||
t = token();
|
||||
if( t != TDot )
|
||||
break;
|
||||
path.push(getIdent());
|
||||
}
|
||||
push(t);
|
||||
var path = parsePath();
|
||||
var params = null;
|
||||
t = token();
|
||||
switch( t ) {
|
||||
case TOp(op):
|
||||
if( op == "<" ) {
|
||||
@@ -861,6 +916,210 @@ class Parser {
|
||||
return args;
|
||||
}
|
||||
|
||||
// ------------------------ module -------------------------------
|
||||
|
||||
public function parseModule( content : String, ?origin : String = "hscript" ) {
|
||||
initParser(origin);
|
||||
this.input = new haxe.io.StringInput(content);
|
||||
allowTypes = true;
|
||||
allowMetadata = true;
|
||||
var decls = [];
|
||||
while( true ) {
|
||||
var tk = token();
|
||||
if( tk == TEof ) break;
|
||||
push(tk);
|
||||
decls.push(parseModuleDecl());
|
||||
}
|
||||
return decls;
|
||||
}
|
||||
|
||||
function parseMetadata() : Metadata {
|
||||
var meta = [];
|
||||
while( true ) {
|
||||
var tk = token();
|
||||
switch( tk ) {
|
||||
case TMeta(name):
|
||||
meta.push({ name : name, params : parseMetaArgs() });
|
||||
default:
|
||||
push(tk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
|
||||
function parseParams() {
|
||||
if( maybe(TOp("<")) )
|
||||
error(EInvalidOp("Unsupported class type parameters"), readPos, readPos);
|
||||
return {};
|
||||
}
|
||||
|
||||
function parseModuleDecl() : ModuleDecl {
|
||||
var meta = parseMetadata();
|
||||
var ident = getIdent();
|
||||
var isPrivate = false, isExtern = false;
|
||||
while( true ) {
|
||||
switch( ident ) {
|
||||
case "private":
|
||||
isPrivate = true;
|
||||
case "extern":
|
||||
isExtern = true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ident = getIdent();
|
||||
}
|
||||
switch( ident ) {
|
||||
case "package":
|
||||
var path = parsePath();
|
||||
ensure(TSemicolon);
|
||||
return DPackage(path);
|
||||
case "import":
|
||||
var path = [getIdent()];
|
||||
var star = false;
|
||||
while( true ) {
|
||||
var t = token();
|
||||
if( t != TDot ) {
|
||||
push(t);
|
||||
break;
|
||||
}
|
||||
t = token();
|
||||
switch( t ) {
|
||||
case TId(id):
|
||||
path.push(id);
|
||||
case TOp("*"):
|
||||
star = true;
|
||||
default:
|
||||
unexpected(t);
|
||||
}
|
||||
}
|
||||
ensure(TSemicolon);
|
||||
return DImport(path, star);
|
||||
case "class":
|
||||
var name = getIdent();
|
||||
var params = parseParams();
|
||||
var extend = null;
|
||||
var implement = [];
|
||||
|
||||
while( true ) {
|
||||
var t = token();
|
||||
switch( t ) {
|
||||
case TId("extends"):
|
||||
extend = parseType();
|
||||
case TId("implements"):
|
||||
implement.push(parseType());
|
||||
default:
|
||||
push(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var fields = [];
|
||||
ensure(TBrOpen);
|
||||
while( !maybe(TBrClose) )
|
||||
fields.push(parseField());
|
||||
|
||||
return DClass({
|
||||
name : name,
|
||||
meta : meta,
|
||||
params : params,
|
||||
extend : extend,
|
||||
implement : implement,
|
||||
fields : fields,
|
||||
isPrivate : isPrivate,
|
||||
isExtern : isExtern,
|
||||
});
|
||||
case "typedef":
|
||||
var name = getIdent();
|
||||
var params = parseParams();
|
||||
ensureToken(TOp("="));
|
||||
var t = parseType();
|
||||
return DTypedef({
|
||||
name : name,
|
||||
meta : meta,
|
||||
params : params,
|
||||
isPrivate : isPrivate,
|
||||
t : t,
|
||||
});
|
||||
default:
|
||||
unexpected(TId(ident));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function parseField() : FieldDecl {
|
||||
var meta = parseMetadata();
|
||||
var access = [];
|
||||
while( true ) {
|
||||
var id = getIdent();
|
||||
switch( id ) {
|
||||
case "override":
|
||||
access.push(AOverride);
|
||||
case "public":
|
||||
access.push(APublic);
|
||||
case "private":
|
||||
access.push(APrivate);
|
||||
case "inline":
|
||||
access.push(AInline);
|
||||
case "static":
|
||||
access.push(AStatic);
|
||||
case "macro":
|
||||
access.push(AMacro);
|
||||
case "function":
|
||||
var name = getIdent();
|
||||
var inf = parseFunctionDecl();
|
||||
return {
|
||||
name : name,
|
||||
meta : meta,
|
||||
access : access,
|
||||
kind : KFunction({
|
||||
args : inf.args,
|
||||
expr : inf.body,
|
||||
ret : inf.ret,
|
||||
}),
|
||||
};
|
||||
case "var":
|
||||
var name = getIdent();
|
||||
var get = null, set = null;
|
||||
if( maybe(TPOpen) ) {
|
||||
get = getIdent();
|
||||
ensure(TComma);
|
||||
set = getIdent();
|
||||
ensure(TPClose);
|
||||
}
|
||||
var type = maybe(TDoubleDot) ? parseType() : null;
|
||||
var expr = maybe(TOp("=")) ? parseExpr() : null;
|
||||
|
||||
if( expr != null ) {
|
||||
if( isBlock(expr) )
|
||||
maybe(TSemicolon);
|
||||
else
|
||||
ensure(TSemicolon);
|
||||
} else if( type != null && type.match(CTAnon(_)) ) {
|
||||
maybe(TSemicolon);
|
||||
} else
|
||||
ensure(TSemicolon);
|
||||
|
||||
return {
|
||||
name : name,
|
||||
meta : meta,
|
||||
access : access,
|
||||
kind : KVar({
|
||||
get : get,
|
||||
set : set,
|
||||
type : type,
|
||||
expr : expr,
|
||||
}),
|
||||
};
|
||||
default:
|
||||
unexpected(TId(id));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// ------------------------ lexing -------------------------------
|
||||
|
||||
inline function incPos() {
|
||||
#if hscriptPos
|
||||
readPos++;
|
||||
@@ -998,10 +1257,27 @@ class Parser {
|
||||
switch( char ) {
|
||||
case 48,49,50,51,52,53,54,55,56,57:
|
||||
n = n * 10 + (char - 48);
|
||||
case 46:
|
||||
case "e".code, "E".code:
|
||||
var tk = token();
|
||||
var pow : Null<Int> = null;
|
||||
switch( tk ) {
|
||||
case TConst(CInt(e)): pow = e;
|
||||
case TOp("-"):
|
||||
tk = token();
|
||||
switch( tk ) {
|
||||
case TConst(CInt(e)): pow = -e;
|
||||
default: push(tk);
|
||||
}
|
||||
default:
|
||||
push(tk);
|
||||
}
|
||||
if( pow == null )
|
||||
invalidChar(char);
|
||||
return TConst(CFloat((Math.pow(10, pow) / exp) * n * 10));
|
||||
case ".".code:
|
||||
if( exp > 0 ) {
|
||||
// in case of '...'
|
||||
if( exp == 10 && readChar() == 46 ) {
|
||||
// in case of '0...'
|
||||
if( exp == 10 && readChar() == ".".code ) {
|
||||
push(TOp("..."));
|
||||
var i = Std.int(n);
|
||||
return TConst( (i == n) ? CInt(i) : CFloat(n) );
|
||||
@@ -1009,7 +1285,7 @@ class Parser {
|
||||
invalidChar(char);
|
||||
}
|
||||
exp = 1.;
|
||||
case 120: // x
|
||||
case "x".code:
|
||||
if( n > 0 || exp > 0 )
|
||||
invalidChar(char);
|
||||
// read hexa
|
||||
@@ -1056,11 +1332,11 @@ class Parser {
|
||||
return TConst( (exp > 0) ? CFloat(n * 10 / exp) : ((i == n) ? CInt(i) : CFloat(n)) );
|
||||
}
|
||||
}
|
||||
case 59: return TSemicolon;
|
||||
case 40: return TPOpen;
|
||||
case 41: return TPClose;
|
||||
case 44: return TComma;
|
||||
case 46:
|
||||
case ";".code: return TSemicolon;
|
||||
case "(".code: return TPOpen;
|
||||
case ")".code: return TPClose;
|
||||
case ",".code: return TComma;
|
||||
case ".".code:
|
||||
char = readChar();
|
||||
switch( char ) {
|
||||
case 48,49,50,51,52,53,54,55,56,57:
|
||||
@@ -1077,23 +1353,22 @@ class Parser {
|
||||
return TConst( CFloat(n/exp) );
|
||||
}
|
||||
}
|
||||
case 46:
|
||||
case ".".code:
|
||||
char = readChar();
|
||||
if( char != 46 )
|
||||
if( char != ".".code )
|
||||
invalidChar(char);
|
||||
return TOp("...");
|
||||
default:
|
||||
this.char = char;
|
||||
return TDot;
|
||||
}
|
||||
case 123: return TBrOpen;
|
||||
case 125: return TBrClose;
|
||||
case 91: return TBkOpen;
|
||||
case 93: return TBkClose;
|
||||
case 39: return TConst( CString(readString(39)) );
|
||||
case 34: return TConst( CString(readString(34)) );
|
||||
case 63: return TQuestion;
|
||||
case 58: return TDoubleDot;
|
||||
case "{".code: return TBrOpen;
|
||||
case "}".code: return TBrClose;
|
||||
case "[".code: return TBkOpen;
|
||||
case "]".code: return TBkClose;
|
||||
case "'".code, '"'.code: return TConst( CString(readString(char)) );
|
||||
case "?".code: return TQuestion;
|
||||
case ":".code: return TDoubleDot;
|
||||
case '='.code:
|
||||
char = readChar();
|
||||
if( char == '='.code )
|
||||
@@ -1116,6 +1391,20 @@ class Parser {
|
||||
}
|
||||
}
|
||||
invalidChar(char);
|
||||
case '#'.code:
|
||||
char = readChar();
|
||||
if( idents[char] ) {
|
||||
var id = String.fromCharCode(char);
|
||||
while( true ) {
|
||||
char = readChar();
|
||||
if( !idents[char] ) {
|
||||
this.char = char;
|
||||
return preprocess(id);
|
||||
}
|
||||
id += String.fromCharCode(char);
|
||||
}
|
||||
}
|
||||
invalidChar(char);
|
||||
default:
|
||||
if( ops[char] ) {
|
||||
var op = String.fromCharCode(char);
|
||||
@@ -1150,6 +1439,93 @@ class Parser {
|
||||
return null;
|
||||
}
|
||||
|
||||
function preprocValue( id : String ) : Dynamic {
|
||||
return preprocesorValues.get(id);
|
||||
}
|
||||
|
||||
var preprocStack : Array<{ r : Bool }>;
|
||||
|
||||
function parsePreproCond() {
|
||||
var tk = token();
|
||||
return switch( tk ) {
|
||||
case TPOpen:
|
||||
push(TPOpen);
|
||||
parseExpr();
|
||||
case TId(id):
|
||||
mk(EIdent(id), tokenMin, tokenMax);
|
||||
case TOp("!"):
|
||||
mk(EUnop("!", true, parsePreproCond()), tokenMin, tokenMax);
|
||||
default:
|
||||
unexpected(tk);
|
||||
}
|
||||
}
|
||||
|
||||
function evalPreproCond( e : Expr ) {
|
||||
switch( expr(e) ) {
|
||||
case EIdent(id):
|
||||
return preprocValue(id) != null;
|
||||
case EUnop("!", _, e):
|
||||
return !evalPreproCond(e);
|
||||
case EParent(e):
|
||||
return evalPreproCond(e);
|
||||
case EBinop("&&", e1, e2):
|
||||
return evalPreproCond(e1) && evalPreproCond(e2);
|
||||
case EBinop("||", e1, e2):
|
||||
return evalPreproCond(e1) || evalPreproCond(e2);
|
||||
default:
|
||||
error(EInvalidPreprocessor("Can't eval " + expr(e).getName()), readPos, readPos);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function preprocess( id : String ) : Token {
|
||||
switch( id ) {
|
||||
case "if":
|
||||
var e = parsePreproCond();
|
||||
if( evalPreproCond(e) ) {
|
||||
preprocStack.push({ r : true });
|
||||
return token();
|
||||
}
|
||||
preprocStack.push({ r : false });
|
||||
skipTokens();
|
||||
return token();
|
||||
case "else", "elseif" if( preprocStack.length > 0 ):
|
||||
if( preprocStack[preprocStack.length - 1].r ) {
|
||||
preprocStack[preprocStack.length - 1].r = false;
|
||||
skipTokens();
|
||||
return token();
|
||||
} else if( id == "else" ) {
|
||||
preprocStack.pop();
|
||||
preprocStack.push({ r : true });
|
||||
return token();
|
||||
} else {
|
||||
// elseif
|
||||
preprocStack.pop();
|
||||
return preprocess("if");
|
||||
}
|
||||
case "end" if( preprocStack.length > 0 ):
|
||||
preprocStack.pop();
|
||||
return token();
|
||||
default:
|
||||
return TPrepro(id);
|
||||
}
|
||||
}
|
||||
|
||||
function skipTokens() {
|
||||
var spos = preprocStack.length - 1;
|
||||
var obj = preprocStack[spos];
|
||||
var pos = readPos;
|
||||
while( true ) {
|
||||
var tk = token();
|
||||
if( tk == TEof )
|
||||
error(EInvalidPreprocessor("Unclosed"), pos, pos);
|
||||
if( preprocStack[spos] != obj ) {
|
||||
push(tk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tokenComment( op : String, char : Int ) {
|
||||
var c = op.charCodeAt(1);
|
||||
var s = input;
|
||||
@@ -1221,6 +1597,7 @@ class Parser {
|
||||
case TQuestion: "?";
|
||||
case TDoubleDot: ":";
|
||||
case TMeta(id): "@" + id;
|
||||
case TPrepro(id): "#" + id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+64
-1
@@ -1,3 +1,24 @@
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
import hscript.Expr;
|
||||
|
||||
@@ -16,6 +37,13 @@ class Printer {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public function typeToString( t : CType ) {
|
||||
buf = new StringBuf();
|
||||
tabs = "";
|
||||
type(t);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
inline function add<T>(s:T) buf.add(s);
|
||||
|
||||
function type( t : CType ) {
|
||||
@@ -258,6 +286,20 @@ class Printer {
|
||||
add(";\n");
|
||||
}
|
||||
add("}");
|
||||
case EMeta(name, args, e):
|
||||
add("@");
|
||||
add(name);
|
||||
if( args != null && args.length > 0 ) {
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(e);
|
||||
}
|
||||
add(")");
|
||||
}
|
||||
add(" ");
|
||||
expr(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,4 +307,25 @@ class Printer {
|
||||
return new Printer().exprToString(e);
|
||||
}
|
||||
|
||||
}
|
||||
public static function errorToString( e : Expr.Error ) {
|
||||
var message = switch( #if hscriptPos e.e #else e #end ) {
|
||||
case EInvalidChar(c): "Invalid character: '"+String.fromCharCode(c)+"' ("+c+")";
|
||||
case EUnexpected(s): "Unexpected token: \""+s+"\"";
|
||||
case EUnterminatedString: "Unterminated string";
|
||||
case EUnterminatedComment: "Unterminated comment";
|
||||
case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")";
|
||||
case EUnknownVariable(v): "Unknown variable: "+v;
|
||||
case EInvalidIterator(v): "Invalid iterator: "+v;
|
||||
case EInvalidOp(op): "Invalid operator: "+op;
|
||||
case EInvalidAccess(f): "Invalid access to field " + f;
|
||||
case ECustom(msg): msg;
|
||||
};
|
||||
#if hscriptPos
|
||||
return e.origin + ":" + e.line + ": " + message;
|
||||
#else
|
||||
return message;
|
||||
#end
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+32
-3
@@ -1,10 +1,31 @@
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
import hscript.Expr;
|
||||
|
||||
class Tools {
|
||||
|
||||
public static function iter( e : Expr, f : Expr -> Void ) {
|
||||
switch( e ) {
|
||||
switch( #if hscriptPos e.e #else e #end ) {
|
||||
case EConst(_), EIdent(_):
|
||||
case EVar(_, _, e): if( e != null ) f(e);
|
||||
case EParent(e): f(e);
|
||||
@@ -34,12 +55,17 @@ class Tools {
|
||||
f(c.expr);
|
||||
}
|
||||
if( def != null ) f(def);
|
||||
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static function map( e : Expr, f : Expr -> Expr ) {
|
||||
#if hscriptPos
|
||||
var edef = switch( e.e ) {
|
||||
#else
|
||||
return switch( e ) {
|
||||
case EConst(_), EIdent(_): e;
|
||||
#end
|
||||
case EConst(_), EIdent(_), EBreak, EContinue: #if hscriptPos e.e #else e #end;
|
||||
case EVar(n, t, e): EVar(n, t, if( e != null ) f(e) else null);
|
||||
case EParent(e): EParent(f(e));
|
||||
case EBlock(el): EBlock([for( e in el ) f(e)]);
|
||||
@@ -51,7 +77,6 @@ class Tools {
|
||||
case EWhile(c, e): EWhile(f(c),f(e));
|
||||
case EDoWhile(c, e): EDoWhile(f(c),f(e));
|
||||
case EFor(v, it, e): EFor(v, f(it), f(e));
|
||||
case EBreak, EContinue: e;
|
||||
case EFunction(args, e, name, t): EFunction(args, f(e), name, t);
|
||||
case EReturn(e): EReturn(if( e != null ) f(e) else null);
|
||||
case EArray(e, i): EArray(f(e),f(i));
|
||||
@@ -62,7 +87,11 @@ class Tools {
|
||||
case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]);
|
||||
case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2));
|
||||
case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) { values : [for( v in c.values ) f(v)], expr : f(c.expr) } ], def == null ? null : f(def));
|
||||
case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e));
|
||||
}
|
||||
#if hscriptPos
|
||||
return { e : edef, pmin : e.pmin, pmax : e.pmax, origin : e.origin, line : e.line };
|
||||
#end
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user