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 |
+11
-16
@@ -4,11 +4,11 @@ os:
|
|||||||
- linux
|
- linux
|
||||||
- osx
|
- osx
|
||||||
|
|
||||||
sudo: false
|
dist: bionic
|
||||||
dist: trusty
|
|
||||||
|
|
||||||
haxe:
|
haxe:
|
||||||
- "3.4.7"
|
- "3.4.7"
|
||||||
|
- "4.0.3"
|
||||||
- development
|
- development
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
@@ -19,27 +19,20 @@ addons:
|
|||||||
- g++-multilib
|
- g++-multilib
|
||||||
# Python
|
# Python
|
||||||
- python3
|
- python3
|
||||||
|
# PHP
|
||||||
|
- php-cli
|
||||||
|
- php-mbstring
|
||||||
# C#
|
# C#
|
||||||
- mono-devel
|
- mono-devel
|
||||||
- mono-mcs
|
- mono-mcs
|
||||||
# Flash
|
|
||||||
- libglib2.0
|
|
||||||
- libfreetype6
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
# os-specific config
|
# os-specific config
|
||||||
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then
|
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
|
||||||
export DISPLAY=:99.0;
|
|
||||||
export AUDIODEV=null;
|
|
||||||
phpenv global 7.0;
|
|
||||||
elif [ "${TRAVIS_OS_NAME}" = "osx" ]; then
|
|
||||||
brew update;
|
brew update;
|
||||||
brew install mono;
|
brew install mono;
|
||||||
brew upgrade python;
|
|
||||||
brew install php;
|
brew install php;
|
||||||
fi
|
fi
|
||||||
# Download and setup a standalone flash player debugger
|
|
||||||
- haxe flash/install.hxml
|
|
||||||
# Install haxelibs
|
# Install haxelibs
|
||||||
- if [ "${TRAVIS_HAXE_VERSION}" = "development" ]; then
|
- if [ "${TRAVIS_HAXE_VERSION}" = "development" ]; then
|
||||||
haxelib git hxcpp https://github.com/HaxeFoundation/hxcpp.git;
|
haxelib git hxcpp https://github.com/HaxeFoundation/hxcpp.git;
|
||||||
@@ -67,8 +60,10 @@ script:
|
|||||||
- haxe bin/build-neko.hxml && neko bin/Test.n
|
- haxe bin/build-neko.hxml && neko bin/Test.n
|
||||||
- haxe bin/build-js.hxml && node bin/Test.js
|
- haxe bin/build-js.hxml && node bin/Test.js
|
||||||
- haxe bin/build-java.hxml && java -jar bin/Test.jar
|
- 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-cpp.hxml && ./bin/Test
|
||||||
- haxe bin/build-flash.hxml -D fdb && haxe flash/run.hxml bin/Test.swf
|
- haxe bin/build-php.hxml -D php7 && php bin/index.php
|
||||||
- haxe bin/build-php.hxml && php bin/index.php
|
|
||||||
- haxe bin/build-python.hxml && python3 bin/Test.py
|
- haxe bin/build-python.hxml && python3 bin/Test.py
|
||||||
|
|||||||
@@ -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 `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
|
Limitations
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Compared to Haxe, limitations are :
|
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)
|
- `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`
|
- 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
|
- 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 enable per-expression position tracking by compiling with `-D hscriptPos`
|
||||||
|
- you can parse some type declarations (import, class, typedef, etc.) with parseModule
|
||||||
|
|
||||||
Install
|
Install
|
||||||
-------
|
-------
|
||||||
|
|
||||||
In order to install Haxe Script, use `haxelib install hscript` and compile your program with `-lib hscript`.
|
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.Expr` : contains enums declarations
|
||||||
- `hscript.Parser` : a small parser that turns a string into an expression structure (AST)
|
- `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
|
- `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,6 +4,7 @@ import hscript.Macro;
|
|||||||
import hscript.Tools;
|
import hscript.Tools;
|
||||||
import hscript.Async;
|
import hscript.Async;
|
||||||
import hscript.Printer;
|
import hscript.Printer;
|
||||||
|
import hscript.Checker;
|
||||||
import haxe.unit.*;
|
import haxe.unit.*;
|
||||||
|
|
||||||
class Test extends TestCase {
|
class Test extends TestCase {
|
||||||
|
|||||||
+1
-9
@@ -8,17 +8,11 @@ install:
|
|||||||
# http://help.appveyor.com/discussions/problems/5616-not-able-to-build-due-to-problem-in-chocolateyinstallps1
|
# http://help.appveyor.com/discussions/problems/5616-not-able-to-build-due-to-problem-in-chocolateyinstallps1
|
||||||
- ps: Set-Service wuauserv -StartupType Manual
|
- ps: Set-Service wuauserv -StartupType Manual
|
||||||
# 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.7 -y
|
- cinst haxe -version 4.0.3 -y
|
||||||
- RefreshEnv
|
- RefreshEnv
|
||||||
# Setup haxelib
|
# Setup haxelib
|
||||||
- mkdir "%HAXELIB_ROOT%"
|
- mkdir "%HAXELIB_ROOT%"
|
||||||
- haxelib setup "%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
|
# 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
|
||||||
@@ -39,6 +33,4 @@ test_script:
|
|||||||
- haxe bin/build-java.hxml && java -jar bin\Test.jar
|
- haxe bin/build-java.hxml && java -jar bin\Test.jar
|
||||||
- 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-php.hxml && php 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,5 +0,0 @@
|
|||||||
*.exe
|
|
||||||
*.app
|
|
||||||
flashplayerdebugger
|
|
||||||
LGPL/
|
|
||||||
license.pdf
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
import Sys.*;
|
|
||||||
import sys.FileSystem.*;
|
|
||||||
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/26/flash_player_sa_linux_debug.x86_64.tar.gz";
|
|
||||||
case "Mac":
|
|
||||||
"http://fpdownload.macromedia.com/pub/flashplayer/updaters/26/flashplayer_26_sa_debug.dmg";
|
|
||||||
case "Windows":
|
|
||||||
"http://fpdownload.macromedia.com/pub/flashplayer/updaters/26/flashplayer_26_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("APPDATA"), "Macromedia", "Flash Player", "#Security", "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";
|
|
||||||
deleteFile(Path.withoutDirectory(fpDownload));
|
|
||||||
case "Mac":
|
|
||||||
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",
|
"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.3.0",
|
"version": "2.4.0",
|
||||||
"releasenote": "",
|
"releasenote": "Haxe 4.0 final + type checking/completion (hscript.Checker)",
|
||||||
"contributors": ["ncannasse"]
|
"contributors": ["ncannasse"]
|
||||||
}
|
}
|
||||||
+45
-20
@@ -22,9 +22,16 @@
|
|||||||
package hscript;
|
package hscript;
|
||||||
import hscript.Expr;
|
import hscript.Expr;
|
||||||
|
|
||||||
|
|
||||||
|
enum VarMode {
|
||||||
|
Defined;
|
||||||
|
ForceSync;
|
||||||
|
}
|
||||||
|
|
||||||
class Async {
|
class Async {
|
||||||
|
|
||||||
var varNames : Array<String>;
|
var definedVars : Array<{ n : String, prev : Null<VarMode> }>;
|
||||||
|
var vars : Map<String,VarMode>;
|
||||||
var currentFun : String;
|
var currentFun : String;
|
||||||
var currentLoop : Expr;
|
var currentLoop : Expr;
|
||||||
var currentBreak : Expr -> Expr;
|
var currentBreak : Expr -> Expr;
|
||||||
@@ -68,15 +75,33 @@ class Async {
|
|||||||
return a.build(e, topLevelSync);
|
return a.build(e, topLevelSync);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public dynamic function getTopLevelEnd() {
|
||||||
|
return ignore();
|
||||||
|
}
|
||||||
|
|
||||||
public function build( e : Expr, topLevelSync = false ) {
|
public function build( e : Expr, topLevelSync = false ) {
|
||||||
if( topLevelSync ) {
|
if( topLevelSync ) {
|
||||||
return buildSync(e,null);
|
return buildSync(e,null);
|
||||||
} else {
|
} else {
|
||||||
var nothing = ignore();
|
var end = getTopLevelEnd();
|
||||||
return new Async().toCps(e, nothing, nothing);
|
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 {
|
function buildSync( e : Expr, exit : Expr ) : Expr {
|
||||||
switch( expr(e) ) {
|
switch( expr(e) ) {
|
||||||
case EFunction(_,_,name,_):
|
case EFunction(_,_,name,_):
|
||||||
@@ -85,16 +110,14 @@ class Async {
|
|||||||
return e;
|
return e;
|
||||||
case EBlock(el):
|
case EBlock(el):
|
||||||
var v = saveVars();
|
var v = saveVars();
|
||||||
for( e in el )
|
lookupFunctions(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);
|
var e = block([for(e in el) buildSync(e,exit)], e);
|
||||||
restoreVars(v);
|
restoreVars(v);
|
||||||
return e;
|
return e;
|
||||||
case EMeta("async", _, e):
|
case EMeta("async", _, e):
|
||||||
return toCps(e, ignore(), ignore());
|
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 ):
|
case EBreak if( currentBreak != null ):
|
||||||
return currentBreak(e);
|
return currentBreak(e);
|
||||||
case EContinue if( currentLoop != null ):
|
case EContinue if( currentLoop != null ):
|
||||||
@@ -115,7 +138,8 @@ class Async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function new() {
|
public function new() {
|
||||||
varNames = [];
|
vars = new Map();
|
||||||
|
definedVars = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
function ignore(?e) : Expr {
|
function ignore(?e) : Expr {
|
||||||
@@ -199,11 +223,14 @@ class Async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function saveVars() {
|
function saveVars() {
|
||||||
return varNames.length;
|
return definedVars.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
function restoreVars(k) {
|
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 {
|
public function toCps( e : Expr, rest : Expr, exit : Expr ) : Expr {
|
||||||
@@ -213,12 +240,7 @@ class Async {
|
|||||||
case EBlock(el):
|
case EBlock(el):
|
||||||
var el = el.copy();
|
var el = el.copy();
|
||||||
var vold = saveVars();
|
var vold = saveVars();
|
||||||
// local recursion
|
lookupFunctions(el);
|
||||||
for( e in el )
|
|
||||||
switch( expr(e) ) {
|
|
||||||
case EFunction(_, _, name, null): if( name != null ) varNames.push(name);
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
while( el.length > 0 ) {
|
while( el.length > 0 ) {
|
||||||
var e = toCps(el.pop(), rest, exit);
|
var e = toCps(el.pop(), rest, exit);
|
||||||
rest = ignore(e);
|
rest = ignore(e);
|
||||||
@@ -228,9 +250,9 @@ class Async {
|
|||||||
case EFunction(args, body, name, t):
|
case EFunction(args, body, name, t):
|
||||||
var vold = saveVars();
|
var vold = saveVars();
|
||||||
if( name != null )
|
if( name != null )
|
||||||
varNames.push(name);
|
defineVar(name, Defined);
|
||||||
for( a in args )
|
for( a in args )
|
||||||
varNames.push(a.name);
|
defineVar(a.name, Defined);
|
||||||
args.unshift( { name : "_onEnd", t : null } );
|
args.unshift( { name : "_onEnd", t : null } );
|
||||||
var frest = ident("_onEnd",e);
|
var frest = ident("_onEnd",e);
|
||||||
var oldFun = currentFun;
|
var oldFun = currentFun;
|
||||||
@@ -251,7 +273,8 @@ class Async {
|
|||||||
var args = [for( a in args ) fun("_rest", toCps(block([a],a), ident("_rest",a), exit))];
|
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);
|
return call(ident("split",e), [rest, mk(EArrayDecl(args),e)],e);
|
||||||
case ECall(expr(_) => EIdent(i), args):
|
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):
|
case ECall(expr(_) => EField(e, f), args):
|
||||||
return makeCall(field(e,"a_"+f,e), args, rest, exit);
|
return makeCall(field(e,"a_"+f,e), args, rest, exit);
|
||||||
case EFor(v, eit, eloop):
|
case EFor(v, eit, eloop):
|
||||||
@@ -391,6 +414,8 @@ class Async {
|
|||||||
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 );
|
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):
|
case EThrow(v):
|
||||||
return toCps(v, mk(EFunction([ { name : "_v", t : null } ], mk(EThrow(v),v)), v), exit);
|
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(_):
|
//case EDoWhile(_), ETry(_), ECall(_):
|
||||||
default:
|
default:
|
||||||
throw "Unsupported async expression " + Printer.toString(e);
|
throw "Unsupported async expression " + Printer.toString(e);
|
||||||
|
|||||||
+296
-52
@@ -23,6 +23,7 @@ enum TType {
|
|||||||
TAbstract( a : CAbstract, args : Array<TType> );
|
TAbstract( a : CAbstract, args : Array<TType> );
|
||||||
TFun( args : Array<{ name : String, opt : Bool, t : TType }>, ret : TType );
|
TFun( args : Array<{ name : String, opt : Bool, t : TType }>, ret : TType );
|
||||||
TAnon( fields : Array<{ name : String, opt : Bool, t : TType }> );
|
TAnon( fields : Array<{ name : String, opt : Bool, t : TType }> );
|
||||||
|
TLazy( f : Void -> TType );
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum WithType {
|
private enum WithType {
|
||||||
@@ -53,13 +54,15 @@ typedef CClass = {> CNamedType,
|
|||||||
|
|
||||||
typedef CField = {
|
typedef CField = {
|
||||||
var isPublic : Bool;
|
var isPublic : Bool;
|
||||||
|
var canWrite : Bool;
|
||||||
|
var complete : Bool;
|
||||||
var params : Array<TType>;
|
var params : Array<TType>;
|
||||||
var name : String;
|
var name : String;
|
||||||
var t : TType;
|
var t : TType;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef CEnum = {> CNamedType,
|
typedef CEnum = {> CNamedType,
|
||||||
var constructors : Map<String,TType>;
|
var constructors : Array<{ name : String, ?args : Array<{ name : String, opt : Bool, t : TType }> }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef CTypedef = {> CNamedType,
|
typedef CTypedef = {> CNamedType,
|
||||||
@@ -67,6 +70,16 @@ typedef CTypedef = {> CNamedType,
|
|||||||
}
|
}
|
||||||
|
|
||||||
typedef CAbstract = {> CNamedType,
|
typedef CAbstract = {> CNamedType,
|
||||||
|
var t : TType;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Completion {
|
||||||
|
public var expr : Expr;
|
||||||
|
public var t : TType;
|
||||||
|
public function new(expr,t) {
|
||||||
|
this.expr = expr;
|
||||||
|
this.t = t;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@:allow(hscript.Checker)
|
@:allow(hscript.Checker)
|
||||||
@@ -118,13 +131,17 @@ class CheckerTypes {
|
|||||||
for( f in c.fields ) {
|
for( f in c.fields ) {
|
||||||
if( f.isOverride || f.name.substr(0,4) == "get_" || f.name.substr(0,4) == "set_" ) continue;
|
if( f.isOverride || f.name.substr(0,4) == "get_" || f.name.substr(0,4) == "set_" ) continue;
|
||||||
var skip = false;
|
var skip = false;
|
||||||
for( m in f.meta )
|
var complete = !StringTools.startsWith(f.name,"__"); // __uid, etc. (no metadata in such fields)
|
||||||
if( m.name == ":noScript" ) {
|
for( m in f.meta ) {
|
||||||
|
if( m.name == ":noScript" ) {
|
||||||
skip = true;
|
skip = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if( m.name == ":noCompletion" )
|
||||||
|
complete = false;
|
||||||
|
}
|
||||||
if( skip ) continue;
|
if( skip ) continue;
|
||||||
var fl : CField = { isPublic : f.isPublic, params : [], name : f.name, t : null };
|
var fl : CField = { isPublic : f.isPublic, canWrite : f.set.match(RNormal | RCall(_) | RDynamic), complete : complete, params : [], name : f.name, t : null };
|
||||||
for( p in f.params ) {
|
for( p in f.params ) {
|
||||||
var pt = TParam(p);
|
var pt = TParam(p);
|
||||||
var key = f.name+"."+p;
|
var key = f.name+"."+p;
|
||||||
@@ -148,12 +165,14 @@ class CheckerTypes {
|
|||||||
var en : CEnum = {
|
var en : CEnum = {
|
||||||
name : e.path,
|
name : e.path,
|
||||||
params : [],
|
params : [],
|
||||||
constructors: new Map(),
|
constructors: [],
|
||||||
};
|
};
|
||||||
for( p in e.params )
|
for( p in e.params )
|
||||||
en.params.push(TParam(p));
|
en.params.push(TParam(p));
|
||||||
todo.push(function() {
|
todo.push(function() {
|
||||||
localParams = [for( t in en.params ) e.path+"."+Checker.typeStr(t) => t];
|
localParams = [for( t in en.params ) e.path+"."+Checker.typeStr(t) => t];
|
||||||
|
for( c in e.constructors )
|
||||||
|
en.constructors.push({ name : c.name, args : c.args == null ? null : [for( a in c.args ) { name : a.name, opt : a.opt, t : makeXmlType(a.t) }] });
|
||||||
localParams = null;
|
localParams = null;
|
||||||
});
|
});
|
||||||
types.set(en.name, CTEnum(en));
|
types.set(en.name, CTEnum(en));
|
||||||
@@ -179,11 +198,13 @@ class CheckerTypes {
|
|||||||
var ta : CAbstract = {
|
var ta : CAbstract = {
|
||||||
name : a.path,
|
name : a.path,
|
||||||
params : [],
|
params : [],
|
||||||
|
t : null,
|
||||||
};
|
};
|
||||||
for( p in a.params )
|
for( p in a.params )
|
||||||
ta.params.push(TParam(p));
|
ta.params.push(TParam(p));
|
||||||
todo.push(function() {
|
todo.push(function() {
|
||||||
localParams = [for( t in ta.params ) a.path+"."+Checker.typeStr(t) => t];
|
localParams = [for( t in ta.params ) a.path+"."+Checker.typeStr(t) => t];
|
||||||
|
ta.t = makeXmlType(a.athis);
|
||||||
localParams = null;
|
localParams = null;
|
||||||
});
|
});
|
||||||
types.set(a.path, CTAbstract(ta));
|
types.set(a.path, CTAbstract(ta));
|
||||||
@@ -220,8 +241,18 @@ class CheckerTypes {
|
|||||||
if( t != null ) return t;
|
if( t != null ) return t;
|
||||||
}
|
}
|
||||||
var t = resolve(name,args);
|
var t = resolve(name,args);
|
||||||
if( t == null )
|
if( t == null ) {
|
||||||
|
var pack = name.split(".");
|
||||||
|
if( pack.length > 1 ) {
|
||||||
|
// bugfix for some args reported as pack._Name.Name while they are not private
|
||||||
|
var priv = pack[pack.length-2];
|
||||||
|
if( priv.charCodeAt(0) == "_".code ) {
|
||||||
|
pack.remove(priv);
|
||||||
|
return getType(pack.join("."), args);
|
||||||
|
}
|
||||||
|
}
|
||||||
return TUnresolved(name); // most likely private class
|
return TUnresolved(name); // most likely private class
|
||||||
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,14 +281,29 @@ class Checker {
|
|||||||
var locals : Map<String,TType>;
|
var locals : Map<String,TType>;
|
||||||
var globals : Map<String,TType> = new Map();
|
var globals : Map<String,TType> = new Map();
|
||||||
var events : Map<String,TType> = new Map();
|
var events : Map<String,TType> = new Map();
|
||||||
|
var currentFunType : TType;
|
||||||
|
var isCompletion : Bool;
|
||||||
|
var allowDefine : Bool;
|
||||||
public var allowAsync : Bool;
|
public var allowAsync : Bool;
|
||||||
public var allowReturn : Null<TType>;
|
public var allowReturn : Null<TType>;
|
||||||
|
public var allowGlobalsDefine : Bool;
|
||||||
|
public var allowUntypedMeta : Bool;
|
||||||
|
|
||||||
public function new( ?types ) {
|
public function new( ?types ) {
|
||||||
if( types == null ) types = new CheckerTypes();
|
if( types == null ) types = new CheckerTypes();
|
||||||
this.types = types;
|
this.types = types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setGlobals( cl : CClass ) {
|
||||||
|
for( f in cl.fields )
|
||||||
|
if( f.isPublic )
|
||||||
|
setGlobal(f.name, f.params.length == 0 ? f.t : TLazy(function() return apply(f.t,f.params,[for( i in 0...f.params.length) makeMono()])));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeGlobal( name : String ) {
|
||||||
|
globals.remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
public function setGlobal( name : String, type : TType ) {
|
public function setGlobal( name : String, type : TType ) {
|
||||||
globals.set(name, type);
|
globals.set(name, type);
|
||||||
}
|
}
|
||||||
@@ -270,9 +316,54 @@ class Checker {
|
|||||||
return globals;
|
return globals;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function check( expr : Expr, ?withType : WithType ) {
|
function typeArgs( args : Array<Argument>, pos : Expr ) {
|
||||||
|
return [for( i in 0...args.length ) {
|
||||||
|
var a = args[i];
|
||||||
|
var at = a.t == null ? makeMono() : makeType(a.t, pos);
|
||||||
|
{ name : a.name, opt : a.opt, t : at };
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function check( expr : Expr, ?withType : WithType, ?isCompletion = false ) {
|
||||||
if( withType == null ) withType = NoValue;
|
if( withType == null ) withType = NoValue;
|
||||||
locals = new Map();
|
locals = new Map();
|
||||||
|
allowDefine = allowGlobalsDefine;
|
||||||
|
this.isCompletion = isCompletion;
|
||||||
|
switch( edef(expr) ) {
|
||||||
|
case EBlock(el):
|
||||||
|
var delayed = [];
|
||||||
|
var last = TVoid;
|
||||||
|
for( e in el ) {
|
||||||
|
while( true ) {
|
||||||
|
switch( edef(e) ) {
|
||||||
|
case EMeta(_,_,e2): e = e2;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch( edef(e) ) {
|
||||||
|
case EFunction(args,_,name,ret) if( name != null ):
|
||||||
|
var tret = ret == null ? makeMono() : makeType(ret, e);
|
||||||
|
var ft = TFun(typeArgs(args,e),tret);
|
||||||
|
locals.set(name, ft);
|
||||||
|
delayed.push(function() {
|
||||||
|
currentFunType = ft;
|
||||||
|
typeExpr(e, NoValue);
|
||||||
|
return ft;
|
||||||
|
});
|
||||||
|
default:
|
||||||
|
for( f in delayed ) f();
|
||||||
|
delayed = [];
|
||||||
|
if( el[el.length-1] == e )
|
||||||
|
last = typeExpr(e, withType);
|
||||||
|
else
|
||||||
|
typeExpr(e, NoValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for( f in delayed )
|
||||||
|
last = f();
|
||||||
|
return last;
|
||||||
|
default:
|
||||||
|
}
|
||||||
return typeExpr(expr,withType);
|
return typeExpr(expr,withType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,7 +378,7 @@ class Checker {
|
|||||||
inline function error( msg : String, curExpr : Expr ) {
|
inline function error( msg : String, curExpr : Expr ) {
|
||||||
var e = ECustom(msg);
|
var e = ECustom(msg);
|
||||||
#if hscriptPos var e = new Error(e, curExpr.pmin, curExpr.pmax, curExpr.origin, curExpr.line); #end
|
#if hscriptPos var e = new Error(e, curExpr.pmin, curExpr.pmax, curExpr.origin, curExpr.line); #end
|
||||||
throw e;
|
if( !isCompletion ) throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveLocals() {
|
function saveLocals() {
|
||||||
@@ -297,8 +388,11 @@ class Checker {
|
|||||||
function makeType( t : CType, e : Expr ) : TType {
|
function makeType( t : CType, e : Expr ) : TType {
|
||||||
return switch (t) {
|
return switch (t) {
|
||||||
case CTPath(path, params):
|
case CTPath(path, params):
|
||||||
var ct = types.resolve(path.join("."),params == null ? [] : [for( p in params ) makeType(t,e)]);
|
var ct = types.resolve(path.join("."),params == null ? [] : [for( p in params ) makeType(p,e)]);
|
||||||
if( ct == null ) error("Unknown type "+path, e);
|
if( ct == null ) {
|
||||||
|
error("Unknown type "+path, e);
|
||||||
|
ct = TDynamic;
|
||||||
|
}
|
||||||
return ct;
|
return ct;
|
||||||
case CTFun(args, ret):
|
case CTFun(args, ret):
|
||||||
var i = 0;
|
var i = 0;
|
||||||
@@ -307,6 +401,10 @@ class Checker {
|
|||||||
return TAnon([for( f in fields ) { name : f.name, opt : false, t : makeType(f.t,e) }]);
|
return TAnon([for( f in fields ) { name : f.name, opt : false, t : makeType(f.t,e) }]);
|
||||||
case CTParent(t):
|
case CTParent(t):
|
||||||
return makeType(t,e);
|
return makeType(t,e);
|
||||||
|
case CTNamed(n, t):
|
||||||
|
return makeType(t,e);
|
||||||
|
case CTOpt(t):
|
||||||
|
return makeType(t,e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,7 +414,11 @@ class Checker {
|
|||||||
case TMono(r): r.r == null ? "Unknown" : typeStr(r.r);
|
case TMono(r): r.r == null ? "Unknown" : typeStr(r.r);
|
||||||
case TInst(c, args): c.name + makeArgs(args);
|
case TInst(c, args): c.name + makeArgs(args);
|
||||||
case TEnum(e, args): e.name + makeArgs(args);
|
case TEnum(e, args): e.name + makeArgs(args);
|
||||||
case TType(t, args): t.name + makeArgs(args);
|
case TType(t, args):
|
||||||
|
if( t.name == "hscript.TypeCheck" )
|
||||||
|
typeStr(args[1]);
|
||||||
|
else
|
||||||
|
t.name + makeArgs(args);
|
||||||
case TAbstract(a, args): a.name + makeArgs(args);
|
case TAbstract(a, args): a.name + makeArgs(args);
|
||||||
case TFun(args, ret): "(" + [for( a in args ) (a.opt?"?":"")+(a.name == "" ? "" : a.name+":")+typeStr(a.t)].join(", ")+") -> "+typeStr(ret);
|
case TFun(args, ret): "(" + [for( a in args ) (a.opt?"?":"")+(a.name == "" ? "" : a.name+":")+typeStr(a.t)].join(", ")+") -> "+typeStr(ret);
|
||||||
case TAnon(fields): "{" + [for( f in fields ) (f.opt?"?":"")+f.name+":"+typeStr(f.t)].join(", ")+"}";
|
case TAnon(fields): "{" + [for( f in fields ) (f.opt?"?":"")+f.name+":"+typeStr(f.t)].join(", ")+"}";
|
||||||
@@ -505,6 +607,25 @@ class Checker {
|
|||||||
if( !typeEq(pl1[i],pl2[i]) )
|
if( !typeEq(pl1[i],pl2[i]) )
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
case [TInst(cl1,pl1),TAnon(fl)]:
|
||||||
|
for( i in 0...fl.length ) {
|
||||||
|
var f2 = fl[i];
|
||||||
|
var f1 = null;
|
||||||
|
var cl = cl1;
|
||||||
|
while( true ) {
|
||||||
|
f1 = cl.fields.get(f2.name);
|
||||||
|
if( f1 != null ) break;
|
||||||
|
if( cl.superClass == null )
|
||||||
|
return false;
|
||||||
|
cl = switch( cl.superClass ) {
|
||||||
|
case TInst(c,_): c;
|
||||||
|
default: throw "assert";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( !typeEq(f1.t,f2.t) )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
case [TInt, TFloat]:
|
case [TInt, TFloat]:
|
||||||
return true;
|
return true;
|
||||||
case [TFun(_), TAbstract({ name : "haxe.Function" },_)]:
|
case [TFun(_), TAbstract({ name : "haxe.Function" },_)]:
|
||||||
@@ -514,12 +635,12 @@ class Checker {
|
|||||||
return typeEq(t1,t2);
|
return typeEq(t1,t2);
|
||||||
}
|
}
|
||||||
|
|
||||||
function unify( t1 : TType, t2 : TType, e : Expr ) {
|
public function unify( t1 : TType, t2 : TType, e : Expr ) {
|
||||||
if( !tryUnify(t1,t2) )
|
if( !tryUnify(t1,t2) )
|
||||||
error(typeStr(t1)+" should be "+typeStr(t2),e);
|
error(typeStr(t1)+" should be "+typeStr(t2),e);
|
||||||
}
|
}
|
||||||
|
|
||||||
function apply( t : TType, params : Array<TType>, args : Array<TType> ) {
|
public function apply( t : TType, params : Array<TType>, args : Array<TType> ) {
|
||||||
if( args.length != params.length ) throw "Invalid number of type parameters";
|
if( args.length != params.length ) throw "Invalid number of type parameters";
|
||||||
if( args.length == 0 )
|
if( args.length == 0 )
|
||||||
return t;
|
return t;
|
||||||
@@ -557,14 +678,17 @@ class Checker {
|
|||||||
return TFun([for( a in args ) { name : a.name, opt : a.opt, t : f(a.t) }], f(ret));
|
return TFun([for( a in args ) { name : a.name, opt : a.opt, t : f(a.t) }], f(ret));
|
||||||
case TAnon(fields):
|
case TAnon(fields):
|
||||||
return TAnon([for( af in fields ) { name : af.name, opt : af.opt, t : f(af.t) }]);
|
return TAnon([for( af in fields ) { name : af.name, opt : af.opt, t : f(af.t) }]);
|
||||||
|
case TLazy(l):
|
||||||
|
return f(l());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function follow( t : TType ) {
|
public function follow( t : TType ) {
|
||||||
return switch( t ) {
|
return switch( t ) {
|
||||||
case TMono(r): if( r.r != null ) follow(r.r) else t;
|
case TMono(r): if( r.r != null ) follow(r.r) else t;
|
||||||
case TType(t,args): apply(t.t, t.params, args);
|
case TType(t,args): follow(apply(t.t, t.params, args));
|
||||||
case TNull(t): follow(t);
|
case TNull(t): follow(t);
|
||||||
|
case TLazy(f): follow(f());
|
||||||
default: t;
|
default: t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -590,7 +714,7 @@ class Checker {
|
|||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getField( t : TType, f : String, e : Expr ) {
|
function getField( t : TType, f : String, e : Expr, forWrite = false ) {
|
||||||
switch( follow(t) ) {
|
switch( follow(t) ) {
|
||||||
case TInst(c, args):
|
case TInst(c, args):
|
||||||
var cf = c.fields.get(f);
|
var cf = c.fields.get(f);
|
||||||
@@ -598,19 +722,23 @@ class Checker {
|
|||||||
cf = c.fields.get("a_"+f);
|
cf = c.fields.get("a_"+f);
|
||||||
if( cf != null ) {
|
if( cf != null ) {
|
||||||
var isPublic = true; // consider a_ prefixed as script specific
|
var isPublic = true; // consider a_ prefixed as script specific
|
||||||
cf = { isPublic : isPublic, params : cf.params, name : cf.name, t : unasync(cf.t) };
|
cf = { isPublic : isPublic, canWrite : false, params : cf.params, name : cf.name, t : unasync(cf.t), complete : cf.complete };
|
||||||
if( cf.t == null ) cf = null;
|
if( cf.t == null ) cf = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( cf == null ) {
|
if( cf == null ) {
|
||||||
if( c.superClass == null ) return null;
|
if( c.superClass == null ) return null;
|
||||||
var ft = getField(c.superClass, f, e);
|
var ft = getField(c.superClass, f, e, forWrite);
|
||||||
if( ft != null ) ft = apply(ft, c.params, args);
|
if( ft != null ) ft = apply(ft, c.params, args);
|
||||||
return ft;
|
return ft;
|
||||||
}
|
}
|
||||||
if( !cf.isPublic )
|
if( !cf.isPublic )
|
||||||
error("Can't access private field "+f+" on "+c.name, e);
|
error("Can't access private field "+f+" on "+c.name, e);
|
||||||
return apply(cf.t, c.params, args);
|
if( forWrite && !cf.canWrite )
|
||||||
|
error("Can't write readonly field "+f+" on "+c.name, e);
|
||||||
|
var t = cf.t;
|
||||||
|
if( cf.params != null ) t = apply(t, cf.params, [for( i in 0...cf.params.length ) makeMono()]);
|
||||||
|
return apply(t, c.params, args);
|
||||||
case TDynamic:
|
case TDynamic:
|
||||||
return makeMono();
|
return makeMono();
|
||||||
case TAnon(fields):
|
case TAnon(fields):
|
||||||
@@ -663,7 +791,28 @@ class Checker {
|
|||||||
return t.match(TInst({name:"String"},_));
|
return t.match(TInst({name:"String"},_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onCompletion( expr : Expr, t : TType ) {
|
||||||
|
if( isCompletion ) throw new Completion(expr, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
function typeField( o : Expr, f : String, expr : Expr, forWrite : Bool ) {
|
||||||
|
var ot = typeExpr(o, Value);
|
||||||
|
if( f == null )
|
||||||
|
onCompletion(expr, ot);
|
||||||
|
var ft = getField(ot, f, expr, forWrite);
|
||||||
|
if( ft == null ) {
|
||||||
|
error(typeStr(ot)+" has no field "+f, expr);
|
||||||
|
ft = TDynamic;
|
||||||
|
}
|
||||||
|
return ft;
|
||||||
|
}
|
||||||
|
|
||||||
function typeExpr( expr : Expr, withType : WithType ) : TType {
|
function typeExpr( expr : Expr, withType : WithType ) : TType {
|
||||||
|
if( expr == null && isCompletion )
|
||||||
|
return switch( withType ) {
|
||||||
|
case WithType(t): t;
|
||||||
|
default: TDynamic;
|
||||||
|
}
|
||||||
switch( edef(expr) ) {
|
switch( edef(expr) ) {
|
||||||
case EConst(c):
|
case EConst(c):
|
||||||
return switch (c) {
|
return switch (c) {
|
||||||
@@ -675,7 +824,12 @@ class Checker {
|
|||||||
var l = locals.get(v);
|
var l = locals.get(v);
|
||||||
if( l != null ) return l;
|
if( l != null ) return l;
|
||||||
var g = globals.get(v);
|
var g = globals.get(v);
|
||||||
if( g != null ) return g;
|
if( g != null ) {
|
||||||
|
return switch( g ) {
|
||||||
|
case TLazy(f): f();
|
||||||
|
default: g;
|
||||||
|
}
|
||||||
|
}
|
||||||
if( allowAsync ) {
|
if( allowAsync ) {
|
||||||
g = globals.get("a_"+v);
|
g = globals.get("a_"+v);
|
||||||
if( g != null ) g = unasync(g);
|
if( g != null ) g = unasync(g);
|
||||||
@@ -689,6 +843,7 @@ class Checker {
|
|||||||
case "trace":
|
case "trace":
|
||||||
return TDynamic;
|
return TDynamic;
|
||||||
default:
|
default:
|
||||||
|
if( isCompletion) return TDynamic;
|
||||||
error("Unknown identifier "+v, expr);
|
error("Unknown identifier "+v, expr);
|
||||||
}
|
}
|
||||||
case EBlock(el):
|
case EBlock(el):
|
||||||
@@ -714,32 +869,34 @@ class Checker {
|
|||||||
case TFun(args, ret):
|
case TFun(args, ret):
|
||||||
for( i in 0...params.length ) {
|
for( i in 0...params.length ) {
|
||||||
var a = args[i];
|
var a = args[i];
|
||||||
if( a == null ) error("Too many arguments", params[i]);
|
if( a == null ) {
|
||||||
var t = typeExpr(params[i], WithType(a.t));
|
error("Too many arguments", params[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var t = typeExpr(params[i], a == null ? Value : WithType(a.t));
|
||||||
unify(t, a.t, params[i]);
|
unify(t, a.t, params[i]);
|
||||||
}
|
}
|
||||||
for( i in params.length...args.length )
|
for( i in params.length...args.length )
|
||||||
if( !args[i].opt )
|
if( !args[i].opt )
|
||||||
error("Missing argument '"+args[i].name+"'", expr);
|
error("Missing argument "+args[i].name+":"+typeStr(args[i].t), expr);
|
||||||
return ret;
|
return ret;
|
||||||
case TDynamic:
|
case TDynamic:
|
||||||
for( p in params ) typeExpr(p,Value);
|
for( p in params ) typeExpr(p,Value);
|
||||||
return TDynamic;
|
return makeMono();
|
||||||
default:
|
default:
|
||||||
error(typeStr(ft)+" cannot be called", e);
|
error(typeStr(ft)+" cannot be called", e);
|
||||||
|
return makeMono();
|
||||||
}
|
}
|
||||||
case EField(o, f):
|
case EField(o, f):
|
||||||
var ot = typeExpr(o, Value);
|
return typeField(o,f,expr,false);
|
||||||
var ft = getField(ot, f, expr);
|
|
||||||
if( ft == null )
|
|
||||||
error(typeStr(ot)+" has no field "+f, expr);
|
|
||||||
return ft;
|
|
||||||
case ECheckType(v, t):
|
case ECheckType(v, t):
|
||||||
var ct = makeType(t, expr);
|
var ct = makeType(t, expr);
|
||||||
var vt = typeExpr(v, WithType(ct));
|
var vt = typeExpr(v, WithType(ct));
|
||||||
unify(vt, ct, v);
|
unify(vt, ct, v);
|
||||||
return ct;
|
return ct;
|
||||||
case EMeta(_, _, e):
|
case EMeta(m, _, e):
|
||||||
|
if( m == ":untyped" && allowUntypedMeta )
|
||||||
|
return makeMono();
|
||||||
return typeExpr(e, withType);
|
return typeExpr(e, withType);
|
||||||
case EIf(cond, e1, e2), ETernary(cond, e1, e2):
|
case EIf(cond, e1, e2), ETernary(cond, e1, e2):
|
||||||
typeExprWith(cond, TBool);
|
typeExprWith(cond, TBool);
|
||||||
@@ -764,8 +921,11 @@ class Checker {
|
|||||||
var map = [for( f in tfields ) f.name => f];
|
var map = [for( f in tfields ) f.name => f];
|
||||||
return TAnon([for( f in fl ) {
|
return TAnon([for( f in fl ) {
|
||||||
var ft = map.get(f.name);
|
var ft = map.get(f.name);
|
||||||
if( ft == null ) error("Extra field "+f.name, f.e);
|
var ft = if( ft == null ) {
|
||||||
{ t : typeExprWith(f.e, ft.t), opt : false, name : f.name }
|
error("Extra field "+f.name, f.e);
|
||||||
|
TDynamic;
|
||||||
|
} else ft.t;
|
||||||
|
{ t : typeExprWith(f.e, ft), opt : false, name : f.name }
|
||||||
}]);
|
}]);
|
||||||
default:
|
default:
|
||||||
return TAnon([for( f in fl ) { t : typeExpr(f.e, Value), opt : false, name : f.name }]);
|
return TAnon([for( f in fl ) { t : typeExpr(f.e, Value), opt : false, name : f.name }]);
|
||||||
@@ -778,7 +938,7 @@ class Checker {
|
|||||||
error("Return not allowed here", expr);
|
error("Return not allowed here", expr);
|
||||||
else
|
else
|
||||||
unify(et, allowReturn, v == null ? expr : v);
|
unify(et, allowReturn, v == null ? expr : v);
|
||||||
return TDynamic;
|
return makeMono();
|
||||||
case EArrayDecl(el):
|
case EArrayDecl(el):
|
||||||
var et = null;
|
var et = null;
|
||||||
for( v in el ) {
|
for( v in el ) {
|
||||||
@@ -787,7 +947,7 @@ class Checker {
|
|||||||
if( tryUnify(et,t) ) et = t else unify(t,et,v);
|
if( tryUnify(et,t) ) et = t else unify(t,et,v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( et == null ) et = TDynamic;
|
if( et == null ) et = makeMono();
|
||||||
return types.getType("Array",[et]);
|
return types.getType("Array",[et]);
|
||||||
case EArray(a, index):
|
case EArray(a, index):
|
||||||
typeExprWith(index, TInt);
|
typeExprWith(index, TInt);
|
||||||
@@ -798,12 +958,26 @@ class Checker {
|
|||||||
}
|
}
|
||||||
case EThrow(e):
|
case EThrow(e):
|
||||||
typeExpr(e, Value);
|
typeExpr(e, Value);
|
||||||
return TDynamic;
|
return makeMono();
|
||||||
case EFunction(args, body, name, ret):
|
case EFunction(args, body, name, ret):
|
||||||
var tret = ret == null ? makeMono() : makeType(ret, expr);
|
var ft = null, tret = null, targs = null;
|
||||||
|
if( currentFunType != null ) {
|
||||||
|
switch( currentFunType ) {
|
||||||
|
case TFun(args,ret):
|
||||||
|
ft = currentFunType;
|
||||||
|
tret = ret; targs = args;
|
||||||
|
default:
|
||||||
|
throw "assert";
|
||||||
|
}
|
||||||
|
currentFunType = null;
|
||||||
|
} else {
|
||||||
|
tret = ret == null ? makeMono() : makeType(ret, expr);
|
||||||
|
}
|
||||||
var locals = saveLocals();
|
var locals = saveLocals();
|
||||||
var oldRet = allowReturn;
|
var oldRet = allowReturn;
|
||||||
|
var oldGDef = allowDefine;
|
||||||
allowReturn = tret;
|
allowReturn = tret;
|
||||||
|
allowDefine = false;
|
||||||
var withArgs = null;
|
var withArgs = null;
|
||||||
if( name != null && !withType.match(WithType(follow(_) => TFun(_))) ) {
|
if( name != null && !withType.match(WithType(follow(_) => TFun(_))) ) {
|
||||||
var ev = events.get(name);
|
var ev = events.get(name);
|
||||||
@@ -813,26 +987,33 @@ class Checker {
|
|||||||
case WithType(follow(_) => TFun(args,ret)): withArgs = args; unify(tret,ret,expr);
|
case WithType(follow(_) => TFun(args,ret)): withArgs = args; unify(tret,ret,expr);
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
var targs = [for( i in 0...args.length ) {
|
if( targs == null )
|
||||||
var a = args[i];
|
targs = typeArgs(args,expr);
|
||||||
var at = a.t == null ? makeMono() : makeType(a.t, expr);
|
for( i in 0...targs.length ) {
|
||||||
if( withArgs != null && withArgs.length > i )
|
var a = targs[i];
|
||||||
unify(withArgs[i].t, at, expr);
|
if( withArgs != null ) {
|
||||||
this.locals.set(a.name, at);
|
if( i < withArgs.length )
|
||||||
{ name : a.name, opt : a.opt, t : at };
|
unify(withArgs[i].t, a.t, expr);
|
||||||
}];
|
else
|
||||||
|
error("Extra argument "+a.name, expr);
|
||||||
|
}
|
||||||
|
this.locals.set(a.name, a.t);
|
||||||
|
}
|
||||||
|
if( withArgs != null && targs.length < withArgs.length )
|
||||||
|
error("Missing "+(withArgs.length - targs.length)+" arguments ("+[for( i in targs.length...withArgs.length ) typeStr(withArgs[i].t)].join(",")+")", expr);
|
||||||
typeExpr(body,NoValue);
|
typeExpr(body,NoValue);
|
||||||
|
allowDefine = oldGDef;
|
||||||
allowReturn = oldRet;
|
allowReturn = oldRet;
|
||||||
this.locals = locals;
|
this.locals = locals;
|
||||||
var ft = TFun(targs,tret);
|
if( ft == null ) {
|
||||||
if( name != null )
|
ft = TFun(targs, tret);
|
||||||
locals.set(name, ft);
|
locals.set(name, ft);
|
||||||
|
}
|
||||||
return ft;
|
return ft;
|
||||||
case EUnop(op, _, e):
|
case EUnop(op, _, e):
|
||||||
var et = typeExpr(e, Value);
|
var et = typeExpr(e, Value);
|
||||||
switch( op ) {
|
switch( op ) {
|
||||||
case "++", "--":
|
case "++", "--", "-":
|
||||||
unify(et,TInt,e);
|
unify(et,TInt,e);
|
||||||
return et;
|
return et;
|
||||||
case "!":
|
case "!":
|
||||||
@@ -847,13 +1028,27 @@ class Checker {
|
|||||||
case TInst({name:"Array"},[t]):
|
case TInst({name:"Array"},[t]):
|
||||||
t;
|
t;
|
||||||
default:
|
default:
|
||||||
|
var ft = getField(itt,"iterator", it);
|
||||||
|
if( ft == null )
|
||||||
|
switch( itt ) {
|
||||||
|
case TAbstract(a, args):
|
||||||
|
// special case : we allow unconditional access
|
||||||
|
// to an abstract iterator() underlying value (eg: ArrayProxy)
|
||||||
|
ft = getField(apply(a.t,a.params,args),"iterator",it);
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
if( ft != null )
|
||||||
|
switch( ft ) {
|
||||||
|
case TFun([],ret): ft = ret;
|
||||||
|
default: ft = null;
|
||||||
|
}
|
||||||
var t = makeMono();
|
var t = makeMono();
|
||||||
var iter = makeIterator(t);
|
var iter = makeIterator(t);
|
||||||
unify(itt,iter,it);
|
unify(ft != null ? ft : itt,iter,it);
|
||||||
t;
|
t;
|
||||||
}
|
}
|
||||||
this.locals.set(v, vt);
|
this.locals.set(v, vt);
|
||||||
typeExpr(e, Value);
|
typeExpr(e, NoValue);
|
||||||
this.locals = locals;
|
this.locals = locals;
|
||||||
return TVoid;
|
return TVoid;
|
||||||
case EBinop(op, e1, e2):
|
case EBinop(op, e1, e2):
|
||||||
@@ -863,7 +1058,19 @@ class Checker {
|
|||||||
typeExprWith(e2,TInt);
|
typeExprWith(e2,TInt);
|
||||||
return TInt;
|
return TInt;
|
||||||
case "=":
|
case "=":
|
||||||
var vt = typeExpr(e1, Value);
|
if( allowDefine ) {
|
||||||
|
switch( edef(e1) ) {
|
||||||
|
case EIdent(i) if( !locals.exists(i) && !globals.exists(i) ):
|
||||||
|
var vt = typeExpr(e2,Value);
|
||||||
|
locals.set(i, vt);
|
||||||
|
return vt;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var vt = switch( edef(e1) ) {
|
||||||
|
case EField(o,f): typeField(o, f, e1, true);
|
||||||
|
default: typeExpr(e1,Value);
|
||||||
|
}
|
||||||
typeExprWith(e2,vt);
|
typeExprWith(e2,vt);
|
||||||
return vt;
|
return vt;
|
||||||
case "+":
|
case "+":
|
||||||
@@ -930,11 +1137,48 @@ class Checker {
|
|||||||
}
|
}
|
||||||
error("Unsupported operation "+op, expr);
|
error("Unsupported operation "+op, expr);
|
||||||
}
|
}
|
||||||
|
case ETry(etry, v, et, ecatch):
|
||||||
|
var vt = typeExpr(etry, withType);
|
||||||
|
|
||||||
|
var old = locals.get(v);
|
||||||
|
locals.set(v, makeType(et, ecatch));
|
||||||
|
var ct = typeExpr(ecatch, withType);
|
||||||
|
if( old != null ) locals.set(v,old) else locals.remove(v);
|
||||||
|
|
||||||
|
if( withType == NoValue )
|
||||||
|
return TVoid;
|
||||||
|
if( tryUnify(vt,ct) )
|
||||||
|
return ct;
|
||||||
|
unify(ct,vt,ecatch);
|
||||||
|
return vt;
|
||||||
|
case ESwitch(value, cases, defaultExpr):
|
||||||
|
var tmin = null;
|
||||||
|
var vt = typeExpr(value, Value);
|
||||||
|
inline function mergeType(t,p) {
|
||||||
|
if( withType != NoValue ) {
|
||||||
|
if( tmin == null )
|
||||||
|
tmin = t;
|
||||||
|
else if( !tryUnify(t,tmin) ) {
|
||||||
|
unify(tmin,t, p);
|
||||||
|
tmin = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for( c in cases ) {
|
||||||
|
for( v in c.values ) {
|
||||||
|
var ct = typeExpr(v, WithType(vt));
|
||||||
|
unify(ct, vt, v);
|
||||||
|
}
|
||||||
|
var et = typeExpr(c.expr, withType);
|
||||||
|
mergeType(et, c.expr);
|
||||||
|
}
|
||||||
|
if( defaultExpr != null )
|
||||||
|
mergeType( typeExpr(defaultExpr, withType), defaultExpr);
|
||||||
|
return withType == NoValue ? TVoid : tmin == null ? makeMono() : tmin;
|
||||||
case ENew(cl, params):
|
case ENew(cl, params):
|
||||||
case ETry(e, v, t, ecatch):
|
|
||||||
case ESwitch(e, cases, defaultExpr):
|
|
||||||
}
|
}
|
||||||
error("Don't know how to type "+edef(expr).getName(), expr);
|
error("Don't know how to type "+edef(expr).getName(), expr);
|
||||||
|
return TDynamic;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+13
-5
@@ -52,13 +52,22 @@ class Interp {
|
|||||||
|
|
||||||
public function new() {
|
public function new() {
|
||||||
#if haxe3
|
#if haxe3
|
||||||
variables = new Map<String,Dynamic>();
|
|
||||||
locals = new Map();
|
locals = new Map();
|
||||||
#else
|
#else
|
||||||
variables = new Hash();
|
|
||||||
locals = new Hash();
|
locals = new Hash();
|
||||||
#end
|
#end
|
||||||
declared = new Array();
|
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("null",null);
|
||||||
variables.set("true",true);
|
variables.set("true",true);
|
||||||
variables.set("false",false);
|
variables.set("false",false);
|
||||||
@@ -68,7 +77,6 @@ class Interp {
|
|||||||
if( el.length > 0 ) inf.customParams = el;
|
if( el.length > 0 ) inf.customParams = el;
|
||||||
haxe.Log.trace(Std.string(v), inf);
|
haxe.Log.trace(Std.string(v), inf);
|
||||||
}));
|
}));
|
||||||
initOps();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function posInfos(): PosInfos {
|
public function posInfos(): PosInfos {
|
||||||
@@ -400,11 +408,11 @@ class Interp {
|
|||||||
else
|
else
|
||||||
minParams++;
|
minParams++;
|
||||||
var f = function(args:Array<Dynamic>) {
|
var f = function(args:Array<Dynamic>) {
|
||||||
if( args.length != params.length ) {
|
if( ( (args == null) ? 0 : args.length ) != params.length ) {
|
||||||
if( args.length < minParams ) {
|
if( args.length < minParams ) {
|
||||||
var str = "Invalid number of parameters. Got " + args.length + ", required " + minParams;
|
var str = "Invalid number of parameters. Got " + args.length + ", required " + minParams;
|
||||||
if( name != null ) str += " for function '" + name+"'";
|
if( name != null ) str += " for function '" + name+"'";
|
||||||
throw str;
|
error(ECustom(str));
|
||||||
}
|
}
|
||||||
// make sure mandatory args are forced
|
// make sure mandatory args are forced
|
||||||
var args2 = [];
|
var args2 = [];
|
||||||
|
|||||||
+1
-1
@@ -214,7 +214,7 @@ class Macro {
|
|||||||
opt : false,
|
opt : false,
|
||||||
value : null,
|
value : null,
|
||||||
});
|
});
|
||||||
EFunction(name, {
|
EFunction(#if haxe4 FNamed(name,false) #else name #end, {
|
||||||
params : [],
|
params : [],
|
||||||
args : targs,
|
args : targs,
|
||||||
expr : convert(e),
|
expr : convert(e),
|
||||||
|
|||||||
+98
-92
@@ -78,8 +78,15 @@ class Parser {
|
|||||||
**/
|
**/
|
||||||
public var allowMetadata : Bool;
|
public var allowMetadata : Bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
resume from parsing errors (when parsing incomplete code, during completion for example)
|
||||||
|
**/
|
||||||
|
public var resumeErrors : Bool;
|
||||||
|
|
||||||
// implementation
|
// implementation
|
||||||
var input : haxe.io.Input;
|
var input : String;
|
||||||
|
var readPos : Int;
|
||||||
|
|
||||||
var char : Int;
|
var char : Int;
|
||||||
var ops : Array<Bool>;
|
var ops : Array<Bool>;
|
||||||
var idents : Array<Bool>;
|
var idents : Array<Bool>;
|
||||||
@@ -87,7 +94,6 @@ class Parser {
|
|||||||
|
|
||||||
#if hscriptPos
|
#if hscriptPos
|
||||||
var origin : String;
|
var origin : String;
|
||||||
var readPos : Int;
|
|
||||||
var tokenMin : Int;
|
var tokenMin : Int;
|
||||||
var tokenMax : Int;
|
var tokenMax : Int;
|
||||||
var oldTokenMin : Int;
|
var oldTokenMin : Int;
|
||||||
@@ -95,7 +101,6 @@ class Parser {
|
|||||||
var tokens : List<{ min : Int, max : Int, t : Token }>;
|
var tokens : List<{ min : Int, max : Int, t : Token }>;
|
||||||
#else
|
#else
|
||||||
static inline var p1 = 0;
|
static inline var p1 = 0;
|
||||||
static inline var readPos = 0;
|
|
||||||
static inline var tokenMin = 0;
|
static inline var tokenMin = 0;
|
||||||
static inline var tokenMax = 0;
|
static inline var tokenMax = 0;
|
||||||
#if haxe3
|
#if haxe3
|
||||||
@@ -142,6 +147,7 @@ class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public inline function error( err, pmin, pmax ) {
|
public inline function error( err, pmin, pmax ) {
|
||||||
|
if( !resumeErrors )
|
||||||
#if hscriptPos
|
#if hscriptPos
|
||||||
throw new Error(err, pmin, pmax, origin, line);
|
throw new Error(err, pmin, pmax, origin, line);
|
||||||
#else
|
#else
|
||||||
@@ -178,12 +184,9 @@ class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function parseString( s : String, ?origin : String = "hscript" ) {
|
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);
|
initParser(origin);
|
||||||
input = s;
|
input = s;
|
||||||
|
readPos = 0;
|
||||||
var a = new Array();
|
var a = new Array();
|
||||||
while( true ) {
|
while( true ) {
|
||||||
var tk = token();
|
var tk = token();
|
||||||
@@ -247,7 +250,7 @@ class Parser {
|
|||||||
|
|
||||||
inline function pmin(e:Expr) {
|
inline function pmin(e:Expr) {
|
||||||
#if hscriptPos
|
#if hscriptPos
|
||||||
return e.pmin;
|
return e == null ? 0 : e.pmin;
|
||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#end
|
#end
|
||||||
@@ -255,7 +258,7 @@ class Parser {
|
|||||||
|
|
||||||
inline function pmax(e:Expr) {
|
inline function pmax(e:Expr) {
|
||||||
#if hscriptPos
|
#if hscriptPos
|
||||||
return e.pmax;
|
return e == null ? 0 : e.pmax;
|
||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#end
|
#end
|
||||||
@@ -273,6 +276,7 @@ class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isBlock(e) {
|
function isBlock(e) {
|
||||||
|
if( e == null ) return false;
|
||||||
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);
|
||||||
@@ -296,7 +300,7 @@ class Parser {
|
|||||||
|
|
||||||
var tk = token();
|
var tk = token();
|
||||||
// this is a hack to support var a,b,c; with a single EVar
|
// 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
|
e = parseStructure("var"); // next variable
|
||||||
exprs.push(e);
|
exprs.push(e);
|
||||||
tk = token();
|
tk = token();
|
||||||
@@ -329,6 +333,7 @@ class Parser {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
unexpected(tk);
|
unexpected(tk);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
ensure(TDoubleDot);
|
ensure(TDoubleDot);
|
||||||
fl.push({ name : id, e : parseExpr() });
|
fl.push({ name : id, e : parseExpr() });
|
||||||
@@ -422,7 +427,7 @@ class Parser {
|
|||||||
while( true ) {
|
while( true ) {
|
||||||
parseFullExpr(a);
|
parseFullExpr(a);
|
||||||
tk = token();
|
tk = token();
|
||||||
if( tk == TBrClose )
|
if( tk == TBrClose || (resumeErrors && tk == TEof) )
|
||||||
break;
|
break;
|
||||||
push(tk);
|
push(tk);
|
||||||
}
|
}
|
||||||
@@ -431,7 +436,7 @@ class Parser {
|
|||||||
if( unops.exists(op) ) {
|
if( unops.exists(op) ) {
|
||||||
var start = tokenMin;
|
var start = tokenMin;
|
||||||
var e = parseExpr();
|
var e = parseExpr();
|
||||||
if( op == "-" )
|
if( op == "-" && e != null )
|
||||||
switch( expr(e) ) {
|
switch( expr(e) ) {
|
||||||
case EConst(CInt(i)):
|
case EConst(CInt(i)):
|
||||||
return mk(EConst(CInt(-i)), start, pmax(e));
|
return mk(EConst(CInt(-i)), start, pmax(e));
|
||||||
@@ -445,14 +450,14 @@ class Parser {
|
|||||||
case TBkOpen:
|
case TBkOpen:
|
||||||
var a = new Array();
|
var a = new Array();
|
||||||
tk = token();
|
tk = token();
|
||||||
while( tk != TBkClose ) {
|
while( tk != TBkClose && (!resumeErrors || tk != TEof) ) {
|
||||||
push(tk);
|
push(tk);
|
||||||
a.push(parseExpr());
|
a.push(parseExpr());
|
||||||
tk = token();
|
tk = token();
|
||||||
if( tk == TComma )
|
if( tk == TComma )
|
||||||
tk = token();
|
tk = token();
|
||||||
}
|
}
|
||||||
if( a.length == 1 )
|
if( a.length == 1 && a[0] != null )
|
||||||
switch( expr(a[0]) ) {
|
switch( expr(a[0]) ) {
|
||||||
case EFor(_), EWhile(_), EDoWhile(_):
|
case EFor(_), EWhile(_), EDoWhile(_):
|
||||||
var tmp = "__a_" + (uid++);
|
var tmp = "__a_" + (uid++);
|
||||||
@@ -485,6 +490,7 @@ class Parser {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
unexpected(tk);
|
unexpected(tk);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ensureToken(TOp("->"));
|
ensureToken(TOp("->"));
|
||||||
@@ -517,6 +523,7 @@ class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mapCompr( tmp : String, e : Expr ) {
|
function mapCompr( tmp : String, e : Expr ) {
|
||||||
|
if( e == null ) return null;
|
||||||
var edef = switch( expr(e) ) {
|
var edef = switch( expr(e) ) {
|
||||||
case EFor(v, it, e2):
|
case EFor(v, it, e2):
|
||||||
EFor(v, it, mapCompr(tmp, e2));
|
EFor(v, it, mapCompr(tmp, e2));
|
||||||
@@ -537,6 +544,8 @@ class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function makeUnop( op, e ) {
|
function makeUnop( op, e ) {
|
||||||
|
if( e == null && resumeErrors )
|
||||||
|
return null;
|
||||||
return switch( expr(e) ) {
|
return switch( expr(e) ) {
|
||||||
case EBinop(bop, e1, e2): mk(EBinop(bop, makeUnop(op, e1), e2), pmin(e1), pmax(e2));
|
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));
|
case ETernary(e1, e2, e3): mk(ETernary(makeUnop(op, e1), e2, e3), pmin(e1), pmax(e3));
|
||||||
@@ -545,6 +554,8 @@ class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function makeBinop( op, e1, e ) {
|
function makeBinop( op, e1, e ) {
|
||||||
|
if( e == null && resumeErrors )
|
||||||
|
return mk(EBinop(op,e1,e),pmin(e1),pmax(e1));
|
||||||
return switch( expr(e) ) {
|
return switch( expr(e) ) {
|
||||||
case EBinop(op2,e2,e3):
|
case EBinop(op2,e2,e3):
|
||||||
if( opPriority.get(op) <= opPriority.get(op2) && !opRightAssoc.exists(op) )
|
if( opPriority.get(op) <= opPriority.get(op2) && !opRightAssoc.exists(op) )
|
||||||
@@ -644,16 +655,16 @@ class Parser {
|
|||||||
case "new":
|
case "new":
|
||||||
var a = new Array();
|
var a = new Array();
|
||||||
a.push(getIdent());
|
a.push(getIdent());
|
||||||
var next = true;
|
while( true ) {
|
||||||
while( next ) {
|
|
||||||
var tk = token();
|
var tk = token();
|
||||||
switch( tk ) {
|
switch( tk ) {
|
||||||
case TDot:
|
case TDot:
|
||||||
a.push(getIdent());
|
a.push(getIdent());
|
||||||
case TPOpen:
|
case TPOpen:
|
||||||
next = false;
|
break;
|
||||||
default:
|
default:
|
||||||
unexpected(tk);
|
unexpected(tk);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var args = parseExprList(TPClose);
|
var args = parseExprList(TPClose);
|
||||||
@@ -696,6 +707,7 @@ class Parser {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
unexpected(tk);
|
unexpected(tk);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var exprs = [];
|
var exprs = [];
|
||||||
@@ -705,6 +717,8 @@ class Parser {
|
|||||||
switch( tk ) {
|
switch( tk ) {
|
||||||
case TId("case"), TId("default"), TBrClose:
|
case TId("case"), TId("default"), TBrClose:
|
||||||
break;
|
break;
|
||||||
|
case TEof if( resumeErrors ):
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
parseFullExpr(exprs);
|
parseFullExpr(exprs);
|
||||||
}
|
}
|
||||||
@@ -725,6 +739,8 @@ class Parser {
|
|||||||
switch( tk ) {
|
switch( tk ) {
|
||||||
case TId("case"), TId("default"), TBrClose:
|
case TId("case"), TId("default"), TBrClose:
|
||||||
break;
|
break;
|
||||||
|
case TEof if( resumeErrors ):
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
parseFullExpr(exprs);
|
parseFullExpr(exprs);
|
||||||
}
|
}
|
||||||
@@ -739,6 +755,7 @@ class Parser {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
unexpected(tk);
|
unexpected(tk);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mk(ESwitch(e, cases, def), p1, tokenMax);
|
mk(ESwitch(e, cases, def), p1, tokenMax);
|
||||||
@@ -809,7 +826,9 @@ class Parser {
|
|||||||
}
|
}
|
||||||
switch( tk ) {
|
switch( tk ) {
|
||||||
case TId(id): name = id;
|
case TId(id): name = id;
|
||||||
default: unexpected(tk);
|
default:
|
||||||
|
unexpected(tk);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
var arg : Argument = { name : name };
|
var arg : Argument = { name : name };
|
||||||
args.push(arg);
|
args.push(arg);
|
||||||
@@ -830,8 +849,8 @@ class Parser {
|
|||||||
unexpected(tk);
|
unexpected(tk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseFunctionDecl() {
|
function parseFunctionDecl() {
|
||||||
@@ -891,6 +910,7 @@ class Parser {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
unexpected(t);
|
unexpected(t);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
push(t);
|
push(t);
|
||||||
@@ -901,13 +921,13 @@ class Parser {
|
|||||||
case TPOpen:
|
case TPOpen:
|
||||||
var a = token(),
|
var a = token(),
|
||||||
b = token();
|
b = token();
|
||||||
|
|
||||||
push(b);
|
push(b);
|
||||||
push(a);
|
push(a);
|
||||||
|
|
||||||
function withReturn(args) {
|
function withReturn(args) {
|
||||||
switch token() { // I think it wouldn't hurt if ensure used enumEq
|
switch token() { // I think it wouldn't hurt if ensure used enumEq
|
||||||
case TOp('->'):
|
case TOp('->'):
|
||||||
case t: unexpected(t);
|
case t: unexpected(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -916,7 +936,7 @@ class Parser {
|
|||||||
|
|
||||||
switch [a, b] {
|
switch [a, b] {
|
||||||
case [TPClose, _] | [TId(_), TDoubleDot]:
|
case [TPClose, _] | [TId(_), TDoubleDot]:
|
||||||
|
|
||||||
var args = [for (arg in parseFunctionArgs()) {
|
var args = [for (arg in parseFunctionArgs()) {
|
||||||
switch arg.value {
|
switch arg.value {
|
||||||
case null:
|
case null:
|
||||||
@@ -929,12 +949,12 @@ class Parser {
|
|||||||
|
|
||||||
return withReturn(args);
|
return withReturn(args);
|
||||||
default:
|
default:
|
||||||
|
|
||||||
var t = parseType();
|
var t = parseType();
|
||||||
return switch token() {
|
return switch token() {
|
||||||
case TComma:
|
case TComma:
|
||||||
var args = [t];
|
var args = [t];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
args.push(parseType());
|
args.push(parseType());
|
||||||
if (!maybe(TComma)) break;
|
if (!maybe(TComma)) break;
|
||||||
@@ -973,6 +993,7 @@ class Parser {
|
|||||||
meta.push({ name : name, params : parseMetaArgs() });
|
meta.push({ name : name, params : parseMetaArgs() });
|
||||||
default:
|
default:
|
||||||
unexpected(t);
|
unexpected(t);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return parseTypeNext(CTAnon(fields));
|
return parseTypeNext(CTAnon(fields));
|
||||||
@@ -1017,6 +1038,7 @@ class Parser {
|
|||||||
default:
|
default:
|
||||||
if( tk == etk ) break;
|
if( tk == etk ) break;
|
||||||
unexpected(tk);
|
unexpected(tk);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
@@ -1026,7 +1048,8 @@ class Parser {
|
|||||||
|
|
||||||
public function parseModule( content : String, ?origin : String = "hscript" ) {
|
public function parseModule( content : String, ?origin : String = "hscript" ) {
|
||||||
initParser(origin);
|
initParser(origin);
|
||||||
this.input = new haxe.io.StringInput(content);
|
input = content;
|
||||||
|
readPos = 0;
|
||||||
allowTypes = true;
|
allowTypes = true;
|
||||||
allowMetadata = true;
|
allowMetadata = true;
|
||||||
var decls = [];
|
var decls = [];
|
||||||
@@ -1219,6 +1242,7 @@ class Parser {
|
|||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
unexpected(TId(id));
|
unexpected(TId(id));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -1226,20 +1250,13 @@ class Parser {
|
|||||||
|
|
||||||
// ------------------------ lexing -------------------------------
|
// ------------------------ lexing -------------------------------
|
||||||
|
|
||||||
inline function incPos() {
|
inline function readChar() {
|
||||||
#if hscriptPos
|
return StringTools.fastCodeAt(input, readPos++);
|
||||||
readPos++;
|
|
||||||
#end
|
|
||||||
}
|
|
||||||
|
|
||||||
function readChar() {
|
|
||||||
incPos();
|
|
||||||
return try input.readByte() catch( e : Dynamic ) 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function readString( until ) {
|
function readString( until ) {
|
||||||
var c = 0;
|
var c = 0;
|
||||||
var b = new haxe.io.BytesOutput();
|
var b = new StringBuf();
|
||||||
var esc = false;
|
var esc = false;
|
||||||
var old = line;
|
var old = line;
|
||||||
var s = input;
|
var s = input;
|
||||||
@@ -1247,38 +1264,26 @@ class Parser {
|
|||||||
var p1 = readPos - 1;
|
var p1 = readPos - 1;
|
||||||
#end
|
#end
|
||||||
while( true ) {
|
while( true ) {
|
||||||
try {
|
var c = readChar();
|
||||||
incPos();
|
if( StringTools.isEof(c) ) {
|
||||||
c = s.readByte();
|
|
||||||
} catch( e : Dynamic ) {
|
|
||||||
line = old;
|
line = old;
|
||||||
error(EUnterminatedString, p1, p1);
|
error(EUnterminatedString, p1, p1);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if( esc ) {
|
if( esc ) {
|
||||||
esc = false;
|
esc = false;
|
||||||
switch( c ) {
|
switch( c ) {
|
||||||
case 'n'.code: b.writeByte(10);
|
case 'n'.code: b.addChar('\n'.code);
|
||||||
case 'r'.code: b.writeByte(13);
|
case 'r'.code: b.addChar('\r'.code);
|
||||||
case 't'.code: b.writeByte(9);
|
case 't'.code: b.addChar('\t'.code);
|
||||||
case "'".code, '"'.code, '\\'.code: b.writeByte(c);
|
case "'".code, '"'.code, '\\'.code: b.addChar(c);
|
||||||
case '/'.code: if( allowJSON ) b.writeByte(c) else invalidChar(c);
|
case '/'.code: if( allowJSON ) b.addChar(c) else invalidChar(c);
|
||||||
case "u".code:
|
case "u".code:
|
||||||
if( !allowJSON ) invalidChar(c);
|
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;
|
var k = 0;
|
||||||
for( i in 0...4 ) {
|
for( i in 0...4 ) {
|
||||||
k <<= 4;
|
k <<= 4;
|
||||||
var char = code.charCodeAt(i);
|
var char = readChar();
|
||||||
switch( char ) {
|
switch( char ) {
|
||||||
case 48,49,50,51,52,53,54,55,56,57: // 0-9
|
case 48,49,50,51,52,53,54,55,56,57: // 0-9
|
||||||
k += char - 48;
|
k += char - 48;
|
||||||
@@ -1287,20 +1292,14 @@ class Parser {
|
|||||||
case 97,98,99,100,101,102: // a-f
|
case 97,98,99,100,101,102: // a-f
|
||||||
k += char - 87;
|
k += char - 87;
|
||||||
default:
|
default:
|
||||||
|
if( StringTools.isEof(char) ) {
|
||||||
|
line = old;
|
||||||
|
error(EUnterminatedString, p1, p1);
|
||||||
|
}
|
||||||
invalidChar(char);
|
invalidChar(char);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// encode k in UTF8
|
b.addChar(k);
|
||||||
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) );
|
|
||||||
}
|
|
||||||
default: invalidChar(c);
|
default: invalidChar(c);
|
||||||
}
|
}
|
||||||
} else if( c == 92 )
|
} else if( c == 92 )
|
||||||
@@ -1309,10 +1308,10 @@ class Parser {
|
|||||||
break;
|
break;
|
||||||
else {
|
else {
|
||||||
if( c == 10 ) line++;
|
if( c == 10 ) line++;
|
||||||
b.writeByte(c);
|
b.addChar(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b.getBytes().toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
function token() {
|
function token() {
|
||||||
@@ -1344,8 +1343,13 @@ class Parser {
|
|||||||
this.char = -1;
|
this.char = -1;
|
||||||
}
|
}
|
||||||
while( true ) {
|
while( true ) {
|
||||||
|
if( StringTools.isEof(char) ) {
|
||||||
|
this.char = char;
|
||||||
|
return TEof;
|
||||||
|
}
|
||||||
switch( char ) {
|
switch( char ) {
|
||||||
case 0: return TEof;
|
case 0:
|
||||||
|
return TEof;
|
||||||
case 32,9,13: // space, tab, CR
|
case 32,9,13: // space, tab, CR
|
||||||
#if hscriptPos
|
#if hscriptPos
|
||||||
tokenMin++;
|
tokenMin++;
|
||||||
@@ -1517,6 +1521,7 @@ class Parser {
|
|||||||
var prev = -1;
|
var prev = -1;
|
||||||
while( true ) {
|
while( true ) {
|
||||||
char = readChar();
|
char = readChar();
|
||||||
|
if( StringTools.isEof(char) ) char = 0;
|
||||||
if( !ops[char] || prev == '='.code ) {
|
if( !ops[char] || prev == '='.code ) {
|
||||||
if( op.charCodeAt(0) == '/'.code )
|
if( op.charCodeAt(0) == '/'.code )
|
||||||
return tokenComment(op,char);
|
return tokenComment(op,char);
|
||||||
@@ -1531,6 +1536,7 @@ class Parser {
|
|||||||
var id = String.fromCharCode(char);
|
var id = String.fromCharCode(char);
|
||||||
while( true ) {
|
while( true ) {
|
||||||
char = readChar();
|
char = readChar();
|
||||||
|
if( StringTools.isEof(char) ) char = 0;
|
||||||
if( !idents[char] ) {
|
if( !idents[char] ) {
|
||||||
this.char = char;
|
this.char = char;
|
||||||
return TId(id);
|
return TId(id);
|
||||||
@@ -1636,14 +1642,11 @@ class Parser {
|
|||||||
var c = op.charCodeAt(1);
|
var c = op.charCodeAt(1);
|
||||||
var s = input;
|
var s = input;
|
||||||
if( c == '/'.code ) { // comment
|
if( c == '/'.code ) { // comment
|
||||||
try {
|
while( char != '\r'.code && char != '\n'.code ) {
|
||||||
while( char != '\r'.code && char != '\n'.code ) {
|
char = readChar();
|
||||||
incPos();
|
if( StringTools.isEof(char) ) break;
|
||||||
char = s.readByte();
|
|
||||||
}
|
|
||||||
this.char = char;
|
|
||||||
} catch( e : Dynamic ) {
|
|
||||||
}
|
}
|
||||||
|
this.char = char;
|
||||||
return token();
|
return token();
|
||||||
}
|
}
|
||||||
if( c == '*'.code ) { /* comment */
|
if( c == '*'.code ) { /* comment */
|
||||||
@@ -1652,21 +1655,24 @@ class Parser {
|
|||||||
this.char = char;
|
this.char = char;
|
||||||
return token();
|
return token();
|
||||||
}
|
}
|
||||||
try {
|
while( true ) {
|
||||||
while( true ) {
|
while( char != '*'.code ) {
|
||||||
while( char != '*'.code ) {
|
if( char == '\n'.code ) line++;
|
||||||
if( char == '\n'.code ) line++;
|
char = readChar();
|
||||||
incPos();
|
if( StringTools.isEof(char) ) {
|
||||||
char = s.readByte();
|
line = old;
|
||||||
}
|
error(EUnterminatedComment, tokenMin, tokenMin);
|
||||||
incPos();
|
|
||||||
char = s.readByte();
|
|
||||||
if( char == '/'.code )
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch( e : Dynamic ) {
|
char = readChar();
|
||||||
line = old;
|
if( StringTools.isEof(char) ) {
|
||||||
error(EUnterminatedComment, tokenMin, tokenMin);
|
line = old;
|
||||||
|
error(EUnterminatedComment, tokenMin, tokenMin);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( char == '/'.code )
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return token();
|
return token();
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -48,7 +48,7 @@ class Printer {
|
|||||||
|
|
||||||
function type( t : CType ) {
|
function type( t : CType ) {
|
||||||
switch( t ) {
|
switch( t ) {
|
||||||
case CTOpt(t):
|
case CTOpt(t):
|
||||||
add('?');
|
add('?');
|
||||||
type(t);
|
type(t);
|
||||||
case CTPath(path, params):
|
case CTPath(path, params):
|
||||||
@@ -331,7 +331,7 @@ class Printer {
|
|||||||
|
|
||||||
public static function errorToString( e : Expr.Error ) {
|
public static function errorToString( e : Expr.Error ) {
|
||||||
var message = switch( #if hscriptPos e.e #else e #end ) {
|
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 EUnexpected(s): "Unexpected token: \""+s+"\"";
|
||||||
case EUnterminatedString: "Unterminated string";
|
case EUnterminatedString: "Unterminated string";
|
||||||
case EUnterminatedComment: "Unterminated comment";
|
case EUnterminatedComment: "Unterminated comment";
|
||||||
|
|||||||
Reference in New Issue
Block a user