Compare commits

..
1 Commits
Author SHA1 Message Date
Nicolas Cannasse 8b9b244512 fix overflow on bigint platforms (close #42) 2017-05-06 11:17:58 +02:00
17 changed files with 332 additions and 1429 deletions
+11 -9
View File
@@ -4,12 +4,10 @@ os:
- linux - linux
- osx - osx
sudo: false osx_image: xcode6.4
dist: trusty
haxe: haxe:
- "3.2.1" - "3.2.1"
- "3.4.2"
- development - development
addons: addons:
@@ -20,25 +18,30 @@ addons:
- g++-multilib - g++-multilib
# Python # Python
- python3 - python3
# PHP
- php5-cli
# C# # C#
- mono-devel - mono-devel
- mono-mcs - mono-mcs
# Flash # Flash
- libglib2.0 - libcurl3:i386
- libfreetype6 - libglib2.0-0:i386
- libx11-6:i386
- libxext6:i386
- libxt6:i386
- libxcursor1:i386
- libnss3:i386
- libgtk2.0-0:i386
install: install:
# os-specific config # os-specific config
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then
export DISPLAY=:99.0; export DISPLAY=:99.0;
export AUDIODEV=null; export AUDIODEV=null;
phpenv global 7.0;
elif [ "${TRAVIS_OS_NAME}" = "osx" ]; then elif [ "${TRAVIS_OS_NAME}" = "osx" ]; then
brew update; brew update;
brew install mono; brew install mono;
brew install python3; brew install python3;
brew tap homebrew/homebrew-php;
brew install php71;
fi fi
# Download and setup a standalone flash player debugger # Download and setup a standalone flash player debugger
- haxe flash/install.hxml - haxe flash/install.hxml
@@ -54,7 +57,6 @@ install:
fi fi
- haxelib install hxjava - haxelib install hxjava
- haxelib install hxcs - haxelib install hxcs
- haxelib install hx3compat
- haxelib dev hscript . - haxelib dev hscript .
- haxelib list - haxelib list
-22
View File
@@ -1,22 +0,0 @@
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.
-2
View File
@@ -64,8 +64,6 @@ 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.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. You can use `new hscript.Macro(pos).convert(ast)` to convert an hscript AST to a Haxe macros one.
Limitations Limitations
+4 -14
View File
@@ -1,9 +1,6 @@
import haxe.ds.EnumValueMap; import haxe.ds.EnumValueMap;
import haxe.ds.Option; import haxe.ds.Option;
import hscript.Macro; import hscript.Macro;
import hscript.Tools;
import hscript.Async;
import hscript.Printer;
import haxe.unit.*; import haxe.unit.*;
class Test extends TestCase { class Test extends TestCase {
@@ -24,15 +21,8 @@ class Test extends TestCase {
function test():Void { function test():Void {
assertScript("0",0); assertScript("0",0);
assertScript("0xFF", 255); assertScript("0xFF", 255);
#if !(php || python) assertScript("0xBFFFFFFF", 0xBFFFFFFF);
#if haxe3 assertScript("0x7FFFFFFF", 0x7FFFFFFF);
assertScript("0xBFFFFFFF", 0xBFFFFFFF);
assertScript("0x7FFFFFFF", 0x7FFFFFFF);
#elseif !neko
assertScript("n(0xBFFFFFFF)", 0xBFFFFFFF, { n : haxe.Int32.toNativeInt });
assertScript("n(0x7FFFFFFF)", 0x7FFFFFFF, { n : haxe.Int32.toNativeInt } );
#end
#end
assertScript("-123",-123); assertScript("-123",-123);
assertScript("- 123",-123); assertScript("- 123",-123);
assertScript("1.546",1.546); assertScript("1.546",1.546);
@@ -100,7 +90,7 @@ class Test extends TestCase {
assertScript("/**/0", 0); assertScript("/**/0", 0);
assertScript("x=1;x*=-2", -2); assertScript("x=1;x*=-2", -2);
} }
function testMap():Void { function testMap():Void {
var objKey = { ok:true }; var objKey = { ok:true };
var vars = { var vars = {
@@ -113,7 +103,7 @@ class Test extends TestCase {
stringIntMap: ["foo" => 100] stringIntMap: ["foo" => 100]
} }
vars.enumMap.set(vars.enumKey, "ok"); vars.enumMap.set(vars.enumKey, "ok");
assertScript('stringMap["foo"]', "Foo", vars); assertScript('stringMap["foo"]', "Foo", vars);
assertScript('intMap[100]', "one hundred", vars); assertScript('intMap[100]', "one hundred", vars);
assertScript('objMap[objKey]', "ok", vars); assertScript('objMap[objKey]', "ok", vars);
+5 -8
View File
@@ -6,22 +6,19 @@ environment:
install: install:
# Install the haxe chocolatey package (https://chocolatey.org/packages/haxe) # Install the haxe chocolatey package (https://chocolatey.org/packages/haxe)
- cinst haxe -version 3.4.2 -y - cinst haxe -version 3.2.1 -y
- RefreshEnv - RefreshEnv
# Setup haxelib # Setup haxelib
- mkdir "%HAXELIB_ROOT%" - mkdir "%HAXELIB_ROOT%"
- haxelib setup "%HAXELIB_ROOT%" - haxelib setup "%HAXELIB_ROOT%"
# Install test dependencies # Install test dependencies
- ps: Set-Service wuauserv -StartupType Manual
- cinst php -y - cinst php -y
- RefreshEnv
# Download and setup a standalone flash player debugger # Download and setup a standalone flash player debugger
- haxe flash/install.hxml - haxe flash/install.hxml
# Install project dependencies # Install project dependencies
- haxelib install hxcpp > 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 hxjava > log.txt || type log.txt && cmd /C exit 1
- haxelib install hxcs > 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 dev hscript .
- haxelib list - haxelib list
@@ -38,5 +35,5 @@ test_script:
- haxe bin/build-cs.hxml && bin\bin\Test.exe - haxe bin/build-cs.hxml && bin\bin\Test.exe
- haxe bin/build-cpp.hxml && bin\Test.exe - haxe bin/build-cpp.hxml && bin\Test.exe
- haxe bin/build-flash.hxml -D fdb && haxe flash\run.hxml bin\Test.swf - haxe bin/build-flash.hxml -D fdb && haxe flash\run.hxml bin\Test.swf
- haxe bin/build-php.hxml && php bin\index.php - haxe bin/build-php.hxml && C:\tools\php\php.exe bin\index.php
- haxe bin/build-python.hxml && C:\Python34-x64\python.exe bin\Test.py - haxe bin/build-python.hxml && C:\Python34-x64\python.exe bin\Test.py
-1
View File
@@ -1,3 +1,2 @@
-main Test -main Test
-dce no -dce no
-lib hx3compat
+4 -7
View File
@@ -7,11 +7,11 @@ class Install {
// https://www.adobe.com/support/flashplayer/downloads.html // https://www.adobe.com/support/flashplayer/downloads.html
static var fpDownload(default, never) = switch (systemName()) { static var fpDownload(default, never) = switch (systemName()) {
case "Linux": case "Linux":
"http://fpdownload.macromedia.com/pub/flashplayer/updaters/25/flash_player_sa_linux_debug.x86_64.tar.gz"; "https://fpdownload.macromedia.com/pub/flashplayer/updaters/11/flashplayer_11_sa_debug.i386.tar.gz";
case "Mac": case "Mac":
"http://fpdownload.macromedia.com/pub/flashplayer/updaters/25/flashplayer_25_sa_debug.dmg"; "https://fpdownload.macromedia.com/pub/flashplayer/updaters/21/flashplayer_21_sa_debug.dmg";
case "Windows": case "Windows":
"http://fpdownload.macromedia.com/pub/flashplayer/updaters/25/flashplayer_25_sa_debug.exe"; "http://fpdownload.macromedia.com/pub/flashplayer/updaters/21/flashplayer_21_sa_debug.exe";
case _: case _:
throw "unsupported system"; throw "unsupported system";
} }
@@ -46,9 +46,6 @@ class Install {
if (command("tar", ["-xf", Path.withoutDirectory(fpDownload), "-C", "flash"]) != 0) if (command("tar", ["-xf", Path.withoutDirectory(fpDownload), "-C", "flash"]) != 0)
throw "failed to extract flash player"; throw "failed to extract flash player";
case "Mac": case "Mac":
// https://github.com/caskroom/homebrew-cask/pull/15381
if (command("brew", ["uninstall", "--force", "brew-cask"]) != 0)
throw "failed to brew uninstall --force brew-cask";
if (command("brew", ["tap", "caskroom/versions"]) != 0) if (command("brew", ["tap", "caskroom/versions"]) != 0)
throw "failed to brew tap caskroom/versions"; throw "failed to brew tap caskroom/versions";
if (command("brew", ["cask", "install", "flash-player-debugger"]) != 0) if (command("brew", ["cask", "install", "flash-player-debugger"]) != 0)
@@ -87,7 +84,7 @@ class Install {
if (command("sudo", ["chmod", "a+rw", dir]) != 0) if (command("sudo", ["chmod", "a+rw", dir]) != 0)
throw 'cannot set permission of $dir'; throw 'cannot set permission of $dir';
case _: case _:
throw 'cannot create $dir: $e'; neko.Lib.rethrow(e);
} }
} }
} }
+3 -4
View File
@@ -21,13 +21,12 @@ class Run {
var exitCode = switch (systemName()) { var exitCode = switch (systemName()) {
case "Linux": case "Linux":
// The flash player has some issues with unexplained crashes, // The flash player has some issues with unexplained crashes,
// but if it runs about 16 times, it should succeed one of those... // but if it runs about 8 times, it should succeed one of those...
var c = -1; var c = -1;
for (i in 0...16) { for (i in 0...8) {
if ((c = command("xvfb-run", ["-a", "flash/flashplayerdebugger", swf])) == 0) if ((c = command("xvfb-run", ["flash/flashplayerdebugger", swf])) == 0)
break; break;
println('retry... (${i+1})'); println('retry... (${i+1})');
sleep(1.5);
} }
c; c;
case "Mac": case "Mac":
+2 -2
View File
@@ -3,7 +3,7 @@
"url": "https://github.com/HaxeFoundation/hscript", "url": "https://github.com/HaxeFoundation/hscript",
"license": "MIT", "license": "MIT",
"description": "Haxe Script is a scripting engine for a subset of the Haxe language", "description": "Haxe Script is a scripting engine for a subset of the Haxe language",
"version": "2.2.0", "version": "2.0.7",
"releasenote": "", "releasenote": "fixes for haxe 3.3, use property access by default",
"contributors": ["ncannasse"] "contributors": ["ncannasse"]
} }
-494
View File
@@ -1,494 +0,0 @@
/*
* 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);
}
}
+20 -27
View File
@@ -1,23 +1,26 @@
/* /*
* Copyright (C)2008-2017 Haxe Foundation * 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:
* *
* Permission is hereby granted, free of charge, to any person obtaining a * - Redistributions of source code must retain the above copyright
* copy of this software and associated documentation files (the "Software"), * notice, this list of conditions and the following disclaimer.
* to deal in the Software without restriction, including without limitation * - Redistributions in binary form must reproduce the above copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice, this list of conditions and the following disclaimer in the
* and/or sell copies of the Software, and to permit persons to whom the * documentation and/or other materials provided with the distribution.
* Software is furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
* all copies or substantial portions of the Software. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* DEALINGS IN THE SOFTWARE. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/ */
package hscript; package hscript;
import hscript.Expr; import hscript.Expr;
@@ -244,11 +247,6 @@ class Bytes {
} }
bout.addByte(255); bout.addByte(255);
if( def == null ) bout.addByte(255) else doEncode(def); 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);
} }
} }
@@ -368,11 +366,6 @@ class Bytes {
case 24: case 24:
var cond = doDecode(); var cond = doDecode();
EDoWhile(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: case 255:
null; null;
default: default:
+54 -85
View File
@@ -1,23 +1,26 @@
/* /*
* Copyright (C)2008-2017 Haxe Foundation * 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:
* *
* Permission is hereby granted, free of charge, to any person obtaining a * - Redistributions of source code must retain the above copyright
* copy of this software and associated documentation files (the "Software"), * notice, this list of conditions and the following disclaimer.
* to deal in the Software without restriction, including without limitation * - Redistributions in binary form must reproduce the above copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice, this list of conditions and the following disclaimer in the
* and/or sell copies of the Software, and to permit persons to whom the * documentation and/or other materials provided with the distribution.
* Software is furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
* all copies or substantial portions of the Software. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* DEALINGS IN THE SOFTWARE. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/ */
package hscript; package hscript;
@@ -67,17 +70,14 @@ enum Expr {
ETernary( cond : Expr, e1 : Expr, e2 : Expr ); ETernary( cond : Expr, e1 : Expr, e2 : Expr );
ESwitch( e : Expr, cases : Array<{ values : Array<Expr>, expr : Expr }>, ?defaultExpr : Expr); ESwitch( e : Expr, cases : Array<{ values : Array<Expr>, expr : Expr }>, ?defaultExpr : Expr);
EDoWhile( cond : Expr, e : Expr); EDoWhile( cond : Expr, e : Expr);
EMeta( name : String, args : Array<Expr>, e : Expr );
} }
typedef Argument = { name : String, ?t : CType, ?opt : Bool, ?value : Expr }; typedef Argument = { name : String, ?t : CType, ?opt : Bool };
typedef Metadata = Array<{ name : String, params : Array<Expr> }>;
enum CType { enum CType {
CTPath( path : Array<String>, ?params : Array<CType> ); CTPath( path : Array<String>, ?params : Array<CType> );
CTFun( args : Array<CType>, ret : CType ); CTFun( args : Array<CType>, ret : CType );
CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> ); CTAnon( fields : Array<{ name : String, t : CType }> );
CTParent( t : CType ); CTParent( t : CType );
} }
@@ -95,8 +95,39 @@ class Error {
this.origin = origin; this.origin = origin;
this.line = line; this.line = line;
} }
private function errorDefToString(): String {
switch (e) {
case EInvalidChar(c):
return "Invalid character: '"+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 { public function toString(): String {
return Printer.errorToString(this); var message = errorDefToString();
message = origin + ":" + line + ": " + message;
return message;
} }
} }
enum ErrorDef { enum ErrorDef {
@@ -107,70 +138,8 @@ enum Error {
EUnexpected( s : String ); EUnexpected( s : String );
EUnterminatedString; EUnterminatedString;
EUnterminatedComment; EUnterminatedComment;
EInvalidPreprocessor( msg : String );
EUnknownVariable( v : String ); EUnknownVariable( v : String );
EInvalidIterator( v : String ); EInvalidIterator( v : String );
EInvalidOp( op : String ); EInvalidOp( op : String );
EInvalidAccess( f : 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>;
} }
+35 -49
View File
@@ -1,23 +1,26 @@
/* /*
* Copyright (C)2008-2017 Haxe Foundation * 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:
* *
* Permission is hereby granted, free of charge, to any person obtaining a * - Redistributions of source code must retain the above copyright
* copy of this software and associated documentation files (the "Software"), * notice, this list of conditions and the following disclaimer.
* to deal in the Software without restriction, including without limitation * - Redistributions in binary form must reproduce the above copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice, this list of conditions and the following disclaimer in the
* and/or sell copies of the Software, and to permit persons to whom the * documentation and/or other materials provided with the distribution.
* Software is furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
* all copies or substantial portions of the Software. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* DEALINGS IN THE SOFTWARE. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/ */
package hscript; package hscript;
import haxe.PosInfos; import haxe.PosInfos;
@@ -26,7 +29,7 @@ import hscript.Expr;
private enum Stop { private enum Stop {
SBreak; SBreak;
SContinue; SContinue;
SReturn; SReturn( v : Dynamic );
} }
class Interp { class Interp {
@@ -44,7 +47,6 @@ class Interp {
var depth : Int; var depth : Int;
var inTry : Bool; var inTry : Bool;
var declared : Array<{ n : String, old : { r : Dynamic } }>; var declared : Array<{ n : String, old : { r : Dynamic } }>;
var returnValue : Dynamic;
#if hscriptPos #if hscriptPos
var curExpr : Expr; var curExpr : Expr;
@@ -62,12 +64,7 @@ class Interp {
variables.set("null",null); variables.set("null",null);
variables.set("true",true); variables.set("true",true);
variables.set("false",false); variables.set("false",false);
variables.set("trace", Reflect.makeVarArgs(function(el) { variables.set("trace",function(e) haxe.Log.trace(Std.string(e), posInfos()));
var inf = posInfos();
var v = el.shift();
if( el.length > 0 ) inf.customParams = el;
haxe.Log.trace(Std.string(v), inf);
}));
initOps(); initOps();
} }
@@ -140,7 +137,7 @@ class Interp {
else { else {
arr[index] = v; arr[index] = v;
} }
default: default:
error(EInvalidOp("=")); error(EInvalidOp("="));
} }
@@ -253,10 +250,7 @@ class Interp {
switch( e ) { switch( e ) {
case SBreak: throw "Invalid break"; case SBreak: throw "Invalid break";
case SContinue: throw "Invalid continue"; case SContinue: throw "Invalid continue";
case SReturn: case SReturn(v): return v;
var v = returnValue;
returnValue = null;
return v;
} }
} }
return null; return null;
@@ -288,18 +282,13 @@ class Interp {
#end #end
} }
inline function error(e : #if hscriptPos ErrorDef #else Error #end, rethrow=false ) : Dynamic { inline function error(e : #if hscriptPos ErrorDef #else Error #end ) : Dynamic {
#if hscriptPos var e = new Error(e, curExpr.pmin, curExpr.pmax, curExpr.origin, curExpr.line); #end #if hscriptPos
if( rethrow ) this.rethrow(e) else throw e; throw new Error(e, curExpr.pmin, curExpr.pmax, curExpr.origin, curExpr.line);
return null;
}
inline function rethrow( e : Dynamic ) {
#if hl
hl.Api.rethrow(e);
#else #else
throw e; throw e;
#end #end
return null;
} }
function resolve( id : String ) : Dynamic { function resolve( id : String ) : Dynamic {
@@ -396,8 +385,7 @@ class Interp {
case EContinue: case EContinue:
throw SContinue; throw SContinue;
case EReturn(e): case EReturn(e):
returnValue = e == null ? null : expr(e); throw SReturn((e == null)?null:expr(e));
throw SReturn;
case EFunction(params,fexpr,name,_): case EFunction(params,fexpr,name,_):
var capturedLocals = duplicate(locals); var capturedLocals = duplicate(locals);
var me = this; var me = this;
@@ -572,8 +560,6 @@ class Interp {
if( !match ) if( !match )
val = def == null ? null : expr(def); val = def == null ? null : expr(def);
return val; return val;
case EMeta(_, _, e):
return expr(e);
} }
return null; return null;
} }
@@ -587,7 +573,7 @@ class Interp {
switch(err) { switch(err) {
case SContinue: case SContinue:
case SBreak: break; case SBreak: break;
case SReturn: throw err; case SReturn(_): throw err;
} }
} }
} }
@@ -604,7 +590,7 @@ class Interp {
switch(err) { switch(err) {
case SContinue: case SContinue:
case SBreak: break; case SBreak: break;
case SReturn: throw err; case SReturn(_): throw err;
} }
} }
} }
@@ -612,7 +598,7 @@ class Interp {
} }
function makeIterator( v : Dynamic ) : Iterator<Dynamic> { function makeIterator( v : Dynamic ) : Iterator<Dynamic> {
#if ((flash && !flash9) || (php && !php7 && haxe_ver < '4.0.0')) #if ((flash && !flash9) || php)
if ( v.iterator != null ) v = v.iterator(); if ( v.iterator != null ) v = v.iterator();
#else #else
try v = v.iterator() catch( e : Dynamic ) {}; try v = v.iterator() catch( e : Dynamic ) {};
@@ -633,7 +619,7 @@ class Interp {
switch( err ) { switch( err ) {
case SContinue: case SContinue:
case SBreak: break; case SBreak: break;
case SReturn: throw err; case SReturn(_): throw err;
} }
} }
} }
@@ -643,7 +629,7 @@ class Interp {
inline function isMap(o:Dynamic):Bool { inline function isMap(o:Dynamic):Bool {
return Std.is(o, haxe.Constraints.IMap); return Std.is(o, haxe.Constraints.IMap);
} }
inline function getMapValue(map:Dynamic, key:Dynamic):Dynamic { inline function getMapValue(map:Dynamic, key:Dynamic):Dynamic {
return cast(map, haxe.Constraints.IMap<Dynamic, Dynamic>).get(key); return cast(map, haxe.Constraints.IMap<Dynamic, Dynamic>).get(key);
} }
@@ -651,7 +637,7 @@ class Interp {
inline function setMapValue(map:Dynamic, key:Dynamic, value:Dynamic):Void { inline function setMapValue(map:Dynamic, key:Dynamic, value:Dynamic):Void {
cast(map, haxe.Constraints.IMap<Dynamic, Dynamic>).set(key, value); cast(map, haxe.Constraints.IMap<Dynamic, Dynamic>).set(key, value);
} }
function get( o : Dynamic, f : String ) : Dynamic { function get( o : Dynamic, f : String ) : Dynamic {
if ( o == null ) error(EInvalidAccess(f)); if ( o == null ) error(EInvalidAccess(f));
return { return {
+29 -36
View File
@@ -1,23 +1,26 @@
/* /*
* Copyright (C)2008-2017 Haxe Foundation * 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:
* *
* Permission is hereby granted, free of charge, to any person obtaining a * - Redistributions of source code must retain the above copyright
* copy of this software and associated documentation files (the "Software"), * notice, this list of conditions and the following disclaimer.
* to deal in the Software without restriction, including without limitation * - Redistributions in binary form must reproduce the above copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice, this list of conditions and the following disclaimer in the
* and/or sell copies of the Software, and to permit persons to whom the * documentation and/or other materials provided with the distribution.
* Software is furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
* all copies or substantial portions of the Software. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* DEALINGS IN THE SOFTWARE. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/ */
package hscript; package hscript;
import hscript.Expr.Error; import hscript.Expr.Error;
@@ -76,9 +79,6 @@ class Macro {
#if haxe3 #if haxe3
case OpArrow: "=>"; case OpArrow: "=>";
#end #end
#if (haxe_ver >= 4)
case OpIn: "in";
#end
}; };
binops.set(str, op); binops.set(str, op);
if( assign ) if( assign )
@@ -129,10 +129,8 @@ class Macro {
TFunction(map(args,convertType), convertType(ret)); TFunction(map(args,convertType), convertType(ret));
case CTAnon(fields): case CTAnon(fields):
var tf = []; var tf = [];
for( f in fields ) { 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 : [], doc : null, access : [], kind : FVar(convertType(f.t),null), pos : p } );
tf.push( { name : f.name, meta : meta, doc : null, access : [], kind : FVar(convertType(f.t), null), pos : p } );
}
TAnonymous(tf); TAnonymous(tf);
}; };
} }
@@ -184,16 +182,14 @@ class Macro {
EWhile(convert(c), convert(e), true); EWhile(convert(c), convert(e), true);
case EDoWhile(c, e): case EDoWhile(c, e):
EWhile(convert(c), convert(e), false); EWhile(convert(c), convert(e), false);
#if (haxe_211 || haxe3)
case EFor(v, it, efor): case EFor(v, it, efor):
#if (haxe_ver >= 4) var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
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));
EFor({ expr : EBinop(OpIn,{ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor)); #else
#elseif (haxe_211 || haxe3) case EFor(v, it, e):
var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end; EFor(v, convert(it), convert(e));
EFor({ expr : EIn({ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor)); #end
#else
EFor(v, convert(it), convert(efor));
#end
case EBreak: case EBreak:
EBreak; EBreak;
case EContinue: case EContinue:
@@ -235,9 +231,6 @@ class Macro {
ETernary(convert(cond), convert(e1), convert(e2)); ETernary(convert(cond), convert(e1), convert(e2));
case ESwitch(e, cases, edef): case ESwitch(e, cases, edef):
ESwitch(convert(e), [for( c in cases ) { values : [for( v in c.values ) convert(v)], expr : convert(c.expr) } ], edef == null ? null : convert(edef)); ESwitch(convert(e), [for( c in cases ) { values : [for( v in c.values ) convert(v)], expr : convert(c.expr) } ], edef == null ? null : convert(edef));
case EMeta(m, params, esub):
var mpos = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
EMeta({ name : m, params : params == null ? [] : [for( p in params ) convert(p)], pos : mpos }, convert(esub));
}, pos : #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end } }, pos : #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end }
} }
+161 -573
View File
@@ -1,23 +1,26 @@
/* /*
* Copyright (C)2008-2017 Haxe Foundation * 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:
* *
* Permission is hereby granted, free of charge, to any person obtaining a * - Redistributions of source code must retain the above copyright
* copy of this software and associated documentation files (the "Software"), * notice, this list of conditions and the following disclaimer.
* to deal in the Software without restriction, including without limitation * - Redistributions in binary form must reproduce the above copyright
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * notice, this list of conditions and the following disclaimer in the
* and/or sell copies of the Software, and to permit persons to whom the * documentation and/or other materials provided with the distribution.
* Software is furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
* all copies or substantial portions of the Software. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* DEALINGS IN THE SOFTWARE. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/ */
package hscript; package hscript;
import hscript.Expr; import hscript.Expr;
@@ -38,8 +41,6 @@ enum Token {
TBkClose; TBkClose;
TQuestion; TQuestion;
TDoubleDot; TDoubleDot;
TMeta( s : String );
TPrepro( s : String );
} }
class Parser { class Parser {
@@ -58,11 +59,6 @@ class Parser {
public var unops : Hash<Bool>; // true if allow postfix public var unops : Hash<Bool>; // true if allow postfix
#end #end
/**
allows to check for #if / #else in code
**/
public var preprocesorValues : Map<String,Dynamic> = new Map();
/** /**
activate JSON compatiblity activate JSON compatiblity
**/ **/
@@ -73,11 +69,6 @@ class Parser {
**/ **/
public var allowTypes : Bool; public var allowTypes : Bool;
/**
allow haxe metadata declarations
**/
public var allowMetadata : Bool;
// implementation // implementation
var input : haxe.io.Input; var input : haxe.io.Input;
var char : Int; var char : Int;
@@ -153,9 +144,13 @@ class Parser {
error(EInvalidChar(c), readPos, readPos); error(EInvalidChar(c), readPos, readPos);
} }
function initParser( origin ) { public function parseString( s : String, ?origin : String = "hscript" ) {
// line=1 - don't reset line : it might be set manualy uid = 0;
preprocStack = []; return parse( new haxe.io.StringInput(s), origin );
}
public function parse( s : haxe.io.Input, ?origin : String = "hscript" ) {
line = 1;
#if hscriptPos #if hscriptPos
this.origin = origin; this.origin = origin;
readPos = 0; readPos = 0;
@@ -168,28 +163,19 @@ class Parser {
tokens = new haxe.FastList<Token>(); tokens = new haxe.FastList<Token>();
#end #end
char = -1; char = -1;
input = s;
ops = new Array(); ops = new Array();
idents = new Array(); idents = new Array();
uid = 0;
for( i in 0...opChars.length ) for( i in 0...opChars.length )
ops[opChars.charCodeAt(i)] = true; ops[opChars.charCodeAt(i)] = true;
for( i in 0...identChars.length ) for( i in 0...identChars.length )
idents[identChars.charCodeAt(i)] = true; 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(); var a = new Array();
while( true ) { while( true ) {
var tk = token(); var tk = token();
if( tk == TEof ) break; if( tk == TEof ) break;
push(tk); push(tk);
parseFullExpr(a); a.push(parseFullExpr());
} }
return if( a.length == 1 ) a[0] else mk(EBlock(a),0); return if( a.length == 1 ) a[0] else mk(EBlock(a),0);
} }
@@ -214,29 +200,6 @@ class Parser {
if( t != tk ) unexpected(t); 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 ) {
case TId(id): return id;
default:
unexpected(tk);
return null;
}
}
inline function expr(e:Expr) { inline function expr(e:Expr) {
#if hscriptPos #if hscriptPos
return e.e; return e.e;
@@ -276,7 +239,7 @@ class Parser {
return switch( expr(e) ) { return switch( expr(e) ) {
case EBlock(_), EObject(_), ESwitch(_): true; case EBlock(_), EObject(_), ESwitch(_): true;
case EFunction(_,e,_,_): isBlock(e); case EFunction(_,e,_,_): isBlock(e);
case EVar(_, t, e): e != null ? isBlock(e) : t != null ? t.match(CTAnon(_)) : false; case EVar(_,_,e): e != null && isBlock(e);
case EIf(_,e1,e2): if( e2 != null ) isBlock(e2) else isBlock(e1); case EIf(_,e1,e2): if( e2 != null ) isBlock(e2) else isBlock(e1);
case EBinop(_,_,e): isBlock(e); case EBinop(_,_,e): isBlock(e);
case EUnop(_,prefix,e): !prefix && isBlock(e); case EUnop(_,prefix,e): !prefix && isBlock(e);
@@ -285,29 +248,20 @@ class Parser {
case EFor(_,_,e): isBlock(e); case EFor(_,_,e): isBlock(e);
case EReturn(e): e != null && isBlock(e); case EReturn(e): e != null && isBlock(e);
case ETry(_, _, _, e): isBlock(e); case ETry(_, _, _, e): isBlock(e);
case EMeta(_, _, e): isBlock(e);
default: false; default: false;
} }
} }
function parseFullExpr( exprs : Array<Expr> ) { function parseFullExpr() {
var e = parseExpr(); var e = parseExpr();
exprs.push(e);
var tk = token(); 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( tk != TSemicolon && tk != TEof ) {
if( isBlock(e) ) if( isBlock(e) )
push(tk); push(tk);
else else
unexpected(tk); unexpected(tk);
} }
return e;
} }
function parseObject(p1) { function parseObject(p1) {
@@ -397,7 +351,7 @@ class Parser {
} }
var a = new Array(); var a = new Array();
while( true ) { while( true ) {
parseFullExpr(a); a.push(parseFullExpr());
tk = token(); tk = token();
if( tk == TBrClose ) if( tk == TBrClose )
break; break;
@@ -405,19 +359,8 @@ class Parser {
} }
return mk(EBlock(a),p1); return mk(EBlock(a),p1);
case TOp(op): case TOp(op):
if( unops.exists(op) ) { if( unops.exists(op) )
var start = tokenMin; return makeUnop(op,parseExpr());
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); return unexpected(tk);
case TBkOpen: case TBkOpen:
var a = new Array(); var a = new Array();
@@ -441,39 +384,12 @@ class Parser {
return parseExprNext(e); return parseExprNext(e);
default: default:
} }
return parseExprNext(mk(EArrayDecl(a), p1)); return parseExprNext(mk(EArrayDecl(a),p1));
case TMeta(id) if( allowMetadata ):
var args = parseMetaArgs();
return mk(EMeta(id, args, parseExpr()),p1);
default: default:
return unexpected(tk); return unexpected(tk);
} }
} }
function parseMetaArgs() {
var tk = token();
if( tk != TPOpen ) {
push(tk);
return null;
}
var args = [];
tk = token();
if( tk != TPClose ) {
push(tk);
while( true ) {
args.push(parseExpr());
switch( token() ) {
case TComma:
case TPClose:
break;
case tk:
unexpected(tk);
}
}
}
return args;
}
function mapCompr( tmp : String, e : Expr ) { function mapCompr( tmp : String, e : Expr ) {
var edef = switch( expr(e) ) { var edef = switch( expr(e) ) {
case EFor(v, it, e2): case EFor(v, it, e2):
@@ -544,8 +460,13 @@ class Parser {
} }
mk(EIf(cond,e1,e2),p1,(e2 == null) ? tokenMax : pmax(e2)); mk(EIf(cond,e1,e2),p1,(e2 == null) ? tokenMax : pmax(e2));
case "var": case "var":
var ident = getIdent();
var tk = token(); var tk = token();
var ident = null;
switch(tk) {
case TId(id): ident = id;
default: unexpected(tk);
}
tk = token();
var t = null; var t = null;
if( tk == TDoubleDot && allowTypes ) { if( tk == TDoubleDot && allowTypes ) {
t = parseType(); t = parseType();
@@ -573,8 +494,14 @@ class Parser {
mk(EDoWhile(econd,e),p1,pmax(econd)); mk(EDoWhile(econd,e),p1,pmax(econd));
case "for": case "for":
ensure(TPOpen); ensure(TPOpen);
var vname = getIdent(); var tk = token();
ensureToken(TId("in")); var vname = null;
switch( tk ) {
case TId(id): vname = id;
default: unexpected(tk);
}
tk = token();
if( !Type.enumEq(tk,TId("in")) ) unexpected(tk);
var eiter = parseExpr(); var eiter = parseExpr();
ensure(TPClose); ensure(TPClose);
var e = parseExpr(); var e = parseExpr();
@@ -582,9 +509,6 @@ class Parser {
case "break": mk(EBreak); case "break": mk(EBreak);
case "continue": mk(EContinue); case "continue": mk(EContinue);
case "else": unexpected(TId(id)); case "else": unexpected(TId(id));
case "inline":
if( !maybe(TId("function")) ) unexpected(TId("inline"));
return parseStructure("function");
case "function": case "function":
var tk = token(); var tk = token();
var name = null; var name = null;
@@ -592,8 +516,51 @@ class Parser {
case TId(id): name = id; case TId(id): name = id;
default: push(tk); default: push(tk);
} }
var inf = parseFunctionDecl(); ensure(TPOpen);
mk(EFunction(inf.args, inf.body, name, inf.ret),p1,pmax(inf.body)); 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));
case "return": case "return":
var tk = token(); var tk = token();
push(tk); push(tk);
@@ -601,13 +568,21 @@ class Parser {
mk(EReturn(e),p1,if( e == null ) tokenMax else pmax(e)); mk(EReturn(e),p1,if( e == null ) tokenMax else pmax(e));
case "new": case "new":
var a = new Array(); var a = new Array();
a.push(getIdent()); var tk = token();
switch( tk ) {
case TId(id): a.push(id);
default: unexpected(tk);
}
var next = true; var next = true;
while( next ) { while( next ) {
var tk = token(); tk = token();
switch( tk ) { switch( tk ) {
case TDot: case TDot:
a.push(getIdent()); tk = token();
switch(tk) {
case TId(id): a.push(id);
default: unexpected(tk);
}
case TPOpen: case TPOpen:
next = false; next = false;
default: default:
@@ -621,15 +596,22 @@ class Parser {
mk(EThrow(e),p1,pmax(e)); mk(EThrow(e),p1,pmax(e));
case "try": case "try":
var e = parseExpr(); var e = parseExpr();
ensureToken(TId("catch")); var tk = token();
if( !Type.enumEq(tk, TId("catch")) ) unexpected(tk);
ensure(TPOpen); ensure(TPOpen);
var vname = getIdent(); tk = token();
var vname = switch( tk ) {
case TId(id): id;
default: unexpected(tk);
}
ensure(TDoubleDot); ensure(TDoubleDot);
var t = null; var t = null;
if( allowTypes ) if( allowTypes )
t = parseType(); t = parseType();
else else {
ensureToken(TId("Dynamic")); tk = token();
if( !Type.enumEq(tk, TId("Dynamic")) ) unexpected(tk);
}
ensure(TPClose); ensure(TPClose);
var ec = parseExpr(); var ec = parseExpr();
mk(ETry(e, vname, t, ec), p1, pmax(ec)); mk(ETry(e, vname, t, ec), p1, pmax(ec));
@@ -664,7 +646,7 @@ class Parser {
case TId("case"), TId("default"), TBrClose: case TId("case"), TId("default"), TBrClose:
break; break;
default: default:
parseFullExpr(exprs); exprs.push(parseFullExpr());
} }
} }
c.expr = if( exprs.length == 1) c.expr = if( exprs.length == 1)
@@ -684,7 +666,7 @@ class Parser {
case TId("case"), TId("default"), TBrClose: case TId("case"), TId("default"), TBrClose:
break; break;
default: default:
parseFullExpr(exprs); exprs.push(parseFullExpr());
} }
} }
def = if( exprs.length == 1) def = if( exprs.length == 1)
@@ -718,7 +700,12 @@ class Parser {
} }
return makeBinop(op,e1,parseExpr()); return makeBinop(op,e1,parseExpr());
case TDot: case TDot:
var field = getIdent(); tk = token();
var field = null;
switch(tk) {
case TId(id): field = id;
default: unexpected(tk);
}
return parseExprNext(mk(EField(e1,field),pmin(e1))); return parseExprNext(mk(EField(e1,field),pmin(e1)));
case TPOpen: case TPOpen:
return parseExprNext(mk(ECall(e1,parseExprList(TPClose)),pmin(e1))); return parseExprNext(mk(ECall(e1,parseExprList(TPClose)),pmin(e1)));
@@ -737,76 +724,24 @@ 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 { function parseType() : CType {
var t = token(); var t = token();
switch( t ) { switch( t ) {
case TId(v): case TId(v):
push(t); var path = [v];
var path = parsePath(); while( true ) {
t = token();
if( t != TDot )
break;
t = token();
switch( t ) {
case TId(v):
path.push(v);
default:
unexpected(t);
}
}
var params = null; var params = null;
t = token();
switch( t ) { switch( t ) {
case TOp(op): case TOp(op):
if( op == "<" ) { if( op == "<" ) {
@@ -823,7 +758,7 @@ class Parser {
tokens.add({ t : TOp(op.substr(1)), min : tokenMax - op.length - 1, max : tokenMax }); tokens.add({ t : TOp(op.substr(1)), min : tokenMax - op.length - 1, max : tokenMax });
#else #else
tokens.add(TOp(op.substr(1))); tokens.add(TOp(op.substr(1)));
#end #end
break; break;
} }
default: default:
@@ -842,29 +777,19 @@ class Parser {
return parseTypeNext(CTParent(t)); return parseTypeNext(CTParent(t));
case TBrOpen: case TBrOpen:
var fields = []; var fields = [];
var meta = null;
while( true ) { while( true ) {
t = token(); t = token();
switch( t ) { switch( t ) {
case TBrClose: break; case TBrClose: break;
case TId("var"):
var name = getIdent();
ensure(TDoubleDot);
fields.push( { name : name, t : parseType(), meta : meta } );
meta = null;
ensure(TSemicolon);
case TId(name): case TId(name):
ensure(TDoubleDot); ensure(TDoubleDot);
fields.push( { name : name, t : parseType(), meta : meta } ); fields.push( { name : name, t : parseType() } );
t = token(); t = token();
switch( t ) { switch( t ) {
case TComma: case TComma:
case TBrClose: break; case TBrClose: break;
default: unexpected(t); default: unexpected(t);
} }
case TMeta(name):
if( meta == null ) meta = [];
meta.push({ name : name, params : parseMetaArgs() });
default: default:
unexpected(t); unexpected(t);
} }
@@ -916,210 +841,6 @@ class Parser {
return args; 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() { inline function incPos() {
#if hscriptPos #if hscriptPos
readPos++; readPos++;
@@ -1257,35 +978,18 @@ class Parser {
switch( char ) { switch( char ) {
case 48,49,50,51,52,53,54,55,56,57: case 48,49,50,51,52,53,54,55,56,57:
n = n * 10 + (char - 48); n = n * 10 + (char - 48);
case "e".code, "E".code: case 46:
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 ) { if( exp > 0 ) {
// in case of '0...' // in case of '...'
if( exp == 10 && readChar() == ".".code ) { if( exp == 10 && readChar() == 46 ) {
push(TOp("...")); push(TOp("..."));
var i = Std.int(n); var i = Std.int(n) & 0xFFFFFFFF;
return TConst( (i == n) ? CInt(i) : CFloat(n) ); return TConst( (i == n) ? CInt(i) : CFloat(n) );
} }
invalidChar(char); invalidChar(char);
} }
exp = 1.; exp = 1.;
case "x".code: case 120: // x
if( n > 0 || exp > 0 ) if( n > 0 || exp > 0 )
invalidChar(char); invalidChar(char);
// read hexa // read hexa
@@ -1302,7 +1006,7 @@ class Parser {
n = (n << 4) + (char - 87); n = (n << 4) + (char - 87);
default: default:
this.char = char; this.char = char;
return TConst(CInt(n)); return TConst(CInt(n & 0xFFFFFFFF));
} }
} }
#else #else
@@ -1332,11 +1036,11 @@ class Parser {
return TConst( (exp > 0) ? CFloat(n * 10 / exp) : ((i == n) ? CInt(i) : CFloat(n)) ); return TConst( (exp > 0) ? CFloat(n * 10 / exp) : ((i == n) ? CInt(i) : CFloat(n)) );
} }
} }
case ";".code: return TSemicolon; case 59: return TSemicolon;
case "(".code: return TPOpen; case 40: return TPOpen;
case ")".code: return TPClose; case 41: return TPClose;
case ",".code: return TComma; case 44: return TComma;
case ".".code: case 46:
char = readChar(); char = readChar();
switch( char ) { switch( char ) {
case 48,49,50,51,52,53,54,55,56,57: case 48,49,50,51,52,53,54,55,56,57:
@@ -1353,22 +1057,23 @@ class Parser {
return TConst( CFloat(n/exp) ); return TConst( CFloat(n/exp) );
} }
} }
case ".".code: case 46:
char = readChar(); char = readChar();
if( char != ".".code ) if( char != 46 )
invalidChar(char); invalidChar(char);
return TOp("..."); return TOp("...");
default: default:
this.char = char; this.char = char;
return TDot; return TDot;
} }
case "{".code: return TBrOpen; case 123: return TBrOpen;
case "}".code: return TBrClose; case 125: return TBrClose;
case "[".code: return TBkOpen; case 91: return TBkOpen;
case "]".code: return TBkClose; case 93: return TBkClose;
case "'".code, '"'.code: return TConst( CString(readString(char)) ); case 39: return TConst( CString(readString(39)) );
case "?".code: return TQuestion; case 34: return TConst( CString(readString(34)) );
case ":".code: return TDoubleDot; case 63: return TQuestion;
case 58: return TDoubleDot;
case '='.code: case '='.code:
char = readChar(); char = readChar();
if( char == '='.code ) if( char == '='.code )
@@ -1377,34 +1082,6 @@ class Parser {
return TOp("=>"); return TOp("=>");
this.char = char; this.char = char;
return TOp("="); return TOp("=");
case '@'.code:
char = readChar();
if( idents[char] || char == ':'.code ) {
var id = String.fromCharCode(char);
while( true ) {
char = readChar();
if( !idents[char] ) {
this.char = char;
return TMeta(id);
}
id += String.fromCharCode(char);
}
}
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: default:
if( ops[char] ) { if( ops[char] ) {
var op = String.fromCharCode(char); var op = String.fromCharCode(char);
@@ -1439,93 +1116,6 @@ class Parser {
return null; 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 ) { function tokenComment( op : String, char : Int ) {
var c = op.charCodeAt(1); var c = op.charCodeAt(1);
var s = input; var s = input;
@@ -1596,8 +1186,6 @@ class Parser {
case TBkClose: "]"; case TBkClose: "]";
case TQuestion: "?"; case TQuestion: "?";
case TDoubleDot: ":"; case TDoubleDot: ":";
case TMeta(id): "@" + id;
case TPrepro(id): "#" + id;
} }
} }
+1 -64
View File
@@ -1,24 +1,3 @@
/*
* 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; package hscript;
import hscript.Expr; import hscript.Expr;
@@ -37,13 +16,6 @@ class Printer {
return buf.toString(); 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); inline function add<T>(s:T) buf.add(s);
function type( t : CType ) { function type( t : CType ) {
@@ -286,20 +258,6 @@ class Printer {
add(";\n"); add(";\n");
} }
add("}"); 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);
} }
} }
@@ -307,25 +265,4 @@ class Printer {
return new Printer().exprToString(e); 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
}
}
+3 -32
View File
@@ -1,31 +1,10 @@
/*
* 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; package hscript;
import hscript.Expr; import hscript.Expr;
class Tools { class Tools {
public static function iter( e : Expr, f : Expr -> Void ) { public static function iter( e : Expr, f : Expr -> Void ) {
switch( #if hscriptPos e.e #else e #end ) { switch( e ) {
case EConst(_), EIdent(_): case EConst(_), EIdent(_):
case EVar(_, _, e): if( e != null ) f(e); case EVar(_, _, e): if( e != null ) f(e);
case EParent(e): f(e); case EParent(e): f(e);
@@ -55,17 +34,12 @@ class Tools {
f(c.expr); f(c.expr);
} }
if( def != null ) f(def); 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 ) { public static function map( e : Expr, f : Expr -> Expr ) {
#if hscriptPos
var edef = switch( e.e ) {
#else
return switch( e ) { return switch( e ) {
#end case EConst(_), EIdent(_): e;
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 EVar(n, t, e): EVar(n, t, if( e != null ) f(e) else null);
case EParent(e): EParent(f(e)); case EParent(e): EParent(f(e));
case EBlock(el): EBlock([for( e in el ) f(e)]); case EBlock(el): EBlock([for( e in el ) f(e)]);
@@ -77,6 +51,7 @@ class Tools {
case EWhile(c, e): EWhile(f(c),f(e)); case EWhile(c, e): EWhile(f(c),f(e));
case EDoWhile(c, e): EDoWhile(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 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 EFunction(args, e, name, t): EFunction(args, f(e), name, t);
case EReturn(e): EReturn(if( e != null ) f(e) else null); case EReturn(e): EReturn(if( e != null ) f(e) else null);
case EArray(e, i): EArray(f(e),f(i)); case EArray(e, i): EArray(f(e),f(i));
@@ -87,11 +62,7 @@ class Tools {
case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]); 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 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 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
} }
} }