Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b32dde3c91 | ||
|
|
b9a566350b | ||
|
|
ce9ce674ea | ||
|
|
b8641779bd | ||
|
|
5e620d784e | ||
|
|
013bcfaffb | ||
|
|
2504c96927 | ||
|
|
e2f4d1481e | ||
|
|
ea3d68573b | ||
|
|
c6cb594ef1 | ||
|
|
948123bc7a | ||
|
|
68f5b26af9 | ||
|
|
5d493630b1 | ||
|
|
f4db6faa80 | ||
|
|
e340f7f5ad | ||
|
|
b4d923b74c | ||
|
|
965f334d59 | ||
|
|
54463b78d2 | ||
|
|
600aec1f50 | ||
|
|
bcfbe81979 | ||
|
|
31e8851bcc | ||
|
|
f464767ee7 | ||
|
|
22eb58b3de | ||
|
|
0daee20545 | ||
|
|
d98073dc33 | ||
|
|
fb199e7dea | ||
|
|
6cea0d97c2 | ||
|
|
058dd2e01e | ||
|
|
975d122491 | ||
|
|
eef4c66374 | ||
|
|
5ce4fbd74d | ||
|
|
f4d8cff26b | ||
|
|
46b6b3c151 | ||
|
|
796b217dec | ||
|
|
1ccc35f464 | ||
|
|
2ed6f15fe1 | ||
|
|
575040be65 | ||
|
|
206959adbd | ||
|
|
dd1c97b6af | ||
|
|
85463dcff0 | ||
|
|
7ff816417e | ||
|
|
3fa2f3898a | ||
|
|
514ce9eec2 | ||
|
|
5bc357b4b3 | ||
|
|
56ddc3c24e | ||
|
|
e407b2a307 | ||
|
|
1ac194ed1d | ||
|
|
62bf5d4cc9 | ||
|
|
27093064a9 | ||
|
|
860a3018a7 | ||
|
|
eb3992dbdb | ||
|
|
8c5f9cc1d3 | ||
|
|
ed78703090 | ||
|
|
29b61bcee9 | ||
|
|
0ff49845a7 | ||
|
|
c17366b2b1 | ||
|
|
5da267fb31 | ||
|
|
dffa3345d0 | ||
|
|
a23c767fb0 | ||
|
|
5d6ec51302 | ||
|
|
585f277bf5 | ||
|
|
aae5f431cb | ||
|
|
4eb84e5c32 |
+18
-22
@@ -4,12 +4,11 @@ os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
sudo: false
|
||||
dist: trusty
|
||||
dist: bionic
|
||||
|
||||
haxe:
|
||||
- "3.2.1"
|
||||
- "3.4.2"
|
||||
- "3.4.7"
|
||||
- "4.0.3"
|
||||
- development
|
||||
|
||||
addons:
|
||||
@@ -20,37 +19,31 @@ addons:
|
||||
- g++-multilib
|
||||
# Python
|
||||
- python3
|
||||
# PHP
|
||||
- php-cli
|
||||
- php-mbstring
|
||||
# C#
|
||||
- mono-devel
|
||||
- mono-mcs
|
||||
# Flash
|
||||
- libglib2.0
|
||||
- libfreetype6
|
||||
|
||||
install:
|
||||
# os-specific config
|
||||
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then
|
||||
export DISPLAY=:99.0;
|
||||
export AUDIODEV=null;
|
||||
phpenv global 7.0;
|
||||
elif [ "${TRAVIS_OS_NAME}" = "osx" ]; then
|
||||
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
|
||||
brew update;
|
||||
brew install mono;
|
||||
brew install python3;
|
||||
brew tap homebrew/homebrew-php;
|
||||
brew install php71;
|
||||
brew install php;
|
||||
fi
|
||||
# Download and setup a standalone flash player debugger
|
||||
- haxe flash/install.hxml
|
||||
# Install haxelibs
|
||||
- if [ "${TRAVIS_HAXE_VERSION}" = "development" ]; then
|
||||
haxelib git hxcpp https://github.com/HaxeFoundation/hxcpp.git;
|
||||
else
|
||||
haxelib install hxcpp;
|
||||
fi
|
||||
- if [ "${TRAVIS_HAXE_VERSION}" = "development" ] || [ "${TRAVIS_HAXE_VERSION}" = "3.2.1" ]; then
|
||||
pushd $(haxelib path hxcpp | head -1);
|
||||
pushd tools/hxcpp; haxe compile.hxml; popd;
|
||||
pushd project; neko build.n; popd;
|
||||
popd;
|
||||
else
|
||||
haxelib install hxcpp;
|
||||
fi
|
||||
- haxelib install hxjava
|
||||
- haxelib install hxcs
|
||||
@@ -63,11 +56,14 @@ script:
|
||||
haxe build.hxml &&
|
||||
popd
|
||||
- haxe bin/build-interp.hxml
|
||||
- haxe bin/build-interp.hxml -D hscriptPos
|
||||
- haxe bin/build-neko.hxml && neko bin/Test.n
|
||||
- haxe bin/build-js.hxml && node bin/Test.js
|
||||
- haxe bin/build-java.hxml && java -jar bin/Test.jar
|
||||
- haxe bin/build-cs.hxml && mono bin/bin/Test.exe
|
||||
# Only test C# for Haxe 4+
|
||||
- if [[ $(haxe -version 2&>1 | head -c 1) > 3 ]]; then
|
||||
haxe bin/build-cs.hxml && mono bin/bin/Test.exe;
|
||||
fi
|
||||
- haxe bin/build-cpp.hxml && ./bin/Test
|
||||
- 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 -D php7 && php bin/index.php
|
||||
- haxe bin/build-python.hxml && python3 bin/Test.py
|
||||
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
// Utilisez IntelliSense pour en savoir plus sur les attributs possibles.
|
||||
// Pointez pour afficher la description des attributs existants.
|
||||
// Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "HashLink (launch)",
|
||||
"request": "launch",
|
||||
"type": "hl",
|
||||
"hxml": "hscript.hxml",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build"
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build",
|
||||
"type": "hxml",
|
||||
"file": "hscript.hxml",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -68,24 +68,36 @@ You can use `parser.allowMetadata` to parse metadata before expressions on in an
|
||||
|
||||
You can use `new hscript.Macro(pos).convert(ast)` to convert an hscript AST to a Haxe macros one.
|
||||
|
||||
You can use `hscript.Checker` in order to type check and even get completion, using `haxe -xml` output for type information.
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
Compared to Haxe, limitations are :
|
||||
|
||||
- no type declarations (classes, enums, typedefs) : only expressions
|
||||
- `switch` construct is supported but not pattern matching (no variable capture, we use strict equality to compare `case` values and `switch` value)
|
||||
- only one variable declaration is allowed in `var`
|
||||
- the parser supports optional types for `var` and `function` if `allowTypes` is set, but the interpreter ignores them
|
||||
- you can enable per-expression position tracking by compiling with `-D hscriptPos`
|
||||
- you can parse some type declarations (import, class, typedef, etc.) with parseModule
|
||||
|
||||
Install
|
||||
-------
|
||||
|
||||
In order to install Haxe Script, use `haxelib install hscript` and compile your program with `-lib hscript`.
|
||||
|
||||
There are only three files in hscript :
|
||||
These are the main required files in hscript :
|
||||
|
||||
- `hscript.Expr` : contains enums declarations
|
||||
- `hscript.Parser` : a small parser that turns a string into an expression structure (AST)
|
||||
- `hscript.Interp` : a small interpreter that execute the AST and returns the latest evaluated value
|
||||
|
||||
Some other optional files :
|
||||
|
||||
- `hscript.Async` : converts Expr into asynchronous version
|
||||
- `hscript.Bytes` : Expr serializer/unserializer
|
||||
- `hscript.Checker` : type checking and completion for hscript Expr
|
||||
- `hscript.Macro` : convert Haxe macro into hscript Expr
|
||||
- `hscript.Printer` : convert hscript Expr to String
|
||||
- `hscript.Tools` : utility functions (map/iter)
|
||||
|
||||
@@ -4,10 +4,11 @@ import hscript.Macro;
|
||||
import hscript.Tools;
|
||||
import hscript.Async;
|
||||
import hscript.Printer;
|
||||
import hscript.Checker;
|
||||
import haxe.unit.*;
|
||||
|
||||
class Test extends TestCase {
|
||||
function assertScript(x,v:Dynamic,?vars : Dynamic,allowTypes=false) {
|
||||
function assertScript(x,v:Dynamic,?vars : Dynamic, allowTypes=false, ?pos:haxe.PosInfos) {
|
||||
var p = new hscript.Parser();
|
||||
p.allowTypes = allowTypes;
|
||||
var program = p.parseString(x);
|
||||
@@ -18,7 +19,7 @@ class Test extends TestCase {
|
||||
for( v in Reflect.fields(vars) )
|
||||
interp.variables.set(v,Reflect.field(vars,v));
|
||||
var ret : Dynamic = interp.execute(program);
|
||||
assertEquals(v, ret);
|
||||
assertEquals(v, ret, pos);
|
||||
}
|
||||
|
||||
function test():Void {
|
||||
@@ -99,6 +100,16 @@ class Test extends TestCase {
|
||||
assertScript("var a:Array<Dynamic>=[1,2,4]; a[2]", 4, null, true);
|
||||
assertScript("/**/0", 0);
|
||||
assertScript("x=1;x*=-2", -2);
|
||||
assertScript("var f = x -> x + 1; f(3)", 4);
|
||||
assertScript("var f = (x) -> x + 1; f(3)", 4);
|
||||
assertScript("var f = (x:Int) -> x + 1; f(3)", 4);
|
||||
assertScript("var f = (x,y) -> x + y; f(3,1)", 4);
|
||||
assertScript("var f = (x,y:Int) -> x + y; f(3,1)", 4);
|
||||
assertScript("var f = (x:Int,y:Int) -> x + y; f(3,1)", 4);
|
||||
assertScript("var f:Int->Int->Int = (x:Int,y:Int) -> x + y; f(3,1)", 4, null, true);
|
||||
assertScript("var f:(x:Int, y:Int)->Int = (x:Int,y:Int) -> x + y; f(3,1)", 4, null, true);
|
||||
assertScript("var f:(x:Int)->(y:Int, z:Int)->Int = (x:Int) -> (y:Int, z:Int) -> x + y + z; f(3)(1, 2)", 6, null, true);
|
||||
assertScript("var f:(x:Int)->(Int, Int)->Int = (x:Int) -> (y:Int, z:Int) -> x + y + z; f(3)(1, 2)", 6, null, true);
|
||||
}
|
||||
|
||||
function testMap():Void {
|
||||
@@ -152,9 +163,16 @@ class Test extends TestCase {
|
||||
}
|
||||
|
||||
static function main() {
|
||||
#if ((haxe_ver < 4) && php)
|
||||
// uncaught exception: The each() function is deprecated. This message will be suppressed on further calls (errno: 8192)
|
||||
// in file: /Users/travis/build/andyli/hscript/bin/lib/Type.class.php line 178
|
||||
untyped __php__("error_reporting(E_ALL ^ E_DEPRECATED);");
|
||||
#end
|
||||
|
||||
var runner = new TestRunner();
|
||||
runner.add(new Test());
|
||||
var succeed = runner.run();
|
||||
|
||||
#if sys
|
||||
Sys.exit(succeed ? 0 : 1);
|
||||
#elseif flash
|
||||
|
||||
+3
-9
@@ -5,18 +5,14 @@ environment:
|
||||
HAXELIB_ROOT: C:\projects\haxelib
|
||||
|
||||
install:
|
||||
# http://help.appveyor.com/discussions/problems/5616-not-able-to-build-due-to-problem-in-chocolateyinstallps1
|
||||
- ps: Set-Service wuauserv -StartupType Manual
|
||||
# Install the haxe chocolatey package (https://chocolatey.org/packages/haxe)
|
||||
- cinst haxe -version 3.4.2 -y
|
||||
- cinst haxe -version 4.0.3 -y
|
||||
- RefreshEnv
|
||||
# Setup haxelib
|
||||
- mkdir "%HAXELIB_ROOT%"
|
||||
- haxelib setup "%HAXELIB_ROOT%"
|
||||
# Install test dependencies
|
||||
- ps: Set-Service wuauserv -StartupType Manual
|
||||
- cinst php -y
|
||||
- RefreshEnv
|
||||
# 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
|
||||
@@ -37,6 +33,4 @@ test_script:
|
||||
- haxe bin/build-java.hxml && java -jar bin\Test.jar
|
||||
- haxe bin/build-cs.hxml && bin\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-php.hxml && php bin\index.php
|
||||
- haxe bin/build-python.hxml && C:\Python34-x64\python.exe bin\Test.py
|
||||
@@ -1,3 +0,0 @@
|
||||
*.exe
|
||||
*.app
|
||||
flashplayerdebugger
|
||||
@@ -1,94 +0,0 @@
|
||||
import Sys.*;
|
||||
import sys.io.File.*;
|
||||
import haxe.*;
|
||||
import haxe.io.*;
|
||||
|
||||
class Install {
|
||||
// https://www.adobe.com/support/flashplayer/downloads.html
|
||||
static var fpDownload(default, never) = switch (systemName()) {
|
||||
case "Linux":
|
||||
"http://fpdownload.macromedia.com/pub/flashplayer/updaters/25/flash_player_sa_linux_debug.x86_64.tar.gz";
|
||||
case "Mac":
|
||||
"http://fpdownload.macromedia.com/pub/flashplayer/updaters/25/flashplayer_25_sa_debug.dmg";
|
||||
case "Windows":
|
||||
"http://fpdownload.macromedia.com/pub/flashplayer/updaters/25/flashplayer_25_sa_debug.exe";
|
||||
case _:
|
||||
throw "unsupported system";
|
||||
}
|
||||
// https://helpx.adobe.com/flash-player/kb/configure-debugger-version-flash-player.html
|
||||
static var mmcfg(default, never) = switch (systemName()) {
|
||||
case "Linux":
|
||||
Path.join([getEnv("HOME"), "mm.cfg"]);
|
||||
case "Mac":
|
||||
"/Library/Application Support/Macromedia/mm.cfg";
|
||||
case "Windows":
|
||||
Path.join([getEnv("HOMEDRIVE") + getEnv("HOMEPATH"), "mm.cfg"]);
|
||||
case _:
|
||||
throw "unsupported system";
|
||||
}
|
||||
// http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7c95.html
|
||||
static var fpTrust(default, never) = switch (systemName()) {
|
||||
case "Linux":
|
||||
Path.join([getEnv("HOME"), ".macromedia/Flash_Player/#Security/FlashPlayerTrust"]);
|
||||
case "Mac":
|
||||
"/Library/Application Support/Macromedia/FlashPlayerTrust";
|
||||
case "Windows":
|
||||
Path.join([getEnv("SYSTEMROOT"), "system32", "Macromed", "Flash", "FlashPlayerTrust"]);
|
||||
case _:
|
||||
throw "unsupported system";
|
||||
}
|
||||
static function main() {
|
||||
switch (systemName()) {
|
||||
case "Linux":
|
||||
// Download and unzip flash player
|
||||
if (command("wget", [fpDownload]) != 0)
|
||||
throw "failed to download flash player";
|
||||
if (command("tar", ["-xf", Path.withoutDirectory(fpDownload), "-C", "flash"]) != 0)
|
||||
throw "failed to extract flash player";
|
||||
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)
|
||||
throw "failed to brew tap caskroom/versions";
|
||||
if (command("brew", ["cask", "install", "flash-player-debugger"]) != 0)
|
||||
throw "failed to install flash-player-debugger";
|
||||
case "Windows":
|
||||
// Download flash player
|
||||
download(fpDownload, "flash\\flashplayer.exe");
|
||||
case _:
|
||||
throw "unsupported system";
|
||||
}
|
||||
|
||||
|
||||
// Create a configuration file so the trace log is enabled
|
||||
createDirectory(Path.directory(mmcfg));
|
||||
saveContent(mmcfg, "ErrorReportingEnable=1\nTraceOutputFileEnable=1");
|
||||
|
||||
// Add the current directory as trusted, so exit() can be used
|
||||
createDirectory(fpTrust);
|
||||
saveContent(Path.join([fpTrust, "test.cfg"]), getCwd());
|
||||
}
|
||||
static function download(url:String, saveAs:String):Void {
|
||||
var http = new Http(url);
|
||||
http.onError = function(e) {
|
||||
throw e;
|
||||
};
|
||||
http.customRequest(false, write(saveAs));
|
||||
}
|
||||
static function createDirectory(dir:String):Void {
|
||||
try {
|
||||
sys.FileSystem.createDirectory(dir);
|
||||
} catch(e:Dynamic) {
|
||||
switch (systemName()) {
|
||||
case "Mac", "Linux":
|
||||
if (command("sudo", ["mkdir", "-p", dir]) != 0)
|
||||
throw 'cannot create $dir';
|
||||
if (command("sudo", ["chmod", "a+rw", dir]) != 0)
|
||||
throw 'cannot set permission of $dir';
|
||||
case _:
|
||||
throw 'cannot create $dir: $e';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import Sys.*;
|
||||
import sys.FileSystem.*;
|
||||
import sys.io.File.*;
|
||||
import haxe.io.*;
|
||||
|
||||
class Run {
|
||||
// https://helpx.adobe.com/flash-player/kb/configure-debugger-version-flash-player.html
|
||||
static var flashlog(default, never) = switch (systemName()) {
|
||||
case "Linux":
|
||||
Path.join([getEnv("HOME"), ".macromedia/Flash_Player/Logs/flashlog.txt"]);
|
||||
case "Mac":
|
||||
Path.join([getEnv("HOME"), "Library/Preferences/Macromedia/Flash Player/Logs/flashlog.txt"]);
|
||||
case "Windows":
|
||||
Path.join([getEnv("APPDATA"), "Macromedia", "Flash Player", "Logs", "flashlog.txt"]);
|
||||
case _:
|
||||
throw "unsupported system";
|
||||
}
|
||||
static function main() {
|
||||
var args = args();
|
||||
var swf = args[0];
|
||||
var exitCode = switch (systemName()) {
|
||||
case "Linux":
|
||||
// The flash player has some issues with unexplained crashes,
|
||||
// but if it runs about 16 times, it should succeed one of those...
|
||||
var c = -1;
|
||||
for (i in 0...16) {
|
||||
if ((c = command("xvfb-run", ["-a", "flash/flashplayerdebugger", swf])) == 0)
|
||||
break;
|
||||
println('retry... (${i+1})');
|
||||
sleep(1.5);
|
||||
}
|
||||
c;
|
||||
case "Mac":
|
||||
command("/Applications/Flash Player Debugger.app/Contents/MacOS/Flash Player Debugger", [fullPath(swf)]);
|
||||
case "Windows":
|
||||
command("flash\\flashplayer.exe", [fullPath(swf)]);
|
||||
case _:
|
||||
throw "unsupported platform";
|
||||
}
|
||||
if (exists(flashlog))
|
||||
println(getContent(flashlog));
|
||||
else {
|
||||
println('does not exist: $flashlog');
|
||||
var parts = Path.normalize(flashlog).split("/");
|
||||
println(parts);
|
||||
for (i in 0...parts.length-1) {
|
||||
var path = parts.splice(0, i+1).join("/");
|
||||
println('ls $path');
|
||||
command("ls", [path]);
|
||||
}
|
||||
}
|
||||
exit(exitCode);
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
-cp flash
|
||||
--run Install
|
||||
@@ -1,2 +0,0 @@
|
||||
-cp flash
|
||||
--run Run
|
||||
+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.2.0",
|
||||
"releasenote": "",
|
||||
"version": "2.4.0",
|
||||
"releasenote": "Haxe 4.0 final + type checking/completion (hscript.Checker)",
|
||||
"contributors": ["ncannasse"]
|
||||
}
|
||||
+2
-1
@@ -1 +1,2 @@
|
||||
bin/build-flash.hxml
|
||||
bin/build-each.hxml
|
||||
-hl bin/Test.hl
|
||||
+72
-37
@@ -22,9 +22,16 @@
|
||||
package hscript;
|
||||
import hscript.Expr;
|
||||
|
||||
|
||||
enum VarMode {
|
||||
Defined;
|
||||
ForceSync;
|
||||
}
|
||||
|
||||
class Async {
|
||||
|
||||
var varNames : Array<String>;
|
||||
var definedVars : Array<{ n : String, prev : Null<VarMode> }>;
|
||||
var vars : Map<String,VarMode>;
|
||||
var currentFun : String;
|
||||
var currentLoop : Expr;
|
||||
var currentBreak : Expr -> Expr;
|
||||
@@ -68,35 +75,53 @@ class Async {
|
||||
return a.build(e, topLevelSync);
|
||||
}
|
||||
|
||||
public dynamic function getTopLevelEnd() {
|
||||
return ignore();
|
||||
}
|
||||
|
||||
public function build( e : Expr, topLevelSync = false ) {
|
||||
if( topLevelSync ) {
|
||||
return buildSync(e,null);
|
||||
} else {
|
||||
var nothing = ignore();
|
||||
return new Async().toCps(e, nothing, nothing);
|
||||
var end = getTopLevelEnd();
|
||||
return toCps(e, end, end);
|
||||
}
|
||||
}
|
||||
|
||||
function defineVar( v : String, mode ) {
|
||||
definedVars.push({ n : v, prev : vars.get(v) });
|
||||
vars.set(v, mode);
|
||||
}
|
||||
|
||||
function lookupFunctions( el : Array<Expr> ) {
|
||||
for( e in el )
|
||||
switch( expr(e) ) {
|
||||
case EFunction(_, _, name, _) if( name != null ): defineVar(name, Defined);
|
||||
case EMeta("sync",_,expr(_) => EFunction(_,_,name,_)) if( name != null ): defineVar(name, ForceSync);
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
function buildSync( e : Expr, exit : Expr ) : Expr {
|
||||
switch( expr(e) ) {
|
||||
case EFunction(_):
|
||||
return toCps(e, null, null);
|
||||
case EFunction(_,_,name,_):
|
||||
if( name != null )
|
||||
return toCps(e, null, null);
|
||||
return e;
|
||||
case EBlock(el):
|
||||
var v = saveVars();
|
||||
for( e in el )
|
||||
switch( expr(e) ) {
|
||||
case EFunction(_, _, name, _) if( name != null ): varNames.push(name);
|
||||
default:
|
||||
}
|
||||
lookupFunctions(el);
|
||||
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 EMeta("sync", args, ef = expr(_) => EFunction(fargs, body, name, ret)):
|
||||
return mk(EMeta("sync",args,mk(EFunction(fargs, buildSync(body,null), name, ret),ef)),e);
|
||||
case EBreak if( currentBreak != null ):
|
||||
return currentBreak(e);
|
||||
case EContinue if( currentLoop != null ):
|
||||
return block([call(currentLoop, [nullId], e), mk(EReturn(),e)],e);
|
||||
return block([retNull(currentLoop, e), mk(EReturn(),e)],e);
|
||||
case EFor(_), EWhile(_):
|
||||
var oldLoop = currentLoop, oldBreak = currentBreak;
|
||||
currentLoop = null;
|
||||
@@ -106,14 +131,15 @@ class Async {
|
||||
currentBreak = oldBreak;
|
||||
return e;
|
||||
case EReturn(eret) if( exit != null ):
|
||||
return block([call(exit,[eret == null ? nullId : eret], e), mk(EReturn(),e)], e);
|
||||
return block([eret == null ? retNull(exit, e) : call(exit,[eret], e), mk(EReturn(),e)], e);
|
||||
default:
|
||||
return Tools.map(e, buildSync.bind(_, exit));
|
||||
}
|
||||
}
|
||||
|
||||
public function new() {
|
||||
varNames = [];
|
||||
vars = new Map();
|
||||
definedVars = [];
|
||||
}
|
||||
|
||||
function ignore(?e) : Expr {
|
||||
@@ -133,7 +159,9 @@ class Async {
|
||||
return mk(EFunction([for( a in arg ) { name : a, t : null }], e, name), e);
|
||||
}
|
||||
|
||||
inline function block(arr, e) {
|
||||
inline function block(arr:Array<Expr>, e) {
|
||||
if( arr.length == 1 && expr(arr[0]).match(EBlock(_)) )
|
||||
return arr[0];
|
||||
return mk(EBlock(arr), e);
|
||||
}
|
||||
|
||||
@@ -149,8 +177,12 @@ class Async {
|
||||
return mk(ECall(e, args), inf);
|
||||
}
|
||||
|
||||
function retNull(e) : Expr {
|
||||
return call(e, [nullId],e);
|
||||
function retNull(e:Expr,?pos) : Expr {
|
||||
switch( expr(e) ) {
|
||||
case EFunction([{name:"_"}], e, _, _): return e;
|
||||
default:
|
||||
}
|
||||
return call(e, [nullId], pos == null ? e : pos);
|
||||
}
|
||||
|
||||
function makeCall( ecall, args : Array<Expr>, rest : Expr, exit, sync = false ) {
|
||||
@@ -179,7 +211,9 @@ class Async {
|
||||
if( !syncFlag )
|
||||
return;
|
||||
switch( expr(e) ) {
|
||||
case ECall(_), EFunction(_):
|
||||
case ECall(_):
|
||||
syncFlag = false;
|
||||
case EFunction(_,_,name,_) if( name != null ):
|
||||
syncFlag = false;
|
||||
case EMeta("sync" | "async", _, _):
|
||||
// isolated from the sync part
|
||||
@@ -189,11 +223,14 @@ class Async {
|
||||
}
|
||||
|
||||
function saveVars() {
|
||||
return varNames.length;
|
||||
return definedVars.length;
|
||||
}
|
||||
|
||||
function restoreVars(k) {
|
||||
while( varNames.length > k ) varNames.pop();
|
||||
while( definedVars.length > k ) {
|
||||
var v = definedVars.pop();
|
||||
if( v.prev == null ) vars.remove(v.n) else vars.set(v.n, v.prev);
|
||||
}
|
||||
}
|
||||
|
||||
public function toCps( e : Expr, rest : Expr, exit : Expr ) : Expr {
|
||||
@@ -203,12 +240,7 @@ class Async {
|
||||
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:
|
||||
}
|
||||
lookupFunctions(el);
|
||||
while( el.length > 0 ) {
|
||||
var e = toCps(el.pop(), rest, exit);
|
||||
rest = ignore(e);
|
||||
@@ -218,9 +250,9 @@ class Async {
|
||||
case EFunction(args, body, name, t):
|
||||
var vold = saveVars();
|
||||
if( name != null )
|
||||
varNames.push(name);
|
||||
defineVar(name, Defined);
|
||||
for( a in args )
|
||||
varNames.push(a.name);
|
||||
defineVar(a.name, Defined);
|
||||
args.unshift( { name : "_onEnd", t : null } );
|
||||
var frest = ident("_onEnd",e);
|
||||
var oldFun = currentFun;
|
||||
@@ -241,7 +273,8 @@ class Async {
|
||||
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);
|
||||
var mode = vars.get(i);
|
||||
return makeCall( ident( mode != null ? i : "a_" + i,e) , args, rest, exit, mode == ForceSync);
|
||||
case ECall(expr(_) => EField(e, f), args):
|
||||
return makeCall(field(e,"a_"+f,e), args, rest, exit);
|
||||
case EFor(v, eit, eloop):
|
||||
@@ -250,7 +283,7 @@ class Async {
|
||||
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);
|
||||
currentBreak = function(inf) return block([retNull(rest, inf), mk(EReturn(),inf)], inf);
|
||||
var efor = block([
|
||||
mk(EVar("_i" + id, call(ident("makeIterator",eit),[eit],eit)),eit),
|
||||
fun("_", block([
|
||||
@@ -258,7 +291,7 @@ class Async {
|
||||
mk(EVar(v, call(field(it, "next",it), [], it)), it),
|
||||
toCps(eloop, loop, exit),
|
||||
], it),"_loop" + id),
|
||||
call(loop, [nullId], e),
|
||||
retNull(loop, e),
|
||||
], e);
|
||||
currentLoop = oldLoop;
|
||||
currentBreak = oldBreak;
|
||||
@@ -306,18 +339,18 @@ class Async {
|
||||
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);
|
||||
currentBreak = function(e) return block([retNull(rest,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)
|
||||
toCps(cond, fun("_c", mk(EIf(ident("_c", cond), toCps(ewh, loop, exit), retNull(rest,cond)),cond)), exit)
|
||||
, "_loop"+id),
|
||||
call(loop, [nullId], cond),
|
||||
retNull(loop, cond),
|
||||
],e);
|
||||
currentLoop = oldLoop;
|
||||
currentBreak = oldBreak;
|
||||
return ewhile;
|
||||
case EReturn(eret):
|
||||
return eret == null ? call(exit, [nullId], e) : toCps(eret, exit, exit);
|
||||
return eret == null ? retNull(exit, e) : toCps(eret, exit, exit);
|
||||
case EObject(fields):
|
||||
var id = "_o" + uid++;
|
||||
var rest = call(rest, [ident(id,e)], e);
|
||||
@@ -353,10 +386,10 @@ class Async {
|
||||
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([e, retNull(rest, 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),
|
||||
toCps(ev, fun("_r", block([binop("=", ident(v,e), ident("_r",e), e), retNull(rest,e)], e)), exit),
|
||||
],e);
|
||||
case EConst(_), EIdent(_), EUnop(_), EField(_):
|
||||
return call(rest, [e], e);
|
||||
@@ -375,12 +408,14 @@ class Async {
|
||||
return currentBreak(e);
|
||||
case EContinue:
|
||||
if( currentLoop == null ) throw "Continue outside loop";
|
||||
return block([call(currentLoop, [nullId], e), mk(EReturn(),e)], e);
|
||||
return block([retNull(currentLoop, 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 EMeta(name,_,e) if( name.charCodeAt(0) == ":".code ): // ignore custom ":" metadata
|
||||
return toCps(e, rest, exit);
|
||||
//case EDoWhile(_), ETry(_), ECall(_):
|
||||
default:
|
||||
throw "Unsupported async expression " + Printer.toString(e);
|
||||
|
||||
+10
-5
@@ -72,10 +72,7 @@ class Bytes {
|
||||
}
|
||||
|
||||
function doEncodeInt(v: Int) {
|
||||
bout.addByte(v & 0xFF);
|
||||
bout.addByte((v >> 8) & 0xFF);
|
||||
bout.addByte((v >> 16) & 0xFF);
|
||||
bout.addByte(v >>> 24);
|
||||
bout.addInt32(v);
|
||||
}
|
||||
|
||||
function doEncodeConst( c : Const ) {
|
||||
@@ -107,7 +104,7 @@ class Bytes {
|
||||
}
|
||||
|
||||
function doDecodeInt() {
|
||||
var i = bin.get(pin) | (bin.get(pin+1) << 8) | (bin.get(pin+2) << 16) | (bin.get(pin+3) << 24);
|
||||
var i = bin.getInt32(pin);
|
||||
pin += 4;
|
||||
return i;
|
||||
}
|
||||
@@ -249,11 +246,17 @@ class Bytes {
|
||||
bout.addByte(args == null ? 0 : args.length + 1);
|
||||
if( args != null ) for( e in args ) doEncode(e);
|
||||
doEncode(e);
|
||||
case ECheckType(e,_):
|
||||
doEncode(e);
|
||||
}
|
||||
}
|
||||
|
||||
function doDecode() : Expr {
|
||||
#if hscriptPos
|
||||
if (bin.get(pin) == 255) {
|
||||
pin++;
|
||||
return null;
|
||||
}
|
||||
var origin = doDecodeString();
|
||||
var line = doDecodeInt();
|
||||
return { e : _doDecode(), pmin : 0, pmax : 0, origin : origin, line : line };
|
||||
@@ -373,6 +376,8 @@ class Bytes {
|
||||
var count = bin.get(pin++);
|
||||
var args = count == 0 ? null : [for( i in 0...count - 1 ) doDecode()];
|
||||
EMeta(name, args, doDecode());
|
||||
case 26:
|
||||
ECheckType(doDecode(), CTPath(["Void"]));
|
||||
case 255:
|
||||
null;
|
||||
default:
|
||||
|
||||
+1184
File diff suppressed because it is too large
Load Diff
@@ -40,6 +40,7 @@ typedef Expr = {
|
||||
}
|
||||
enum ExprDef {
|
||||
#else
|
||||
typedef ExprDef = Expr;
|
||||
enum Expr {
|
||||
#end
|
||||
EConst( c : Const );
|
||||
@@ -68,6 +69,7 @@ enum Expr {
|
||||
ESwitch( e : Expr, cases : Array<{ values : Array<Expr>, expr : Expr }>, ?defaultExpr : Expr);
|
||||
EDoWhile( cond : Expr, e : Expr);
|
||||
EMeta( name : String, args : Array<Expr>, e : Expr );
|
||||
ECheckType( e : Expr, t : CType );
|
||||
}
|
||||
|
||||
typedef Argument = { name : String, ?t : CType, ?opt : Bool, ?value : Expr };
|
||||
@@ -79,6 +81,8 @@ enum CType {
|
||||
CTFun( args : Array<CType>, ret : CType );
|
||||
CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> );
|
||||
CTParent( t : CType );
|
||||
CTOpt( t : CType );
|
||||
CTNamed( n : String, t : CType );
|
||||
}
|
||||
|
||||
#if hscriptPos
|
||||
|
||||
+20
-18
@@ -52,13 +52,22 @@ class Interp {
|
||||
|
||||
public function new() {
|
||||
#if haxe3
|
||||
variables = new Map<String,Dynamic>();
|
||||
locals = new Map();
|
||||
#else
|
||||
variables = new Hash();
|
||||
locals = new Hash();
|
||||
#end
|
||||
declared = new Array();
|
||||
resetVariables();
|
||||
initOps();
|
||||
}
|
||||
|
||||
private function resetVariables(){
|
||||
#if haxe3
|
||||
variables = new Map<String,Dynamic>();
|
||||
#else
|
||||
variables = new Hash();
|
||||
#end
|
||||
|
||||
variables.set("null",null);
|
||||
variables.set("true",true);
|
||||
variables.set("false",false);
|
||||
@@ -68,7 +77,6 @@ class Interp {
|
||||
if( el.length > 0 ) inf.customParams = el;
|
||||
haxe.Log.trace(Std.string(v), inf);
|
||||
}));
|
||||
initOps();
|
||||
}
|
||||
|
||||
public function posInfos(): PosInfos {
|
||||
@@ -122,7 +130,7 @@ class Interp {
|
||||
|
||||
function assign( e1 : Expr, e2 : Expr ) : Dynamic {
|
||||
var v = expr(e2);
|
||||
switch( edef(e1) ) {
|
||||
switch( Tools.expr(e1) ) {
|
||||
case EIdent(id):
|
||||
var l = locals.get(id);
|
||||
if( l == null )
|
||||
@@ -154,7 +162,7 @@ class Interp {
|
||||
|
||||
function evalAssignOp(op,fop,e1,e2) : Dynamic {
|
||||
var v;
|
||||
switch( edef(e1) ) {
|
||||
switch( Tools.expr(e1) ) {
|
||||
case EIdent(id):
|
||||
var l = locals.get(id);
|
||||
v = fop(expr(e1),expr(e2));
|
||||
@@ -280,14 +288,6 @@ class Interp {
|
||||
}
|
||||
}
|
||||
|
||||
inline function edef( e : Expr ) {
|
||||
#if hscriptPos
|
||||
return e.e;
|
||||
#else
|
||||
return e;
|
||||
#end
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -372,7 +372,7 @@ class Interp {
|
||||
for( p in params )
|
||||
args.push(expr(p));
|
||||
|
||||
switch( edef(e) ) {
|
||||
switch( Tools.expr(e) ) {
|
||||
case EField(e,f):
|
||||
var obj = expr(e);
|
||||
if( obj == null ) error(EInvalidAccess(f));
|
||||
@@ -408,11 +408,11 @@ class Interp {
|
||||
else
|
||||
minParams++;
|
||||
var f = function(args:Array<Dynamic>) {
|
||||
if( args.length != params.length ) {
|
||||
if( ( (args == null) ? 0 : args.length ) != params.length ) {
|
||||
if( args.length < minParams ) {
|
||||
var str = "Invalid number of parameters. Got " + args.length + ", required " + minParams;
|
||||
if( name != null ) str += " for function '" + name+"'";
|
||||
throw str;
|
||||
error(ECustom(str));
|
||||
}
|
||||
// make sure mandatory args are forced
|
||||
var args2 = [];
|
||||
@@ -468,7 +468,7 @@ class Interp {
|
||||
}
|
||||
return f;
|
||||
case EArrayDecl(arr):
|
||||
if (arr.length > 0 && edef(arr[0]).match(EBinop("=>", _))) {
|
||||
if (arr.length > 0 && Tools.expr(arr[0]).match(EBinop("=>", _))) {
|
||||
var isAllString:Bool = true;
|
||||
var isAllInt:Bool = true;
|
||||
var isAllObject:Bool = true;
|
||||
@@ -476,7 +476,7 @@ class Interp {
|
||||
var keys:Array<Dynamic> = [];
|
||||
var values:Array<Dynamic> = [];
|
||||
for (e in arr) {
|
||||
switch(edef(e)) {
|
||||
switch(Tools.expr(e)) {
|
||||
case EBinop("=>", eKey, eValue): {
|
||||
var key:Dynamic = expr(eKey);
|
||||
var value:Dynamic = expr(eValue);
|
||||
@@ -574,6 +574,8 @@ class Interp {
|
||||
return val;
|
||||
case EMeta(_, _, e):
|
||||
return expr(e);
|
||||
case ECheckType(e,_):
|
||||
return expr(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+10
-1
@@ -113,6 +113,7 @@ class Macro {
|
||||
|
||||
function convertType( t : Expr.CType ) : ComplexType {
|
||||
return switch( t ) {
|
||||
case CTOpt(t): TOptional(convertType(t));
|
||||
case CTPath(pack, args):
|
||||
var params = [];
|
||||
if( args != null )
|
||||
@@ -127,6 +128,12 @@ class Macro {
|
||||
case CTParent(t): TParent(convertType(t));
|
||||
case CTFun(args, ret):
|
||||
TFunction(map(args,convertType), convertType(ret));
|
||||
case CTNamed(name, convertType(_) => ct):
|
||||
#if (haxe_ver >= 4)
|
||||
TNamed(name, ct);
|
||||
#else
|
||||
ct;
|
||||
#end
|
||||
case CTAnon(fields):
|
||||
var tf = [];
|
||||
for( f in fields ) {
|
||||
@@ -207,7 +214,7 @@ class Macro {
|
||||
opt : false,
|
||||
value : null,
|
||||
});
|
||||
EFunction(name, {
|
||||
EFunction(#if haxe4 FNamed(name,false) #else name #end, {
|
||||
params : [],
|
||||
args : targs,
|
||||
expr : convert(e),
|
||||
@@ -238,6 +245,8 @@ class Macro {
|
||||
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));
|
||||
case ECheckType(e, t):
|
||||
ECheckType(convert(e), convertType(t));
|
||||
}, pos : #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end }
|
||||
}
|
||||
|
||||
|
||||
+205
-93
@@ -78,8 +78,15 @@ class Parser {
|
||||
**/
|
||||
public var allowMetadata : Bool;
|
||||
|
||||
/**
|
||||
resume from parsing errors (when parsing incomplete code, during completion for example)
|
||||
**/
|
||||
public var resumeErrors : Bool;
|
||||
|
||||
// implementation
|
||||
var input : haxe.io.Input;
|
||||
var input : String;
|
||||
var readPos : Int;
|
||||
|
||||
var char : Int;
|
||||
var ops : Array<Bool>;
|
||||
var idents : Array<Bool>;
|
||||
@@ -87,7 +94,6 @@ class Parser {
|
||||
|
||||
#if hscriptPos
|
||||
var origin : String;
|
||||
var readPos : Int;
|
||||
var tokenMin : Int;
|
||||
var tokenMax : Int;
|
||||
var oldTokenMin : Int;
|
||||
@@ -95,7 +101,6 @@ class Parser {
|
||||
var tokens : List<{ min : Int, max : Int, t : Token }>;
|
||||
#else
|
||||
static inline var p1 = 0;
|
||||
static inline var readPos = 0;
|
||||
static inline var tokenMin = 0;
|
||||
static inline var tokenMax = 0;
|
||||
#if haxe3
|
||||
@@ -142,6 +147,7 @@ class Parser {
|
||||
}
|
||||
|
||||
public inline function error( err, pmin, pmax ) {
|
||||
if( !resumeErrors )
|
||||
#if hscriptPos
|
||||
throw new Error(err, pmin, pmax, origin, line);
|
||||
#else
|
||||
@@ -150,7 +156,7 @@ class Parser {
|
||||
}
|
||||
|
||||
public function invalidChar(c) {
|
||||
error(EInvalidChar(c), readPos, readPos);
|
||||
error(EInvalidChar(c), readPos-1, readPos-1);
|
||||
}
|
||||
|
||||
function initParser( origin ) {
|
||||
@@ -178,12 +184,9 @@ class Parser {
|
||||
}
|
||||
|
||||
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;
|
||||
readPos = 0;
|
||||
var a = new Array();
|
||||
while( true ) {
|
||||
var tk = token();
|
||||
@@ -247,7 +250,7 @@ class Parser {
|
||||
|
||||
inline function pmin(e:Expr) {
|
||||
#if hscriptPos
|
||||
return e.pmin;
|
||||
return e == null ? 0 : e.pmin;
|
||||
#else
|
||||
return 0;
|
||||
#end
|
||||
@@ -255,7 +258,7 @@ class Parser {
|
||||
|
||||
inline function pmax(e:Expr) {
|
||||
#if hscriptPos
|
||||
return e.pmax;
|
||||
return e == null ? 0 : e.pmax;
|
||||
#else
|
||||
return 0;
|
||||
#end
|
||||
@@ -273,6 +276,7 @@ class Parser {
|
||||
}
|
||||
|
||||
function isBlock(e) {
|
||||
if( e == null ) return false;
|
||||
return switch( expr(e) ) {
|
||||
case EBlock(_), EObject(_), ESwitch(_): true;
|
||||
case EFunction(_,e,_,_): isBlock(e);
|
||||
@@ -296,7 +300,7 @@ class Parser {
|
||||
|
||||
var tk = token();
|
||||
// this is a hack to support var a,b,c; with a single EVar
|
||||
while( tk == TComma && expr(e).match(EVar(_)) ) {
|
||||
while( tk == TComma && e != null && expr(e).match(EVar(_)) ) {
|
||||
e = parseStructure("var"); // next variable
|
||||
exprs.push(e);
|
||||
tk = token();
|
||||
@@ -329,6 +333,7 @@ class Parser {
|
||||
break;
|
||||
default:
|
||||
unexpected(tk);
|
||||
break;
|
||||
}
|
||||
ensure(TDoubleDot);
|
||||
fl.push({ name : id, e : parseExpr() });
|
||||
@@ -359,8 +364,31 @@ class Parser {
|
||||
return parseExprNext(mk(EConst(c)));
|
||||
case TPOpen:
|
||||
var e = parseExpr();
|
||||
ensure(TPClose);
|
||||
return parseExprNext(mk(EParent(e),p1,tokenMax));
|
||||
tk = token();
|
||||
switch( tk ) {
|
||||
case TPClose:
|
||||
return parseExprNext(mk(EParent(e),p1,tokenMax));
|
||||
case TDoubleDot:
|
||||
var t = parseType();
|
||||
tk = token();
|
||||
switch( tk ) {
|
||||
case TPClose:
|
||||
return parseExprNext(mk(ECheckType(e,t),p1,tokenMax));
|
||||
case TComma:
|
||||
switch( expr(e) ) {
|
||||
case EIdent(v): return parseLambda([{ name : v, t : t }], pmin(e));
|
||||
default:
|
||||
}
|
||||
default:
|
||||
}
|
||||
case TComma:
|
||||
switch( expr(e) ) {
|
||||
case EIdent(v): return parseLambda([{name:v}], pmin(e));
|
||||
default:
|
||||
}
|
||||
default:
|
||||
}
|
||||
return unexpected(tk);
|
||||
case TBrOpen:
|
||||
tk = token();
|
||||
switch( tk ) {
|
||||
@@ -399,7 +427,7 @@ class Parser {
|
||||
while( true ) {
|
||||
parseFullExpr(a);
|
||||
tk = token();
|
||||
if( tk == TBrClose )
|
||||
if( tk == TBrClose || (resumeErrors && tk == TEof) )
|
||||
break;
|
||||
push(tk);
|
||||
}
|
||||
@@ -408,7 +436,7 @@ class Parser {
|
||||
if( unops.exists(op) ) {
|
||||
var start = tokenMin;
|
||||
var e = parseExpr();
|
||||
if( op == "-" )
|
||||
if( op == "-" && e != null )
|
||||
switch( expr(e) ) {
|
||||
case EConst(CInt(i)):
|
||||
return mk(EConst(CInt(-i)), start, pmax(e));
|
||||
@@ -422,14 +450,14 @@ class Parser {
|
||||
case TBkOpen:
|
||||
var a = new Array();
|
||||
tk = token();
|
||||
while( tk != TBkClose ) {
|
||||
while( tk != TBkClose && (!resumeErrors || tk != TEof) ) {
|
||||
push(tk);
|
||||
a.push(parseExpr());
|
||||
tk = token();
|
||||
if( tk == TComma )
|
||||
tk = token();
|
||||
}
|
||||
if( a.length == 1 )
|
||||
if( a.length == 1 && a[0] != null )
|
||||
switch( expr(a[0]) ) {
|
||||
case EFor(_), EWhile(_), EDoWhile(_):
|
||||
var tmp = "__a_" + (uid++);
|
||||
@@ -450,6 +478,26 @@ class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
function parseLambda( args : Array<Argument>, pmin ) {
|
||||
while( true ) {
|
||||
var id = getIdent();
|
||||
var t = maybe(TDoubleDot) ? parseType() : null;
|
||||
args.push({ name : id, t : t });
|
||||
var tk = token();
|
||||
switch( tk ) {
|
||||
case TComma:
|
||||
case TPClose:
|
||||
break;
|
||||
default:
|
||||
unexpected(tk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ensureToken(TOp("->"));
|
||||
var eret = parseExpr();
|
||||
return mk(EFunction(args, mk(EReturn(eret),pmin)), pmin);
|
||||
}
|
||||
|
||||
function parseMetaArgs() {
|
||||
var tk = token();
|
||||
if( tk != TPOpen ) {
|
||||
@@ -475,6 +523,7 @@ class Parser {
|
||||
}
|
||||
|
||||
function mapCompr( tmp : String, e : Expr ) {
|
||||
if( e == null ) return null;
|
||||
var edef = switch( expr(e) ) {
|
||||
case EFor(v, it, e2):
|
||||
EFor(v, it, mapCompr(tmp, e2));
|
||||
@@ -495,6 +544,8 @@ class Parser {
|
||||
}
|
||||
|
||||
function makeUnop( op, e ) {
|
||||
if( e == null && resumeErrors )
|
||||
return null;
|
||||
return switch( expr(e) ) {
|
||||
case EBinop(bop, e1, e2): mk(EBinop(bop, makeUnop(op, e1), e2), pmin(e1), pmax(e2));
|
||||
case ETernary(e1, e2, e3): mk(ETernary(makeUnop(op, e1), e2, e3), pmin(e1), pmax(e3));
|
||||
@@ -503,6 +554,8 @@ class Parser {
|
||||
}
|
||||
|
||||
function makeBinop( op, e1, e ) {
|
||||
if( e == null && resumeErrors )
|
||||
return mk(EBinop(op,e1,e),pmin(e1),pmax(e1));
|
||||
return switch( expr(e) ) {
|
||||
case EBinop(op2,e2,e3):
|
||||
if( opPriority.get(op) <= opPriority.get(op2) && !opRightAssoc.exists(op) )
|
||||
@@ -602,16 +655,16 @@ class Parser {
|
||||
case "new":
|
||||
var a = new Array();
|
||||
a.push(getIdent());
|
||||
var next = true;
|
||||
while( next ) {
|
||||
while( true ) {
|
||||
var tk = token();
|
||||
switch( tk ) {
|
||||
case TDot:
|
||||
a.push(getIdent());
|
||||
case TPOpen:
|
||||
next = false;
|
||||
break;
|
||||
default:
|
||||
unexpected(tk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
var args = parseExprList(TPClose);
|
||||
@@ -654,6 +707,7 @@ class Parser {
|
||||
break;
|
||||
default:
|
||||
unexpected(tk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
var exprs = [];
|
||||
@@ -663,6 +717,8 @@ class Parser {
|
||||
switch( tk ) {
|
||||
case TId("case"), TId("default"), TBrClose:
|
||||
break;
|
||||
case TEof if( resumeErrors ):
|
||||
break;
|
||||
default:
|
||||
parseFullExpr(exprs);
|
||||
}
|
||||
@@ -683,6 +739,8 @@ class Parser {
|
||||
switch( tk ) {
|
||||
case TId("case"), TId("default"), TBrClose:
|
||||
break;
|
||||
case TEof if( resumeErrors ):
|
||||
break;
|
||||
default:
|
||||
parseFullExpr(exprs);
|
||||
}
|
||||
@@ -697,6 +755,7 @@ class Parser {
|
||||
break;
|
||||
default:
|
||||
unexpected(tk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mk(ESwitch(e, cases, def), p1, tokenMax);
|
||||
@@ -709,6 +768,21 @@ class Parser {
|
||||
var tk = token();
|
||||
switch( tk ) {
|
||||
case TOp(op):
|
||||
|
||||
if( op == "->" ) {
|
||||
// single arg reinterpretation of `f -> e` , `(f) -> e` and `(f:T) -> e`
|
||||
switch( expr(e1) ) {
|
||||
case EIdent(i), EParent(expr(_) => EIdent(i)):
|
||||
var eret = parseExpr();
|
||||
return mk(EFunction([{ name : i }], mk(EReturn(eret),pmin(eret))), pmin(e1));
|
||||
case ECheckType(expr(_) => EIdent(i), t):
|
||||
var eret = parseExpr();
|
||||
return mk(EFunction([{ name : i, t : t }], mk(EReturn(eret),pmin(eret))), pmin(e1));
|
||||
default:
|
||||
}
|
||||
unexpected(tk);
|
||||
}
|
||||
|
||||
if( unops.get(op) ) {
|
||||
if( isBlock(e1) || switch(expr(e1)) { case EParent(_): true; default: false; } ) {
|
||||
push(tk);
|
||||
@@ -737,8 +811,7 @@ class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
function parseFunctionDecl() {
|
||||
ensure(TPOpen);
|
||||
function parseFunctionArgs() {
|
||||
var args = new Array();
|
||||
var tk = token();
|
||||
if( tk != TPClose ) {
|
||||
@@ -753,7 +826,9 @@ class Parser {
|
||||
}
|
||||
switch( tk ) {
|
||||
case TId(id): name = id;
|
||||
default: unexpected(tk);
|
||||
default:
|
||||
unexpected(tk);
|
||||
break;
|
||||
}
|
||||
var arg : Argument = { name : name };
|
||||
args.push(arg);
|
||||
@@ -775,9 +850,15 @@ class Parser {
|
||||
}
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
function parseFunctionDecl() {
|
||||
ensure(TPOpen);
|
||||
var args = parseFunctionArgs();
|
||||
var ret = null;
|
||||
if( allowTypes ) {
|
||||
tk = token();
|
||||
var tk = token();
|
||||
if( tk != TDoubleDot )
|
||||
push(tk);
|
||||
else
|
||||
@@ -829,6 +910,7 @@ class Parser {
|
||||
default:
|
||||
}
|
||||
unexpected(t);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
push(t);
|
||||
@@ -837,9 +919,53 @@ class Parser {
|
||||
}
|
||||
return parseTypeNext(CTPath(path, params));
|
||||
case TPOpen:
|
||||
var t = parseType();
|
||||
ensure(TPClose);
|
||||
return parseTypeNext(CTParent(t));
|
||||
var a = token(),
|
||||
b = token();
|
||||
|
||||
push(b);
|
||||
push(a);
|
||||
|
||||
function withReturn(args) {
|
||||
switch token() { // I think it wouldn't hurt if ensure used enumEq
|
||||
case TOp('->'):
|
||||
case t: unexpected(t);
|
||||
}
|
||||
|
||||
return CTFun(args, parseType());
|
||||
}
|
||||
|
||||
switch [a, b] {
|
||||
case [TPClose, _] | [TId(_), TDoubleDot]:
|
||||
|
||||
var args = [for (arg in parseFunctionArgs()) {
|
||||
switch arg.value {
|
||||
case null:
|
||||
case v:
|
||||
error(ECustom('Default values not allowed in function types'), #if hscriptPos v.pmin, v.pmax #else 0, 0 #end);
|
||||
}
|
||||
|
||||
CTNamed(arg.name, if (arg.opt) CTOpt(arg.t) else arg.t);
|
||||
}];
|
||||
|
||||
return withReturn(args);
|
||||
default:
|
||||
|
||||
var t = parseType();
|
||||
return switch token() {
|
||||
case TComma:
|
||||
var args = [t];
|
||||
|
||||
while (true) {
|
||||
args.push(parseType());
|
||||
if (!maybe(TComma)) break;
|
||||
}
|
||||
ensure(TPClose);
|
||||
withReturn(args);
|
||||
case TPClose:
|
||||
parseTypeNext(CTParent(t));
|
||||
case t: unexpected(t);
|
||||
}
|
||||
}
|
||||
case TBrOpen:
|
||||
var fields = [];
|
||||
var meta = null;
|
||||
@@ -867,6 +993,7 @@ class Parser {
|
||||
meta.push({ name : name, params : parseMetaArgs() });
|
||||
default:
|
||||
unexpected(t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return parseTypeNext(CTAnon(fields));
|
||||
@@ -911,6 +1038,7 @@ class Parser {
|
||||
default:
|
||||
if( tk == etk ) break;
|
||||
unexpected(tk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return args;
|
||||
@@ -920,7 +1048,8 @@ class Parser {
|
||||
|
||||
public function parseModule( content : String, ?origin : String = "hscript" ) {
|
||||
initParser(origin);
|
||||
this.input = new haxe.io.StringInput(content);
|
||||
input = content;
|
||||
readPos = 0;
|
||||
allowTypes = true;
|
||||
allowMetadata = true;
|
||||
var decls = [];
|
||||
@@ -1113,6 +1242,7 @@ class Parser {
|
||||
};
|
||||
default:
|
||||
unexpected(TId(id));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -1120,20 +1250,13 @@ class Parser {
|
||||
|
||||
// ------------------------ lexing -------------------------------
|
||||
|
||||
inline function incPos() {
|
||||
#if hscriptPos
|
||||
readPos++;
|
||||
#end
|
||||
}
|
||||
|
||||
function readChar() {
|
||||
incPos();
|
||||
return try input.readByte() catch( e : Dynamic ) 0;
|
||||
inline function readChar() {
|
||||
return StringTools.fastCodeAt(input, readPos++);
|
||||
}
|
||||
|
||||
function readString( until ) {
|
||||
var c = 0;
|
||||
var b = new haxe.io.BytesOutput();
|
||||
var b = new StringBuf();
|
||||
var esc = false;
|
||||
var old = line;
|
||||
var s = input;
|
||||
@@ -1141,38 +1264,26 @@ class Parser {
|
||||
var p1 = readPos - 1;
|
||||
#end
|
||||
while( true ) {
|
||||
try {
|
||||
incPos();
|
||||
c = s.readByte();
|
||||
} catch( e : Dynamic ) {
|
||||
var c = readChar();
|
||||
if( StringTools.isEof(c) ) {
|
||||
line = old;
|
||||
error(EUnterminatedString, p1, p1);
|
||||
break;
|
||||
}
|
||||
if( esc ) {
|
||||
esc = false;
|
||||
switch( c ) {
|
||||
case 'n'.code: b.writeByte(10);
|
||||
case 'r'.code: b.writeByte(13);
|
||||
case 't'.code: b.writeByte(9);
|
||||
case "'".code, '"'.code, '\\'.code: b.writeByte(c);
|
||||
case '/'.code: if( allowJSON ) b.writeByte(c) else invalidChar(c);
|
||||
case 'n'.code: b.addChar('\n'.code);
|
||||
case 'r'.code: b.addChar('\r'.code);
|
||||
case 't'.code: b.addChar('\t'.code);
|
||||
case "'".code, '"'.code, '\\'.code: b.addChar(c);
|
||||
case '/'.code: if( allowJSON ) b.addChar(c) else invalidChar(c);
|
||||
case "u".code:
|
||||
if( !allowJSON ) invalidChar(c);
|
||||
var code = null;
|
||||
try {
|
||||
incPos();
|
||||
incPos();
|
||||
incPos();
|
||||
incPos();
|
||||
code = s.readString(4);
|
||||
} catch( e : Dynamic ) {
|
||||
line = old;
|
||||
error(EUnterminatedString, p1, p1);
|
||||
}
|
||||
var k = 0;
|
||||
for( i in 0...4 ) {
|
||||
k <<= 4;
|
||||
var char = code.charCodeAt(i);
|
||||
var char = readChar();
|
||||
switch( char ) {
|
||||
case 48,49,50,51,52,53,54,55,56,57: // 0-9
|
||||
k += char - 48;
|
||||
@@ -1181,20 +1292,14 @@ class Parser {
|
||||
case 97,98,99,100,101,102: // a-f
|
||||
k += char - 87;
|
||||
default:
|
||||
if( StringTools.isEof(char) ) {
|
||||
line = old;
|
||||
error(EUnterminatedString, p1, p1);
|
||||
}
|
||||
invalidChar(char);
|
||||
}
|
||||
}
|
||||
// encode k in UTF8
|
||||
if( k <= 0x7F )
|
||||
b.writeByte(k);
|
||||
else if( k <= 0x7FF ) {
|
||||
b.writeByte( 0xC0 | (k >> 6));
|
||||
b.writeByte( 0x80 | (k & 63));
|
||||
} else {
|
||||
b.writeByte( 0xE0 | (k >> 12) );
|
||||
b.writeByte( 0x80 | ((k >> 6) & 63) );
|
||||
b.writeByte( 0x80 | (k & 63) );
|
||||
}
|
||||
b.addChar(k);
|
||||
default: invalidChar(c);
|
||||
}
|
||||
} else if( c == 92 )
|
||||
@@ -1203,10 +1308,10 @@ class Parser {
|
||||
break;
|
||||
else {
|
||||
if( c == 10 ) line++;
|
||||
b.writeByte(c);
|
||||
b.addChar(c);
|
||||
}
|
||||
}
|
||||
return b.getBytes().toString();
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
function token() {
|
||||
@@ -1238,8 +1343,13 @@ class Parser {
|
||||
this.char = -1;
|
||||
}
|
||||
while( true ) {
|
||||
if( StringTools.isEof(char) ) {
|
||||
this.char = char;
|
||||
return TEof;
|
||||
}
|
||||
switch( char ) {
|
||||
case 0: return TEof;
|
||||
case 0:
|
||||
return TEof;
|
||||
case 32,9,13: // space, tab, CR
|
||||
#if hscriptPos
|
||||
tokenMin++;
|
||||
@@ -1411,6 +1521,7 @@ class Parser {
|
||||
var prev = -1;
|
||||
while( true ) {
|
||||
char = readChar();
|
||||
if( StringTools.isEof(char) ) char = 0;
|
||||
if( !ops[char] || prev == '='.code ) {
|
||||
if( op.charCodeAt(0) == '/'.code )
|
||||
return tokenComment(op,char);
|
||||
@@ -1425,6 +1536,7 @@ class Parser {
|
||||
var id = String.fromCharCode(char);
|
||||
while( true ) {
|
||||
char = readChar();
|
||||
if( StringTools.isEof(char) ) char = 0;
|
||||
if( !idents[char] ) {
|
||||
this.char = char;
|
||||
return TId(id);
|
||||
@@ -1530,14 +1642,11 @@ class Parser {
|
||||
var c = op.charCodeAt(1);
|
||||
var s = input;
|
||||
if( c == '/'.code ) { // comment
|
||||
try {
|
||||
while( char != '\r'.code && char != '\n'.code ) {
|
||||
incPos();
|
||||
char = s.readByte();
|
||||
}
|
||||
this.char = char;
|
||||
} catch( e : Dynamic ) {
|
||||
while( char != '\r'.code && char != '\n'.code ) {
|
||||
char = readChar();
|
||||
if( StringTools.isEof(char) ) break;
|
||||
}
|
||||
this.char = char;
|
||||
return token();
|
||||
}
|
||||
if( c == '*'.code ) { /* comment */
|
||||
@@ -1546,21 +1655,24 @@ class Parser {
|
||||
this.char = char;
|
||||
return token();
|
||||
}
|
||||
try {
|
||||
while( true ) {
|
||||
while( char != '*'.code ) {
|
||||
if( char == '\n'.code ) line++;
|
||||
incPos();
|
||||
char = s.readByte();
|
||||
}
|
||||
incPos();
|
||||
char = s.readByte();
|
||||
if( char == '/'.code )
|
||||
while( true ) {
|
||||
while( char != '*'.code ) {
|
||||
if( char == '\n'.code ) line++;
|
||||
char = readChar();
|
||||
if( StringTools.isEof(char) ) {
|
||||
line = old;
|
||||
error(EUnterminatedComment, tokenMin, tokenMin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch( e : Dynamic ) {
|
||||
line = old;
|
||||
error(EUnterminatedComment, tokenMin, tokenMin);
|
||||
char = readChar();
|
||||
if( StringTools.isEof(char) ) {
|
||||
line = old;
|
||||
error(EUnterminatedComment, tokenMin, tokenMin);
|
||||
break;
|
||||
}
|
||||
if( char == '/'.code )
|
||||
break;
|
||||
}
|
||||
return token();
|
||||
}
|
||||
|
||||
+23
-1
@@ -48,6 +48,9 @@ class Printer {
|
||||
|
||||
function type( t : CType ) {
|
||||
switch( t ) {
|
||||
case CTOpt(t):
|
||||
add('?');
|
||||
type(t);
|
||||
case CTPath(path, params):
|
||||
add(path.join("."));
|
||||
if( params != null ) {
|
||||
@@ -59,6 +62,19 @@ class Printer {
|
||||
}
|
||||
add(">");
|
||||
}
|
||||
case CTNamed(name, t):
|
||||
add(name);
|
||||
add(':');
|
||||
type(t);
|
||||
case CTFun(args, ret) if (Lambda.exists(args, function (a) return a.match(CTNamed(_, _)))):
|
||||
add('(');
|
||||
for (a in args)
|
||||
switch a {
|
||||
case CTNamed(_, _): type(a);
|
||||
default: type(CTNamed('_', a));
|
||||
}
|
||||
add(')->');
|
||||
type(ret);
|
||||
case CTFun(args, ret):
|
||||
if( args.length == 0 )
|
||||
add("Void -> ");
|
||||
@@ -300,6 +316,12 @@ class Printer {
|
||||
}
|
||||
add(" ");
|
||||
expr(e);
|
||||
case ECheckType(e, t):
|
||||
add("(");
|
||||
expr(e);
|
||||
add(" : ");
|
||||
addType(t);
|
||||
add(")");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,7 +331,7 @@ class Printer {
|
||||
|
||||
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 EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF" : String.fromCharCode(c))+"' ("+c+")";
|
||||
case EUnexpected(s): "Unexpected token: \""+s+"\"";
|
||||
case EUnterminatedString: "Unterminated string";
|
||||
case EUnterminatedComment: "Unterminated comment";
|
||||
|
||||
+20
-8
@@ -25,7 +25,7 @@ import hscript.Expr;
|
||||
class Tools {
|
||||
|
||||
public static function iter( e : Expr, f : Expr -> Void ) {
|
||||
switch( #if hscriptPos e.e #else e #end ) {
|
||||
switch( expr(e) ) {
|
||||
case EConst(_), EIdent(_):
|
||||
case EVar(_, _, e): if( e != null ) f(e);
|
||||
case EParent(e): f(e);
|
||||
@@ -56,16 +56,13 @@ class Tools {
|
||||
}
|
||||
if( def != null ) f(def);
|
||||
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e);
|
||||
case ECheckType(e,_): f(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static function map( e : Expr, f : Expr -> Expr ) {
|
||||
#if hscriptPos
|
||||
var edef = switch( e.e ) {
|
||||
#else
|
||||
return switch( e ) {
|
||||
#end
|
||||
case EConst(_), EIdent(_), EBreak, EContinue: #if hscriptPos e.e #else e #end;
|
||||
var edef = switch( expr(e) ) {
|
||||
case EConst(_), EIdent(_), EBreak, EContinue: expr(e);
|
||||
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)]);
|
||||
@@ -88,9 +85,24 @@ class Tools {
|
||||
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));
|
||||
case ECheckType(e,t): ECheckType(f(e), t);
|
||||
}
|
||||
return mk(edef, e);
|
||||
}
|
||||
|
||||
public static inline function expr( e : Expr ) : ExprDef {
|
||||
#if hscriptPos
|
||||
return { e : edef, pmin : e.pmin, pmax : e.pmax, origin : e.origin, line : e.line };
|
||||
return e.e;
|
||||
#else
|
||||
return e;
|
||||
#end
|
||||
}
|
||||
|
||||
public static inline function mk( e : ExprDef, p : Expr ) {
|
||||
#if hscriptPos
|
||||
return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line };
|
||||
#else
|
||||
return e;
|
||||
#end
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@echo off
|
||||
set PATH="C:\Program Files\7-Zip";%PATH%
|
||||
rm -rf release
|
||||
mkdir release
|
||||
cp haxelib.json README.md extraParams.hxml release
|
||||
|
||||
Reference in New Issue
Block a user