diff --git a/.merlin b/.merlin deleted file mode 100644 index 7c9eaf64b74868e06a2a8f43afce2b9d88c1cba6..0000000000000000000000000000000000000000 --- a/.merlin +++ /dev/null @@ -1,14 +0,0 @@ -S src/** -B _build/src/** -S libs/** -B libs/** -B +threads -PKG ptmap -PKG sedlex -PKG extlib -PKG camlzip -PKG xml-light -PKG sha -FLG -safe-string -FLG -w -3 -FLG -w -40 \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 5e0f5a757b8b460919c3b18e12388f192c387a8a..5d63d3481c74fd6bb37fc82b76a9a842cec37617 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,5 +1,5 @@ { - "version": "2.0.0", + "version": "2.0.0", "tasks": [ { "label": "make: haxe", diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 48183c808661f72a690c068b02b99b204ebf9c47..96dce683d910ed9242042130b481120e862dda7f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,7 +53,7 @@ Please also bear the following in mind: ### Using a debugger -To debug the Haxe compiler, you can use either a system debugger (`gdb`/`lldb`), or [ocamldebug](http://caml.inria.fr/pub/docs/manual-ocaml/debugger.html). `ocamldebug` provides a better debugging experience. To use it, compile with `make BYTECODE=1`. +To debug the Haxe compiler, you can use either a system debugger (`gdb`/`lldb`), or [ocamldebug](http://caml.inria.fr/pub/docs/manual-ocaml/debugger.html). `ocamldebug` provides a better debugging experience. To use it, uncomment `(modes byte)` from [src/dune](src/dune) and recompile. ### Using printf diff --git a/Makefile b/Makefile index db7616511f0eb06e0063ca878a9dccb957b3aea1..e7cc0f1ffaa2a99698f285e7596c91cb47694b02 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ PACKAGE_SRC_EXTENSION=.tar.gz MAKEFILENAME?=Makefile PLATFORM?=unix +DUNE_COMMAND=dune HAXE_OUTPUT=haxe HAXELIB_OUTPUT=haxelib PREBUILD_OUTPUT=prebuild @@ -28,49 +29,20 @@ EXTENSION= LFLAGS= STATICLINK?=0 -# Configuration - -# Modules in these directories should only depend on modules that are in directories to the left -HAXE_DIRECTORIES=core core/json core/display syntax context context/display codegen codegen/gencommon generators generators/jvm optimization filters macro macro/eval macro/eval/bytes typing compiler -EXTLIB_LIBS=extlib-leftovers extc neko javalib swflib ttflib ilib objsize pcre ziplib -OCAML_LIBS=unix str threads dynlink -OPAM_LIBS=sedlex.ppx xml-light extlib ptmap sha - -FINDLIB_LIBS=$(OCAML_LIBS) -FINDLIB_LIBS+=$(OPAM_LIBS) - -# Includes, packages and compiler - -HAXE_INCLUDES=$(HAXE_DIRECTORIES:%=-I _build/src/%) -EXTLIB_INCLUDES=$(EXTLIB_LIBS:%=-I libs/%) -ALL_INCLUDES=$(EXTLIB_INCLUDES) $(HAXE_INCLUDES) -FINDLIB_PACKAGES=$(FINDLIB_LIBS:%=-package %) -CFLAGS= -ALL_CFLAGS=-bin-annot -safe-string -thread -g -w -3 -w -40 $(CFLAGS) $(ALL_INCLUDES) $(FINDLIB_PACKAGES) - -MESSAGE_FILTER=sed -e 's/_build\/src\//src\//' tmp.tmp - -ifeq ($(BYTECODE),1) - TARGET_FLAG = bytecode - COMPILER = ocamlfind ocamlc - LIB_EXT = cma - MODULE_EXT = cmo - NATIVE_LIB_FLAG = -custom +SYSTEM_NAME=Unknown +ifeq ($(OS),Windows_NT) + SYSTEM_NAME=Windows else - TARGET_FLAG = native - COMPILER = ocamlfind ocamlopt - LIB_EXT = cmxa - MODULE_EXT = cmx - OCAMLDEP_FLAGS = -native + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Linux) + SYSTEM_NAME=Linux + endif + ifeq ($(UNAME_S),Darwin) + SYSTEM_NAME=Mac + endif endif -CC_CMD = ($(COMPILER) $(ALL_CFLAGS) -c $< 2>tmp.tmp && $(MESSAGE_FILTER)) || ($(MESSAGE_FILTER) && exit 1) - -# Meta information - -BUILD_DIRECTORIES := $(HAXE_DIRECTORIES:%=_build/src/%) -HAXE_SRC := $(wildcard $(HAXE_DIRECTORIES:%=src/%/*.ml)) -BUILD_SRC := $(HAXE_SRC:%=_build/%) +# Configuration ADD_REVISION?=0 @@ -87,94 +59,34 @@ PACKAGE_FILE_NAME=haxe_$(COMMIT_DATE)_$(COMMIT_SHA) HAXE_VERSION=$(shell $(CURDIR)/$(HAXE_OUTPUT) -version 2>&1 | awk '{print $$1;}') HAXE_VERSION_SHORT=$(shell echo "$(HAXE_VERSION)" | grep -oE "^[0-9]+\.[0-9]+\.[0-9]+") -# using $(CURDIR) on Windows will not work since it might be a Cygwin path -ifdef SYSTEMROOT - EXTENSION=.exe -else - export HAXE_STD_PATH=$(CURDIR)/std -endif - -# Native libraries - ifneq ($(STATICLINK),0) - LIB_PARAMS= -cclib '-Wl,-Bstatic -lpcre -lz -Wl,-Bdynamic ' + LIB_PARAMS= -cclib '-Wl,-Bstatic -lpcre -lz -lmbedtls -lmbedx509 -lmbedcrypto -Wl,-Bdynamic ' else - LIB_PARAMS?= -cclib -lpcre -cclib -lz + LIB_PARAMS?= -cclib -lpcre -cclib -lz -cclib -lmbedtls -cclib -lmbedx509 -cclib -lmbedcrypto endif - -NATIVE_LIBS=-thread -cclib libs/extc/extc_stubs.o -cclib libs/extc/process_stubs.o -cclib libs/objsize/c_objsize.o -cclib libs/pcre/pcre_stubs.o -ccopt -L/usr/local/lib $(LIB_PARAMS) - -# Modules - --include Makefile.modules - -# Rules - -all: libs haxe tools - -libs: - $(foreach lib,$(EXTLIB_LIBS),$(MAKE) -C libs/$(lib) $(TARGET_FLAG) &&) true - -_build/%:% - mkdir -p $(dir $@) - cp $< $@ - -build_dirs: - @mkdir -p $(BUILD_DIRECTORIES) - -_build/src/syntax/grammar.ml:src/syntax/grammar.mly - camlp5o -impl $< -o $@ - -_build/src/compiler/version.ml: FORCE -ifneq ($(ADD_REVISION),0) - $(MAKE) -f Makefile.version_extra -s --no-print-directory ADD_REVISION=$(ADD_REVISION) BRANCH=$(BRANCH) COMMIT_SHA=$(COMMIT_SHA) COMMIT_DATE=$(COMMIT_DATE) > _build/src/compiler/version.ml -else - echo let version_extra = None > _build/src/compiler/version.ml +ifeq ($(SYSTEM_NAME),Mac) + LIB_PARAMS+= -cclib '-framework Security -framework CoreFoundation' endif -_build/src/core/defineList.ml: src-json/define.json prebuild - ./$(PREBUILD_OUTPUT) define $< > $@ - -_build/src/core/metaList.ml: src-json/meta.json prebuild - ./$(PREBUILD_OUTPUT) meta $< > $@ - -build_src: | $(BUILD_SRC) _build/src/syntax/grammar.ml _build/src/compiler/version.ml _build/src/core/defineList.ml _build/src/core/metaList.ml - -prebuild: _build/src/core/json/json.ml _build/src/prebuild/main.ml - $(COMPILER) -safe-string -linkpkg -g -o $(PREBUILD_OUTPUT) -package sedlex.ppx -package extlib -I _build/src/core/json _build/src/core/json/json.ml _build/src/prebuild/main.ml +all: haxe tools -haxe: build_src - $(MAKE) -f $(MAKEFILENAME) build_pass_1 - $(MAKE) -f $(MAKEFILENAME) build_pass_2 - $(MAKE) -f $(MAKEFILENAME) build_pass_3 - $(MAKE) -f $(MAKEFILENAME) build_pass_4 +haxe: + $(DUNE_COMMAND) build --workspace dune-workspace.dev src-prebuild/prebuild.exe + _build/default/src-prebuild/prebuild.exe libparams $(LIB_PARAMS) > lib.sexp + _build/default/src-prebuild/prebuild.exe version $(ADD_REVISION) $(BRANCH) $(COMMIT_SHA) > src/compiler/version.ml + $(DUNE_COMMAND) build --workspace dune-workspace.dev src/haxe.exe + cp -f _build/default/src/haxe.exe ./${HAXE_OUTPUT} -build_pass_1: - printf MODULES= > Makefile.modules - ls -1 $(HAXE_DIRECTORIES:%=_build/src/%/*.ml) | tr '\n' ' ' >> Makefile.modules - -build_pass_2: - printf MODULES= > Makefile.modules - ocamlfind ocamldep -sort -slash $(HAXE_INCLUDES) $(MODULES) | sed -e "s/\.ml//g" >> Makefile.modules - -build_pass_3: - ocamlfind ocamldep -slash $(OCAMLDEP_FLAGS) $(HAXE_INCLUDES) $(MODULES:%=%.ml) > Makefile.dependencies - -build_pass_4: $(MODULES:%=%.$(MODULE_EXT)) - $(COMPILER) -safe-string -linkpkg -g -o $(HAXE_OUTPUT) $(NATIVE_LIBS) $(NATIVE_LIB_FLAG) $(LFLAGS) $(FINDLIB_PACKAGES) $(EXTLIB_INCLUDES) $(EXTLIB_LIBS:=.$(LIB_EXT)) $(MODULES:%=%.$(MODULE_EXT)) +plugin: haxe + $(DUNE_COMMAND) build --workspace dune-workspace.dev plugins/$(PLUGIN)/$(PLUGIN).cmxs + mkdir -p plugins/$(PLUGIN)/cmxs/$(SYSTEM_NAME) + cp -f _build/default/plugins/$(PLUGIN)/$(PLUGIN).cmxs plugins/$(PLUGIN)/cmxs/$(SYSTEM_NAME)/plugin.cmxs kill_exe_win: ifdef SYSTEMROOT -@taskkill /F /IM haxe.exe 2>/dev/null endif -plugin: -ifeq ($(BYTECODE),1) - $(CC_CMD) $(PLUGIN).ml -else - $(COMPILER) $(ALL_CFLAGS) -shared -o $(PLUGIN).cmxs $(PLUGIN).ml -endif - # Only use if you have only changed gencpp.ml quickcpp: build_src build_pass_4 copy_haxetoolkit @@ -211,14 +123,16 @@ uninstall: rm -rf $(DESTDIR)$(INSTALL_STD_DIR) opam_install: - opam install $(OPAM_LIBS) camlp5 ocamlfind --yes - -# Dependencies + opam install camlp5 ocamlfind dune --yes --include Makefile.dependencies +haxe_deps: + opam pin add haxe . --no-action + opam install haxe --deps-only --yes # Package +package_env: opam_install haxe_deps + package_src: mkdir -p $(PACKAGE_OUT_DIR) # use git-archive-all since we have submodules @@ -300,10 +214,7 @@ package_installer_mac: $(INSTALLER_TMP_DIR)/neko-osx64.tar.gz package_unix # Clean -clean: clean_libs clean_haxe clean_tools clean_package - -clean_libs: - $(foreach lib,$(EXTLIB_LIBS),$(MAKE) -C libs/$(lib) clean &&) true +clean: clean_haxe clean_tools clean_package clean_haxe: rm -f -r _build $(HAXE_OUTPUT) $(PREBUILD_OUTPUT) @@ -324,4 +235,4 @@ FORCE: .ml.cmo: $(CC_CMD) -.PHONY: haxe libs haxelib +.PHONY: haxe haxelib diff --git a/Makefile.version_extra b/Makefile.version_extra deleted file mode 100644 index f423bf9975158768914fbe4f2b799f1cc915fe3b..0000000000000000000000000000000000000000 --- a/Makefile.version_extra +++ /dev/null @@ -1,11 +0,0 @@ -# A hack to print the content of version.ml consistently across Windows (cygwin / command prompt) and Unix. -# The hack: http://stackoverflow.com/a/7284135/267998 -# The issue: https://github.com/HaxeFoundation/haxe/commit/4f8f6a99ddf810ea045492cdd6d40c55abc03e15#commitcomment-10660400 - -all: ; - -ifneq ($(ADD_REVISION),0) - $(info let version_extra = Some ("git build $(BRANCH)","$(COMMIT_SHA)")) -else - $(info let version_extra = None) -endif \ No newline at end of file diff --git a/Makefile.win b/Makefile.win index b57d559da27d2d0a28cb56c718d6808021bffa35..67e1a97ac9431a214966f1d56a9027a1dbdaa649 100644 --- a/Makefile.win +++ b/Makefile.win @@ -7,6 +7,7 @@ PREBUILD_OUTPUT=prebuild.exe EXTENSION=.exe PACKAGE_SRC_EXTENSION=.zip ARCH?=32 +DUNE_COMMAND=dune.exe ifeq ($(ARCH),64) NEKO_ARCH_STR=64 @@ -41,7 +42,16 @@ ifdef FILTER CC_CMD=($(COMPILER) $(ALL_CFLAGS) -c $< 2>tmp.cmi && $(FILTER)) || ($(FILTER) && exit 1) endif -PACKAGE_FILES=$(HAXE_OUTPUT) $(HAXELIB_OUTPUT) std "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep zlib1.dll | sed -e 's/^\s*//')" "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libpcre-1.dll | sed -e 's/^\s*//')" +ifeq ($(STATICLINK),0) + LIB_PARAMS = -cclib -lpcre -cclib -lz -cclib -lcrypt32 -cclib -lmbedtls -cclib -lmbedcrypto -cclib -lmbedx509 +endif + +PACKAGE_FILES=$(HAXE_OUTPUT) $(HAXELIB_OUTPUT) std \ + "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep zlib1.dll | sed -e 's/^\s*//')" \ + "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libpcre-1.dll | sed -e 's/^\s*//')" \ + "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libmbedcrypto.dll | sed -e 's/^\s*//')" \ + "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libmbedtls.dll | sed -e 's/^\s*//')" \ + "$$(cygcheck $(CURDIR)/$(HAXE_OUTPUT) | grep libmbedx509.dll | sed -e 's/^\s*//')" echo_package_files: echo $(PACKAGE_FILES) diff --git a/README.md b/README.md index 21c57647dabebd1de96695854119c60031c57622..675f704783f8218a1739b8f6f98dd034da1c0ced 100644 --- a/README.md +++ b/README.md @@ -23,13 +23,13 @@ Haxe allows you to compile for the following targets: * C++ * C# * Java + * JVM * Lua - * PHP + * PHP 7 * Python 3 * [HashLink](https://hashlink.haxe.org/) * [NekoVM](https://nekovm.org/) * Flash (SWF Bytecode) - * ActionScript 3 * And its own [interpreter](https://haxe.org/blog/eval/) You can try Haxe directly from your browser at [try.haxe.org](https://try.haxe.org)! @@ -88,19 +88,14 @@ You can get help and talk with fellow Haxers from around the world via: ## Version compatibility -Haxe | Neko | SWF | Python | HL | PHP | Lua | ----- | ---- | ---- | ---- | ---- | ---- | ---- | -2.* | 1.* | 8-10 | - | - | - | - | -3.0.0 | 2.0.0 | | - | - | 5.1+ | - | -3.2.0 | | 12-14 | 3.2+ | - | | - | -3.3.0 | 2.1.0 | 21 | | - | | 5.1, 5.2, 5.3, LuaJIT 2.0, 2.1 | -3.4.0 | | | | 1.1 | 5.4+ and 7.0+ (with `-D php7`) | | -4.0.0-preview.1 | | | | 1.2 | 7.0+ | | -4.0.0-preview.3 | | | | 1.3 | | | -4.0.0-preview.4 | | | | 1.6 | | | -4.0.0-preview.5 | | | | 1.8 | | | -4.0.0-rc.1 | | | | 1.9 | | | -4.0.0-rc.3 | | | | 1.10 | | | +Haxe | Neko | SWF | Python | HL | PHP | Lua | +--------------- | ----- | ----- | ------ | ---- | ---- | --- | +2.* | 1.* | 8-10 | - | - | - | - | +3.0.0 | 2.0.0 | | - | - | 5.1+ | - | +3.2.0 | | 12-14 | 3.2+ | - | | - | +3.3.0 | 2.1.0 | 21 | | - | | 5.1, 5.2, 5.3, LuaJIT 2.0, 2.1 | +3.4.0 | | | | 1.1 | 5.4+ and 7.0+ (with `-D php7`) | | +4.0.0 | 2.3.0 | | | 1.11 | 7.0+ | | ## Contributing diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 36b21299b55f4d52d364ff85c7f7e950f995005f..2c47c025fc8478de96c57cd3471fa56f753fb2d2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -63,7 +63,7 @@ stages: php: TEST: php flash: - TEST: flash9,as3 + TEST: flash9 APT_PACKAGES: libglib2.0 libfreetype6 xvfb DISPLAY: ':99.0' AUDIODEV: 'null' @@ -118,7 +118,7 @@ stages: - job: TestMac dependsOn: BuildMac pool: - vmImage: 'macOS-10.13' + vmImage: 'macOS-10.14' strategy: matrix: macro: @@ -140,7 +140,7 @@ stages: php: TEST: php flash: - TEST: flash9,as3 + TEST: flash9 python: TEST: python lua: @@ -174,7 +174,10 @@ stages: - script: brew install $BREW_PACKAGES condition: and(succeeded(), variables['BREW_PACKAGES']) displayName: Install homebrew packages - - script: haxe RunCi.hxml + - script: | + # disable invalid Unicode filenames on APFS + echo "" > sys/compile-fs.hxml + haxe RunCi.hxml workingDirectory: $(Build.SourcesDirectory)/tests displayName: Test diff --git a/dune b/dune new file mode 100644 index 0000000000000000000000000000000000000000..2ac21fc498e91b638f0e79bc591857cf8bbd8709 --- /dev/null +++ b/dune @@ -0,0 +1 @@ +(data_only_dirs extra lib std tests) \ No newline at end of file diff --git a/dune-project b/dune-project new file mode 100644 index 0000000000000000000000000000000000000000..31dd0af322ad424d15f93b7ea340e1b54b893ebe --- /dev/null +++ b/dune-project @@ -0,0 +1,10 @@ +(lang dune 1.11) +(name haxe) + +(package + (name haxe) +) + +(package + (name haxe_prebuild) +) \ No newline at end of file diff --git a/dune-workspace.dev b/dune-workspace.dev new file mode 100644 index 0000000000000000000000000000000000000000..8856b4db15bc01519c2ff2646f7ae9210d3c9aac --- /dev/null +++ b/dune-workspace.dev @@ -0,0 +1,2 @@ +(lang dune 1.11) +(profile release) \ No newline at end of file diff --git a/extra/CHANGES.txt b/extra/CHANGES.txt index 2d3dd83ffc81b6769ba953d1f34fdd7ed23f068f..cd438159f7107eb5c4e91dae95f45dd65f17850b 100644 --- a/extra/CHANGES.txt +++ b/extra/CHANGES.txt @@ -1,3 +1,102 @@ +2020-05-13: 4.1.0 + + New features: + + all : added tail recursion elimination (#8908) + all : added unified exception handling (#9124) + all : allow `try {} catch(e) {}` as a shortcut for `try {} catch(e:haxe.Exception) {}` (#9269) + eval : added SSL support (#9009) + jvm : the JVM target is no longer considered experimental + + General improvements: + + all : implemented different display support approach (#8962) + all : improved display services related to reference finding + all : added go-to-implementation support (#9043) + all : made various improvements to diagnostics + all : support completion for map keys (#9133) + all : improved parser robustness for incomplete syntax (#9148) + all : disallowed the combination of `@:overload` and inline (#3846) + all : improved renaming of local variables (#9304) + all : better inlining of for-loops with anonymous iterators (#8848) + all : remove redundant final `return` in `Void` functions (#6420) + all : remove redundant `continue` in loops (#8952) + all : improved various compilation errors reporting + all : allowed `(get,default)` property access combination (#6195, #8825) + all : allowed ++ and -- on member properties of abstracts (#8930) + js : use abstract type name for generating its implementation class (#9006) + js : improve haxe.ds.StringMap implementation (#8909) + js : improve interface checking and make it more minifier-friendly (#9178) + js : generate `let` instead of `var` when compiler with `-D js-es=6` (#9280) + js : optimize `.bind` on constructors (#9227) + jvm : rewrote function handling to me much faster and more portable (#9208) + jvm : generate interfaces for typedefs for improved performance (#9195) + jvm : added support for haxe.MainLoop + jvm : support `@:jvm.synthetic` and use it to hide some generated fields (#9213) + jvm : respect `@:private` and `@:protected` + lua : improve error handling behavior when throwing objects/instances + lua : optimize `haxe.iterators.StringIterator` + php : optimize `Std.isOfType` for String, Bool and Float + php : make Haxe Array implement native interfaces Iterator, IteratorAggregate, Countable (#8821, 9377) + cs : support `@:assemblyMeta` and `@:assemblyStrict` (#8347) + python : added `__contains__` and `__getitem__` implementations to generated python code for `_hx_AnonObject`, so it is subscribable and behaves like a python dict (#9109) + + Standard Library: + + all : negative `startIndex` argument of `String.indexOf` and `String.lastIndexOf` is unspecified (#8365) + all : changed Array.iterator() to return instances of haxe.iterators.ArrayIterator (#8987) + all : added Array.contains (#9179) + all : added Array.keyValueIterator (#7422) + all : added haxe.Constraints.NotVoid (#8357) + all : added Lambda.findIndex() (#9071) + all : added Lambda.foldi() (#9054) + all : added array access and key-value iteration support to haxe.ds.HashMap (#9056) + jvm : added JVM-specific versions of sys.thread.Lock and sys.thread.Thread + jvm : added JVM-specific version of haxe.ds.StringMap + java/jvm : use native versions of MD-5, SHA-1 and SHA-256 for `haxe.crypto` modules (#9298) + macro : added haxe.macro.Context.containsDisplayPosition(pos) (#9077) + nullsafety : treat Strict as a single-threaded mode; added StrictThreaded (#8895) + + Deprecations: + + all : deprecated `Std.is`; use `Std.isOfType` instead (#2976) + all : added a warning for an uninitialized variable usage captured in a closure (#7447) + js : deprecated `untyped __js__(code, args)`; use `js.Syntax.code(code, args)` instead + php/neko : deprecated neko.Web and php.Web; will be moved to hx4compat library later (#9153) + + Bugfixes: + + all : fixed display support for static imports (#9012) + all : fixed completion in macro mode picking up the wrong type (#7703) + all : fixed wonky analyzer transformation related to locals captured in closures (#9305) + all : allow `return;` in abstract constructors (#7809) + all : fixed static @:op([]) functions (#9347) + all : fixed `@:optional` handling in the inheritance of `@:structInit` classes (#7559) + all : support negative numbers as constant type parameters for `@:generic` types (#9149) + all : fixed false positive compilation server error with empty methods in inheritance (#9029) + all : fixed default values for manually defined @:structInit constructors (#9177, #9258) + all : fixed inference of `Void` return type for arrow functions (#9181) + all : fixed inconsistencies in wildcard imports resolution (#9189, #9190) + all : fix array comprehension for a chain of `if..else if` without final `else` (#9040) + all : prohibit @:structInit on interfaces (#9017) + macro : fixed handling `TAnonymous` in `haxe.macro.TypeTools.map` (#9147) + eval : fixed EReg.matchSub handling with negative length (#9333) + eval : fixed extern classes being generated and causing errors in some cases (#9366) + eval : fixed StringBuf.addSub unicode handling (#9382) + jvm : fixed Void being generated with the wrong casing (#8717) + jvm : fixed debugging-related data being generated in the wrong place + jvm : fixed switches on string values being too optimistic + jvm : fixed problems with Std.parseInt and Std.parseFloat + jvm : made sure type parameter types are boxed + jvm : fixed dynamic access on `null` yielding `null` (#8452) + cpp : fixed native compilation if there is a `hx` package in a project (#8543) + cs : fixed `null` to `0` conversion in parametrized functions for `Null` params (#7428) + cs : fixed integer division handling (#9232) + php : fixed closure creation out of fields with `null` value (#9316) + js : fixed interface generation for minification with Google Closure Compiler in advanced mode (#9172) + js : fixed a crash at startup in IE8 (#9062) + hl : fixed BLOB handling in SQLite (#9048) + 2019-12-17: 4.0.5 Bugfixes: @@ -44,7 +143,6 @@ all : fixed `@:using` static extensions on `Null` (#8928) php : fixed static methods with the same name in parent and child classes (#8944) - 2019-11-04: 4.0.1 Bugfixes: diff --git a/extra/azure-pipelines/build-linux.yml b/extra/azure-pipelines/build-linux.yml index cb2b13b4f8d9a4c5c5f59cec4741c909b2f0d1ff..aa60631f10bdbe56d82977f62fccb109f9d2e886 100644 --- a/extra/azure-pipelines/build-linux.yml +++ b/extra/azure-pipelines/build-linux.yml @@ -15,9 +15,10 @@ jobs: submodules: recursive - script: | set -ex - sudo add-apt-repository ppa:avsm/ppa -y # provides newer version of OCaml and OPAM + sudo add-apt-repository ppa:avsm/ppa -y # provides OPAM 2 + sudo add-apt-repository ppa:haxe/ocaml -y # provides newer version of mbedtls sudo apt-get update -qqy - sudo apt-get install -qqy ocaml-nox camlp5 opam libpcre3-dev zlib1g-dev libgtk2.0-dev ninja-build + sudo apt-get install -qqy ocaml-nox camlp5 opam libpcre3-dev zlib1g-dev libgtk2.0-dev libmbedtls-dev ninja-build displayName: Install dependencies - template: install-neko-snapshot.yaml parameters: @@ -33,8 +34,6 @@ jobs: displayName: Install OCaml libraries - script: | set -ex - opam config exec -- make -s STATICLINK=1 libs - opam config exec -- make -s STATICLINK=1 prebuild opam config exec -- make -s -j`nproc` STATICLINK=1 haxe opam config exec -- make -s haxelib make -s package_bin diff --git a/extra/azure-pipelines/build-mac.yml b/extra/azure-pipelines/build-mac.yml index c16b594332eb9d4451fcc7ac5b53fc1923bb4d73..0622100200e4a3f40894fd6de4256eedf0fedf1d 100644 --- a/extra/azure-pipelines/build-mac.yml +++ b/extra/azure-pipelines/build-mac.yml @@ -1,6 +1,6 @@ parameters: name: 'BuildMac' - vmImage: 'macOS-10.13' + vmImage: 'macOS-10.14' jobs: - job: ${{ parameters.name }} @@ -16,6 +16,7 @@ jobs: - script: | set -ex brew update || brew update || brew update + brew unlink python@2 brew bundle --file=tests/Brewfile --no-upgrade displayName: Install dependencies - template: install-neko-snapshot.yaml @@ -32,9 +33,7 @@ jobs: displayName: Install OCaml libraries - script: | set -ex - opam config exec -- make -s STATICLINK=1 "LIB_PARAMS=/usr/local/opt/zlib/lib/libz.a /usr/local/lib/libpcre.a" libs - opam config exec -- make -s STATICLINK=1 "LIB_PARAMS=/usr/local/opt/zlib/lib/libz.a /usr/local/lib/libpcre.a" prebuild - opam config exec -- make -s -j`sysctl -n hw.ncpu` STATICLINK=1 "LIB_PARAMS=/usr/local/opt/zlib/lib/libz.a /usr/local/lib/libpcre.a" haxe + opam config exec -- make -s -j`sysctl -n hw.ncpu` STATICLINK=1 "LIB_PARAMS=/usr/local/opt/zlib/lib/libz.a /usr/local/lib/libpcre.a /usr/local/lib/libmbedtls.a /usr/local/lib/libmbedcrypto.a /usr/local/lib/libmbedx509.a -cclib '-framework Security -framework CoreFoundation'" haxe opam config exec -- make -s haxelib make -s package_bin package_installer_mac ls -l out diff --git a/extra/azure-pipelines/build-windows.yml b/extra/azure-pipelines/build-windows.yml index 37787a11a8bb72bef5c920a63f29fddd01ae92d5..1ae96b2d2d5df3490a0a2111686dbfeccfa17d58 100644 --- a/extra/azure-pipelines/build-windows.yml +++ b/extra/azure-pipelines/build-windows.yml @@ -25,11 +25,12 @@ jobs: steps: - checkout: self submodules: recursive - - powershell: | - Set-PSDebug -Trace 1 - choco install --no-progress nsis.portable --version 3.02 -y - choco install --no-progress curl wget 7zip.portable -y - displayName: Install dependencies + - powershell: choco install --no-progress nsis.portable --version 3.02 -y + displayName: choco install nsis + - powershell: choco install --no-progress curl wget 7zip.portable -y + displayName: choco install things + - powershell: Write-Host "##vso[task.prependpath]C:\ProgramData\chocolatey\bin" + displayName: Prepend Chocolatey path - template: install-neko-snapshot.yaml parameters: ${{ if eq(parameters.arch, '64') }}: @@ -39,9 +40,11 @@ jobs: - powershell: | Set-PSDebug -Trace 1 curl.exe -fsSL -o cygwin-setup.exe --retry 3 $(CYGWIN_SETUP) - Start-Process -FilePath "cygwin-setup.exe" -ArgumentList "-B -q -R $(CYG_ROOT) -l C:/tmp -s $(CYG_MIRROR) -P default -P make -P git -P zlib-devel -P rsync -P patch -P diffutils -P curl -P unzip -P tar -P m4 -P perl -P libpcre-devel -P mingw64-$(MINGW_ARCH)-zlib -P mingw64-$(MINGW_ARCH)-gcc-core -P mingw64-$(MINGW_ARCH)-pcre" -Wait + Start-Process -FilePath "cygwin-setup.exe" -ArgumentList "-B -q -R $(CYG_ROOT) -l C:/tmp -s $(CYG_MIRROR) -P default -P make -P git -P zlib-devel -P rsync -P patch -P diffutils -P curl -P unzip -P tar -P m4 -P perl -P libpcre-devel -P mbedtls-devel -P mingw64-$(MINGW_ARCH)-zlib -P mingw64-$(MINGW_ARCH)-gcc-core -P mingw64-$(MINGW_ARCH)-pcre" -Wait curl.exe -fsSL -o "opam.tar.xz" --retry 3 https://github.com/fdopen/opam-repository-mingw/releases/download/0.0.0.2/opam$(ARCH).tar.xz + curl.exe -fsSL -o "libmbedtls.tar.xz" --retry 3 https://github.com/Simn/mingw64-mbedtls/releases/download/2.16.3/mingw64-$(MINGW_ARCH)-mbedtls-2.16.3-1.tar.xz & "$(CYG_ROOT)/bin/bash.exe" @('-lc', 'echo "$OLDPWD"') + & "$(CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -C / -xvf libmbedtls.tar.xz') & "$(CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && tar -xf opam.tar.xz') & "$(CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && bash opam$(ARCH)/install.sh') & "$(CYG_ROOT)/bin/bash.exe" @('-lc', 'opam init mingw "https://github.com/fdopen/opam-repository-mingw.git#opam2" --comp 4.07.0+mingw$(ARCH)c --switch 4.07.0+mingw$(ARCH)c --auto-setup --yes 2>&1') @@ -55,7 +58,6 @@ jobs: displayName: Expose mingw dll files - powershell: | Set-PSDebug -Trace 1 - & "$(CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam config exec -- make -s -f Makefile.win libs prebuild 2>&1') & "$(CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam config exec -- make -s -f Makefile.win -j`nproc` haxe 2>&1') & "$(CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam config exec -- make -s -f Makefile.win haxelib 2>&1') & "$(CYG_ROOT)/bin/bash.exe" @('-lc', 'cd "$OLDPWD" && opam config exec -- make -f Makefile.win echo_package_files package_bin package_installer_win package_choco 2>&1') diff --git a/extra/azure-pipelines/test-windows.yml b/extra/azure-pipelines/test-windows.yml index bbb84d66b1edba7929b6e3f852cbd14e88efbd4a..842eb43c1979380305559844c0272bd650ea07ce 100644 --- a/extra/azure-pipelines/test-windows.yml +++ b/extra/azure-pipelines/test-windows.yml @@ -37,7 +37,7 @@ jobs: TEST: php # TODO. flash has never been enabled on our AppVeyor builds. # flash: - # TEST: flash9,as3 + # TEST: flash9 python: TEST: python # TODO. Lua has never been enabled on our AppVeyor builds. diff --git a/extra/brew-flash-update.md b/extra/brew-flash-update.md new file mode 100644 index 0000000000000000000000000000000000000000..e52e971daeb6d8e3074ca003f17a7e0dfeaee6a3 --- /dev/null +++ b/extra/brew-flash-update.md @@ -0,0 +1,16 @@ +# How to update flash player signatures in Brew + +It's easiest to use a mac to do the update since there is a developer script provided by homebrew-cask that can semi-automate the thing. + +Steps: +1. clone https://github.com/Homebrew/homebrew-cask +2. Run ./developer/bin/update_cask_family flash $NEW_VERSION_STRING + +If homebrew-cask's CI succeed, the PR will be automatically merged by a bot, and our CI is saved. + +The super annoying thing is that, homebrew-cask's CI will check Adobe's appcast for the version string, but the appcast is usually outdated until about a day after the new Flash Player release. + +See https://github.com/Homebrew/homebrew-cask/pull/73950#issuecomment-563920561 + +---- +Example PR: https://github.com/Homebrew/homebrew-cask/pull/73952 \ No newline at end of file diff --git a/extra/release-checklist.txt b/extra/release-checklist.txt index ae28e8e518ec904184a566056b0afc5a8d0fe682..46256d12e777797ea7834faa0cf594155f282296 100644 --- a/extra/release-checklist.txt +++ b/extra/release-checklist.txt @@ -3,6 +3,7 @@ - Check that haxelib is working - Make sure to update the haxelib submodule - Check that the run-time haxelibs are ready for release: hxcpp, hxjava, hxcs +- Check that the osx & windows installers has the latest neko release in "Makefile" and "Makefile.win" files # Making the release diff --git a/libs/extc/dune b/libs/extc/dune new file mode 100644 index 0000000000000000000000000000000000000000..38cd2da6e1c1299fa8cf960de99b5f910f8aa36b --- /dev/null +++ b/libs/extc/dune @@ -0,0 +1,16 @@ +(include_subdirs no) + +(library + (name extc) + (libraries extlib) + (c_names extc_stubs) + (modules extc) + (wrapped false) +) + +(library + (name extproc) + (c_names process_stubs) + (modules process) + (wrapped false) +) \ No newline at end of file diff --git a/libs/extc/extc.ml b/libs/extc/extc.ml index 65b375ddc5a7199c17583dcbc687a2ddfaef998e..890b978b5c8e725ef08a885c1dfa8b54a4e37ad2 100644 --- a/libs/extc/extc.ml +++ b/libs/extc/extc.ml @@ -51,29 +51,6 @@ external zlib_crc32 : bytes -> int -> int32 = "zlib_crc32" external time : unit -> float = "sys_time" -type library -type sym -type value - -external dlopen : string -> library = "sys_dlopen" -external dlsym : library -> string -> sym = "sys_dlsym" -external dlcall0 : sym -> value = "sys_dlcall0" -external dlcall1 : sym -> value -> value = "sys_dlcall1" -external dlcall2 : sym -> value -> value -> value = "sys_dlcall2" -external dlcall3 : sym -> value -> value -> value -> value = "sys_dlcall3" -external dlcall4 : sym -> value -> value -> value -> value -> value = "sys_dlcall4" -external dlcall5 : sym -> value -> value -> value -> value -> value -> value = "sys_dlcall5_bc" "sys_dlcall5" -external dlint : int -> value = "sys_dlint" -external dltoint : value -> int = "sys_dltoint" -external dlstring : string -> value = "%identity" -external dladdr : value -> int -> value = "sys_dladdr" -external dlptr : value -> value = "sys_dlptr" -external dlsetptr : value -> value -> unit = "sys_dlsetptr" -external dlalloc_string : value -> string = "sys_dlalloc_string" -external dlmemcpy : value -> value -> int -> unit = "sys_dlmemcpy" -external dlcallback : int -> value = "sys_dlcallback" -external dlcaml_callback : int -> value = "sys_dlcaml_callback" -external dlint32 : int32 -> value = "sys_dlint32" external getch : bool -> int = "sys_getch" external filetime : string -> float = "sys_filetime" diff --git a/libs/extc/extc_stubs.c b/libs/extc/extc_stubs.c index b5dd96dad5ff7e7e6c1f57038fcf08abdcbd2254..30dc986d5c4d76ac36b989d7b6c963f903d52e40 100644 --- a/libs/extc/extc_stubs.c +++ b/libs/extc/extc_stubs.c @@ -572,143 +572,4 @@ CAMLprim value sys_filetime( value file ) { return caml_copy_double(0.); return caml_copy_double( sbuf.st_mtime ); # endif -} - -// --------------- Support for NekoVM Bridge - -CAMLprim value sys_dlopen( value lib ) { -#ifdef _WIN32 - return (value)LoadLibrary(String_val(lib)); -#else - return (value)dlopen(String_val(lib),RTLD_LAZY); -#endif -} - -CAMLprim value sys_dlsym( value dl, value name ) { -#ifdef _WIN32 - return (value)GetProcAddress((HANDLE)dl,String_val(name)); -#else - return (value)dlsym((void*)dl,String_val(name)); -#endif -} - -CAMLprim value sys_dlint( value i ) { - return Int_val(i); -} - -CAMLprim value sys_dltoint( value i ) { - return Val_int((int)i); -} - -CAMLprim value sys_dlint32( value i ) { - return (value)Int32_val(i); -} - -typedef value (*c_prim0)(); -typedef value (*c_prim1)(value); -typedef value (*c_prim2)(value,value); -typedef value (*c_prim3)(value,value,value); -typedef value (*c_prim4)(value,value,value,value); -typedef value (*c_prim5)(value,value,value,value,value); - -CAMLprim value sys_dlcall0( value f ) { - return ((c_prim0)f)(); -} - -CAMLprim value sys_dlcall1( value f, value a ) { - return ((c_prim1)f)(a); -} - -CAMLprim value sys_dlcall2( value f, value a, value b ) { - return ((c_prim2)f)(a,b); -} - -CAMLprim value sys_dlcall3( value f, value a, value b, value c ) { - return ((c_prim3)f)(a,b,c); -} - -CAMLprim value sys_dlcall4( value f, value a, value b, value c, value d ) { - return ((c_prim4)f)(a,b,c,d); -} - -CAMLprim value sys_dlcall5( value f, value a, value b, value c, value d, value e ) { - return ((c_prim5)f)(a,b,c,d,e); -} - -CAMLprim value sys_dlcall5_bc( value *args, int nargs ) { - return ((c_prim5)args[0])(args[1],args[2],args[3],args[4],args[5]); -} - -CAMLprim value sys_dladdr( value v, value a ) { - return (value)((char*)v + Int_val(a)); -} - -CAMLprim value sys_dlptr( value v ) { - return *((value*)v); -} - -CAMLprim value sys_dlsetptr( value p, value v ) { - *((value*)p) = v; - return Val_unit; -} - -CAMLprim value sys_dlalloc_string( value v ) { - return caml_copy_string((char*)v); -} - -CAMLprim value sys_dlmemcpy( value dst, value src, value len ) { - memcpy((char*)dst,(char*)src,Int_val(len)); - return Val_unit; -} - -static value __callb0( value callb ) { - return caml_callbackN(callb,0,NULL); -} - -static value __callb1( value a, value callb ) { - return caml_callback(callb,a); -} - -static value __callb2( value a, value b, value callb ) { - return caml_callback2(callb,a,b); -} - -static value __callb3( value a, value b, value c, value callb ) { - return caml_callback3(callb,a,b,c); -} - -CAMLprim value sys_dlcallback( value nargs ) { - switch( Int_val(nargs) ) { - case 0: - return (value)__callb0; - case 1: - return (value)__callb1; - case 2: - return (value)__callb2; - case 3: - return (value)__callb3; - default: - failwith("dlcallback(too_many_args)"); - } - return Val_unit; -} - -static value __caml_callb1( value a ) { - return caml_callback(*caml_named_value("dlcallb1"),a); -} - -static value __caml_callb2( value a, value b ) { - return caml_callback2(*caml_named_value("dlcallb2"),a,b); -} - -CAMLprim value sys_dlcaml_callback( value nargs ) { - switch( Int_val(nargs) ) { - case 1: - return (value)__caml_callb1; - case 2: - return (value)__caml_callb2; - default: - failwith("sys_dlcaml_callback(too_many_args)"); - } - return Val_unit; -} +} \ No newline at end of file diff --git a/libs/extlib-leftovers/dune b/libs/extlib-leftovers/dune new file mode 100644 index 0000000000000000000000000000000000000000..8321c4c2de69110bd64af77c98caa3fea5fe5c50 --- /dev/null +++ b/libs/extlib-leftovers/dune @@ -0,0 +1,7 @@ +(include_subdirs no) + +(library + (name extlib_leftovers) + (libraries extlib) + (wrapped false) +) \ No newline at end of file diff --git a/libs/ilib/dune b/libs/ilib/dune new file mode 100644 index 0000000000000000000000000000000000000000..b00c4d1fa868efc8e002f8ac6c0a58c747034577 --- /dev/null +++ b/libs/ilib/dune @@ -0,0 +1,9 @@ +(include_subdirs no) + +(library + (name ilib) + (modules_without_implementation ilData ilMeta) + (modules (:standard \ dump)) + (libraries extlib) + (wrapped false) +) \ No newline at end of file diff --git a/libs/ilib/ilMetaWriter.ml b/libs/ilib/ilMetaWriter.ml index 7e9b5465c65ef26c8758c21661606491d184f971..c6daa544fa7f1cd0439e77603a221a9a9d96113d 100644 --- a/libs/ilib/ilMetaWriter.ml +++ b/libs/ilib/ilMetaWriter.ml @@ -68,11 +68,11 @@ let int_of_type_def_string = function let int_of_type_def_flags f = int_of_type_def_vis f.tdf_vis - logor + lor int_of_type_def_layout f.tdf_layout - logor + lor int_of_type_def_semantics f.tdf_semantics - logor + lor int_of_type_def_impl f.tdf_impl - logor + lor int_of_type_def_string f.tdf_string diff --git a/libs/javalib/dune b/libs/javalib/dune new file mode 100644 index 0000000000000000000000000000000000000000..0892cd1a4315157e88a5713747c666750ee01c39 --- /dev/null +++ b/libs/javalib/dune @@ -0,0 +1,7 @@ +(include_subdirs no) + +(library + (name javalib) + (libraries extlib) + (wrapped false) +) \ No newline at end of file diff --git a/libs/json/dune b/libs/json/dune new file mode 100644 index 0000000000000000000000000000000000000000..3ef8b8d625004559b76224c181d972c4857b243d --- /dev/null +++ b/libs/json/dune @@ -0,0 +1,6 @@ +(include_subdirs no) + +(library + (name json) + (preprocess (pps sedlex.ppx)) +) \ No newline at end of file diff --git a/src/core/json/json.ml b/libs/json/json.ml similarity index 100% rename from src/core/json/json.ml rename to libs/json/json.ml diff --git a/libs/mbedtls/dune b/libs/mbedtls/dune new file mode 100644 index 0000000000000000000000000000000000000000..890250edb2546c969a522350ba8519a4d0e406ee --- /dev/null +++ b/libs/mbedtls/dune @@ -0,0 +1,9 @@ +(include_subdirs no) + +(library + (name mbedtls) + (c_names + mbedtls_stubs + ) + (wrapped false) +) \ No newline at end of file diff --git a/libs/mbedtls/mbedtls.ml b/libs/mbedtls/mbedtls.ml new file mode 100644 index 0000000000000000000000000000000000000000..dac738dde3780df0497d3e8a84ecdcf7ac169fe5 --- /dev/null +++ b/libs/mbedtls/mbedtls.ml @@ -0,0 +1,69 @@ +type mbedtls_ctr_drbg_context +type mbedtls_entropy_context +type mbedtls_ssl_config +type mbedtls_ssl_context +type mbedtls_x509_crt +type mbedtls_pk_context + +type mbedtls_result = int + +type t_mbedtls_entropy_func = mbedtls_entropy_context -> bytes -> int -> mbedtls_result + +external mbedtls_strerror : int -> string = "ml_mbedtls_strerror" + +external mbedtls_ctr_drbg_init : unit -> mbedtls_ctr_drbg_context = "ml_mbedtls_ctr_drbg_init" +external mbedtls_ctr_drbg_random : mbedtls_ctr_drbg_context -> bytes -> int -> mbedtls_result = "ml_mbedtls_ctr_drbg_random" +external mbedtls_ctr_drbg_seed : + mbedtls_ctr_drbg_context -> + 'a -> + string option -> + mbedtls_result = "ml_mbedtls_ctr_drbg_seed" + +external mbedtls_entropy_func : mbedtls_entropy_context -> bytes -> int -> mbedtls_result = "ml_mbedtls_entropy_func" +external mbedtls_entropy_init : unit -> mbedtls_entropy_context = "ml_mbedtls_entropy_init" + +external mbedtls_ssl_conf_ca_chain : mbedtls_ssl_config -> mbedtls_x509_crt -> unit = "ml_mbedtls_ssl_conf_ca_chain" +external mbedtls_ssl_config_authmode : mbedtls_ssl_config -> int -> unit = "ml_mbedtls_ssl_conf_authmode" +external mbedtls_ssl_config_defaults : mbedtls_ssl_config -> int -> int -> int -> mbedtls_result = "ml_mbedtls_ssl_config_defaults" +external mbedtls_ssl_config_init : unit -> mbedtls_ssl_config = "ml_mbedtls_ssl_config_init" +external mbedtls_ssl_config_rng : mbedtls_ssl_config -> 'a -> unit = "ml_mbedtls_ssl_conf_rng" + +external mbedtls_ssl_init : unit -> mbedtls_ssl_context = "ml_mbedtls_ssl_init" +external mbedtls_ssl_get_peer_cert : mbedtls_ssl_context -> mbedtls_x509_crt option = "ml_mbedtls_ssl_get_peer_cert" +external mbedtls_ssl_handshake : mbedtls_ssl_context -> mbedtls_result = "ml_mbedtls_ssl_handshake" +external mbedtls_ssl_read : mbedtls_ssl_context -> bytes -> int -> int -> mbedtls_result = "ml_mbedtls_ssl_read" +external mbedtls_ssl_set_bio : + mbedtls_ssl_context -> + 'a -> + ('a -> bytes -> mbedtls_result) -> + ('a -> bytes -> mbedtls_result) -> + unit = "ml_mbedtls_ssl_set_bio" +external mbedtls_ssl_set_hostname : mbedtls_ssl_context -> string -> mbedtls_result = "ml_mbedtls_ssl_set_hostname" +external mbedtls_ssl_setup : mbedtls_ssl_context -> mbedtls_ssl_config -> mbedtls_result = "ml_mbedtls_ssl_setup" +external mbedtls_ssl_write : mbedtls_ssl_context -> bytes -> int -> int -> mbedtls_result = "ml_mbedtls_ssl_write" + +external mbedtls_pk_init : unit -> mbedtls_pk_context = "ml_mbedtls_pk_init" +external mbedtls_pk_parse_key : mbedtls_pk_context -> bytes -> string option -> mbedtls_result = "ml_mbedtls_pk_parse_key" +external mbedtls_pk_parse_keyfile : mbedtls_pk_context -> string -> string option -> mbedtls_result = "ml_mbedtls_pk_parse_keyfile" +external mbedtls_pk_parse_public_keyfile : mbedtls_pk_context -> string -> mbedtls_result = "ml_mbedtls_pk_parse_public_keyfile" +external mbedtls_pk_parse_public_key : mbedtls_pk_context -> bytes -> mbedtls_result = "ml_mbedtls_pk_parse_public_key" + +external mbedtls_x509_crt_init : unit -> mbedtls_x509_crt = "ml_mbedtls_x509_crt_init" +external mbedtls_x509_next : mbedtls_x509_crt -> mbedtls_x509_crt option = "ml_mbedtls_x509_next" +external mbedtls_x509_crt_parse : mbedtls_x509_crt -> bytes -> mbedtls_result = "ml_mbedtls_x509_crt_parse" +external mbedtls_x509_crt_parse_file : mbedtls_x509_crt -> string -> mbedtls_result = "ml_mbedtls_x509_crt_parse_file" +external mbedtls_x509_crt_parse_path : mbedtls_x509_crt -> string -> mbedtls_result = "ml_mbedtls_x509_crt_parse_path" + +external hx_cert_get_alt_names : mbedtls_x509_crt -> string array = "hx_cert_get_alt_names" +external hx_cert_get_issuer : mbedtls_x509_crt -> string -> string option = "hx_cert_get_issuer" +external hx_cert_get_notafter : mbedtls_x509_crt -> float = "hx_cert_get_notafter" +external hx_cert_get_notbefore : mbedtls_x509_crt -> float = "hx_cert_get_notbefore" +external hx_cert_get_subject : mbedtls_x509_crt -> string -> string option = "hx_cert_get_subject" + +(* glue *) + +external hx_cert_load_defaults : mbedtls_x509_crt -> int = "hx_cert_load_defaults" +external hx_get_ssl_authmode_flags : unit -> (string * int) array = "hx_get_ssl_authmode_flags" +external hx_get_ssl_endpoint_flags : unit -> (string * int) array = "hx_get_ssl_endpoint_flags" +external hx_get_ssl_preset_flags : unit -> (string * int) array = "hx_get_ssl_preset_flags" +external hx_get_ssl_transport_flags : unit -> (string * int) array = "hx_get_ssl_transport_flags" diff --git a/libs/mbedtls/mbedtls_stubs.c b/libs/mbedtls/mbedtls_stubs.c new file mode 100644 index 0000000000000000000000000000000000000000..f675e63213f68a56d70e2c80dc2fbdec883276d8 --- /dev/null +++ b/libs/mbedtls/mbedtls_stubs.c @@ -0,0 +1,598 @@ +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#endif + +#ifdef __APPLE__ +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "mbedtls/debug.h" +#include "mbedtls/error.h" +#include "mbedtls/config.h" +#include "mbedtls/ssl.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/certs.h" +#include "mbedtls/oid.h" + +#define PVoid_val(v) (*((void**) Data_custom_val(v))) + +void debug(void* ctx, int debug_level, const char* file_name, int line, const char* message) { + printf("%s:%i: %s", file_name, line, message); +} + +#define Val_none Val_int(0) + +static value Val_some(value v) { + CAMLparam1(v); + CAMLlocal1(some); + some = caml_alloc(1, 0); + Store_field(some, 0, v); + CAMLreturn(some); +} + +CAMLprim value ml_mbedtls_strerror(value code) { + CAMLparam1(code); + CAMLlocal1(r); + char buf[128]; + mbedtls_strerror(Int_val(code), buf, sizeof(buf)); + r = caml_copy_string(buf); + CAMLreturn(r); +} + +// CtrDrbg + +#define CtrDrbg_val(v) (*((mbedtls_ctr_drbg_context**) Data_custom_val(v))) + +static void ml_mbedtls_ctr_drbg_finalize(value v) { + mbedtls_ctr_drbg_context* ctr_drbg = CtrDrbg_val(v); + if (ctr_drbg != NULL) { + mbedtls_ctr_drbg_free(ctr_drbg); + } +} + +static struct custom_operations ctr_drbg_ops = { + .identifier = "ml_ctr_drbg", + .finalize = ml_mbedtls_ctr_drbg_finalize, + .compare = custom_compare_default, + .hash = custom_hash_default, + .serialize = custom_serialize_default, + .deserialize = custom_deserialize_default, +}; + +CAMLprim value ml_mbedtls_ctr_drbg_init(void) { + CAMLparam0(); + CAMLlocal1(obj); + obj = caml_alloc_custom(&ctr_drbg_ops, sizeof(mbedtls_ctr_drbg_context*), 0, 1); + mbedtls_ctr_drbg_context* ctr_drbg = malloc(sizeof(mbedtls_ctr_drbg_context)); + mbedtls_ctr_drbg_init(ctr_drbg); + CtrDrbg_val(obj) = ctr_drbg; + CAMLreturn(obj); +} + +CAMLprim value ml_mbedtls_ctr_drbg_random(value p_rng, value output, value output_len) { + CAMLparam3(p_rng, output, output_len); + CAMLreturn(Val_int(mbedtls_ctr_drbg_random(CtrDrbg_val(p_rng), String_val(output), Int_val(output_len)))); +} + +CAMLprim value ml_mbedtls_ctr_drbg_seed(value ctx, value p_entropy, value custom) { + CAMLparam2(ctx, custom); + CAMLreturn(Val_int(mbedtls_ctr_drbg_seed(CtrDrbg_val(ctx), mbedtls_entropy_func, PVoid_val(p_entropy), NULL, 0))); +} + +// Entropy + +#define Entropy_val(v) (*((mbedtls_entropy_context**) Data_custom_val(v))) + +static void ml_mbedtls_entropy_finalize(value v) { + mbedtls_entropy_context* entropy = Entropy_val(v); + if (entropy != NULL) { + mbedtls_entropy_free(entropy); + } +} + +static struct custom_operations entropy_ops = { + .identifier = "ml_entropy", + .finalize = ml_mbedtls_entropy_finalize, + .compare = custom_compare_default, + .hash = custom_hash_default, + .serialize = custom_serialize_default, + .deserialize = custom_deserialize_default, +}; + +CAMLprim value ml_mbedtls_entropy_init(void) { + CAMLparam0(); + CAMLlocal1(obj); + obj = caml_alloc_custom(&entropy_ops, sizeof(mbedtls_entropy_context*), 0, 1); + mbedtls_entropy_context* entropy = malloc(sizeof(mbedtls_entropy_context)); + mbedtls_entropy_init(entropy); + Entropy_val(obj) = entropy; + CAMLreturn(obj); +} + +CAMLprim value ml_mbedtls_entropy_func(value data, value output, value len) { + CAMLparam3(data, output, len); + CAMLreturn(Val_int(mbedtls_entropy_func(PVoid_val(data), String_val(output), Int_val(len)))); +} + +// Certificate + +#define X509Crt_val(v) (*((mbedtls_x509_crt**) Data_custom_val(v))) + +static void ml_mbedtls_x509_crt_finalize(value v) { + mbedtls_x509_crt* x509_crt = X509Crt_val(v); + if (x509_crt != NULL) { + mbedtls_x509_crt_free(x509_crt); + } +} + +static struct custom_operations x509_crt_ops = { + .identifier = "ml_x509_crt", + .finalize = ml_mbedtls_x509_crt_finalize, + .compare = custom_compare_default, + .hash = custom_hash_default, + .serialize = custom_serialize_default, + .deserialize = custom_deserialize_default, +}; + +CAMLprim value ml_mbedtls_x509_crt_init(void) { + CAMLparam0(); + CAMLlocal1(obj); + obj = caml_alloc_custom(&x509_crt_ops, sizeof(mbedtls_x509_crt*), 0, 1); + mbedtls_x509_crt* x509_crt = malloc(sizeof(mbedtls_x509_crt)); + mbedtls_x509_crt_init(x509_crt); + X509Crt_val(obj) = x509_crt; + CAMLreturn(obj); +} + +CAMLprim value ml_mbedtls_x509_next(value chain) { + CAMLparam1(chain); + CAMLlocal2(r, obj); + mbedtls_x509_crt* cert = X509Crt_val(chain); + if (cert->next == NULL) { + CAMLreturn(Val_none); + } + obj = caml_alloc_custom(&x509_crt_ops, sizeof(mbedtls_x509_crt*), 0, 1); + X509Crt_val(obj) = cert->next; + CAMLreturn(Val_some(obj)); +} + +CAMLprim value ml_mbedtls_x509_crt_parse(value chain, value bytes) { + CAMLparam2(chain, bytes); + const char* buf = String_val(bytes); + int len = caml_string_length(bytes); + CAMLreturn(Val_int(mbedtls_x509_crt_parse(X509Crt_val(chain), buf, len + 1))); +} + +CAMLprim value ml_mbedtls_x509_crt_parse_file(value chain, value path) { + CAMLparam2(chain, path); + CAMLreturn(Val_int(mbedtls_x509_crt_parse_file(X509Crt_val(chain), String_val(path)))); +} + +CAMLprim value ml_mbedtls_x509_crt_parse_path(value chain, value path) { + CAMLparam2(chain, path); + CAMLreturn(Val_int(mbedtls_x509_crt_parse_path(X509Crt_val(chain), String_val(path)))); +} + +// Certificate Haxe API + +value caml_string_of_asn1_buf(mbedtls_asn1_buf* dat) { + CAMLparam0(); + CAMLlocal1(s); + s = caml_alloc_string(dat->len); + memcpy(String_val(s), dat->p, dat->len); + CAMLreturn(s); +} + +CAMLprim value hx_cert_get_alt_names(value chain) { + CAMLparam1(chain); + CAMLlocal1(obj); + mbedtls_x509_crt* cert = X509Crt_val(chain); + if (cert->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME == 0 || &cert->subject_alt_names == NULL) { + obj = Atom(0); + } else { + mbedtls_asn1_sequence* cur = &cert->subject_alt_names; + int i = 0; + while (cur != NULL) { + ++i; + cur = cur->next; + } + obj = caml_alloc(i, 0); + cur = &cert->subject_alt_names; + i = 0; + while (cur != NULL) { + Store_field(obj, i, caml_string_of_asn1_buf(&cur->buf)); + ++i; + cur = cur->next; + } + } + CAMLreturn(obj); +} + +CAMLprim value hx_cert_get_subject(value chain, value objname) { + CAMLparam2(chain, objname); + mbedtls_x509_name *obj; + mbedtls_x509_crt* cert = X509Crt_val(chain); + const char *oname, *rname; + obj = &cert->subject; + rname = String_val(objname); + while (obj != NULL) { + int r = mbedtls_oid_get_attr_short_name(&obj->oid, &oname); + if (r == 0 && strcmp(oname, rname) == 0) { + CAMLreturn(Val_some(caml_string_of_asn1_buf(&obj->val))); + } + obj = obj->next; + } + CAMLreturn(Val_none); +} + +CAMLprim value hx_cert_get_issuer(value chain, value objname) { + CAMLparam2(chain, objname); + mbedtls_x509_name *obj; + mbedtls_x509_crt* cert = X509Crt_val(chain); + int r; + const char *oname, *rname; + obj = &cert->issuer; + rname = String_val(objname); + while (obj != NULL) { + r = mbedtls_oid_get_attr_short_name(&obj->oid, &oname); + if (r == 0 && strcmp(oname, rname) == 0) { + CAMLreturn(Val_some(caml_string_of_asn1_buf(&obj->val))); + } + obj = obj->next; + } + CAMLreturn(Val_none); +} + +time_t time_to_time_t(mbedtls_x509_time* t) { + struct tm info; + info.tm_year = t->year - 1900; + info.tm_mon = t->mon - 1; + info.tm_mday = t->day; + info.tm_hour = t->hour; + info.tm_min = t->min; + info.tm_sec = t->sec; + return mktime(&info); +} + +CAMLprim value hx_cert_get_notafter(value chain) { + CAMLparam1(chain); + mbedtls_x509_crt* cert = X509Crt_val(chain); + mbedtls_x509_time *t = &cert->valid_to; + time_t time = time_to_time_t(t); + CAMLreturn(caml_copy_double((double)time)); +} + +CAMLprim value hx_cert_get_notbefore(value chain) { + CAMLparam1(chain); + mbedtls_x509_crt* cert = X509Crt_val(chain); + mbedtls_x509_time *t = &cert->valid_from; + time_t time = time_to_time_t(t); + CAMLreturn(caml_copy_double((double)time)); +} + +// Config + +#define Config_val(v) (*((mbedtls_ssl_config**) Data_custom_val(v))) + +static void ml_mbedtls_ssl_config_finalize(value v) { + mbedtls_ssl_config* ssl_config = Config_val(v); + if (ssl_config != NULL) { + mbedtls_ssl_config_free(ssl_config); + } +} + +static struct custom_operations ssl_config_ops = { + .identifier = "ml_ssl_config", + .finalize = ml_mbedtls_ssl_config_finalize, + .compare = custom_compare_default, + .hash = custom_hash_default, + .serialize = custom_serialize_default, + .deserialize = custom_deserialize_default, +}; + +CAMLprim value ml_mbedtls_ssl_config_init(void) { + CAMLparam0(); + CAMLlocal1(obj); + obj = caml_alloc_custom(&ssl_config_ops, sizeof(mbedtls_ssl_config*), 0, 1); + mbedtls_ssl_config* ssl_config = malloc(sizeof(mbedtls_ssl_config)); + mbedtls_ssl_config_init(ssl_config); + Config_val(obj) = ssl_config; + CAMLreturn(obj); +} + +CAMLprim value ml_mbedtls_ssl_conf_authmode(value conf, value authmode) { + CAMLparam2(conf, authmode); + mbedtls_ssl_conf_authmode(Config_val(conf), Int_val(authmode)); + CAMLreturn(Val_unit); +} + +CAMLprim value ml_mbedtls_ssl_conf_ca_chain(value conf, value ca_chain) { + CAMLparam2(conf, ca_chain); + mbedtls_ssl_conf_ca_chain(Config_val(conf), X509Crt_val(ca_chain), NULL); + CAMLreturn(Val_unit); +} + +CAMLprim value ml_mbedtls_ssl_config_defaults(value conf, value endpoint, value transport, value preset) { + CAMLparam4(conf, endpoint, transport, preset); + CAMLreturn(Val_int(mbedtls_ssl_config_defaults(Config_val(conf), Int_val(endpoint), Int_val(transport), Int_val(preset)))); +} + +CAMLprim value ml_mbedtls_ssl_conf_rng(value conf, value p_rng) { + CAMLparam2(conf, p_rng); + mbedtls_ssl_conf_rng(Config_val(conf), mbedtls_ctr_drbg_random, PVoid_val(p_rng)); + CAMLreturn(Val_unit); +} + +// Pk + +#define PkContext_val(v) (*((mbedtls_pk_context**) Data_custom_val(v))) + +static void ml_mbedtls_pk_context_finalize(value v) { + mbedtls_pk_context* pk_context = PkContext_val(v); + if (pk_context != NULL) { + mbedtls_pk_free(pk_context); + } +} + +static struct custom_operations pk_context_ops = { + .identifier = "ml_pk_context", + .finalize = ml_mbedtls_pk_context_finalize, + .compare = custom_compare_default, + .hash = custom_hash_default, + .serialize = custom_serialize_default, + .deserialize = custom_deserialize_default, +}; + +CAMLprim value ml_mbedtls_pk_init(void) { + CAMLparam0(); + CAMLlocal1(obj); + obj = caml_alloc_custom(&pk_context_ops, sizeof(mbedtls_pk_context*), 0, 1); + mbedtls_pk_context* pk_context = malloc(sizeof(mbedtls_pk_context)); + mbedtls_pk_init(pk_context); + PkContext_val(obj) = pk_context; + CAMLreturn(obj); +} + +CAMLprim value ml_mbedtls_pk_parse_key(value ctx, value key, value password) { + CAMLparam3(ctx, key, password); + const char* pwd = NULL; + size_t pwdlen = 0; + if (password != Val_none) { + pwd = String_val(Field(password, 0)); + pwdlen = caml_string_length(Field(password, 0)); + } + CAMLreturn(mbedtls_pk_parse_key(PkContext_val(ctx), String_val(key), caml_string_length(key) + 1, pwd, pwdlen)); +} + +CAMLprim value ml_mbedtls_pk_parse_keyfile(value ctx, value path, value password) { + CAMLparam3(ctx, path, password); + const char* pwd = NULL; + if (password != Val_none) { + pwd = String_val(Field(password, 0)); + } + CAMLreturn(mbedtls_pk_parse_keyfile(PkContext_val(ctx), String_val(path), pwd)); +} + +CAMLprim value ml_mbedtls_pk_parse_public_key(value ctx, value key) { + CAMLparam2(ctx, key); + CAMLreturn(mbedtls_pk_parse_public_key(PkContext_val(ctx), String_val(key), caml_string_length(key) + 1)); +} + +CAMLprim value ml_mbedtls_pk_parse_public_keyfile(value ctx, value path) { + CAMLparam2(ctx, path); + CAMLreturn(mbedtls_pk_parse_public_keyfile(PkContext_val(ctx), String_val(path))); +} + +// Ssl + +#define SslContext_val(v) (*((mbedtls_ssl_context**) Data_custom_val(v))) + +static void ml_mbedtls_ssl_context_finalize(value v) { + mbedtls_ssl_context* ssl_context = SslContext_val(v); + if (ssl_context != NULL) { + mbedtls_ssl_free(ssl_context); + } +} + +static struct custom_operations ssl_context_ops = { + .identifier = "ml_ssl_context", + .finalize = ml_mbedtls_ssl_context_finalize, + .compare = custom_compare_default, + .hash = custom_hash_default, + .serialize = custom_serialize_default, + .deserialize = custom_deserialize_default, +}; + +CAMLprim value ml_mbedtls_ssl_init(void) { + CAMLparam0(); + CAMLlocal1(obj); + obj = caml_alloc_custom(&ssl_context_ops, sizeof(mbedtls_ssl_context*), 0, 1); + mbedtls_ssl_context* ssl_context = malloc(sizeof(mbedtls_ssl_context)); + mbedtls_ssl_init(ssl_context); + SslContext_val(obj) = ssl_context; + CAMLreturn(obj); +} + +CAMLprim value ml_mbedtls_ssl_get_peer_cert(value ssl) { + CAMLparam1(ssl); + CAMLlocal1(obj); + mbedtls_ssl_context* ssl_context = SslContext_val(ssl); + mbedtls_x509_crt* crt = (mbedtls_x509_crt*)mbedtls_ssl_get_peer_cert(ssl_context); + if (crt == NULL) { + CAMLreturn(Val_none); + } + obj = caml_alloc_custom(&x509_crt_ops, sizeof(mbedtls_x509_crt*), 0, 1); + X509Crt_val(obj) = crt; + CAMLreturn(Val_some(obj)); +} + +CAMLprim value ml_mbedtls_ssl_handshake(value ssl) { + CAMLparam1(ssl); + CAMLreturn(Val_int(mbedtls_ssl_handshake(SslContext_val(ssl)))); +} + +CAMLprim value ml_mbedtls_ssl_read(value ssl, value buf, value pos, value len) { + CAMLparam4(ssl, buf, pos, len); + CAMLreturn(Val_int(mbedtls_ssl_read(SslContext_val(ssl), String_val(buf) + Int_val(pos), Int_val(len)))); +} + +static int bio_write_cb(void* ctx, const unsigned char* buf, size_t len) { + CAMLparam0(); + CAMLlocal3(r, s, vctx); + vctx = (value)ctx; + s = caml_alloc_string(len); + memcpy(String_val(s), buf, len); + r = caml_callback2(Field(vctx, 1), Field(vctx, 0), s); + CAMLreturn(Int_val(r)); +} + +static int bio_read_cb(void* ctx, unsigned char* buf, size_t len) { + CAMLparam0(); + CAMLlocal3(r, s, vctx); + vctx = (value)ctx; + s = caml_alloc_string(len); + r = caml_callback2(Field(vctx, 2), Field(vctx, 0), s); + memcpy(buf, String_val(s), len); + CAMLreturn(Int_val(r)); +} + +CAMLprim value ml_mbedtls_ssl_set_bio(value ssl, value p_bio, value f_send, value f_recv) { + CAMLparam4(ssl, p_bio, f_send, f_recv); + CAMLlocal1(ctx); + ctx = caml_alloc(3, 0); + Store_field(ctx, 0, p_bio); + Store_field(ctx, 1, f_send); + Store_field(ctx, 2, f_recv); + mbedtls_ssl_set_bio(SslContext_val(ssl), (void*)ctx, bio_write_cb, bio_read_cb, NULL); + CAMLreturn(Val_unit); +} + +CAMLprim value ml_mbedtls_ssl_set_hostname(value ssl, value hostname) { + CAMLparam2(ssl, hostname); + CAMLreturn(Val_int(mbedtls_ssl_set_hostname(SslContext_val(ssl), String_val(hostname)))); +} + +CAMLprim value ml_mbedtls_ssl_setup(value ssl, value conf) { + CAMLparam2(ssl, conf); + CAMLreturn(Val_int(mbedtls_ssl_setup(SslContext_val(ssl), Config_val(conf)))); +} + +CAMLprim value ml_mbedtls_ssl_write(value ssl, value buf, value pos, value len) { + CAMLparam4(ssl, buf, pos, len); + CAMLreturn(Val_int(mbedtls_ssl_write(SslContext_val(ssl), String_val(buf) + Int_val(pos), Int_val(len)))); +} + +// glue + +CAMLprim value hx_cert_load_defaults(value certificate) { + CAMLparam1(certificate); + int r = 1; + + mbedtls_x509_crt *chain = X509Crt_val(certificate); + + #ifdef _WIN32 + HCERTSTORE store; + PCCERT_CONTEXT cert; + + if (store = CertOpenSystemStore(0, "Root")) { + cert = NULL; + while (cert = CertEnumCertificatesInStore(store, cert)) { + r = mbedtls_x509_crt_parse_der(chain, (unsigned char *)cert->pbCertEncoded, cert->cbCertEncoded); + if (r != 0) { + CAMLreturn(Val_int(r)); + } + } + CertCloseStore(store, 0); + } + #endif + + #ifdef __APPLE__ + CFMutableDictionaryRef search; + CFArrayRef result; + SecKeychainRef keychain; + SecCertificateRef item; + CFDataRef dat; + // Load keychain + if (SecKeychainOpen("/System/Library/Keychains/SystemRootCertificates.keychain", &keychain) == errSecSuccess) { + // Search for certificates + search = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); + CFDictionarySetValue(search, kSecClass, kSecClassCertificate); + CFDictionarySetValue(search, kSecMatchLimit, kSecMatchLimitAll); + CFDictionarySetValue(search, kSecReturnRef, kCFBooleanTrue); + CFDictionarySetValue(search, kSecMatchSearchList, CFArrayCreate(NULL, (const void **)&keychain, 1, NULL)); + if (SecItemCopyMatching(search, (CFTypeRef *)&result) == errSecSuccess) { + CFIndex n = CFArrayGetCount(result); + for (CFIndex i = 0; i < n; i++) { + item = (SecCertificateRef)CFArrayGetValueAtIndex(result, i); + + // Get certificate in DER format + dat = SecCertificateCopyData(item); + if (dat) { + r = mbedtls_x509_crt_parse_der(chain, (unsigned char *)CFDataGetBytePtr(dat), CFDataGetLength(dat)); + CFRelease(dat); + if (r != 0) { + CAMLreturn(Val_int(r)); + } + } + } + } + CFRelease(keychain); + } + #endif + + CAMLreturn(Val_int(r)); +} + +static value build_fields(int num_fields, const char* names[], int values[]) { + CAMLparam0(); + CAMLlocal2(ret, tuple); + ret = caml_alloc(num_fields, 0); + for (int i = 0; i < num_fields; ++i) { + tuple = caml_alloc_tuple(2); + Store_field(tuple, 0, caml_copy_string(names[i])); + Store_field(tuple, 1, Val_int(values[i])); + Store_field(ret, i, tuple); + } + CAMLreturn(ret); +} + +CAMLprim value hx_get_ssl_authmode_flags(value unit) { + CAMLparam1(unit); + const char* names[] = {"SSL_VERIFY_NONE", "SSL_VERIFY_OPTIONAL", "SSL_VERIFY_REQUIRED"}; + int values[] = {MBEDTLS_SSL_VERIFY_NONE, MBEDTLS_SSL_VERIFY_OPTIONAL, MBEDTLS_SSL_VERIFY_REQUIRED}; + CAMLreturn(build_fields(sizeof(values) / sizeof(values[0]), names, values)); +} + +CAMLprim value hx_get_ssl_endpoint_flags(value unit) { + CAMLparam1(unit); + const char* names[] = {"SSL_IS_CLIENT", "SSL_IS_SERVER"}; + int values[] = {MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_IS_SERVER}; + CAMLreturn(build_fields(sizeof(values) / sizeof(values[0]), names, values)); +} + +CAMLprim value hx_get_ssl_preset_flags(value unit) { + CAMLparam1(unit); + const char* names[] = {"SSL_PRESET_DEFAULT", "SSL_PRESET_SUITEB"}; + int values[] = {MBEDTLS_SSL_PRESET_DEFAULT, MBEDTLS_SSL_PRESET_SUITEB}; + CAMLreturn(build_fields(sizeof(values) / sizeof(values[0]), names, values)); +} + +CAMLprim value hx_get_ssl_transport_flags(value unit) { + CAMLparam1(unit); + const char* names[] = {"SSL_TRANSPORT_STREAM", "SSL_TRANSPORT_DATAGRAM"}; + int values[] = {MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_TRANSPORT_DATAGRAM}; + CAMLreturn(build_fields(sizeof(values) / sizeof(values[0]), names, values)); +} \ No newline at end of file diff --git a/libs/neko/dune b/libs/neko/dune new file mode 100644 index 0000000000000000000000000000000000000000..b882b39dc34e6e610f262d42e389714dffc42bc5 --- /dev/null +++ b/libs/neko/dune @@ -0,0 +1,7 @@ +(include_subdirs no) + +(library + (name neko) + (libraries extlib) + (wrapped false) +) \ No newline at end of file diff --git a/libs/objsize/dune b/libs/objsize/dune new file mode 100644 index 0000000000000000000000000000000000000000..dfdbebcd61f333baa7bc14221e1fe60a849def2d --- /dev/null +++ b/libs/objsize/dune @@ -0,0 +1,9 @@ +(include_subdirs no) + +(library + (name objsize) + (c_names c_objsize) + (c_flags (-I../../../../libs/objsize)) ; TODO: This is stupid + (wrapped false) + (modules objsize) +) \ No newline at end of file diff --git a/libs/pcre/dune b/libs/pcre/dune new file mode 100644 index 0000000000000000000000000000000000000000..68d4fee0864eba3010bdf63043a69312422716ef --- /dev/null +++ b/libs/pcre/dune @@ -0,0 +1,7 @@ +(include_subdirs no) + +(library + (name pcre) + (c_names pcre_stubs) + (wrapped false) +) \ No newline at end of file diff --git a/libs/swflib/dune b/libs/swflib/dune new file mode 100644 index 0000000000000000000000000000000000000000..12aa4eeb40f5666218387129941e7a2001356236 --- /dev/null +++ b/libs/swflib/dune @@ -0,0 +1,8 @@ +(include_subdirs no) + +(library + (name swflib) + (libraries extc extlib extlib_leftovers) + (modules_without_implementation as3 as3hl) + (wrapped false) +) \ No newline at end of file diff --git a/libs/ttflib/dune b/libs/ttflib/dune new file mode 100644 index 0000000000000000000000000000000000000000..6999e79ba2fa1ab44e8c8e815f9a5cee8e1b3a97 --- /dev/null +++ b/libs/ttflib/dune @@ -0,0 +1,8 @@ +(include_subdirs no) + +(library + (name ttflib) + (libraries extlib extlib_leftovers swflib unix) + (modules (:standard \ main)) + (wrapped false) +) \ No newline at end of file diff --git a/libs/ttflib/main.ml b/libs/ttflib/main.ml index 068a6fad4bbafffe35be03d4b44d8c165ceb1164..ab500ec52406c8302f0bf396c05d9d4be2244d5c 100644 --- a/libs/ttflib/main.ml +++ b/libs/ttflib/main.ml @@ -65,6 +65,8 @@ let process args = let config = { ttfc_range_str = range_str; ttfc_font_name = None; + ttfc_font_weight = TFWRegular; + ttfc_font_posture = TFPNormal; } in let f2 = TTFSwfWriter.to_swf ttf config in let ch = IO.output_channel (open_out_bin (dir ^ "/" ^ ttf.ttf_font_name ^ ".dat")) in diff --git a/libs/ziplib/dune b/libs/ziplib/dune new file mode 100644 index 0000000000000000000000000000000000000000..506e97bd596a50096637456b7e92acaa3f448d05 --- /dev/null +++ b/libs/ziplib/dune @@ -0,0 +1,7 @@ +(include_subdirs no) + +(library + (name ziplib) + (libraries extc unix) + (wrapped false) +) \ No newline at end of file diff --git a/opam b/opam index 95bc53d1914fe83db1dadc4eed64290a3c317056..4dcad7a0d3fdf5d95d02aaf9d64dc0dcc3101455 100644 --- a/opam +++ b/opam @@ -1,6 +1,6 @@ opam-version: "2.0" name: "haxe" -version: "4.0.0" +version: "4.1.0" synopsis: "Multi-target universal programming language" description: """ Haxe is an open source toolkit based on a modern, diff --git a/plugins/example/README.md b/plugins/example/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7b19441b6ada605483aa1db3010368007ca25aa8 --- /dev/null +++ b/plugins/example/README.md @@ -0,0 +1,24 @@ +# How to build a plugin + +``` +$ make plugin PLUGIN=example +``` +This command builds plugin for current OS only. + +# How to use your plugins in a Haxe project + +Setup your plugin as a haxe library: +``` +$ haxelib dev example path/to/haxe/plugins/example +``` +And then access it inside of a macro: +```haxe +macro static public function testPlugin() { + Example.plugin.hello(); + return macro {} +} +``` + +# How to start a new plugin + +Just make a copy of an "example" plugin directory and replace all occurrences of "example" word with your own plugin name. \ No newline at end of file diff --git a/plugins/example/dune b/plugins/example/dune new file mode 100644 index 0000000000000000000000000000000000000000..9de3fa43b75e87c171144b9df1df98b8c05d03e2 --- /dev/null +++ b/plugins/example/dune @@ -0,0 +1,7 @@ +(data_only_dirs cmxs hx) +(include_subdirs unqualified) + +(library + (name example) + (libraries haxe) +) \ No newline at end of file diff --git a/plugins/example/haxelib.json b/plugins/example/haxelib.json new file mode 100644 index 0000000000000000000000000000000000000000..5067c04a689ab642b456dc08282175a78750d6fd --- /dev/null +++ b/plugins/example/haxelib.json @@ -0,0 +1,12 @@ +{ + "name" : "example", + "url" : "http://haxe.org", + "license" : "MIT", + "description" : "Example Plugin", + "version" : "0.1.0", + "releasenote" : "Initial release", + "classPath": "hx", + "contributors" : ["example"], + "tags": ["plugin"], + "dependencies" : {} +} \ No newline at end of file diff --git a/plugins/example/hx/Example.macro.hx b/plugins/example/hx/Example.macro.hx new file mode 100644 index 0000000000000000000000000000000000000000..ea0d9efa7a17b54951fda885107423a6d6c48a1a --- /dev/null +++ b/plugins/example/hx/Example.macro.hx @@ -0,0 +1,32 @@ +import haxe.PosInfos; + +using haxe.io.Path; + +typedef ExamplePluginApi = { + function hello():Void; + function stringifyPosition(p:haxe.macro.Expr.Position):String; + function hijackStaticTest():Void; +} + +class Example { + /** Access plugin API */ + static public var plugin(get,never):ExamplePluginApi; + + static var _plugin:ExamplePluginApi; + static function get_plugin():ExamplePluginApi { + if(_plugin == null) { + try { + _plugin = eval.vm.Context.loadPlugin(getPluginPath()); + } catch(e:Dynamic) { + throw 'Failed to load plugin: $e'; + } + } + return _plugin; + } + + static function getPluginPath():String { + var currentFile = (function(?p:PosInfos) return p.fileName)(); + var srcDir = currentFile.directory().directory(); + return Path.join([srcDir, 'cmxs', Sys.systemName(), 'plugin.cmxs']); + } +} \ No newline at end of file diff --git a/plugins/example/ml/example.ml b/plugins/example/ml/example.ml new file mode 100644 index 0000000000000000000000000000000000000000..ca81f3d18276105d3a6cbf8419ded6f808ebc12c --- /dev/null +++ b/plugins/example/ml/example.ml @@ -0,0 +1,70 @@ +open EvalValue +open Type + +class plugin = + object (self) + (** + Prints greeting to stdout. + Takes no arguments, returns Void. + *) + method hello () : value = + print_endline "Hello from plugin"; + (* + Plugin architecture requires to return something even for methods typed Void on Haxe side. + Return `null` + *) + vnull + (** + Takes `haxe.macro.Position` and returns a string of that position in the same format used for + compiler errors + *) + method stringify_position (pos:value) : value = + let pos = EvalDecode.decode_pos pos in + let str = Lexer.get_error_pos (Printf.sprintf "%s:%d:") pos in + EvalEncode.encode_string str + (** + Change all static methods named "test" to throw "Hello from plugin". + This is an example how to modify typed syntax tree. + *) + method hijack_static_test () : value = + let compiler = (EvalContext.get_ctx()).curapi in + (** + Add a callback like `haxe.macro.Context.onAfterTyping` + *) + compiler.after_typing (fun haxe_types -> + List.iter + (fun hx_type -> + match hx_type with + | TClassDecl cls -> + List.iter + (fun field -> + match field.cf_name, field.cf_expr with + | "test", Some e -> + let hello = { + eexpr = TConst (TString "Hello from plugin"); + etype = (compiler.get_com()).basic.tstring; + epos = Globals.null_pos; + } in + field.cf_expr <- Some { e with eexpr = TThrow hello } + | _ -> () + ) + cls.cl_ordered_statics + | _ -> () + ) + haxe_types + ); + vnull + end +;; + +let api = new plugin in + +(** + Register our plugin API. + This code is executed upon `eval.vm.Context.loadPlugin` call. +*) +EvalStdLib.StdContext.register [ + ("hello", EvalEncode.vfun0 api#hello); + ("stringifyPosition", EvalEncode.vfun1 api#stringify_position); + ("hijackStaticTest", EvalEncode.vfun0 api#hijack_static_test); +] \ No newline at end of file diff --git a/src-json/define.json b/src-json/define.json index 5e0f0c31aa498f4c954bb5540209aaa82f30a033..0d10f248854aed718e0b066457f49d6989aca747 100644 --- a/src-json/define.json +++ b/src-json/define.json @@ -10,17 +10,17 @@ "doc": "Allow the SWF to be measured with Monocle tool.", "platforms": ["flash"] }, + { + "name": "AnalyzerOptimize", + "define": "analyzer_optimize", + "doc": "Perform advanced optimizations." + }, { "name": "AnnotateSource", "define": "annotate_source", "doc": "Add additional comments to generated source code.", "platforms": ["cpp"] }, - { - "name": "As3", - "define": "as3", - "doc": "Defined when outputting flash9 as3 source code." - }, { "name": "CheckXmlProxy", "define": "check_xml_proxy", @@ -163,6 +163,11 @@ "doc": "Record per-method execution times in macro/interp mode. Implies eval_stack.", "platforms": ["eval"] }, + { + "name": "FilterTimes", + "define": "filter_times", + "doc": "Record per-filter execution times upon --times." + }, { "name": "FastCast", "define": "fast_cast", @@ -233,6 +238,13 @@ "define": "haxe", "doc": "The current Haxe version value in SemVer format." }, + { + "name": "HlVer", + "define": "hl_ver", + "doc": "The HashLink version to target. (default: 1.10.0)", + "platforms": ["hl"], + "params": ["version"] + }, { "name": "HxcppApiLevel", "define": "hxcpp_api_level", @@ -652,5 +664,10 @@ "name": "WarnVarShadowing", "define": "warn_var_shadowing", "doc": "Warn about shadowing variable declarations." + }, + { + "name": "NoTre", + "define": "no_tre", + "doc": "Disable tail recursion elimination." } ] diff --git a/src-json/meta.json b/src-json/meta.json index 10ac2079f37fe5f6e9cfd246b1b84dc0444e3107..208c6e713a993031b902a4d7fb8b6061424192b4 100644 --- a/src-json/meta.json +++ b/src-json/meta.json @@ -52,6 +52,20 @@ "targets": ["TAbstract", "TAbstractField"], "links": ["https://haxe.org/manual/types-abstract-array-access.html"] }, + { + "name": "AssemblyMeta", + "metadata": ":cs.assemblyMeta", + "doc": "Used to declare a native C# assembly attribute", + "platforms": ["cs"], + "targets": ["TClass"] + }, + { + "name": "AssemblyStrict", + "metadata": ":cs.assemblyStrict", + "doc": "Used to declare a native C# assembly attribute; is type checked", + "platforms": ["cs"], + "targets": ["TClass"] + }, { "name": "Ast", "metadata": ":ast", @@ -148,7 +162,7 @@ "name": "CompilerGenerated", "metadata": ":compilerGenerated", "doc": "Marks a field as generated by the compiler. Should not be used by the end user.", - "platforms": ["java", "cs"] + "internal": true }, { "name": "Const", @@ -195,6 +209,13 @@ "targets": ["TClass", "TEnum"], "internal": true }, + { + "name": "CsUsing", + "metadata": ":cs.using", + "doc": "Add using directives to your module", + "platforms": ["cs"], + "targets": ["TClass"] + }, { "name": "Dce", "metadata": ":dce", @@ -419,6 +440,12 @@ "targets": ["TClassField"], "internal": true }, + { + "name": "GenericClassPerMethod", + "metadata": ":genericClassPerMethod", + "doc": "Makes compiler generate separate class per generic static method specialization", + "targets": ["TClass"] + }, { "name": "Getter", "metadata": ":getter", @@ -576,6 +603,13 @@ "targets": ["TClass", "TEnum"], "internal": true }, + { + "name": "JvmSynthetic", + "metadata": ":jvm.synthetic", + "doc": "Mark generated class, field or method as synthetic", + "platforms": ["java"], + "targets": ["TClass", "TEnum", "TAnyField"] + }, { "name": "JsRequire", "metadata": ":jsRequire", @@ -678,11 +712,18 @@ { "name": "Native", "metadata": ":native", - "doc": "Rewrites the path of a class or enum during generation.", - "params": ["Output type path"], - "targets": ["TClass", "TEnum"], + "doc": "Rewrites the path of a type or class field during generation.", + "params": ["Output path"], + "targets": ["TClass", "TEnum", "TAbstract", "TClassField"], "links": ["https://haxe.org/manual/lf-externs.html"] }, + { + "name": "NativeJni", + "metadata": ":java.native", + "doc": "Annotates that a function has implementation in native code through JNI.", + "platforms": ["java"], + "targets": ["TClassField"] + }, { "name": "NativeChildren", "metadata": ":nativeChildren", @@ -803,7 +844,7 @@ "name": "NullSafety", "metadata": ":nullSafety", "doc": "Enables null safety for classes or fields. Disables null safety for classes, fields or expressions if provided with `Off` as an argument.", - "params": ["Off | Loose | Strict"], + "params": ["Off | Loose | Strict | StrictThreaded"], "targets": ["TClass", "TClassField", "TExpr"], "links": ["https://haxe.org/manual/cr-null-safety.html"] }, @@ -922,7 +963,7 @@ { "name": "Property", "metadata": ":property", - "doc": "Marks a property field to be compiled as a native C# property.", + "doc": "Marks a field to be compiled as a native C# property.", "platforms": ["cs"], "targets": ["TClassField"] }, @@ -1101,6 +1142,12 @@ "platforms": ["java"], "targets": ["TClass"] }, + { + "name": "TailRecursion", + "metadata": ":tailRecursion", + "doc": "Internally used for tail recursion elimination.", + "internal": true + }, { "name": "TemplatedCall", "metadata": ":templatedCall", @@ -1191,12 +1238,26 @@ "name": "Value", "metadata": ":value", "doc": "Used to store default values for fields and function arguments.", - "targets": ["TClassField"] + "targets": ["TClassField"], + "internal": true + }, + { + "name": "HaxeArguments", + "metadata": ":haxe.arguments", + "doc": "Used to store function arguments.", + "targets": ["TClassField"], + "internal": true }, { "name": "Void", "metadata": ":void", "doc": "Use Cpp native `void` return type.", "platforms": ["cpp"] + }, + { + "name": "NeedsExceptionStack", + "metadata": ":needsExceptionStack", + "doc": "Internally used for some of auto-generated `catch` vars", + "internal": true } -] \ No newline at end of file +] diff --git a/src-prebuild/dune b/src-prebuild/dune new file mode 100644 index 0000000000000000000000000000000000000000..8bd71acbebf42bb2a3347718603979df7b75d6e2 --- /dev/null +++ b/src-prebuild/dune @@ -0,0 +1,8 @@ +(include_subdirs no) + +(executable + (name prebuild) + (public_name haxe_prebuild) + (package haxe_prebuild) + (libraries extlib json) +) \ No newline at end of file diff --git a/src/prebuild/main.ml b/src-prebuild/prebuild.ml similarity index 90% rename from src/prebuild/main.ml rename to src-prebuild/prebuild.ml index 39c1c5eb06703e4626ee64f489da9ad7b7e241aa..842f66447e001529c49af6b0736130055ca0624c 100644 --- a/src/prebuild/main.ml +++ b/src-prebuild/prebuild.ml @@ -196,8 +196,8 @@ type meta_parameter = ;; -match Sys.argv with - | [|_; "define"; define_path|] -> +match Array.to_list (Sys.argv) with + | [_; "define"; define_path]-> let defines = parse_file_array define_path parse_define in Printf.printf "%s" define_header; Printf.printf "type strict_defined =\n"; @@ -205,8 +205,8 @@ match Sys.argv with Printf.printf "\n\t| Last\n\n"; (* must be last *) Printf.printf "let infos = function\n"; Printf.printf "%s" (gen_define_info defines); - Printf.printf "\n\t| Last -> assert false\n" - | [|_; "meta"; meta_path|] -> + Printf.printf "\n\t| Last -> die \"\" __LOC__\n" + | [_; "meta"; meta_path]-> let metas = parse_file_array meta_path parse_meta in Printf.printf "%s" meta_header; Printf.printf "type strict_meta =\n"; @@ -214,5 +214,15 @@ match Sys.argv with Printf.printf "\n\t| Last\n\t| Dollar of string\n\t| Custom of string\n\n"; Printf.printf "let get_info = function\n"; Printf.printf "%s" (gen_meta_info metas); - Printf.printf "\n\t| Last -> assert false\n\t| Dollar s -> \"$\" ^ s,(\"\",[])\n\t| Custom s -> s,(\"\",[])\n" - | _ -> () + Printf.printf "\n\t| Last -> die \"\" __LOC__\n\t| Dollar s -> \"$\" ^ s,(\"\",[])\n\t| Custom s -> s,(\"\",[])\n" + | _ :: "libparams" :: params -> + Printf.printf "(%s)" (String.concat " " (List.map (fun s -> Printf.sprintf "\"%s\"" s) params)) + | [_ ;"version";add_revision;branch;sha] -> + begin match add_revision with + | "0" | "" -> + print_endline "let version_extra = None" + | _ -> + Printf.printf "let version_extra = Some (\"git build %s\",\"%s\")" branch sha + end + | args -> + print_endline (String.concat ", " args) diff --git a/src/codegen/codegen.ml b/src/codegen/codegen.ml index 7a1bc02cb802ad014fe51e00d5f6547265d3a6d1..f5a7aa83d047279cd6008740d99fba01fcc88e7f 100644 --- a/src/codegen/codegen.ml +++ b/src/codegen/codegen.ml @@ -58,7 +58,7 @@ let add_property_field com c = let cf = mk_field n com.basic.tstring p null_pos in PMap.add n cf fields,((n,null_pos,NoQuotes),Texpr.Builder.make_string com.basic v p) :: values ) (PMap.empty,[]) props in - let t = mk_anon fields in + let t = mk_anon ~fields (ref Closed) in let e = mk (TObjectDecl values) t p in let cf = mk_field "__properties__" t p null_pos in cf.cf_expr <- Some e; @@ -94,7 +94,7 @@ let update_cache_dependencies t = | TAnon an -> PMap.iter (fun _ cf -> check_field m cf) an.a_fields | TMono r -> - (match !r with + (match r.tm_type with | Some t -> check_t m t | _ -> ()) | TLazy f -> @@ -154,7 +154,7 @@ let fix_override com c f fd = let f2 = (try Some (find_field com c f) with Not_found -> None) in match f2,fd with | Some (f2), Some(fd) -> - let targs, tret = (match follow f2.cf_type with TFun (args,ret) -> args, ret | _ -> assert false) in + let targs, tret = (match follow f2.cf_type with TFun (args,ret) -> args, ret | _ -> die "" __LOC__) in let changed_args = ref [] in let prefix = "_tmp_" in let nargs = List.map2 (fun ((v,ct) as cur) (_,_,t2) -> @@ -189,14 +189,12 @@ let fix_override com c f fd = { e with eexpr = TBlock (el_v @ el) } ); } in - (* as3 does not allow wider visibility, so the base method has to be made public *) - if Common.defined com Define.As3 && has_class_field_flag f CfPublic then add_class_field_flag f2 CfPublic; let targs = List.map (fun(v,c) -> (v.v_name, Option.is_some c, v.v_type)) nargs in - let fde = (match f.cf_expr with None -> assert false | Some e -> e) in + let fde = (match f.cf_expr with None -> die "" __LOC__ | Some e -> e) in f.cf_expr <- Some { fde with eexpr = TFunction fd2 }; f.cf_type <- TFun(targs,tret); | Some(f2), None when c.cl_interface -> - let targs, tret = (match follow f2.cf_type with TFun (args,ret) -> args, ret | _ -> assert false) in + let targs, tret = (match follow f2.cf_type with TFun (args,ret) -> args, ret | _ -> die "" __LOC__) in f.cf_type <- TFun(targs,tret) | _ -> () @@ -247,7 +245,7 @@ let fix_abstract_inheritance com t = let rec is_volatile t = match t with | TMono r -> - (match !r with + (match r.tm_type with | Some t -> is_volatile t | _ -> false) | TLazy f -> @@ -422,7 +420,7 @@ module Dump = struct | None -> platform_name_macro com | Some s -> s in - let dump_dependencies_path = [dump_path com;target_name;".dependencies"] in + let dump_dependencies_path = [dump_path com;target_name;"dependencies"] in let buf,close = create_dumpfile [] dump_dependencies_path in let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in let dep = Hashtbl.create 0 in @@ -435,7 +433,7 @@ module Dump = struct ) m.m_extra.m_deps; ) com.Common.modules; close(); - let dump_dependants_path = [dump_path com;target_name;".dependants"] in + let dump_dependants_path = [dump_path com;target_name;"dependants"] in let buf,close = create_dumpfile [] dump_dependants_path in let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in Hashtbl.iter (fun n ml -> @@ -454,21 +452,21 @@ end let default_cast ?(vtmp="$t") com e texpr t p = let api = com.basic in let mk_texpr = function - | TClassDecl c -> TAnon { a_fields = PMap.empty; a_status = ref (Statics c) } - | TEnumDecl e -> TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics e) } - | TAbstractDecl a -> TAnon { a_fields = PMap.empty; a_status = ref (AbstractStatics a) } - | TTypeDecl _ -> assert false + | TClassDecl c -> mk_anon (ref (Statics c)) + | TEnumDecl e -> mk_anon (ref (EnumStatics e)) + | TAbstractDecl a -> mk_anon (ref (AbstractStatics a)) + | TTypeDecl _ -> die "" __LOC__ in let vtmp = alloc_var VGenerated vtmp e.etype e.epos in let var = mk (TVar (vtmp,Some e)) api.tvoid p in let vexpr = mk (TLocal vtmp) e.etype p in let texpr = mk (TTypeExpr texpr) (mk_texpr texpr) p in - let std = (try List.find (fun t -> t_path t = ([],"Std")) com.types with Not_found -> assert false) in + let std = (try List.find (fun t -> t_path t = ([],"Std")) com.types with Not_found -> die "" __LOC__) in let fis = (try - let c = (match std with TClassDecl c -> c | _ -> assert false) in - FStatic (c, PMap.find "is" c.cl_statics) + let c = (match std with TClassDecl c -> c | _ -> die "" __LOC__) in + FStatic (c, PMap.find "isOfType" c.cl_statics) with Not_found -> - assert false + die "" __LOC__ ) in let std = mk (TTypeExpr std) (mk_texpr std) p in let is = mk (TField (std,fis)) (tfun [t_dynamic;t_dynamic] api.tbool) p in @@ -511,7 +509,7 @@ module UnificationCallback = struct in let check e = match e.eexpr with | TBinop((OpAssign | OpAssignOp _),e1,e2) -> - assert false; (* this trigger #4347, to be fixed before enabling + die "" __LOC__; (* this trigger #4347, to be fixed before enabling let e2 = f e2 e1.etype in {e with eexpr = TBinop(op,e1,e2)} *) | TVar(v,Some ev) -> diff --git a/src/codegen/dotnet.ml b/src/codegen/dotnet.ml index 5b36117164d2a09a4fab996e32b6671a7d3d1cf7..c0e919cee1855e1ca64d64ff1375061dd9f39858 100644 --- a/src/codegen/dotnet.ml +++ b/src/codegen/dotnet.ml @@ -220,10 +220,8 @@ let ilpath_s = function let get_cls = function | _,_,c -> c -(* TODO: When possible on Haxe, use this to detect flag enums, and make an abstract with @:op() *) -(* that behaves like an enum, and with an enum as its underlying type *) -let enum_is_flag ilcls = - let check_flag name ns = name = "FlagsAttribute" && ns = ["System"] in +let has_attr expected_name expected_ns ilcls = + let check_flag name ns = (name = expected_name && ns = expected_ns) in List.exists (fun a -> match a.ca_type with | TypeRef r -> @@ -246,6 +244,12 @@ let enum_is_flag ilcls = false ) ilcls.cattrs +(* TODO: When possible on Haxe, use this to detect flag enums, and make an abstract with @:op() *) +(* that behaves like an enum, and with an enum as its underlying type *) +let enum_is_flag = has_attr "FlagsAttribute" ["System"] + +let is_compiler_generated = has_attr "CompilerGeneratedAttribute" ["System"; "Runtime"; "CompilerServices"] + let convert_ilenum ctx p ?(is_flag=false) ilcls = let meta = ref [ Meta.Native, [EConst (String (ilpath_s ilcls.cpath,SDoubleQuotes) ), p], p; @@ -414,7 +418,7 @@ let convert_ilmethod ctx p m is_explicit_impl = Printf.printf "\t%smethod %s : %s\n" (if !is_static then "static " else "") cff_name (IlMetaDebug.ilsig_s m.msig.ssig); let acc = match is_final with - | None | Some true when not force_check -> + | None | Some true when not force_check && not !is_static -> (AFinal,null_pos) :: acc | _ -> acc @@ -573,12 +577,12 @@ let convert_ilprop ctx p prop is_explicit_impl = cff_kind = kind; } -let get_type_path ctx ct = match ct with | CTPath p -> p | _ -> assert false +let get_type_path ctx ct = match ct with | CTPath p -> p | _ -> die "" __LOC__ let is_explicit ctx ilcls i = let s = match i with | LClass(path,_) | LValueType(path,_) -> ilpath_s path - | _ -> assert false + | _ -> die "" __LOC__ in let len = String.length s in List.exists (fun m -> @@ -1188,7 +1192,7 @@ class net_library com name file_path std = object(self) let path = netpath_to_hx std ilpath in build path ) cls.cnested - | Some cls -> + | Some cls when not (is_compiler_generated cls) -> let ctx = self#get_ctx in let hxcls = convert_ilclass ctx p cls in cp := (hxcls,p) :: !cp; diff --git a/src/codegen/gencommon/arrayDeclSynf.ml b/src/codegen/gencommon/arrayDeclSynf.ml index bcdc3f7de6d8e5cbb9795e8b1d78b5b6914ad141..605e4e243b761db095ab9c95a026102fbe2d31bf 100644 --- a/src/codegen/gencommon/arrayDeclSynf.ml +++ b/src/codegen/gencommon/arrayDeclSynf.ml @@ -33,7 +33,7 @@ let init (native_array_cl : tclass) (change_type_params : module_type -> t list let cl, params = match follow e.etype with | TInst(({ cl_path = ([], "Array") } as cl), ( _ :: _ as params)) -> cl, params | TInst(({ cl_path = ([], "Array") } as cl), []) -> cl, [t_dynamic] - | _ -> assert false + | _ -> Globals.die "" __LOC__ in let params = change_type_params (TClassDecl cl) params in let e_inner_decl = mk (TArrayDecl (List.map run el)) (TInst (native_array_cl, params)) e.epos in diff --git a/src/codegen/gencommon/castDetect.ml b/src/codegen/gencommon/castDetect.ml index eda7f23843962af0295f698728c1c319b2db700e..f4634a64191bedcca6f21c200a032595ce09368c 100644 --- a/src/codegen/gencommon/castDetect.ml +++ b/src/codegen/gencommon/castDetect.ml @@ -86,7 +86,7 @@ struct match e.eexpr with | TReturn (eopt) -> (* a return must be inside a function *) - let ret_type = match !current_ret_type with | Some(s) -> s | None -> gen.gcon.error "Invalid return outside function declaration." e.epos; assert false in + let ret_type = match !current_ret_type with | Some(s) -> s | None -> gen.gcon.error "Invalid return outside function declaration." e.epos; die "" __LOC__ in (match eopt with | None when not (ExtType.is_void ret_type) -> Texpr.Builder.mk_return (null ret_type e.epos) @@ -200,13 +200,13 @@ let rec type_eq gen param a b = with Not_found -> if is_closed a2 then Type.error [has_no_field b n]; - if not (link (ref None) b f1.cf_type) then Type.error [cannot_unify a b]; + if not (link (Monomorph.create()) b f1.cf_type) then Type.error [cannot_unify a b]; a2.a_fields <- PMap.add n f1 a2.a_fields ) a1.a_fields; PMap.iter (fun n f2 -> if not (PMap.mem n a1.a_fields) then begin if is_closed a1 then Type.error [has_no_field a n]; - if not (link (ref None) a f2.cf_type) then Type.error [cannot_unify a b]; + if not (link (Monomorph.create()) a f2.cf_type) then Type.error [cannot_unify a b]; a1.a_fields <- PMap.add n f2 a1.a_fields end; ) a2.a_fields; @@ -428,7 +428,7 @@ let rec handle_cast gen e real_to_t real_from_t = in let tclass = match get_type gen ([],"Class") with | TAbstractDecl(a) -> a - | _ -> assert false in + | _ -> die "" __LOC__ in handle_cast gen e real_to_t (gen.greal_type (TAbstract(tclass, [p2]))) with | Not_found -> mk_cast false to_t e) @@ -570,13 +570,13 @@ let select_overload gen applied_f overloads types params = cf,t,true (* no compatible overload was found *) else check_overload overloads - | [] -> assert false + | [] -> die "" __LOC__ in check_overload overloads | _ -> match overloads with (* issue #1742 *) | (t,cf) :: [] -> cf,t,true | (t,cf) :: _ -> cf,t,false - | _ -> assert false + | _ -> die "" __LOC__ let rec cur_ctor c tl = match c.cl_constructor with @@ -737,7 +737,7 @@ let handle_type_parameter gen e e1 ef ~clean_ef ~overloads_cast_to_base f elist ); List.map (fun t -> - match follow t with + match follow_without_null t with | TMono _ -> t_empty | t -> t ) monos @@ -834,7 +834,9 @@ let handle_type_parameter gen e e1 ef ~clean_ef ~overloads_cast_to_base f elist (* let called_t = TFun(List.map (fun e -> "arg",false,e.etype) elist, ecall.etype) in *) let called_t = match follow e1.etype with | TFun _ -> e1.etype | _ -> TFun(List.map (fun e -> "arg",false,e.etype) elist, ecall.etype) in (* workaround for issue #1742 *) let called_t = change_rest called_t elist in - let fparams = infer_params ecall.epos (get_fun (apply_params cl.cl_params params actual_t)) (get_fun called_t) cf.cf_params calls_parameters_explicitly in + let original = (get_fun (apply_params cl.cl_params params actual_t)) in + let applied = (get_fun called_t) in + let fparams = infer_params ecall.epos original applied cf.cf_params calls_parameters_explicitly in (* get what the backend actually sees *) (* actual field's function *) let actual_t = get_real_fun gen actual_t in @@ -888,7 +890,7 @@ let handle_type_parameter gen e e1 ef ~clean_ef ~overloads_cast_to_base f elist | FClassField (cl,params,_,cf,_,actual_t,_) -> return_var (handle_cast gen { e1 with eexpr = TField({ ef with etype = t_dynamic }, f) } e1.etype t_dynamic) (* force dynamic and cast back to needed type *) | FEnumField (en, efield, true) -> - let ecall = match e with | None -> trace (field_name f); trace efield.ef_name; gen.gcon.error "This field should be called immediately" ef.epos; assert false | Some ecall -> ecall in + let ecall = match e with | None -> trace (field_name f); trace efield.ef_name; gen.gcon.error "This field should be called immediately" ef.epos; die "" __LOC__ | Some ecall -> ecall in (match en.e_params with (* | [] -> @@ -898,7 +900,7 @@ let handle_type_parameter gen e e1 ef ~clean_ef ~overloads_cast_to_base f elist *) | _ -> let pt = match e with | None -> real_type | Some _ -> snd (get_fun e1.etype) in - let _params = match follow pt with | TEnum(_, p) -> p | _ -> gen.gcon.warning (debug_expr e1) e1.epos; assert false in + let _params = match follow pt with | TEnum(_, p) -> p | _ -> gen.gcon.warning (debug_expr e1) e1.epos; die "" __LOC__ in let args, ret = get_fun efield.ef_type in let actual_t = TFun(List.map (fun (n,o,t) -> (n,o,gen.greal_type t)) args, gen.greal_type ret) in (* @@ -917,7 +919,7 @@ let handle_type_parameter gen e e1 ef ~clean_ef ~overloads_cast_to_base f elist handle_cast gen new_ecall (gen.greal_type ecall.etype) (gen.greal_type ret) ) - | FEnumField _ when is_some e -> assert false + | FEnumField _ when is_some e -> die "" __LOC__ | FEnumField (en,efield,_) -> return_var { e1 with eexpr = TField({ ef with eexpr = TTypeExpr( TEnumDecl en ); },FEnum(en,efield)) } (* no target by date will uses this.so this code may not be correct at all *) @@ -1049,7 +1051,7 @@ let configure gen ?(overloads_cast_to_base = false) maybe_empty_t calls_paramete | TInt _ -> gen.gcon.basic.tint | TFloat _ -> gen.gcon.basic.tfloat | TBool _ -> gen.gcon.basic.tbool - | _ -> assert false + | _ -> die "" __LOC__ in handle e t real_t | TCast( { eexpr = TConst TNull }, _ ) -> @@ -1086,7 +1088,7 @@ let configure gen ?(overloads_cast_to_base = false) maybe_empty_t calls_paramete (match gen.gcurrent_class with | Some cl -> print_endline (s_type_path cl.cl_path) | _ -> ()); - assert false + die "" __LOC__ in let base_type = List.hd base_type in { e with eexpr = TArrayDecl( List.map (fun e -> handle (run e) base_type e.etype) el ); etype = et } @@ -1094,7 +1096,7 @@ let configure gen ?(overloads_cast_to_base = false) maybe_empty_t calls_paramete let et = e.etype in let base_type = match follow et with | TInst(cl, bt) -> gen.greal_type_param (TClassDecl cl) bt - | _ -> assert false + | _ -> die "" __LOC__ in let base_type = List.hd base_type in { e with eexpr = TCall(arr_local, List.map (fun e -> handle (run e) base_type e.etype) el ); etype = et } @@ -1107,7 +1109,7 @@ let configure gen ?(overloads_cast_to_base = false) maybe_empty_t calls_paramete let cl, tparams = match follow ef.etype with | TInst(cl,p) -> cl,p - | _ -> assert false in + | _ -> die "" __LOC__ in (try let is_overload, cf, sup, stl = choose_ctor gen cl tparams (List.map (fun e -> e.etype) eparams) maybe_empty_t e.epos in let handle e t1 t2 = diff --git a/src/codegen/gencommon/closuresToClass.ml b/src/codegen/gencommon/closuresToClass.ml index d4a3e74020d7b0e38bfae3ef16a07bc649d19bd0..d9f335120b22a5d5570caf802c1311a849837ca9 100644 --- a/src/codegen/gencommon/closuresToClass.ml +++ b/src/codegen/gencommon/closuresToClass.ml @@ -200,7 +200,7 @@ let traverse gen ?tparam_anon_decl ?tparam_anon_acc (handle_anon_func:texpr->tfu ) | TBinop(OpAssign, { eexpr = TLocal({ v_extra = Some(_ :: _, _) } as v)}, ({ eexpr= TFunction tf } as f)) when is_some tparam_anon_decl -> (match tparam_anon_decl with - | None -> assert false + | None -> die "" __LOC__ | Some tparam_anon_decl -> tparam_anon_decl v f { tf with tf_expr = run tf.tf_expr }; { e with eexpr = TBlock([]) } @@ -291,7 +291,7 @@ let rec get_type_params acc t = PMap.fold (fun cf acc -> let params = List.map (fun (_,t) -> match follow t with | TInst(c,_) -> c - | _ -> assert false) cf.cf_params + | _ -> die "" __LOC__) cf.cf_params in List.filter (fun t -> not (List.memq t params)) (get_type_params acc cf.cf_type) ) a.a_fields acc @@ -305,7 +305,7 @@ let rec get_type_params acc t = | TEnum(_, params) | TInst(_, params) -> List.fold_left get_type_params acc params - | TMono r -> (match !r with + | TMono r -> (match r.tm_type with | Some t -> get_type_params acc t | None -> acc) | _ -> get_type_params acc (follow_once t) @@ -392,7 +392,7 @@ let configure gen ft = let captured = List.sort (fun e1 e2 -> match e1, e2 with | { eexpr = TLocal v1 }, { eexpr = TLocal v2 } -> compare v1.v_name v2.v_name - | _ -> assert false) captured + | _ -> die "" __LOC__) captured in (*let cltypes = List.map (fun cl -> (snd cl.cl_path, TInst(map_param cl, []) )) tparams in*) @@ -448,7 +448,7 @@ let configure gen ft = let ctor_v = alloc_var v.v_name v.v_type in ((ctor_v, None) :: ctor_args, (v.v_name, false, v.v_type) :: ctor_sig, (mk_this_assign v cls.cl_pos) :: ctor_exprs) - | _ -> assert false + | _ -> die "" __LOC__ ) ([],[],[]) captured in (* change all captured variables to this.capturedVariable *) @@ -593,11 +593,11 @@ let configure gen ft = let captured = List.sort (fun e1 e2 -> match e1, e2 with | { eexpr = TLocal v1 }, { eexpr = TLocal v2 } -> compare v1.v_name v2.v_name - | _ -> assert false) captured + | _ -> die "" __LOC__) captured in let types = match v.v_extra with | Some(t,_) -> t - | _ -> assert false + | _ -> die "" __LOC__ in let monos = List.map (fun _ -> mk_mono()) types in let vt = match follow v.v_type with @@ -741,7 +741,7 @@ struct in if arity >= max_arity then begin - let varray = match changed_args with | [v,_] -> v | _ -> assert false in + let varray = match changed_args with | [v,_] -> v | _ -> die "" __LOC__ in let varray_local = mk_local varray pos in let mk_varray i = { eexpr = TArray(varray_local, make_int gen.gcon.basic i pos); etype = t_dynamic; epos = pos } in let el = @@ -773,7 +773,7 @@ struct epos = pos } )); etype = basic.tvoid; epos = pos } :: acc in loop acc args fargs dargs - | _ -> assert false + | _ -> die "" __LOC__ in loop [] args float_args dyn_args @@ -797,7 +797,7 @@ struct let ret_t = if is_dynamic_func then t_dynamic else ret_t in (TFun(args_real_to_func_sig _sig, ret_t), arity, type_n, ret_t, ExtType.is_void ret, is_dynamic_func) - | _ -> (print_endline (s_type (print_context()) (follow old_sig) )); assert false + | _ -> (print_endline (s_type (print_context()) (follow old_sig) )); die "" __LOC__ in let tf_expr = if is_void then begin @@ -810,7 +810,7 @@ struct let e = mk_block (map tfunc.tf_expr) in match e.eexpr with | TBlock bl -> { e with eexpr = TBlock (bl @ [mk_return (null t_dynamic e.epos)]) } - | _ -> assert false + | _ -> die "" __LOC__ end else tfunc.tf_expr in let changed_sig_ret = if is_dynamic_func then t_dynamic else changed_sig_ret in @@ -854,7 +854,7 @@ struct let dynamic_fun_call call_expr = let tc, params = match call_expr.eexpr with | TCall(tc, params) -> tc, params - | _ -> assert false + | _ -> die "" __LOC__ in let ct = gen.greal_type call_expr.etype in let postfix, ret_t = diff --git a/src/codegen/gencommon/dynamicFieldAccess.ml b/src/codegen/gencommon/dynamicFieldAccess.ml index 2ecbc07260d30aeffc9496dcd36ded49975286bd..d79efaa2f5325fd0961ab550bf58cafdd581c168 100644 --- a/src/codegen/gencommon/dynamicFieldAccess.ml +++ b/src/codegen/gencommon/dynamicFieldAccess.ml @@ -71,7 +71,7 @@ let configure gen (is_dynamic:texpr->Type.tfield_access->bool) (change_expr:texp | TInst( ({ cl_kind = KTypeParameter(tl) } as tp_cl), tp_tl) -> let t = apply_params tp_cl.cl_params tp_tl (List.find (fun t -> not (is_dynamic { fexpr with etype = t } f)) tl) in { e with eexpr = TField(mk_cast t (run fexpr), f) } - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | TField(fexpr, f) when is_some (anon_class fexpr.etype) -> let decl = get (anon_class fexpr.etype) in @@ -86,7 +86,7 @@ let configure gen (is_dynamic:texpr->Type.tfield_access->bool) (change_expr:texp { e with eexpr = TField ({ fexpr with eexpr = TTypeExpr decl }, FEnum (en, ef)) } | TAbstractDecl _ (* abstracts don't have TFields *) | TTypeDecl _ -> (* anon_class doesn't return TTypeDecl *) - assert false + Globals.die "" __LOC__ with Not_found -> match f with | FStatic (cl, cf) when has_class_field_flag cf CfExtern -> @@ -118,10 +118,10 @@ let configure gen (is_dynamic:texpr->Type.tfield_access->bool) (change_expr:texp Type.map_expr run e) | TBinop (OpAssignOp _, { eexpr = TField (fexpr, f) }, _) when is_dynamic fexpr f -> - assert false (* this case shouldn't happen *) + Globals.die "" __LOC__ (* this case shouldn't happen *) | TUnop (Increment, _, { eexpr = TField (({ eexpr = TLocal _ } as fexpr), f)}) | TUnop (Decrement, _, { eexpr = TField (({ eexpr = TLocal _ } as fexpr), f)}) when is_dynamic fexpr f -> - assert false (* this case shouldn't happen *) + Globals.die "" __LOC__ (* this case shouldn't happen *) | TCall ({ eexpr = TField (fexpr, f) }, params) when is_dynamic fexpr f && (not (is_nondynamic_tparam fexpr f)) -> call_expr e (run fexpr) (field_name f) (List.map run params) diff --git a/src/codegen/gencommon/dynamicOperators.ml b/src/codegen/gencommon/dynamicOperators.ml index 538a9a06818d913b58392e4fc49652145896e163..e114db1e4bfe3d0b12401276131eed981f7e8fe4 100644 --- a/src/codegen/gencommon/dynamicOperators.ml +++ b/src/codegen/gencommon/dynamicOperators.ml @@ -89,11 +89,11 @@ let init com handle_strings (should_change:texpr->bool) (equals_handler:texpr->t (mk (TVar (v, Some (run e1a))) com.basic.tvoid e1.epos); (mk (TVar (v2, Some (run e2a))) com.basic.tvoid e1.epos) ] - | _ -> assert false + | _ -> Globals.die "" __LOC__ in { e with eexpr = TBlock (rest @ [{ e with eexpr = TBinop (OpAssign, eleft, run { e with eexpr = TBinop (op, eleft, e2) }) }]) } | _ -> - assert false) + Globals.die "" __LOC__) | TBinop (OpAssign, e1, e2) | TBinop (OpInterval, e1, e2) -> @@ -120,7 +120,7 @@ let init com handle_strings (should_change:texpr->bool) (equals_handler:texpr->t | OpAnd | OpOr | OpXor | OpShl | OpShr | OpUShr -> { e with eexpr = TBinop (op, mk_cast com.basic.tint (run e1), mk_cast com.basic.tint (run e2)) } | OpAssign | OpAssignOp _ | OpInterval | OpArrow | OpIn -> - assert false) + Globals.die "" __LOC__) | TUnop (Increment as op, flag, e1) | TUnop (Decrement as op, flag, e1) when should_change e -> @@ -137,7 +137,7 @@ let init com handle_strings (should_change:texpr->bool) (equals_handler:texpr->t *) let one = get_etype_one e in let etype = one.etype in - let op = (match op with Increment -> OpAdd | Decrement -> OpSub | _ -> assert false) in + let op = (match op with Increment -> OpAdd | Decrement -> OpSub | _ -> Globals.die "" __LOC__) in let block = let vars, getvar = diff --git a/src/codegen/gencommon/enumToClass.ml b/src/codegen/gencommon/enumToClass.ml index b4331cd6de7271a10713a26095b0f9671551a9e4..17c0eb51ce7a6958df6eb575f1209540610764a2 100644 --- a/src/codegen/gencommon/enumToClass.ml +++ b/src/codegen/gencommon/enumToClass.ml @@ -154,7 +154,7 @@ struct | _ -> let actual_t = match follow ef.ef_type with | TEnum(e, p) -> TEnum(e, List.map (fun _ -> t_dynamic) p) - | _ -> assert false + | _ -> die "" __LOC__ in let cf = mk_class_field name actual_t true pos (Var { v_read = AccNormal; v_write = AccNever }) [] in let args = if has_params then diff --git a/src/codegen/gencommon/enumToClass2.ml b/src/codegen/gencommon/enumToClass2.ml index 1c4ebef2a43bc67f58aa7cd43c6a709d7ce2525b..5fcf2fce440f201e082b8c8e37b34f2da591e360 100644 --- a/src/codegen/gencommon/enumToClass2.ml +++ b/src/codegen/gencommon/enumToClass2.ml @@ -85,7 +85,7 @@ module EnumToClass2Modf = struct let e_pack, e_name = en.e_path in let cl_enum_t = TInst (cl_enum, []) in let cf_getTag_t = tfun [] basic.tstring in - let cf_getParams_ret = basic.tarray (mk_anon PMap.empty) in + let cf_getParams_ret = basic.tarray (mk_anon (ref Closed)) in let cf_getParams_t = tfun [] cf_getParams_ret in let static_ctors = ref [] in let ctors_map = ref PMap.empty in @@ -379,7 +379,7 @@ module EnumToClass2Exprf = struct | TFun (params, _) -> let fname, _, _ = List.nth params i in field ecast fname e.etype e.epos - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | _ -> Type.map_expr run e in diff --git a/src/codegen/gencommon/expressionUnwrap.ml b/src/codegen/gencommon/expressionUnwrap.ml index 1a4d2be9f26beda4390b68702454b9d3672f067b..333bbf66b2c0a58f67de339a1d16136ad4e1e767 100644 --- a/src/codegen/gencommon/expressionUnwrap.ml +++ b/src/codegen/gencommon/expressionUnwrap.ml @@ -157,7 +157,7 @@ let rec expr_stat_map fn (expr:texpr) = | TBinop ( (OpAssign as op), left_e, right_e ) | TBinop ( (OpAssignOp _ as op), left_e, right_e ) -> { expr with eexpr = TBinop(op, fn left_e, fn right_e) } - | TParenthesis _ -> assert false + | TParenthesis _ -> Globals.die "" __LOC__ | TCall(left_e, params) -> { expr with eexpr = TCall(fn left_e, List.map fn params) } | TNew(cl, tparams, params) -> @@ -184,7 +184,7 @@ let rec expr_stat_map fn (expr:texpr) = | TBlock _ -> expr (* there is no expected expression here. Only statements *) | TMeta(m,e) -> { expr with eexpr = TMeta(m,expr_stat_map fn e) } - | _ -> assert false (* we only expect valid statements here. other expressions aren't valid statements *) + | _ -> Globals.die "" __LOC__ (* we only expect valid statements here. other expressions aren't valid statements *) let is_expr = function | Expression _ -> true | _ -> false @@ -293,7 +293,7 @@ and expr_kind expr = aggregate true (List.map snd sel) | TCast (e,_) -> aggregate false [e] - | _ -> trace (debug_expr expr); assert false (* should have been read as Statement by shallow_expr_type *) + | _ -> trace (debug_expr expr); Globals.die "" __LOC__ (* should have been read as Statement by shallow_expr_type *) let get_kinds (statement:texpr) = let kinds = ref [] in @@ -381,7 +381,7 @@ let rec apply_assign assign_fun right = match follow right.etype with | TAbstract ({ a_path = ([], "Void") },[]) -> right - | _ -> trace (debug_expr right); assert false (* a statement is required *) + | _ -> trace (debug_expr right); Globals.die "" __LOC__ (* a statement is required *) let short_circuit_op_unwrap com add_statement expr :texpr = let do_not expr = @@ -413,7 +413,7 @@ let short_circuit_op_unwrap com add_statement expr :texpr = add_statement tvars; ({ expr with eexpr = TBinop(op, left, local) }, [ do_not left, { right with eexpr = TBinop(OpAssign, local, right) } ]) - | _ when acc = [] -> assert false + | _ when acc = [] -> Globals.die "" __LOC__ | _ -> let var = mk_temp "boolv" expr.etype in let tvars = { expr with eexpr = TVar(var, Some( { expr with etype = com.basic.tbool } )); etype = com.basic.tvoid } in @@ -444,7 +444,7 @@ let short_circuit_op_unwrap com add_statement expr :texpr = epos = assign.epos; }, None); etype = com.basic.tvoid; epos = assign.epos } - | [] -> assert false + | [] -> Globals.die "" __LOC__ in add_statement (loop local_assign_list); @@ -478,7 +478,7 @@ let try_call_unwrap_statement com handle_cast problematic_expression_unwrap (add match expr_kind left with | KExprWithStatement -> problematic_expression_unwrap add_statement left KExprWithStatement - | KStatement -> assert false (* doesn't make sense a KStatement as a left side expression *) + | KStatement -> Globals.die "" __LOC__ (* doesn't make sense a KStatement as a left side expression *) | _ -> left in @@ -606,7 +606,7 @@ let configure gen = problematic_expression_unwrap process_statement e hd end else e - | [] -> assert false + | [] -> Globals.die "" __LOC__ ) e in new_block := (traverse new_e) :: !new_block diff --git a/src/codegen/gencommon/fixOverrides.ml b/src/codegen/gencommon/fixOverrides.ml index 002702543b685ce47ea8cdbd3500eb97ec2413c2..18734d31c0c22aa92a4f0c34855c0b32c176b5ab 100644 --- a/src/codegen/gencommon/fixOverrides.ml +++ b/src/codegen/gencommon/fixOverrides.ml @@ -109,7 +109,7 @@ let run ~explicit_fn_name ~get_vmtype gen = (* override return type and cast implemented function *) let args, newr = match follow t2, follow (apply_params f.cf_params (List.map snd f2.cf_params) real_ftype) with | TFun(a,_), TFun(_,r) -> a,r - | _ -> assert false + | _ -> Globals.die "" __LOC__ in f2.cf_type <- TFun(args,newr); (match f2.cf_expr with @@ -153,7 +153,7 @@ let run ~explicit_fn_name ~get_vmtype gen = with | Not_found -> c.cl_fields <- PMap.add name newf c.cl_fields; c.cl_ordered_fields <- newf :: c.cl_ordered_fields) - | _ -> assert false + | _ -> Globals.die "" __LOC__ end with | Not_found -> () in @@ -201,7 +201,7 @@ let run ~explicit_fn_name ~get_vmtype gen = with Unify_error _ -> true with Unify_error _ -> false) current_args original_args - | _ -> assert false + | _ -> Globals.die "" __LOC__ in if (not (Meta.has Meta.Overload f.cf_meta) && has_contravariant_args) then f.cf_meta <- (Meta.Overload, [], f.cf_pos) :: f.cf_meta; diff --git a/src/codegen/gencommon/gencommon.ml b/src/codegen/gencommon/gencommon.ml index c05245c37209f7e277d8c6a1eb5c5ba82e61b38b..e7fc3ac19b5d8e999f1f3dc4ba06cdd921f5d5b4 100644 --- a/src/codegen/gencommon/gencommon.ml +++ b/src/codegen/gencommon/gencommon.ml @@ -104,7 +104,7 @@ let rec like_i64 t = let follow_once t = match t with | TMono r -> - (match !r with + (match r.tm_type with | Some t -> t | _ -> t_dynamic) (* avoid infinite loop / should be the same in this context *) | TLazy f -> @@ -116,7 +116,7 @@ let follow_once t = | _ -> t -let t_empty = TAnon({ a_fields = PMap.empty; a_status = ref Closed }) +let t_empty = mk_anon (ref Closed) let alloc_var n t = Type.alloc_var VGenerated n t null_pos @@ -163,10 +163,10 @@ let anon_class t = | EnumStatics e -> TEnumDecl e | Statics cl -> TClassDecl cl | AbstractStatics a -> TAbstractDecl a - | _ -> assert false) + | _ -> die "" __LOC__) | TLazy f -> t_to_md (lazy_type f) - | TMono r -> (match !r with | Some t -> t_to_md t | None -> assert false) - | _ -> assert false + | TMono r -> (match r.tm_type with | Some t -> t_to_md t | None -> die "" __LOC__) + | _ -> die "" __LOC__ let get_cl mt = match mt with TClassDecl cl -> cl | _ -> failwith (Printf.sprintf "Unexpected module type (class expected) for %s: %s" (s_type_path (t_path mt)) (s_module_type_kind mt)) @@ -175,7 +175,7 @@ let get_abstract mt = match mt with TAbstractDecl a -> a | _ -> failwith (Printf let get_fun t = match follow t with | TFun (args, ret) -> args, ret - | t -> (trace (debug_type t)); assert false + | t -> (trace (debug_type t)); die "" __LOC__ let mk_cast t e = Type.mk_cast e t e.epos @@ -378,6 +378,8 @@ type generator_ctx = (* this is all you need to care about *) gcon : Common.context; + gentry_point : (string * tclass * texpr) option; + gclasses : gen_classes; gtools : gen_tools; @@ -566,19 +568,20 @@ let new_ctx con = | TClassDecl c -> c | TAbstractDecl a -> mk_class a.a_module ([], "Dynamic") a.a_pos null_pos - | _ -> assert false + | _ -> die "" __LOC__ in let rec gen = { gcon = con; + gentry_point = get_entry_point con; gclasses = { cl_reflect = get_cl (get_type ([], "Reflect")); cl_type = get_cl (get_type ([], "Type")); cl_dyn = cl_dyn; - nativearray = (fun _ -> assert false); - nativearray_type = (fun _ -> assert false); - nativearray_len = (fun _ -> assert false); + nativearray = (fun _ -> die "" __LOC__); + nativearray_type = (fun _ -> die "" __LOC__); + nativearray_len = (fun _ -> die "" __LOC__); }; gtools = { r_fields = (fun is_used_only_by_iteration expr -> @@ -597,7 +600,7 @@ let new_ctx con = mk_cast t { eexpr = TCall(fieldcall, [obj; field]); etype = t_dynamic; epos = obj.epos } ); - r_create_empty = (fun _ _ pos -> gen.gcon.error "r_create_empty implementation is not provided" pos; assert false); + r_create_empty = (fun _ _ pos -> gen.gcon.error "r_create_empty implementation is not provided" pos; die "" __LOC__); }; gexpr_filters = new rule_map_dispatcher "gexpr_filters"; gmodule_filters = new rule_map_dispatcher "gmodule_filters"; @@ -656,7 +659,7 @@ let init_ctx gen = let follow t = match t with | TMono r -> - (match !r with + (match r.tm_type with | Some t -> follow_f t | _ -> Some t) | TLazy f -> @@ -836,7 +839,7 @@ let write_file gen w source_dir path extension out_files = close_out f end; - out_files := (Path.unique_full_path s_path) :: !out_files; + out_files := (Path.UniqueKey.create s_path) :: !out_files; t() @@ -851,7 +854,7 @@ let clean_files path excludes verbose = let pack = pack @ [file] in iter_files (pack) (Unix.opendir filepath) filepath; try Unix.rmdir filepath with Unix.Unix_error (ENOTEMPTY,_,_) -> (); - else if not (String.ends_with filepath ".meta") && not (List.mem (Path.unique_full_path filepath) excludes) then begin + else if not (String.ends_with filepath ".meta") && not (List.mem (Path.UniqueKey.create filepath) excludes) then begin if verbose then print_endline ("Removing " ^ filepath); Sys.remove filepath end @@ -915,19 +918,19 @@ let dump_descriptor gen name path_s module_s = SourceWriter.write w "end modules"; SourceWriter.newline w; (* dump all resources *) - (match gen.gcon.main_class with - | Some path -> - SourceWriter.write w "begin main"; - SourceWriter.newline w; - (try - SourceWriter.write w (Hashtbl.find main_paths path) - with - | Not_found -> SourceWriter.write w (path_s path)); - SourceWriter.newline w; - SourceWriter.write w "end main"; - SourceWriter.newline w - | _ -> () - ); + (match gen.gentry_point with + | Some (_,cl,_) -> + SourceWriter.write w "begin main"; + SourceWriter.newline w; + let path = cl.cl_path in + (try + SourceWriter.write w (Hashtbl.find main_paths path) + with Not_found -> + SourceWriter.write w (path_s path)); + SourceWriter.newline w; + SourceWriter.write w "end main"; + SourceWriter.newline w + | _ -> ()); SourceWriter.write w "begin resources"; SourceWriter.newline w; Hashtbl.iter (fun name _ -> @@ -1010,7 +1013,7 @@ let follow_module follow_func md = match md with | TEnum(e,_) -> TEnumDecl e | TType(t,_) -> TTypeDecl t | TAbstract(a,_) -> TAbstractDecl a - | _ -> assert false + | _ -> die "" __LOC__ (* hxgen means if the type was generated by haxe. If a type was generated by haxe, it means @@ -1045,14 +1048,14 @@ let mt_to_t mt params = | TClassDecl (cl) -> TInst(cl, params) | TEnumDecl (e) -> TEnum(e, params) | TAbstractDecl a -> TAbstract(a, params) - | _ -> assert false + | _ -> die "" __LOC__ let t_to_mt t = match follow t with | TInst(cl, _) -> TClassDecl(cl) | TEnum(e, _) -> TEnumDecl(e) | TAbstract(a, _) -> TAbstractDecl a - | _ -> assert false + | _ -> die "" __LOC__ let rec get_last_ctor cl = Option.map_default (fun (super,_) -> if is_some super.cl_constructor then Some(get super.cl_constructor) else get_last_ctor super) None cl.cl_super @@ -1068,8 +1071,8 @@ let add_constructor cl cf = let rec replace_mono t = match t with | TMono t -> - (match !t with - | None -> t := Some t_dynamic + (match t.tm_type with + | None -> Monomorph.bind t t_dynamic | Some _ -> ()) | TEnum (_,p) | TInst (_,p) | TType (_,p) | TAbstract (_,p) -> List.iter replace_mono p @@ -1099,7 +1102,7 @@ let map_param cl = ret let get_cl_t t = - match follow t with | TInst (cl,_) -> cl | _ -> assert false + match follow t with | TInst (cl,_) -> cl | _ -> die "" __LOC__ let mk_class m path pos = let cl = Type.mk_class m path pos null_pos in @@ -1223,7 +1226,7 @@ let rec field_access gen (t:t) (field:string) : (tfield_access) = but for now, we're going to find the generated class and make a field access to it instead. *) (try let cl_enum = List.find (function TClassDecl cl when cl.cl_path = en.e_path && Meta.has Meta.Enum cl.cl_meta -> true | _ -> false) gen.gtypes_list in - let cl_enum = match cl_enum with TClassDecl cl -> TInst (cl,params) | _ -> assert false in + let cl_enum = match cl_enum with TClassDecl cl -> TInst (cl,params) | _ -> die "" __LOC__ in field_access gen cl_enum field with Not_found -> FNotFound) @@ -1274,7 +1277,7 @@ let mk_field_access gen expr field pos = { eexpr = TField(expr, FDynamic field); etype = t; epos = pos } | FNotFound -> { eexpr = TField(expr, FDynamic field); etype = t_dynamic; epos = pos } - | FEnumField _ -> assert false + | FEnumField _ -> die "" __LOC__ (* ******************************************* *) (* Module dependency resolution *) diff --git a/src/codegen/gencommon/hardNullableSynf.ml b/src/codegen/gencommon/hardNullableSynf.ml index d2f944a678174a1007cb16c91a20e08254469dac..be2467f7b3fe02b2c3412dfb6c549596b687676e 100644 --- a/src/codegen/gencommon/hardNullableSynf.ml +++ b/src/codegen/gencommon/hardNullableSynf.ml @@ -52,7 +52,7 @@ let rec is_null_t gen t = match gen.greal_type t with in Some (take_off_null of_t) - | TMono r -> (match !r with | Some t -> is_null_t gen t | None -> None) + | TMono r -> (match r.tm_type with | Some t -> is_null_t gen t | None -> None) | TLazy f -> is_null_t gen (lazy_type f) | TType (t, tl) -> is_null_t gen (apply_params t.t_params tl t.t_type) @@ -200,7 +200,7 @@ let configure gen unwrap_null wrap_val null_to_dynamic has_value opeq_handler = { e with eexpr = TBinop( Ast.OpAssign, e1, handle_wrap { e with eexpr = TBinop (op, handle_unwrap t1 e1, handle_unwrap t2 (run e2) ) } t1 ) } ]) } ) - | _ -> assert false + | _ -> Globals.die "" __LOC__ ) | _ -> diff --git a/src/codegen/gencommon/initFunction.ml b/src/codegen/gencommon/initFunction.ml index 4f10bd83711bdac39c8cae3e7bb1b2b00240b4cb..653404af5cdfe2d5ad08b19713fd14c4a94e06d1 100644 --- a/src/codegen/gencommon/initFunction.ml +++ b/src/codegen/gencommon/initFunction.ml @@ -57,11 +57,11 @@ let handle_override_dynfun acc e this field = match e.eexpr with | TField ({ eexpr = TConst TSuper }, f) -> let n = field_name f in - if n <> field then assert false; + if n <> field then Globals.die "" __LOC__; if Option.is_none !add_expr then add_expr := Some { e with eexpr = TVar(v, Some this) }; mk_local v e.epos - | TConst TSuper -> assert false + | TConst TSuper -> Globals.die "" __LOC__ | _ -> Type.map_expr loop e in let e = loop e in @@ -217,7 +217,7 @@ let handle_class com cl = let tf_expr = add_fn (mk_block tf.tf_expr) in { e with eexpr = TFunction { tf with tf_expr = tf_expr } } | _ -> - assert false + Globals.die "" __LOC__ in ctor.cf_expr <- Some func in diff --git a/src/codegen/gencommon/intDivisionSynf.ml b/src/codegen/gencommon/intDivisionSynf.ml index 71d51618976be21f7dca3a321e89298d42066e94..532740e8e969881c619edb5621ddbf6f7139ff10 100644 --- a/src/codegen/gencommon/intDivisionSynf.ml +++ b/src/codegen/gencommon/intDivisionSynf.ml @@ -56,18 +56,15 @@ let init com = match e.eexpr with | TBinop ((OpDiv as op), e1, e2) when is_int e1 && is_int e2 -> { e with eexpr = TBinop (op, mk_cast com.basic.tfloat (run e1), run e2) } - | TCall ( { eexpr = TField (_, FStatic ({ cl_path = ([], "Std") }, { cf_name = "int" })) }, [ { eexpr = TBinop ((OpDiv as op), e1, e2) } as ebinop ] ) when is_int e1 && is_int e2 -> - let e = { ebinop with eexpr = TBinop (op, run e1, run e2); etype = com.basic.tint } in if not (is_exactly_int e1 && is_exactly_int e2) then mk_cast com.basic.tint e else - Type.map_expr run e - + e | TCast ({ eexpr = TBinop((OpDiv as op), e1, e2) } as ebinop, _ ) | TCast ({ eexpr = TBinop(((OpAssignOp OpDiv) as op), e1, e2) } as ebinop, _ ) when is_int e1 && is_int e2 && is_int e -> let ret = { ebinop with eexpr = TBinop (op, run e1, run e2); etype = e.etype } in diff --git a/src/codegen/gencommon/normalize.ml b/src/codegen/gencommon/normalize.ml index 2b687bf8ff61f869ef346fd645cf2dfd2f98c57c..9616d966ebe339255affd3751ec9d938e362b105 100644 --- a/src/codegen/gencommon/normalize.ml +++ b/src/codegen/gencommon/normalize.ml @@ -34,7 +34,7 @@ let rec filter_param (stack:t list) t = | TInst({ cl_kind = KTypeParameter _ } as c,_) when Meta.has Meta.EnumConstructorParam c.cl_meta -> t_dynamic | TMono r -> - (match !r with + (match r.tm_type with | None -> t_dynamic | Some t -> filter_param stack t) | TInst(_,[]) | TEnum(_,[]) | TAbstract(_,[]) -> @@ -54,10 +54,8 @@ let rec filter_param (stack:t list) t = | TAbstract(a,tl) -> TAbstract(a, List.map (filter_param stack) tl) | TAnon a -> - TAnon { - a_fields = PMap.map (fun f -> { f with cf_type = filter_param stack f.cf_type }) a.a_fields; - a_status = a.a_status - } + let fields = PMap.map (fun f -> { f with cf_type = filter_param stack f.cf_type }) a.a_fields in + mk_anon ~fields a.a_status | TFun(args,ret) -> TFun(List.map (fun (n,o,t) -> (n,o,filter_param stack t)) args, filter_param stack ret) | TDynamic _ -> diff --git a/src/codegen/gencommon/objectDeclMap.ml b/src/codegen/gencommon/objectDeclMap.ml index 7d657ac83d5c6f2fb78d8bf4dc826ffe8c60ede2..fbdfc967806120704400a4b9d0a429ef0ea6a67d 100644 --- a/src/codegen/gencommon/objectDeclMap.ml +++ b/src/codegen/gencommon/objectDeclMap.ml @@ -30,7 +30,7 @@ let configure gen map_fn = match e.eexpr with | TObjectDecl odecl -> let e = Type.map_expr run e in - (match e.eexpr with TObjectDecl odecl -> map_fn e odecl | _ -> assert false) + (match e.eexpr with TObjectDecl odecl -> map_fn e odecl | _ -> Globals.die "" __LOC__) | _ -> Type.map_expr run e in diff --git a/src/codegen/gencommon/overloadingConstructor.ml b/src/codegen/gencommon/overloadingConstructor.ml index f1f2b9f3a70d209b01ebfd23e4b6a53898bebf25..3d1dfae0b1fbd37f94ae72a6031024f8b8dbb228 100644 --- a/src/codegen/gencommon/overloadingConstructor.ml +++ b/src/codegen/gencommon/overloadingConstructor.ml @@ -132,7 +132,7 @@ let create_static_ctor com ~empty_ctor_expr cl ctor follow_type = let fn_type = TFun((me.v_name,false, me.v_type) :: List.map (fun (n,o,t) -> (n,o,apply_params cl.cl_params ctor_params t)) fn_args, com.basic.tvoid) in let cur_tf_args = match ctor.cf_expr with | Some { eexpr = TFunction(tf) } -> tf.tf_args - | _ -> assert false + | _ -> Globals.die "" __LOC__ in let changed_tf_args = List.map (fun (v,_) -> (v,None)) cur_tf_args in @@ -185,7 +185,7 @@ let create_static_ctor com ~empty_ctor_expr cl ctor follow_type = let expr = match expr.eexpr with | TFunction(tf) -> { expr with etype = fn_type; eexpr = TFunction({ tf with tf_args = static_tf_args }) } - | _ -> assert false in + | _ -> Globals.die "" __LOC__ in static_ctor.cf_expr <- Some expr; (* add to the statics *) (try @@ -217,7 +217,7 @@ let create_static_ctor com ~empty_ctor_expr cl ctor follow_type = epos = p }] in ctor.cf_expr <- Some { e with eexpr = TFunction({ tf with tf_expr = { tf.tf_expr with eexpr = TBlock block_contents }; tf_args = changed_tf_args }) } - | _ -> assert false + | _ -> Globals.die "" __LOC__ (* makes constructors that only call super() for the 'ctor' argument *) let clone_ctors com ctor sup stl cl = @@ -257,7 +257,7 @@ let clone_ctors com ctor sup stl cl = match clones with | [] -> (* raise Not_found *) - assert false (* should never happen *) + Globals.die "" __LOC__ (* should never happen *) | cf :: [] -> cf | cf :: overl -> cf.cf_meta <- (Meta.Overload,[],cf.cf_pos) :: cf.cf_meta; diff --git a/src/codegen/gencommon/realTypeParams.ml b/src/codegen/gencommon/realTypeParams.ml index 4d8b3b0e3e60b0db1632580ababd2e14675e88f7..cdb21f22d1d099dc13fd3370e958f80f901d7902 100644 --- a/src/codegen/gencommon/realTypeParams.ml +++ b/src/codegen/gencommon/realTypeParams.ml @@ -279,7 +279,7 @@ let rec set_hxgeneric gen mds isfirst md = Some true end end - | _ -> assert false + | _ -> Globals.die "" __LOC__ end let path_s = function @@ -294,7 +294,7 @@ let set_hxgeneric gen md = let md = match t with | TInst(cl,_) -> TClassDecl cl | TEnum(e,_) -> TEnumDecl e - | _ -> assert false + | _ -> Globals.die "" __LOC__ in let ret = set_hxgeneric gen [] true md in if ret = None then get (set_hxgeneric gen [] false md) else get ret) @@ -341,7 +341,7 @@ let set_hxgeneric gen md = "because it explicitly has the metadata @:nativeGeneric set" in gen.gcon.error (reason) pos; - assert false + Globals.die "" __LOC__ let params_has_tparams params = List.fold_left (fun acc t -> acc || has_type_params t) false params @@ -506,7 +506,7 @@ struct | TEnum (e,_) -> e.e_path | TAbstract (a,_) -> a.a_path | TMono _ | TDynamic _ -> ([], "Dynamic") - | _ -> assert false + | _ -> Globals.die "" __LOC__ in List.map (fun (cf, t_cl, t_cf) -> let t_cf = follow (gen.greal_type t_cf) in @@ -518,7 +518,7 @@ struct (try (Hashtbl.find gen.gtparam_cast (get_path t_cf)) this_field t_cf with Not_found -> (* if not found tparam cast, it shouldn't be a valid hxgeneric *) print_endline ("Could not find a gtparam_cast for " ^ (String.concat "." (fst (get_path t_cf)) ^ "." ^ (snd (get_path t_cf)))); - assert false) + Globals.die "" __LOC__) t_cf pos in @@ -543,8 +543,8 @@ struct | (TInst(cl1,[]) as v), (TInst(cl2,[]) as v2) -> mk_typehandle_cond (v :: hd) (v2 :: hd2) | _ -> - assert false) - | _ -> assert false + Globals.die "" __LOC__) + | _ -> Globals.die "" __LOC__ in let fn = { tf_args = []; @@ -712,7 +712,7 @@ struct let cf_type = if is_override && not (Meta.has Meta.Overload cf.cf_meta) then match find_first_declared_field gen cl cf.cf_name with | Some(_,_,declared_t,_,_,_,_) -> declared_t - | _ -> assert false + | _ -> Globals.die "" __LOC__ else cf.cf_type in diff --git a/src/codegen/gencommon/reflectionCFs.ml b/src/codegen/gencommon/reflectionCFs.ml index 1c73437ae3ed473a70e6cf4373ef16d015188d29..f855b57319a3ac3e59e1d50147d8c93fe3737d74 100644 --- a/src/codegen/gencommon/reflectionCFs.ml +++ b/src/codegen/gencommon/reflectionCFs.ml @@ -536,7 +536,7 @@ let get_delete_field ctx cl is_dynamic = ] in if ctx.rcf_optimize then - let v_name = match tf_args with (v,_) :: _ -> v | _ -> assert false in + let v_name = match tf_args with (v,_) :: _ -> v | _ -> Globals.die "" __LOC__ in let local_name = mk_local v_name pos in let conflict_ctx = Option.get ctx.rcf_hash_conflict_ctx in let ehead = mk_this (mk_internal_name "hx" "conflicts") conflict_ctx.t in @@ -647,7 +647,7 @@ let implement_dynamic_object_ctor ctx cl = match e1.eexpr, e2.eexpr with | TConst(TInt i1), TConst(TInt i2) -> compare i1 i2 | TConst(TString s1), TConst(TString s2) -> compare s1 s2 - | _ -> assert false + | _ -> Globals.die "" __LOC__ in let odecl, odecl_f = List.sort sort_fn odecl, List.sort sort_fn odecl_f in @@ -999,7 +999,7 @@ let implement_get_set ctx cl = in (if fields <> [] then has_fields := true); let cases = List.map (fun (names, cf) -> - (if names = [] then assert false); + (if names = [] then Globals.die "" __LOC__); (List.map (switch_case ctx pos) names, do_field cf cf.cf_type) ) fields in let default = Some(do_default()) in diff --git a/src/codegen/gencommon/renameTypeParameters.ml b/src/codegen/gencommon/renameTypeParameters.ml index 716aae029e40d898f54b32d0ae3a0c59c93855d5..2383da1d491385dbdc7e4bf5bea91fcfe5bac8a7 100644 --- a/src/codegen/gencommon/renameTypeParameters.ml +++ b/src/codegen/gencommon/renameTypeParameters.ml @@ -44,7 +44,7 @@ let run types = let get_cls t = match follow t with | TInst(cl,_) -> cl - | _ -> assert false + | _ -> Globals.die "" __LOC__ in let iter_types (nt,t) = diff --git a/src/codegen/gencommon/switchToIf.ml b/src/codegen/gencommon/switchToIf.ml index 01803c44e0054ff994d52bc59dfe691fff9ea0a1..5aae6427576a11e0420b1574f57012d2f6d66f53 100644 --- a/src/codegen/gencommon/switchToIf.ml +++ b/src/codegen/gencommon/switchToIf.ml @@ -81,7 +81,7 @@ let configure gen (should_convert:texpr->bool) = | cond :: tl -> mk (TBinop (Ast.OpBoolOr, mk_eq (run cond), mk_many_cond tl)) basic.tbool cond.epos | [] -> - assert false + Globals.die "" __LOC__ in let mk_many_cond conds = diff --git a/src/codegen/genxml.ml b/src/codegen/genxml.ml index 0fa5854421f40056b75e932ae7ffd5101990e884..839977eed64f7b21d2b6664405fe157a3a256c56 100644 --- a/src/codegen/genxml.ml +++ b/src/codegen/genxml.ml @@ -52,7 +52,7 @@ let gen_doc s = let gen_doc_opt d = match d with | None -> [] - | Some s -> [gen_doc s] + | Some d -> [gen_doc (Ast.gen_doc_text d)] let gen_arg_name (name,opt,_) = (if opt then "?" else "") ^ name @@ -72,7 +72,7 @@ let tpath t = let rec follow_param t = match t with | TMono r -> - (match !r with + (match r.tm_type with | Some t -> follow_param t | _ -> t) | TAbstract ({ a_path = [],"Null" },[t]) -> @@ -92,7 +92,7 @@ let gen_meta meta = let rec gen_type ?(values=None) t = match t with - | TMono m -> (match !m with None -> tag "unknown" | Some t -> gen_type t) + | TMono m -> (match m.tm_type with None -> tag "unknown" | Some t -> gen_type t) | TEnum (e,params) -> gen_type_decl "e" (TEnumDecl e) params | TInst (c,params) -> gen_type_decl "c" (TClassDecl c) params | TAbstract (a,params) -> gen_type_decl "x" (TAbstractDecl a) params @@ -236,7 +236,8 @@ let rec gen_type_decl com pos t = let meta = gen_meta c.cl_meta in let ext = (if c.cl_extern then [("extern","1")] else []) in let interf = (if c.cl_interface then [("interface","1")] else []) in - node "class" (gen_type_params pos c.cl_private (tpath t) c.cl_params c.cl_pos m @ ext @ interf) (tree @ stats @ fields @ constr @ doc @ meta) + let final = (if c.cl_final then [("final","1")] else []) in + node "class" (gen_type_params pos c.cl_private (tpath t) c.cl_params c.cl_pos m @ ext @ interf @ final) (tree @ stats @ fields @ constr @ doc @ meta) | TEnumDecl e -> let doc = gen_doc_opt e.e_doc in let meta = gen_meta e.e_meta in diff --git a/src/codegen/java.ml b/src/codegen/java.ml index 77deced1e6078b2e08986f8e2b7858f5added78c..dd700bfd0d5bd8eb8db0d5e0a9c3f5d5e8612e70 100644 --- a/src/codegen/java.ml +++ b/src/codegen/java.ml @@ -152,9 +152,9 @@ and convert_signature ctx p jsig = | TObjectInner (pack, (name, params) :: inners) -> let actual_param = match List.rev inners with | (_, p) :: _ -> p - | _ -> assert false in + | _ -> die "" __LOC__ in mk_type_path ctx (pack, name ^ "$" ^ String.concat "$" (List.map fst inners)) (List.map (fun param -> convert_arg ctx p param) actual_param) - | TObjectInner (pack, inners) -> assert false + | TObjectInner (pack, inners) -> die "" __LOC__ | TArray (jsig, _) -> mk_type_path ctx (["java"], "NativeArray") [ TPType (convert_signature ctx p jsig,null_pos) ] | TMethod _ -> JReader.error "TMethod cannot be converted directly into Complex Type" | TTypeParameter s -> (match ctx.jtparams with @@ -205,7 +205,7 @@ let convert_param ctx p parent param = tp_meta = []; } -let get_type_path ctx ct = match ct with | CTPath p -> p | _ -> assert false +let get_type_path ctx ct = match ct with | CTPath p -> p | _ -> die "" __LOC__ let is_override field = List.exists (function | AttrVisibleAnnotations [{ ann_type = TObject( (["java";"lang"], "Override"), _ ) }] -> true | _ -> false) field.jf_attributes @@ -472,7 +472,7 @@ let convert_java_enum ctx p pe = | CTPath path -> let pos = { p with pfile = p.pfile ^ " (" ^ f.jf_name ^" @:throws)" } in EImport( List.map (fun s -> s,pos) (path.tpackage @ [path.tname]), INormal ) - | _ -> assert false + | _ -> die "" __LOC__ ) f.jf_throws ) jc.cmethods) in @@ -638,7 +638,7 @@ let compare_type com s1 s2 = p1, p2 | TObjectInner(_, npl1), TObjectInner(_, npl2) -> snd (List.hd (List.rev npl1)), snd (List.hd (List.rev npl2)) - | _ -> assert false (* not tobject *) + | _ -> die "" __LOC__ (* not tobject *) in let p1, p2 = simplify_args p1, simplify_args p2 in let lp1 = List.length p1 in @@ -697,7 +697,7 @@ let select_best com flist = if com.verbose then print_endline (f.jf_name ^ ": The types " ^ (s_sig r) ^ " and " ^ (s_sig r2) ^ " are incompatible"); (* bet that the current best has "beaten" other types *) loop cur_best flist - | _ -> assert false + | _ -> die "" __LOC__ with | Exit -> (* incompatible type parameters *) (* error mode *) if com.verbose then print_endline (f.jf_name ^ ": Incompatible argument return signatures: " ^ (s_sig r) ^ " and " ^ (s_sig r2)); @@ -994,7 +994,7 @@ class virtual java_library com name file_path = object(self) match ncls with | EClass c :: imports -> (EClass { c with d_name = (fst c.d_name ^ "_Statics"),snd c.d_name }, pos) :: inner @ List.map (fun i -> i,pos) imports - | _ -> assert false + | _ -> die "" __LOC__ with | Not_found -> inner in diff --git a/src/codegen/overloads.ml b/src/codegen/overloads.ml index afe5abce524a5ad7020757d335d521a0c9794436..c7f48e60af79a78888ec92df25ace1d84f453e30 100644 --- a/src/codegen/overloads.ml +++ b/src/codegen/overloads.ml @@ -26,7 +26,7 @@ let compare_overload_args ?(get_vmtype) ?(ctx) t1 t2 f1 f2 = | Some ctx -> not (distinguishes_funs_as_params ctx) in let rec follow_skip_null t = match t with | TMono r -> - (match !r with + (match r.tm_type with | Some t -> follow_skip_null t | _ -> t) | TLazy f -> @@ -66,7 +66,7 @@ let compare_overload_args ?(get_vmtype) ?(ctx) t1 t2 f1 f2 = | result -> result in loop a1 a2 - | _ -> assert false + | _ -> die "" __LOC__ let same_overload_args ?(get_vmtype) t1 t2 f1 f2 = compare_overload_args ?get_vmtype t1 t2 f1 f2 <> Different @@ -112,7 +112,7 @@ struct | TAbstract(a,tl) -> simplify_t (Abstract.get_underlying_type a tl) | TType(t, tl) -> simplify_t (apply_params t.t_params tl t.t_type) - | TMono r -> (match !r with + | TMono r -> (match r.tm_type with | Some t -> simplify_t t | None -> t_dynamic) | TAnon _ -> t_dynamic @@ -263,7 +263,7 @@ struct mk_rate ((max_int - 1, 0) :: acc) elist args | _ -> mk_rate (rate_conv 0 t e.etype :: acc) elist args) - | _ -> assert false + | _ -> die "" __LOC__ in let rated = ref [] in @@ -271,7 +271,7 @@ struct | (elist,TFun(args,ret),d) -> (try rated := ( (elist,TFun(args,ret),d), mk_rate [] elist args ) :: !rated with | Not_found -> ()) - | _ -> assert false + | _ -> die "" __LOC__ ) compatible; let rec loop best rem = match best, rem with diff --git a/src/codegen/swfLoader.ml b/src/codegen/swfLoader.ml index dbfbf906a394eb59cee5bc7ddcfb50eff8f80ff3..fc90027c28b988328a1a7345147653d6ae6f156a 100644 --- a/src/codegen/swfLoader.ml +++ b/src/codegen/swfLoader.ml @@ -102,17 +102,17 @@ let rec make_tpath = function tsub = None; } | HMMultiName _ -> - assert false + die "" __LOC__ | HMRuntimeName _ -> - assert false + die "" __LOC__ | HMRuntimeNameLate -> - assert false + die "" __LOC__ | HMMultiNameLate _ -> - assert false + die "" __LOC__ | HMAttrib _ -> - assert false + die "" __LOC__ | HMAny -> - assert false + die "" __LOC__ | HMParams (t,params) -> let params = List.map (fun t -> TPType (CTPath (make_tpath t),null_pos)) params in { (make_tpath t) with tparams = params } @@ -173,7 +173,7 @@ let build_class com c file = in loop ns | HMPath _ -> i - | _ -> assert false + | _ -> die "" __LOC__ ) in if c.hlc_interface then HExtends (make_tpath i,null_pos) else HImplements (make_tpath i,null_pos) ) (Array.to_list c.hlc_implements) @ flags in @@ -260,9 +260,12 @@ let build_class com c file = | None -> None | Some v -> let v = (match v with - | HVNone | HVNull | HVNamespace _ | HVString _ -> + | HVNone | HVNull | HVNamespace _ -> is_opt := true; None + | HVString s -> + is_opt := true; + Some (String (s,SDoubleQuotes)) | HVBool b -> Some (Ident (if b then "true" else "false")) | HVInt i | HVUInt i -> @@ -295,7 +298,7 @@ let build_class com c file = Hashtbl.add getters (name,stat) (m.hlm_type.hlmt_ret,mk_meta()); acc | MK3Setter -> - Hashtbl.add setters (name,stat) ((match m.hlm_type.hlmt_args with [t] -> t | _ -> assert false),mk_meta()); + Hashtbl.add setters (name,stat) ((match m.hlm_type.hlmt_args with [t] -> t | _ -> die "" __LOC__),mk_meta()); acc ) | _ -> acc @@ -315,7 +318,7 @@ let build_class com c file = let fields = Array.fold_left (make_field true) fields c.hlc_static_fields in let make_get_set name stat tget tset = let get, set, t, meta = (match tget, tset with - | None, None -> assert false + | None, None -> die "" __LOC__ | Some (t,meta), None -> true, false, t, meta | None, Some (t,meta) -> false, true, t, meta | Some (t1,meta1), Some (t2,meta2) -> true, true, (if t1 <> t2 then None else t1), meta1 @ (List.filter (fun m -> not (List.mem m meta1)) meta2) diff --git a/src/compiler/displayOutput.ml b/src/compiler/displayOutput.ml index 9c2bafc55638cf3680a6cd33b9c374d8dfdea7d0..68e61b39675193e6235a0c3d58eab61052e4848a 100644 --- a/src/compiler/displayOutput.ml +++ b/src/compiler/displayOutput.ml @@ -71,26 +71,26 @@ let print_fields fields = | ITModule path -> "type",snd path,"",None | ITMetadata meta -> let s,(doc,_) = Meta.get_info meta in - "metadata","@" ^ s,"",Some doc - | ITTimer(name,value) -> "timer",name,"",Some value + "metadata","@" ^ s,"",doc_from_string doc + | ITTimer(name,value) -> "timer",name,"",doc_from_string value | ITLiteral s -> let t = match k.ci_type with None -> t_dynamic | Some (t,_) -> t in "literal",s,s_type (print_context()) t,None | ITLocal v -> "local",v.v_name,s_type (print_context()) v.v_type,None | ITKeyword kwd -> "keyword",Ast.s_keyword kwd,"",None - | ITExpression _ | ITAnonymous _ | ITTypeParameter _ | ITDefine _ -> assert false + | ITExpression _ | ITAnonymous _ | ITTypeParameter _ | ITDefine _ -> die "" __LOC__ in let fields = List.sort (fun k1 k2 -> compare (legacy_sort k1) (legacy_sort k2)) fields in let fields = List.map convert fields in List.iter (fun(k,n,t,d) -> - let d = match d with None -> "" | Some d -> d in + let d = match d with None -> "" | Some d -> gen_doc_text d in Buffer.add_string b (Printf.sprintf "%s%s\n" n k (htmlescape t) (htmlescape d)) ) fields; Buffer.add_string b "\n"; Buffer.contents b -let maybe_print_doc d = - Option.map_default (fun s -> Printf.sprintf " d=\"%s\"" (htmlescape s)) "" d +let maybe_print_doc d_opt = + Option.map_default (fun d -> Printf.sprintf " d=\"%s\"" (htmlescape (gen_doc_text d))) "" d_opt let print_toplevel il = let b = Buffer.create 0 in @@ -141,7 +141,7 @@ let print_type t p doc = if p = null_pos then Buffer.add_string b " Buffer.add_string b " Buffer.add_string b (Printf.sprintf " d=\"%s\"" (htmlescape s))) doc; + Option.may (fun d -> Buffer.add_string b (Printf.sprintf " d=\"%s\"" (htmlescape (gen_doc_text d)))) doc; Buffer.add_string b ">\n"; Buffer.add_string b (htmlescape (s_type (print_context()) (TFun(args,ret)))); Buffer.add_string b "\n\n"; @@ -197,7 +197,7 @@ let print_signature tl display_arg = "label",JString label; "parameters",JArray parameters; ] in - JObject (match doc with None -> js | Some s -> ("documentation",JString s) :: js) + JObject (match doc with None -> js | Some d -> ("documentation",JString (gen_doc_text d)) :: js) ) tl in let jo = JObject [ "signatures",JArray siginf; @@ -230,11 +230,12 @@ let handle_display_argument com file_pos pre_compilation did_something = (try Memory.display_memory com with e -> prerr_endline (Printexc.get_backtrace ())); | "diagnostics" -> Common.define com Define.NoCOpt; - com.display <- DisplayMode.create (DMDiagnostics true); - Parser.display_mode := DMDiagnostics true; + com.display <- DisplayMode.create (DMDiagnostics []); + Parser.display_mode := DMDiagnostics []; | _ -> let file, pos = try ExtString.String.split file_pos "@" with _ -> failwith ("Invalid format: " ^ file_pos) in let file = unquote file in + let file_unique = Path.UniqueKey.create file in let pos, smode = try ExtString.String.split pos "@" with _ -> pos,"" in let mode = match smode with | "position" -> @@ -242,7 +243,7 @@ let handle_display_argument com file_pos pre_compilation did_something = DMDefinition | "usage" -> Common.define com Define.NoCOpt; - DMUsage false + DMUsage (false,false,false) (*| "rename" -> Common.define com Define.NoCOpt; DMUsage true*) @@ -258,7 +259,7 @@ let handle_display_argument com file_pos pre_compilation did_something = DMModuleSymbols None; | "diagnostics" -> Common.define com Define.NoCOpt; - DMDiagnostics false; + DMDiagnostics [file_unique]; | "statistics" -> Common.define com Define.NoCOpt; DMStatistics @@ -283,14 +284,18 @@ let handle_display_argument com file_pos pre_compilation did_something = Parser.display_mode := mode; if not com.display.dms_full_typing then Common.define_value com Define.Display (if smode <> "" then smode else "1"); DisplayPosition.display_position#set { - pfile = Path.unique_full_path file; + pfile = Path.get_full_path file; pmin = pos; pmax = pos; } +let file_input_marker = Path.get_full_path "? input" + type display_path_kind = | DPKNormal of path | DPKMacro of path + | DPKDirect of string + | DPKInput of string | DPKNone let process_display_file com classes = @@ -317,6 +322,16 @@ let process_display_file com classes = match com.display.dms_display_file_policy with | DFPNo -> DPKNone + | DFPOnly when (DisplayPosition.display_position#get).pfile = file_input_marker -> + classes := []; + com.main_class <- None; + begin match !TypeloadParse.current_stdin with + | Some input -> + TypeloadParse.current_stdin := None; + DPKInput input + | None -> + DPKNone + end | dfp -> if dfp = DFPOnly then begin classes := []; @@ -334,8 +349,12 @@ let process_display_file com classes = | [name] -> classes := path :: !classes; DPKNormal path - | _ -> - assert false + | [name;target] -> + let path = fst path, name in + classes := path :: !classes; + DPKNormal path + | e -> + die "" __LOC__ in path | None -> @@ -343,16 +362,43 @@ let process_display_file com classes = (match List.rev (ExtString.String.nsplit real Path.path_sep) with | file :: _ when file.[0] >= 'a' && file.[0] <= 'z' -> failwith ("Display file '" ^ file ^ "' should not start with a lowercase letter") | _ -> ()); - failwith "Display file was not found in class path" + DPKDirect real in Common.log com ("Display file : " ^ real); Common.log com ("Classes found : [" ^ (String.concat "," (List.map s_type_path !classes)) ^ "]"); path +let load_display_file_standalone ctx file = + let com = ctx.com in + let pack,decls = TypeloadParse.parse_module_file com file null_pos in + let path = Path.FilePath.parse file in + let name = match path.file_name with + | None -> "?DISPLAY" + | Some name -> name + in + begin match path.directory with + | None -> () + | Some dir -> + (* Chop off number of package parts from the dir and use that as class path. *) + let parts = ExtString.String.nsplit dir (if path.backslash then "\\" else "/") in + let parts = List.rev (ExtList.List.drop (List.length pack) (List.rev parts)) in + let dir = ExtString.String.join (if path.backslash then "\\" else "/") parts in + com.class_path <- dir :: com.class_path + end; + ignore(TypeloadModule.type_module ctx (pack,name) file ~dont_check_path:true decls null_pos) + +let load_display_content_standalone ctx input = + let com = ctx.com in + let file = file_input_marker in + let p = {pfile = file; pmin = 0; pmax = 0} in + let parsed = TypeloadParse.parse_file_from_string com file p input in + let pack,decls = TypeloadParse.handle_parser_result com p parsed in + ignore(TypeloadModule.type_module ctx (pack,"?DISPLAY") file ~dont_check_path:true decls p) + let promote_type_hints tctx = let rec explore_type_hint (md,p,t) = match t with - | TMono r -> (match !r with None -> () | Some t -> explore_type_hint (md,p,t)) + | TMono r -> (match r.tm_type with None -> () | Some t -> explore_type_hint (md,p,t)) | TLazy f -> explore_type_hint (md,p,lazy_type f) | TInst(({cl_name_pos = pn;cl_path = (_,name)}),_) | TEnum(({e_name_pos = pn;e_path = (_,name)}),_) @@ -367,12 +413,14 @@ let promote_type_hints tctx = let process_global_display_mode com tctx = promote_type_hints tctx; match com.display.dms_kind with - | DMUsage with_definition -> + | DMUsage (with_definition,_,_) -> FindReferences.find_references tctx com with_definition - | DMDiagnostics global -> - Diagnostics.run com global + | DMImplementation -> + FindReferences.find_implementations tctx com + | DMDiagnostics _ -> + Diagnostics.run com | DMStatistics -> - let stats = Statistics.collect_statistics tctx (SFFile (DisplayPosition.display_position#get).pfile) in + let stats = Statistics.collect_statistics tctx (SFFile (DisplayPosition.display_position#get).pfile) true in raise_statistics (Statistics.Printer.print_statistics stats) | DMModuleSymbols (Some "") -> () | DMModuleSymbols filter -> @@ -380,7 +428,8 @@ let process_global_display_mode com tctx = | None -> [] | Some cs -> let l = cs#get_context_files ((Define.get_signature com.defines) :: (match com.get_macros() with None -> [] | Some com -> [Define.get_signature com.defines])) in - List.fold_left (fun acc (file,cfile) -> + List.fold_left (fun acc (file_key,cfile) -> + let file = cfile.CompilationServer.c_file_path in if (filter <> None || DisplayPosition.display_position#is_in_file file) then (file,DocumentSymbols.collect_module_symbols (filter = None) (cfile.c_package,cfile.c_decls)) :: acc else @@ -442,7 +491,7 @@ let handle_syntax_completion com kind subj = Buffer.add_string b "\n"; List.iter (fun item -> match item.ci_kind with | ITKeyword kwd -> Buffer.add_string b (Printf.sprintf "%s" (s_keyword kwd)); - | _ -> assert false + | _ -> die "" __LOC__ ) l; Buffer.add_string b ""; let s = Buffer.contents b in diff --git a/src/compiler/main.ml b/src/compiler/haxe.ml similarity index 94% rename from src/compiler/main.ml rename to src/compiler/haxe.ml index 97061d3e3cf1d65e1b3072461af5184977653cf0..94b645208a2283307a8d171d65510589b2877d74 100644 --- a/src/compiler/main.ml +++ b/src/compiler/haxe.ml @@ -82,7 +82,7 @@ let error ctx msg p = let reserved_flags = [ "true";"false";"null";"cross";"js";"lua";"neko";"flash";"php";"cpp";"cs";"java";"python"; - "as3";"swc";"macro";"sys";"static";"utf16";"haxe";"haxe_ver" + "swc";"macro";"sys";"static";"utf16";"haxe";"haxe_ver" ] let reserved_flag_namespaces = ["target"] @@ -273,7 +273,7 @@ module Initialize = struct "python" | Hl -> add_std "hl"; - if not (Common.raw_defined com "hl_ver") then Define.raw_define_value com.defines "hl_ver" (try Std.input_file (Common.find_file com "hl/hl_version") with Not_found -> assert false); + if not (Common.defined com Define.HlVer) then Define.define_value com.defines Define.HlVer (try Std.input_file (Common.find_file com "hl/hl_version") with Not_found -> die "" __LOC__); "hl" | Eval -> add_std "eval"; @@ -308,8 +308,6 @@ let generate tctx ext interp swf_header = () else begin let generate,name = match com.platform with - | Flash when Common.defined com Define.As3 -> - Genas3.generate,"AS3" | Flash -> Genswf.generate swf_header,"swf" | Neko -> @@ -336,7 +334,7 @@ let generate tctx ext interp swf_header = | Eval -> (fun _ -> MacroContext.interpret tctx),"eval" | Cross -> - assert false + die "" __LOC__ in Common.log com ("Generating " ^ name ^ ": " ^ com.file); let t = Timer.timer ["generate";name] in @@ -396,7 +394,7 @@ let setup_common_context ctx com = ) (List.rev ctx.messages))) in com.get_messages <- (fun () -> (List.map (fun msg -> (match msg with - | CMError(_,_) -> assert false; + | CMError(_,_) -> die "" __LOC__; | CMInfo(_,_) | CMWarning(_,_) -> msg;) ) (filter_messages false (fun _ -> true)))); com.filter_messages <- (fun predicate -> (ctx.messages <- (List.rev (filter_messages true predicate)))); @@ -460,21 +458,21 @@ let process_display_configuration ctx = end let run_or_diagnose com f arg = - let handle_diagnostics global msg p kind = + let handle_diagnostics msg p kind = add_diagnostics_message com msg p kind DisplayTypes.DiagnosticsSeverity.Error; - Diagnostics.run com global; + Diagnostics.run com; in match com.display.dms_kind with - | DMDiagnostics global -> + | DMDiagnostics _ -> begin try f arg with | Error.Error(msg,p) -> - handle_diagnostics global (Error.error_msg msg) p DisplayTypes.DiagnosticsKind.DKCompilerError + handle_diagnostics (Error.error_msg msg) p DisplayTypes.DiagnosticsKind.DKCompilerError | Parser.Error(msg,p) -> - handle_diagnostics global (Parser.error_msg msg) p DisplayTypes.DiagnosticsKind.DKParserError + handle_diagnostics (Parser.error_msg msg) p DisplayTypes.DiagnosticsKind.DKParserError | Lexer.Error(msg,p) -> - handle_diagnostics global (Lexer.error_msg msg) p DisplayTypes.DiagnosticsKind.DKParserError + handle_diagnostics (Lexer.error_msg msg) p DisplayTypes.DiagnosticsKind.DKParserError end | _ -> f arg @@ -503,6 +501,7 @@ let do_type tctx config_macros classes = CommonCache.lock_signature com "after_init_macros"; List.iter (fun f -> f ()) (List.rev com.callbacks#get_after_init_macros); run_or_diagnose com (fun () -> + if com.display.dms_kind <> DMNone then Option.may (DisplayTexpr.check_display_file tctx) (CompilationServer.get ()); List.iter (fun cpath -> ignore(tctx.Typecore.g.Typecore.do_load_module tctx cpath null_pos)) (List.rev classes); Finalization.finalize tctx; ) (); @@ -510,7 +509,7 @@ let do_type tctx config_macros classes = (* If we are trying to find references, let's syntax-explore everything we know to check for the identifier we are interested in. We then type only those modules that contain the identifier. *) begin match !CompilationServer.instance,com.display.dms_kind with - | Some cs,DMUsage _ -> FindReferences.find_possible_references tctx cs; + | Some cs,(DMUsage _ | DMImplementation) -> FindReferences.find_possible_references tctx cs; | _ -> () end; t() @@ -597,8 +596,7 @@ let filter ctx tctx display_file_dot_path = mctx.Typecore.com.Common.modules <- modules end; DisplayOutput.process_global_display_mode com tctx; - if not (Common.defined com Define.NoDeprecationWarnings) then - DeprecationCheck.run com; + DeprecationCheck.run com; Filters.run com tctx main; t() @@ -646,7 +644,8 @@ let rec process_params create pl = | "--cwd" :: dir :: l | "-C" :: dir :: l -> (* we need to change it immediately since it will affect hxml loading *) (try Unix.chdir dir with _ -> raise (Arg.Bad ("Invalid directory: " ^ dir))); - loop acc l + (* Push the --cwd arg so the arg processor know we did something. *) + loop (dir :: "--cwd" :: acc) l | "--connect" :: hp :: l -> (match CompilationServer.get() with | None -> @@ -677,7 +676,7 @@ let rec process_params create pl = and init ctx = let usage = Printf.sprintf - "Haxe Compiler %s - (C)2005-2019 Haxe Foundation\nUsage: haxe%s [options] [hxml files...]\n" + "Haxe Compiler %s - (C)2005-2020 Haxe Foundation\nUsage: haxe%s [options] [hxml files...]\n" (s_version true) (if Sys.os_type = "Win32" then ".exe" else "") in let com = ctx.com in @@ -717,11 +716,6 @@ try ("Target",["--js"],["-js"],Arg.String (Initialize.set_platform com Js),"","compile code to JavaScript file"); ("Target",["--lua"],["-lua"],Arg.String (Initialize.set_platform com Lua),"","compile code to Lua file"); ("Target",["--swf"],["-swf"],Arg.String (Initialize.set_platform com Flash),"","compile code to Flash SWF file"); - ("Target",["--as3"],["-as3"],Arg.String (fun dir -> - Initialize.set_platform com Flash dir; - Common.define com Define.As3; - Common.define com Define.NoInline; - ),"","generate AS3 code into target directory"); ("Target",["--neko"],["-neko"],Arg.String (Initialize.set_platform com Neko),"","compile code to Neko Binary"); ("Target",["--php"],["-php"],Arg.String (fun dir -> classes := (["php"],"Boot") :: !classes; @@ -815,7 +809,7 @@ try List.iter (fun msg -> ctx.com.print (msg ^ "\n")) all; did_something := true ),"","print help for all compiler metadatas"); - ("Misc",["--run"],[], Arg.Unit (fun() -> assert false), " [args...]","compile and execute a Haxe module with command line arguments"); + ("Misc",["--run"],[], Arg.Unit (fun() -> die "" __LOC__), " [args...]","compile and execute a Haxe module with command line arguments"); ] in let adv_args_spec = [ ("Optimization",["--dce"],["-dce"],Arg.String (fun mode -> @@ -842,18 +836,18 @@ try _ -> raise (Arg.Bad "Invalid SWF header format, expected width:height:fps[:color]") ),"
","define SWF header (width:height:fps:color)"); ("Target-specific",["--flash-strict"],[], define Define.FlashStrict, "","more type strict flash API"); - ("Target-specific",[],["--swf-lib";"-swf-lib"],Arg.String (fun file -> + ("Target-specific",["--swf-lib"],["-swf-lib"],Arg.String (fun file -> process_libs(); (* linked swf order matters, and lib might reference swf as well *) add_native_lib file false; ),"","add the SWF library to the compiled SWF"); (* FIXME: replace with -D define *) - ("Target-specific",[],["--swf-lib-extern";"-swf-lib-extern"],Arg.String (fun file -> + ("Target-specific",["--swf-lib-extern"],["-swf-lib-extern"],Arg.String (fun file -> add_native_lib file true; ),"","use the SWF library for type checking"); - ("Target-specific",[],["--java-lib";"-java-lib"],Arg.String (fun file -> + ("Target-specific",["--java-lib"],["-java-lib"],Arg.String (fun file -> add_native_lib file false; ),"","add an external JAR or class directory library"); - ("Target-specific",[],["--net-lib";"-net-lib"],Arg.String (fun file -> + ("Target-specific",["--net-lib"],["-net-lib"],Arg.String (fun file -> add_native_lib file false; ),"[@std]","add an external .NET DLL file"); ("Target-specific",["--net-std"],["-net-std"],Arg.String (fun file -> @@ -887,14 +881,14 @@ try ),"","run the specified command after successful compilation"); (* FIXME: replace with -D define *) ("Optimization",["--no-traces"],[], define Define.NoTraces, "","don't compile trace calls in the program"); - ("Batch",["--next"],[], Arg.Unit (fun() -> assert false), "","separate several haxe compilations"); - ("Batch",["--each"],[], Arg.Unit (fun() -> assert false), "","append preceding parameters to all Haxe compilations separated by --next"); + ("Batch",["--next"],[], Arg.Unit (fun() -> die "" __LOC__), "","separate several haxe compilations"); + ("Batch",["--each"],[], Arg.Unit (fun() -> die "" __LOC__), "","append preceding parameters to all Haxe compilations separated by --next"); ("Services",["--display"],[], Arg.String (fun input -> let input = String.trim input in if String.length input > 0 && (input.[0] = '[' || input.[0] = '{') then begin did_something := true; force_typing := true; - DisplayJson.parse_input com input measure_times + DisplayJson.parse_input com input Timer.measure_times end else DisplayOutput.handle_display_argument com input pre_compilation did_something; ),"","display code tips"); @@ -905,7 +899,7 @@ try json_out := Some file ),"","generate JSON types description"); ("Optimization",["--no-output"],[], Arg.Unit (fun() -> no_output := true),"","compiles but does not generate any file"); - ("Debug",["--times"],[], Arg.Unit (fun() -> measure_times := true),"","measure compilation times"); + ("Debug",["--times"],[], Arg.Unit (fun() -> Timer.measure_times := true),"","measure compilation times"); ("Optimization",["--no-inline"],[], define Define.NoInline, "","disable inlining"); ("Optimization",["--no-opt"],[], Arg.Unit (fun() -> com.foptimize <- false; @@ -935,10 +929,11 @@ try wait_loop process_params com.verbose accept ),"[host:]port]","connect to the given port and wait for commands to run"); ("Compilation Server",["--connect"],[],Arg.String (fun _ -> - assert false + die "" __LOC__ ),"<[host:]port>","connect on the given port and run commands there"); ("Compilation",["-C";"--cwd"],[], Arg.String (fun dir -> - assert false + (* This is handled by process_params, but passed through so we know we did something. *) + did_something := true; ),"","set current working directory"); ("Compilation",["--haxelib-global"],[], Arg.Unit (fun () -> ()),"","pass --global argument to haxelib"); ] in @@ -1023,7 +1018,7 @@ try let ext = Initialize.initialize_target ctx com classes in (* if we are at the last compilation step, allow all packages accesses - in case of macros or opening another project file *) if com.display.dms_display then begin match com.display.dms_kind with - | DMDefault -> () + | DMDefault | DMUsage _ -> () | _ -> if not ctx.has_next then com.package_rules <- PMap.foldi (fun p r acc -> match r with Forbidden -> acc | _ -> PMap.add p r acc) com.package_rules PMap.empty; end; com.config <- get_config com; (* make sure to adapt all flags changes defined after platform *) @@ -1045,6 +1040,12 @@ try Some path | DPKNone -> None + | DPKDirect file -> + DisplayOutput.load_display_file_standalone tctx file; + None + | DPKInput input -> + DisplayOutput.load_display_content_standalone tctx input; + None in begin try do_type tctx !config_macros !classes; @@ -1103,7 +1104,7 @@ with | Some api -> let ctx = DisplayJson.create_json_context api.jsonrpc (match de with DisplayFields _ -> true | _ -> false) in api.send_result (DisplayException.to_json ctx de) - | _ -> assert false + | _ -> die "" __LOC__ end (* | Parser.TypePath (_,_,_,p) when ctx.com.json_out <> None -> begin match com.json_out with @@ -1112,14 +1113,14 @@ with let fields = DisplayToplevel.collect tctx true Typecore.NoValue in let jctx = Genjson.create_context Genjson.GMMinimum in f (DisplayException.fields_to_json jctx fields CRImport (Some (Parser.cut_pos_at_display p)) false) - | _ -> assert false + | _ -> die "" __LOC__ end *) | DisplayException(DisplayPackage pack) -> DisplayPosition.display_position#reset; raise (DisplayOutput.Completion (String.concat "." pack)) | DisplayException(DisplayFields Some r) -> DisplayPosition.display_position#reset; - let fields = if !measure_times then begin + let fields = if !Timer.measure_times then begin Timer.close_times(); (List.map (fun (name,value) -> CompletionItem.make_ci_timer ("@TIME " ^ name) value @@ -1192,12 +1193,16 @@ with | Parser.SyntaxCompletion(kind,subj) -> DisplayOutput.handle_syntax_completion com kind subj; error ctx ("Error: No completion point was found") null_pos - | DisplayException(ModuleSymbols s | Diagnostics s | Statistics s | Metadata s) -> + | DisplayException(DisplayDiagnostics dctx) -> + let s = Json.string_of_json (DiagnosticsPrinter.json_of_diagnostics dctx) in + DisplayPosition.display_position#reset; + raise (DisplayOutput.Completion s) + | DisplayException(ModuleSymbols s | Statistics s | Metadata s) -> DisplayPosition.display_position#reset; raise (DisplayOutput.Completion s) | EvalExceptions.Sys_exit i | Hlinterp.Sys_exit i -> ctx.flush(); - if !measure_times then Timer.report_times prerr_endline; + if !Timer.measure_times then Timer.report_times prerr_endline; exit i | DisplayOutput.Completion _ as exc -> raise exc @@ -1226,4 +1231,4 @@ with DisplayOutput.Completion c -> exit 1 ); other(); -if !measure_times then Timer.report_times prerr_endline +if !Timer.measure_times then Timer.report_times prerr_endline diff --git a/src/compiler/server.ml b/src/compiler/server.ml index 1e7cbc08b08cd89800ffd1bc980c9a03a4207f1c..2a73e9b95ba981fa74f3e596d670d553978de769 100644 --- a/src/compiler/server.ml +++ b/src/compiler/server.ml @@ -12,7 +12,6 @@ open Json exception Dirty of path exception ServerError of string -let measure_times = ref false let prompt = ref false let start_time = ref (Timer.get_time()) @@ -27,19 +26,10 @@ type context = { mutable has_error : bool; } -let s_version with_build = - let pre = Option.map_default (fun pre -> "-" ^ pre) "" version_pre in - let build = - match with_build, Version.version_extra with - | true, Some (_,build) -> "+" ^ build - | _, _ -> "" - in - Printf.sprintf "%d.%d.%d%s%s" version_major version_minor version_revision pre build - let check_display_flush ctx f_otherwise = match ctx.com.json_out with | None -> begin match ctx.com.display.dms_kind with - | DMDiagnostics global-> + | DMDiagnostics _-> List.iter (fun msg -> let msg,p,kind = match msg with | CMInfo(msg,p) -> msg,p,DisplayTypes.DiagnosticsSeverity.Information @@ -48,7 +38,7 @@ let check_display_flush ctx f_otherwise = match ctx.com.json_out with in add_diagnostics_message ctx.com msg p DisplayTypes.DiagnosticsKind.DKCompilerError kind ) (List.rev ctx.messages); - raise (Completion (Diagnostics.print ctx.com global)) + raise (Completion (Diagnostics.print ctx.com)) | _ -> f_otherwise () end @@ -132,8 +122,9 @@ let current_stdin = ref None let parse_file cs com file p = let cc = CommonCache.get_cache cs com in - let ffile = Path.unique_full_path file in - let is_display_file = ffile = (DisplayPosition.display_position#get).pfile in + let ffile = Path.get_full_path file + and fkey = Path.UniqueKey.create file in + let is_display_file = DisplayPosition.display_position#is_in_file ffile in match is_display_file, !current_stdin with | true, Some stdin when Common.defined com Define.DisplayStdin -> TypeloadParse.parse_file_from_string com file p stdin @@ -141,23 +132,30 @@ let parse_file cs com file p = let ftime = file_time ffile in let data = Std.finally (Timer.timer ["server";"parser cache"]) (fun () -> try - let cfile = cc#find_file ffile in + let cfile = cc#find_file fkey in if cfile.c_time <> ftime then raise Not_found; - Parser.ParseSuccess(cfile.c_package,cfile.c_decls) + Parser.ParseSuccess((cfile.c_package,cfile.c_decls),false,cfile.c_pdi) with Not_found -> let parse_result = TypeloadParse.parse_file com file p in let info,is_unusual = match parse_result with | ParseError(_,_,_) -> "not cached, has parse error",true - | ParseDisplayFile _ -> "not cached, is display file",true - | ParseSuccess data -> - begin try + | ParseSuccess(data,is_display_file,pdi) -> + if is_display_file then begin + if pdi.pd_errors <> [] then + "not cached, is display file with parse errors",true + else if com.display.dms_per_file then begin + cc#cache_file fkey ffile ftime data pdi; + "cached, is intact display file",true + end else + "not cached, is display file",true + end else begin try (* We assume that when not in display mode it's okay to cache stuff that has #if display checks. The reasoning is that non-display mode has more information than display mode. *) if not com.display.dms_display then raise Not_found; - let ident = Hashtbl.find Parser.special_identifier_files ffile in + let ident = Hashtbl.find Parser.special_identifier_files fkey in Printf.sprintf "not cached, using \"%s\" define" ident,true with Not_found -> - cc#cache_file ffile ftime data; + cc#cache_file fkey ffile ftime data pdi; "cached",false end in @@ -289,9 +287,9 @@ let check_module sctx ctx m p = let com = ctx.Typecore.com in let cc = CommonCache.get_cache sctx.cs com in let content_changed m file = - let ffile = Path.unique_full_path file in + let fkey = Path.UniqueKey.create file in try - let cfile = cc#find_file ffile in + let cfile = cc#find_file fkey in (* We must use the module path here because the file path is absolute and would cause positions in the parsed declarations to differ. *) let new_data = TypeloadParse.parse_module ctx m.m_path p in @@ -333,7 +331,7 @@ let check_module sctx ctx m p = match load m.m_path p with | None -> loop l | Some _ -> - if Path.unique_full_path file <> m.m_extra.m_file then begin + if Path.UniqueKey.create file <> Path.UniqueKey.create m.m_extra.m_file then begin if sctx.verbose then print_endline ("Library file was changed for " ^ s_type_path m.m_path); (* TODO *) raise Not_found; end @@ -365,7 +363,7 @@ let check_module sctx ctx m p = ServerMessage.unchanged_content com "" m.m_extra.m_file; end else begin ServerMessage.not_cached com "" m; - if m.m_extra.m_kind = MFake then Hashtbl.remove Typecore.fake_modules m.m_extra.m_file; + if m.m_extra.m_kind = MFake then Hashtbl.remove Typecore.fake_modules (Path.UniqueKey.create m.m_extra.m_file); raise Not_found; end end @@ -499,14 +497,6 @@ let create sctx write params = ServerMessage.defines ctx.com ""; ServerMessage.signature ctx.com "" sign; ServerMessage.display_position ctx.com "" (DisplayPosition.display_position#get); - (* Special case for diagnostics: It's not treated as a display mode, but we still want to invalidate the - current file in order to run diagnostics on it again. *) - if ctx.com.display.dms_display || (match ctx.com.display.dms_kind with DMDiagnostics _ -> true | _ -> false) then begin - let file = (DisplayPosition.display_position#get).pfile in - (* force parsing again : if the completion point have been changed *) - cs#remove_files file; - cs#taint_modules file; - end; try if (Hashtbl.find sctx.class_paths sign) <> ctx.com.class_path then begin ServerMessage.class_paths_changed ctx.com ""; @@ -544,55 +534,6 @@ let cleanup () = | None -> () end -module Ring = struct - type 'a t = { - values : 'a array; - mutable index : int; - mutable num_filled : int; - } - - let create len x = { - values = Array.make len x; - index = 0; - num_filled = 0; - } - - let push r x = - r.values.(r.index) <- x; - r.num_filled <- r.num_filled + 1; - if r.index = Array.length r.values - 1 then begin - r.index <- 0; - end else - r.index <- r.index + 1 - - let iter r f = - let len = Array.length r.values in - for i = 0 to len - 1 do - let off = r.index + i in - let off = if off >= len then off - len else off in - f r.values.(off) - done - - let fold r acc f = - let len = Array.length r.values in - let rec loop i acc = - if i = len then - acc - else begin - let off = r.index + i in - let off = if off >= len then off - len else off in - loop (i + 1) (f acc r.values.(off)) - end - in - loop 0 acc - - let is_filled r = - r.num_filled >= Array.length r.values - - let reset_filled r = - r.num_filled <- 0 -end - let gc_heap_stats () = let stats = Gc.quick_stat() in stats.major_words,stats.heap_words @@ -600,6 +541,72 @@ let gc_heap_stats () = let fmt_percent f = int_of_float (f *. 100.) +module Tasks = struct + class gc_task (max_working_memory : float) (heap_size : float) = object(self) + inherit server_task ["gc"] 100 + + method private execute = + let t0 = get_time() in + let stats = Gc.stat() in + let live_words = float_of_int stats.live_words in + (* Maximum heap size needed for the last X compilations = sum of what's live + max working memory. *) + let needed_max = live_words +. max_working_memory in + (* Additional heap percentage needed = what's live / max of what was live. *) + let percent_needed = (1. -. live_words /. needed_max) in + (* Effective cache size percentage = what's live / heap size. *) + let percent_used = live_words /. heap_size in + (* Set allowed space_overhead to the maximum of what we needed during the last X compilations. *) + let new_space_overhead = int_of_float ((percent_needed +. 0.05) *. 100.) in + let old_gc = Gc.get() in + Gc.set { old_gc with Gc.space_overhead = new_space_overhead; }; + (* Compact if less than 80% of our heap words consist of the cache and there's less than 50% overhead. *) + let do_compact = percent_used < 0.8 && percent_needed < 0.5 in + begin if do_compact then + Gc.compact() + else + Gc.full_major(); + end; + Gc.set old_gc; + ServerMessage.gc_stats (get_time() -. t0) stats do_compact new_space_overhead + end + + class class_maintenance_task (cs : CompilationServer.t) (c : tclass) = object(self) + inherit server_task ["module maintenance"] 70 + + method private execute = + let rec field cf = + (* Unset cf_expr. This holds the optimized version for generators, which we don't need to persist. If + we compile again, the semi-optimized expression will be restored by calling cl_restore(). *) + cf.cf_expr <- None; + List.iter field cf.cf_overloads + in + (* What we're doing here at the moment is free, so we can just do it in one task. If this ever gets more expensive, + we should spawn a task per-field. *) + List.iter field c.cl_ordered_fields; + List.iter field c.cl_ordered_statics; + Option.may field c.cl_constructor; + end + + class module_maintenance_task (cs : CompilationServer.t) (m : module_def) = object(self) + inherit server_task ["module maintenance"] 80 + + method private execute = + List.iter (fun mt -> match mt with + | TClassDecl c -> + cs#add_task (new class_maintenance_task cs c) + | _ -> + () + ) m.m_types + end + + class server_exploration_task (cs : CompilationServer.t) = object(self) + inherit server_task ["server explore"] 90 + + method private execute = + cs#iter_modules (fun m -> cs#add_task (new module_maintenance_task cs m)) + end +end + (* The server main loop. Waits for the [accept] call to then process the sent compilation parameters through [process_params]. *) let wait_loop process_params verbose accept = @@ -621,39 +628,16 @@ let wait_loop process_params verbose accept = Ring.push ring words_allocated; if Ring.is_filled ring then begin Ring.reset_filled ring; - let t0 = get_time() in - let stats = Gc.stat() in - let live_words = float_of_int stats.live_words in (* Maximum working memory for the last X compilations. *) let max = Ring.fold ring 0. (fun m i -> if i > m then i else m) in - (* Maximum heap size needed for the last X compilations = sum of what's live + max working memory. *) - let needed_max = live_words +. max in - (* Additional heap percentage needed = what's live / max of what was live. *) - let percent_needed = (1. -. live_words /. needed_max) in - (* Effective cache size percentage = what's live / heap size. *) - let percent_used = live_words /. heap_size in - (* Set allowed space_overhead to the maximum of what we needed during the last X compilations. *) - let new_space_overhead = int_of_float ((percent_needed +. 0.05) *. 100.) in - let old_gc = Gc.get() in - Gc.set { old_gc with Gc.space_overhead = new_space_overhead; }; - (* Compact if less than 80% of our heap words consist of the cache and there's less than 50% overhead. *) - let do_compact = percent_used < 0.8 && percent_needed < 0.5 in - begin if do_compact then - Gc.compact() - else - Gc.full_major(); - end; - Gc.set old_gc; - ServerMessage.gc_stats (get_time() -. t0) stats do_compact new_space_overhead + cs#add_task (new Tasks.gc_task max heap_size) end; heap_stats_start := heap_stats_now; in (* Main loop: accept connections and process arguments *) while true do - let read, write, close = accept() in - begin try - (* Read arguments *) - let s = read() in + let support_nonblock, read, write, close = accept() in + let process s = let t0 = get_time() in let hxml = try @@ -681,6 +665,24 @@ let wait_loop process_params verbose accept = end; run_delays sctx; ServerMessage.stats stats (get_time() -. t0) + in + begin try + (* Read arguments *) + let rec loop block = + match read block with + | Some data -> + process data + | None -> + if not cs#has_task then + (* If there is no pending task, turn into blocking mode. *) + loop true + else begin + (* Otherwise run the task and loop to check if there are more or if there's a request now. *) + cs#get_task#run; + loop false + end; + in + loop (not support_nonblock) with Unix.Unix_error _ -> ServerMessage.socket_message "Connection Aborted" | e -> @@ -698,18 +700,55 @@ let wait_loop process_params verbose accept = current_stdin := None; cleanup(); update_heap(); + (* If our connection always blocks, we have to execute all pending tasks now. *) + if not support_nonblock then + while cs#has_task do cs#get_task#run done + else if sctx.was_compilation then + cs#add_task (new Tasks.server_exploration_task cs) done -let mk_length_prefixed_communication chin chout = +let mk_length_prefixed_communication allow_nonblock chin chout = + let sin = Unix.descr_of_in_channel chin in let chin = IO.input_channel chin in let chout = IO.output_channel chout in let bout = Buffer.create 0 in - let read = fun () -> - let len = IO.read_i32 chin in - IO.really_nread_string chin len + let block () = Unix.clear_nonblock sin in + let unblock () = Unix.set_nonblock sin in + + let read_nonblock _ = + let len = IO.read_i32 chin in + Some (IO.really_nread_string chin len) in + let read = if allow_nonblock then fun do_block -> + if do_block then begin + block(); + read_nonblock true; + end else begin + let c0 = + unblock(); + try + Some (IO.read_byte chin) + with + | Sys_blocked_io + (* TODO: We're supposed to catch Sys_blocked_io only, but that doesn't work on my PC... *) + | Sys_error _ -> + None + in + begin match c0 with + | Some c0 -> + block(); (* We got something, make sure we block until we're done. *) + let c1 = IO.read_byte chin in + let c2 = IO.read_byte chin in + let c3 = IO.read_byte chin in + let len = c3 lsl 24 + c2 lsl 16 + c1 lsl 8 + c0 in + Some (IO.really_nread_string chin len) + | None -> + None + end + end + else read_nonblock in let write = Buffer.add_string bout in @@ -721,19 +760,19 @@ let mk_length_prefixed_communication chin chout = fun () -> Buffer.clear bout; - read, write, close + allow_nonblock, read, write, close (* The accept-function to wait for a stdio connection. *) let init_wait_stdio() = set_binary_mode_in stdin true; set_binary_mode_out stderr true; - mk_length_prefixed_communication stdin stderr + mk_length_prefixed_communication false stdin stderr (* Connect to given host/port and return accept function for communication *) let init_wait_connect host port = let host = Unix.inet_addr_of_string host in let chin, chout = Unix.open_connection (Unix.ADDR_INET (host,port)) in - mk_length_prefixed_communication chin chout + mk_length_prefixed_communication true chin chout (* The accept-function to wait for a socket connection. *) let init_wait_socket host port = @@ -771,10 +810,10 @@ let init_wait_socket host port = read_loop (count + 1); end in - let read = fun() -> (let s = read_loop 0 in Unix.clear_nonblock sin; s) in + let read = fun _ -> (let s = read_loop 0 in Unix.clear_nonblock sin; Some s) in let write s = ssend sin (Bytes.unsafe_of_string s) in let close() = Unix.close sin in - read, write, close + false, read, write, close ) in accept @@ -782,8 +821,19 @@ let init_wait_socket host port = let do_connect host port args = let sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in (try Unix.connect sock (Unix.ADDR_INET (Unix.inet_addr_of_string host,port)) with _ -> failwith ("Couldn't connect on " ^ host ^ ":" ^ string_of_int port)); + let rec display_stdin args = + match args with + | [] -> "" + | "-D" :: ("display_stdin" | "display-stdin") :: _ -> + let accept = init_wait_stdio() in + let _, read, _, _ = accept() in + Option.default "" (read true) + | _ :: args -> + display_stdin args + in let args = ("--cwd " ^ Unix.getcwd()) :: args in - ssend sock (Bytes.of_string (String.concat "" (List.map (fun a -> a ^ "\n") args) ^ "\000")); + let s = (String.concat "" (List.map (fun a -> a ^ "\n") args)) ^ (display_stdin args) in + ssend sock (Bytes.of_string (s ^ "\000")); let has_error = ref false in let rec print line = match (if line = "" then '\x00' else line.[0]) with diff --git a/src/context/abstractCast.ml b/src/context/abstractCast.ml index 12f0a548030cfcd6706a0e28b37d6c728aa3e0bf..8a57ef8031b919550c1d6824d4075bb7bc034bb0 100644 --- a/src/context/abstractCast.ml +++ b/src/context/abstractCast.ml @@ -21,7 +21,7 @@ let rec make_static_call ctx c cf a pl args t p = let e = try cast_or_unify_raise ctx t e p with Error(Unify _,_) -> raise Not_found in f(); e - | _ -> assert false + | _ -> die "" __LOC__ end else Typecore.make_static_call ctx c cf (apply_params a.a_params pl) args t p @@ -49,7 +49,7 @@ and do_check_cast ctx tleft eright p = let ret = make_static_call ctx c cf a tl [eright] tleft p in { ret with eexpr = TMeta( (Meta.ImplicitCast,[],ret.epos), ret) } ) - | None -> assert false + | None -> die "" __LOC__ in if type_iseq tleft eright.etype then eright @@ -110,7 +110,8 @@ and cast_or_unify ctx tleft eright p = let find_array_access_raise ctx a pl e1 e2o p = let is_set = e2o <> None in let ta = apply_params a.a_params pl a.a_this in - let rec loop cfl = match cfl with + let rec loop cfl = + match cfl with | [] -> raise Not_found | cf :: cfl -> let monos = List.map (fun _ -> mk_mono()) cf.cf_params in @@ -122,10 +123,14 @@ let find_array_access_raise ctx a pl e1 e2o p = | _ -> () ) monos cf.cf_params; in + let get_ta() = + if has_meta Meta.Impl cf.cf_meta then ta + else TAbstract(a,pl) + in match follow (map cf.cf_type) with | TFun([(_,_,tab);(_,_,ta1);(_,_,ta2)],r) as tf when is_set -> begin try - Type.unify tab ta; + Type.unify tab (get_ta()); let e1 = cast_or_unify_raise ctx ta1 e1 p in let e2o = match e2o with None -> None | Some e2 -> Some (cast_or_unify_raise ctx ta2 e2 p) in check_constraints(); @@ -135,7 +140,7 @@ let find_array_access_raise ctx a pl e1 e2o p = end | TFun([(_,_,tab);(_,_,ta1)],r) as tf when not is_set -> begin try - Type.unify tab ta; + Type.unify tab (get_ta()); let e1 = cast_or_unify_raise ctx ta1 e1 p in check_constraints(); cf,tf,r,e1,None @@ -148,11 +153,13 @@ let find_array_access_raise ctx a pl e1 e2o p = let find_array_access ctx a tl e1 e2o p = try find_array_access_raise ctx a tl e1 e2o p - with Not_found -> match e2o with + with Not_found -> + let s_type = s_type (print_context()) in + match e2o with | None -> - error (Printf.sprintf "No @:arrayAccess function accepts argument of %s" (s_type (print_context()) e1.etype)) p + error (Printf.sprintf "No @:arrayAccess function for %s accepts argument of %s" (s_type (TAbstract(a,tl))) (s_type e1.etype)) p | Some e2 -> - error (Printf.sprintf "No @:arrayAccess function accepts arguments of %s and %s" (s_type (print_context()) e1.etype) (s_type (print_context()) e2.etype)) p + error (Printf.sprintf "No @:arrayAccess function for %s accepts arguments of %s and %s" (s_type (TAbstract(a,tl))) (s_type e1.etype) (s_type e2.etype)) p let find_multitype_specialization com a pl p = let m = mk_mono() in @@ -188,7 +195,7 @@ let find_multitype_specialization com a pl p = stack := t :: !stack; match follow t with | TAbstract ({ a_path = [],"Class" },_) -> - error (Printf.sprintf "Cannot use %s as key type to Map because Class is not comparable" (s_type (print_context()) t1)) p; + error (Printf.sprintf "Cannot use %s as key type to Map because Class is not comparable on JavaScript" (s_type (print_context()) t1)) p; | TEnum(en,tl) -> PMap.iter (fun _ ef -> ignore(loop ef.ef_type)) en.e_constrs; Type.map loop t @@ -197,7 +204,7 @@ let find_multitype_specialization com a pl p = end in ignore(loop t1) - | _ -> assert false + | _ -> die "" __LOC__ end; tl in @@ -239,7 +246,7 @@ let handle_abstract_casts ctx e = e end | _ -> - assert false + die "" __LOC__ end | TCall(e1, el) -> begin try diff --git a/src/context/common.ml b/src/context/common.ml index 500d448a4931a0e0cb216ec122945f9f7c395f94..66c66422a52d6c7308ec288e1bb3f74372ff7c27 100644 --- a/src/context/common.ml +++ b/src/context/common.ml @@ -79,6 +79,62 @@ type capture_policy = (** similar to wrap ref, but will only apply to the locals that are declared in loops *) | CPLoopVars +type exceptions_config = { + (* Base types which may be thrown from Haxe code without wrapping. *) + ec_native_throws : path list; + (* Base types which may be caught from Haxe code without wrapping. *) + ec_native_catches : path list; + (* Path of a native class or interface, which can be used for wildcard catches. *) + ec_wildcard_catch : path; + (* + Path of a native base class or interface, which can be thrown. + This type is used to cast `haxe.Exception.thrown(v)` calls to. + For example `throw 123` is compiled to `throw (cast Exception.thrown(123):ec_base_throw)` + *) + ec_base_throw : path; +} + +type var_scope = + | FunctionScope + | BlockScope + +type var_scoping_flags = + (** + Variables are hoisted in their scope + *) + | VarHoisting + (** + It's not allowed to shadow existing variables in a scope. + *) + | NoShadowing + (** + Local vars cannot have the same name as the current top-level package or + (if in the root package) current class name + *) + | ReserveCurrentTopLevelSymbol + (** + Local vars cannot have a name used for any top-level symbol + (packages and classes in the root package) + *) + | ReserveAllTopLevelSymbols + (** + Reserve all type-paths converted to "flat path" with `Path.flat_path` + *) + | ReserveAllTypesFlat + (** + List of names cannot be taken by local vars + *) + | ReserveNames of string list + (** + Cases in a `switch` won't have blocks, but will share the same outer scope. + *) + | SwitchCasesNoBlocks + +type var_scoping_config = { + vs_flags : var_scoping_flags list; + vs_scope : var_scope; +} + type platform_config = { (** has a static type system, with not-nullable basic types (Int/Float/Bool) *) pf_static : bool; @@ -106,6 +162,10 @@ type platform_config = { pf_supports_threads : bool; (** target supports Unicode **) pf_supports_unicode : bool; + (** exceptions handling config **) + pf_exceptions : exceptions_config; + (** the scoping of local variables *) + pf_scoping : var_scoping_config; } class compiler_callbacks = object(self) @@ -153,14 +213,11 @@ class compiler_callbacks = object(self) end type shared_display_information = { - mutable import_positions : (pos,bool ref * placed_name list) PMap.t; mutable diagnostics_messages : (string * pos * DisplayTypes.DiagnosticsKind.t * DisplayTypes.DiagnosticsSeverity.t) list; - mutable dead_blocks : (string,(pos * expr) list) Hashtbl.t; } type display_information = { mutable unresolved_identifiers : (string * pos * (string * CompletionItem.t * int) list) list; - mutable interface_field_implementations : (tclass * tclass_field * tclass * tclass_field option) list; mutable display_module_has_macro_defines : bool; } @@ -323,6 +380,16 @@ let default_config = pf_this_before_super = true; pf_supports_threads = false; pf_supports_unicode = true; + pf_exceptions = { + ec_native_throws = []; + ec_native_catches = []; + ec_wildcard_catch = (["StdTypes"],"Dynamic"); + ec_base_throw = (["StdTypes"],"Dynamic"); + }; + pf_scoping = { + vs_scope = BlockScope; + vs_flags = []; + } } let get_config com = @@ -331,13 +398,26 @@ let get_config com = | Cross -> default_config | Js -> + let es6 = get_es_version com >= 6 in { default_config with pf_static = false; pf_sys = false; - pf_capture_policy = CPLoopVars; + pf_capture_policy = if es6 then CPNone else CPLoopVars; pf_reserved_type_paths = [([],"Object");([],"Error")]; - pf_this_before_super = (get_es_version com) < 6; (* cannot access `this` before `super()` when generating ES6 classes *) + pf_this_before_super = not es6; (* cannot access `this` before `super()` when generating ES6 classes *) + pf_exceptions = { default_config.pf_exceptions with + ec_native_throws = [ + ["js";"lib"],"Error"; + ["haxe"],"Exception"; + ]; + }; + pf_scoping = { + vs_scope = if es6 then BlockScope else FunctionScope; + vs_flags = + (if defined Define.JsUnflatten then ReserveAllTopLevelSymbols else ReserveAllTypesFlat) + :: if es6 then [NoShadowing; SwitchCasesNoBlocks;] else [VarHoisting]; + } } | Lua -> { @@ -354,14 +434,9 @@ let get_config com = pf_uses_utf16 = false; pf_supports_threads = true; pf_supports_unicode = false; - } - | Flash when defined Define.As3 -> - { - default_config with - pf_sys = false; - pf_capture_policy = CPLoopVars; - pf_add_final_return = true; - pf_can_skip_non_nullable_argument = false; + pf_scoping = { default_config.pf_scoping with + vs_flags = [ReserveAllTopLevelSymbols]; + } } | Flash -> { @@ -370,12 +445,38 @@ let get_config com = pf_capture_policy = CPLoopVars; pf_can_skip_non_nullable_argument = false; pf_reserved_type_paths = [([],"Object");([],"Error")]; + pf_exceptions = { default_config.pf_exceptions with + ec_native_throws = [ + ["flash";"errors"],"Error"; + ["haxe"],"Exception"; + ]; + ec_native_catches = [ + ["flash";"errors"],"Error"; + ["haxe"],"Exception"; + ]; + } } | Php -> { default_config with pf_static = false; pf_uses_utf16 = false; + pf_exceptions = { + ec_native_throws = [ + ["php"],"Throwable"; + ["haxe"],"Exception"; + ]; + ec_native_catches = [ + ["php"],"Throwable"; + ["haxe"],"Exception"; + ]; + ec_wildcard_catch = (["php"],"Throwable"); + ec_base_throw = (["php"],"Throwable"); + }; + pf_scoping = { + vs_scope = FunctionScope; + vs_flags = [VarHoisting] + } } | Cpp -> { @@ -385,6 +486,9 @@ let get_config com = pf_add_final_return = true; pf_supports_threads = true; pf_supports_unicode = (defined Define.Cppia) || not (defined Define.DisableUnicodeStrings); + pf_scoping = { default_config.pf_scoping with + vs_flags = [NoShadowing] + } } | Cs -> { @@ -393,6 +497,22 @@ let get_config com = pf_pad_nulls = true; pf_overload = true; pf_supports_threads = true; + pf_exceptions = { + ec_native_throws = [ + ["cs";"system"],"Exception"; + ["haxe"],"Exception"; + ]; + ec_native_catches = [ + ["cs";"system"],"Exception"; + ["haxe"],"Exception"; + ]; + ec_wildcard_catch = (["cs";"system"],"Exception"); + ec_base_throw = (["cs";"system"],"Exception"); + }; + pf_scoping = { + vs_scope = FunctionScope; + vs_flags = [NoShadowing] + }; } | Java -> { @@ -402,6 +522,26 @@ let get_config com = pf_overload = true; pf_supports_threads = true; pf_this_before_super = false; + pf_exceptions = { + ec_native_throws = [ + ["java";"lang"],"RuntimeException"; + ["haxe"],"Exception"; + ]; + ec_native_catches = [ + ["java";"lang"],"Throwable"; + ["haxe"],"Exception"; + ]; + ec_wildcard_catch = (["java";"lang"],"Throwable"); + ec_base_throw = (["java";"lang"],"RuntimeException"); + }; + pf_scoping = + if defined Jvm then + default_config.pf_scoping + else + { + vs_scope = FunctionScope; + vs_flags = [NoShadowing; ReserveAllTopLevelSymbols; ReserveNames(["_"])]; + } } | Python -> { @@ -409,6 +549,20 @@ let get_config com = pf_static = false; pf_capture_policy = CPLoopVars; pf_uses_utf16 = false; + pf_exceptions = { + ec_native_throws = [ + ["python";"Exceptions"],"BaseException"; + ]; + ec_native_catches = [ + ["python";"Exceptions"],"BaseException"; + ]; + ec_wildcard_catch = ["python";"Exceptions"],"BaseException"; + ec_base_throw = ["python";"Exceptions"],"BaseException"; + }; + pf_scoping = { + vs_scope = FunctionScope; + vs_flags = [VarHoisting] + }; } | Hl -> { @@ -416,6 +570,14 @@ let get_config com = pf_capture_policy = CPWrapRef; pf_pad_nulls = true; pf_supports_threads = true; + pf_exceptions = { default_config.pf_exceptions with + ec_native_throws = [ + ["haxe"],"Exception"; + ]; + ec_native_catches = [ + ["haxe"],"Exception"; + ]; + } } | Eval -> { @@ -443,14 +605,11 @@ let create version s_version args = args = args; shared = { shared_display_information = { - import_positions = PMap.empty; diagnostics_messages = []; - dead_blocks = Hashtbl.create 0; } }; display_information = { unresolved_identifiers = []; - interface_field_implementations = []; display_module_has_macro_defines = false; }; sys_args = args; @@ -487,9 +646,9 @@ let create version s_version args = values = defines; }; get_macros = (fun() -> None); - info = (fun _ _ -> assert false); - warning = (fun _ _ -> assert false); - error = (fun _ _ -> assert false); + info = (fun _ _ -> die "" __LOC__); + warning = (fun _ _ -> die "" __LOC__); + error = (fun _ _ -> die "" __LOC__); get_messages = (fun() -> []); filter_messages = (fun _ -> ()); pass_debug_messages = DynArray.create(); @@ -498,9 +657,9 @@ let create version s_version args = tint = m; tfloat = m; tbool = m; - tnull = (fun _ -> assert false); + tnull = (fun _ -> die "" __LOC__); tstring = m; - tarray = (fun _ -> assert false); + tarray = (fun _ -> die "" __LOC__); }; file_lookup_cache = Hashtbl.create 0; readdir_cache = Hashtbl.create 0; @@ -529,7 +688,6 @@ let clone com = callbacks = new compiler_callbacks; display_information = { unresolved_identifiers = []; - interface_field_implementations = []; display_module_has_macro_defines = false; }; defines = { @@ -624,7 +782,7 @@ let rec has_feature com f = with Not_found -> if com.types = [] then not (has_dce com) else match List.rev (ExtString.String.nsplit f ".") with - | [] -> assert false + | [] -> die "" __LOC__ | [cl] -> has_feature com (cl ^ ".*") | field :: cl :: pack -> let r = (try @@ -826,7 +984,7 @@ let utf16_to_utf8 str = add (c lsr 8); loop (i + 2); end else - assert false; + die "" __LOC__; end in loop 0; @@ -864,4 +1022,12 @@ let adapt_defines_to_macro_context defines = let is_legacy_completion com = match com.json_out with | None -> true - | Some api -> !ServerConfig.legacy_completion \ No newline at end of file + | Some api -> !ServerConfig.legacy_completion + +let get_entry_point com = + Option.map (fun path -> + let m = List.find (fun m -> m.m_path = path) com.modules in + let c = ExtList.List.find_map (fun t -> match t with TClassDecl c when c.cl_path = path -> Some c | _ -> None) m.m_types in + let e = Option.get com.main in (* must be present at this point *) + (snd path, c, e) + ) com.main_class diff --git a/src/context/compilationServer.ml b/src/context/compilationServer.ml index 434121aeac23f36381f15252423a748d2152d3bd..d3073ba060f86c428433f417d4f59d860d3cdcf3 100644 --- a/src/context/compilationServer.ml +++ b/src/context/compilationServer.ml @@ -5,10 +5,12 @@ open Type open Define type cached_file = { + c_file_path : string; c_time : float; c_package : string list; c_decls : type_decl list; mutable c_module_name : string option; + mutable c_pdi : Parser.parser_display_information; } type cached_directory = { @@ -22,7 +24,7 @@ type cached_native_lib = { } class context_cache (index : int) = object(self) - val files : (string,cached_file) Hashtbl.t = Hashtbl.create 0 + val files : (Path.UniqueKey.t,cached_file) Hashtbl.t = Hashtbl.create 0 val modules : (path,module_def) Hashtbl.t = Hashtbl.create 0 val removed_files = Hashtbl.create 0 val mutable json = JNull @@ -33,14 +35,15 @@ class context_cache (index : int) = object(self) method find_file key = Hashtbl.find files key - method cache_file key time data = - Hashtbl.replace files key { c_time = time; c_package = fst data; c_decls = snd data; c_module_name = None } + method cache_file key path time data pdi = + Hashtbl.replace files key { c_file_path = path; c_time = time; c_package = fst data; c_decls = snd data; c_module_name = None; c_pdi = pdi } method remove_file key = - if Hashtbl.mem files key then begin + try + let f = Hashtbl.find files key in Hashtbl.remove files key; - Hashtbl.replace removed_files key () - end + Hashtbl.replace removed_files key f.c_file_path + with Not_found -> () (* Like remove_file, but doesn't keep track of the file *) method remove_file_for_real key = @@ -77,12 +80,24 @@ let create_directory path mtime = { c_mtime = mtime; } +class virtual server_task (id : string list) (priority : int) = object(self) + method private virtual execute : unit + + method run : unit = + let t = Timer.timer ("server" :: "task" :: id) in + Std.finally t (fun () -> self#execute) () + + method get_priority = priority + method get_id = id +end + class cache = object(self) val contexts : (string,context_cache) Hashtbl.t = Hashtbl.create 0 val mutable context_list = [] val haxelib : (string list, string list) Hashtbl.t = Hashtbl.create 0 val directories : (string, cached_directory list) Hashtbl.t = Hashtbl.create 0 val native_libs : (string,cached_native_lib) Hashtbl.t = Hashtbl.create 0 + val mutable tasks : (server_task PriorityQueue.t) = PriorityQueue.Empty (* contexts *) @@ -131,6 +146,13 @@ class cache = object(self) (* modules *) + method iter_modules f = + Hashtbl.iter (fun _ cc -> + Hashtbl.iter (fun _ m -> + f m + ) cc#get_modules + ) contexts + method get_modules = Hashtbl.fold (fun _ cc acc -> Hashtbl.fold (fun _ m acc -> @@ -138,10 +160,10 @@ class cache = object(self) ) cc#get_modules acc ) contexts [] - method taint_modules file = + method taint_modules file_key = Hashtbl.iter (fun _ cc -> Hashtbl.iter (fun _ m -> - if m.m_extra.m_file = file then m.m_extra.m_dirty <- Some m.m_path + if Path.UniqueKey.create m.m_extra.m_file = file_key then m.m_extra.m_dirty <- Some m.m_path ) cc#get_modules ) contexts @@ -193,6 +215,36 @@ class cache = object(self) try Some (Hashtbl.find native_libs key) with Not_found -> None + (* tasks *) + + method add_task (task : server_task) : unit = + tasks <- PriorityQueue.insert tasks task#get_priority task + + method has_task = + not (PriorityQueue.is_empty tasks) + + method get_task = + let (_,task,queue) = PriorityQueue.extract tasks in + tasks <- queue; + task + + method run_tasks recursive f = + let rec loop acc = + let current = tasks in + tasks <- Empty; + let f (ran_task,acc) prio task = + if f task then begin + task#run; + (true,acc) + end else + ran_task,PriorityQueue.insert acc prio task + in + let ran_task,folded = PriorityQueue.fold current f (false,acc) in + if recursive && ran_task then loop folded + else folded + in + tasks <- PriorityQueue.merge tasks (loop PriorityQueue.Empty); + (* Pointers for memory inspection. *) method get_pointers : unit array = [|Obj.magic contexts;Obj.magic haxelib;Obj.magic directories;Obj.magic native_libs|] @@ -219,7 +271,7 @@ let get () = let runs () = !instance <> None -let force () = match !instance with None -> assert false | Some i -> i +let force () = match !instance with None -> die "" __LOC__ | Some i -> i let get_module_name_of_cfile file cfile = match cfile.c_module_name with | None -> diff --git a/src/context/display/deprecationCheck.ml b/src/context/display/deprecationCheck.ml index 8478d7347785bdc27cffbb1bafdc8891f5022aa1..fb1da87d35db6b7c3fb43738ad92ae35df976dbe 100644 --- a/src/context/display/deprecationCheck.ml +++ b/src/context/display/deprecationCheck.ml @@ -8,8 +8,9 @@ let curclass = ref null_class let warned_positions = Hashtbl.create 0 let warn_deprecation com s p_usage = - if not (Hashtbl.mem warned_positions p_usage) then begin - Hashtbl.replace warned_positions p_usage s; + let pkey p = (p.pfile,p.pmin) in + if not (Hashtbl.mem warned_positions (pkey p_usage)) then begin + Hashtbl.add warned_positions (pkey p_usage) (s,p_usage); match com.display.dms_kind with | DMDiagnostics _ -> () | _ -> com.warning s p_usage; @@ -93,4 +94,31 @@ let run com = curclass := null_class; | _ -> () - ) com.types \ No newline at end of file + ) com.types + +let if_enabled ?(force=false) com fn = + if force || not (defined com Define.NoDeprecationWarnings) then fn() + +let warn_deprecation ?(force=false) com s p_usage = if_enabled ~force com (fun() -> warn_deprecation com s p_usage) + +let print_deprecation_message ?(force=false) com meta s p_usage = if_enabled ~force com (fun() -> print_deprecation_message com meta s p_usage) + +let check_meta ?(force=false) com meta s p_usage = if_enabled ~force com (fun() -> check_meta com meta s p_usage) + +let check_cf ?(force=false) com cf p = if_enabled ~force com (fun() -> check_cf com cf p) + +let check_class ?(force=false) com c p = if_enabled ~force com (fun() -> check_class com c p) + +let check_enum ?(force=false) com en p = if_enabled ~force com (fun() -> check_enum com en p) + +let check_ef ?(force=false) com ef p = if_enabled ~force com (fun() -> check_ef com ef p) + +let check_typedef ?(force=false) com t p = if_enabled ~force com (fun() -> check_typedef com t p) + +let check_module_type ?(force=false) com mt p = if_enabled ~force com (fun() -> check_module_type com mt p) + +let run_on_expr ?(force=false) com e = if_enabled ~force com (fun() -> run_on_expr com e) + +let run_on_field ?(force=false) com cf = if_enabled ~force com (fun() -> run_on_field com cf) + +let run ?(force=false) com = if_enabled ~force com (fun() -> run com) \ No newline at end of file diff --git a/src/context/display/diagnostics.ml b/src/context/display/diagnostics.ml index d59309a0fda976e3439fe40a3f2b621e4d9d26c6..9fea1c72d0013978ef51eeeba49e8ef46c31cd16 100644 --- a/src/context/display/diagnostics.ml +++ b/src/context/display/diagnostics.ml @@ -5,17 +5,15 @@ open Typecore open Common open Display open DisplayTypes.DisplayMode - -type diagnostics_context = { - com : Common.context; - mutable removable_code : (string * pos * pos) list; -} - open DisplayTypes +open DisplayException +open DiagnosticsTypes let add_removable_code ctx s p prange = ctx.removable_code <- (s,p,prange) :: ctx.removable_code +let is_diagnostics_run p = DiagnosticsPrinter.is_diagnostics_file p.pfile + let find_unused_variables com e = let vars = Hashtbl.create 0 in let pmin_map = Hashtbl.create 0 in @@ -93,137 +91,82 @@ let check_other_things com e = in loop true e -let prepare_field dctx cf = match cf.cf_expr with +let prepare_field dctx com cf = match cf.cf_expr with | None -> () | Some e -> find_unused_variables dctx e; - check_other_things dctx.com e; - DeprecationCheck.run_on_expr dctx.com e + check_other_things com e; + DeprecationCheck.run_on_expr ~force:true com e -let prepare com global = +let prepare com = let dctx = { removable_code = []; - com = com; + import_positions = PMap.empty; + dead_blocks = Hashtbl.create 0; + diagnostics_messages = []; + unresolved_identifiers = []; } in List.iter (function - | TClassDecl c when global || DisplayPosition.display_position#is_in_file c.cl_pos.pfile -> - List.iter (prepare_field dctx) c.cl_ordered_fields; - List.iter (prepare_field dctx) c.cl_ordered_statics; - (match c.cl_constructor with None -> () | Some cf -> prepare_field dctx cf); + | TClassDecl c when DiagnosticsPrinter.is_diagnostics_file c.cl_pos.pfile -> + List.iter (prepare_field dctx com) c.cl_ordered_fields; + List.iter (prepare_field dctx com) c.cl_ordered_statics; + (match c.cl_constructor with None -> () | Some cf -> prepare_field dctx com cf); | _ -> () ) com.types; + let handle_dead_blocks com = match com.cache with + | Some cc -> + let macro_defines = adapt_defines_to_macro_context com.defines in + let display_defines = {macro_defines with values = PMap.add "display" "1" macro_defines.values} in + let is_true defines e = + ParserEntry.is_true (ParserEntry.eval defines e) + in + Hashtbl.iter (fun file_key cfile -> + if DisplayPosition.display_position#is_in_file cfile.CompilationServer.c_file_path then begin + let dead_blocks = cfile.CompilationServer.c_pdi.pd_dead_blocks in + let dead_blocks = List.filter (fun (_,e) -> not (is_true display_defines e)) dead_blocks in + try + let dead_blocks2 = Hashtbl.find dctx.dead_blocks file_key in + (* Intersect *) + let dead_blocks2 = List.filter (fun (p,_) -> List.mem_assoc p dead_blocks) dead_blocks2 in + Hashtbl.replace dctx.dead_blocks file_key dead_blocks2 + with Not_found -> + Hashtbl.add dctx.dead_blocks file_key dead_blocks + end + ) cc#get_files + | None -> + () + in + handle_dead_blocks com; + let process_modules com = + List.iter (fun m -> + PMap.iter (fun p b -> + if not (PMap.mem p dctx.import_positions) then + dctx.import_positions <- PMap.add p b dctx.import_positions + else if !b then begin + let b' = PMap.find p dctx.import_positions in + b' := true + end + ) m.m_extra.m_display.m_import_positions + ) com.modules + in + process_modules com; + begin match com.get_macros() with + | None -> () + | Some com -> process_modules com + end; + (* We do this at the end because some of the prepare functions might add information to the common context. *) + dctx.diagnostics_messages <- com.shared.shared_display_information.diagnostics_messages; + dctx.unresolved_identifiers <- com.display_information.unresolved_identifiers; dctx -let is_diagnostics_run p = match (!Parser.display_mode) with - | DMDiagnostics true -> true - | DMDiagnostics false -> DisplayPosition.display_position#is_in_file p.pfile - | _ -> false - let secure_generated_code ctx e = if is_diagnostics_run e.epos then mk (TMeta((Meta.Extern,[],e.epos),e)) e.etype e.epos else e -module Printer = struct - open Json - open DiagnosticsKind - open DisplayTypes - - type t = DiagnosticsKind.t * pos - - module UnresolvedIdentifierSuggestion = struct - type t = - | UISImport - | UISTypo - - let to_int = function - | UISImport -> 0 - | UISTypo -> 1 - end - - open UnresolvedIdentifierSuggestion - open CompletionItem - open CompletionModuleType - - let print_diagnostics dctx com global = - let diag = Hashtbl.create 0 in - let add dk p sev args = - let file = if p = null_pos then p.pfile else Path.get_real_path p.pfile in - let diag = try - Hashtbl.find diag file - with Not_found -> - let d = Hashtbl.create 0 in - Hashtbl.add diag file d; - d - in - if not (Hashtbl.mem diag p) then - Hashtbl.add diag p (dk,p,sev,args) - in - let add dk p sev args = - if global || p = null_pos || DisplayPosition.display_position#is_in_file p.pfile then add dk p sev args - in - List.iter (fun (s,p,suggestions) -> - let suggestions = ExtList.List.filter_map (fun (s,item,r) -> - match item.ci_kind with - | ITType(t,_) when r = 0 -> - let path = if t.module_name = t.name then (t.pack,t.name) else (t.pack @ [t.module_name],t.name) in - Some (JObject [ - "kind",JInt (to_int UISImport); - "name",JString (s_type_path path); - ]) - | _ when r = 0 -> - (* TODO !!! *) - None - | _ -> - Some (JObject [ - "kind",JInt (to_int UISTypo); - "name",JString s; - ]) - ) suggestions in - add DKUnresolvedIdentifier p DiagnosticsSeverity.Error (JArray suggestions); - ) com.display_information.unresolved_identifiers; - PMap.iter (fun p (r,_) -> - if not !r then add DKUnusedImport p DiagnosticsSeverity.Warning (JArray []) - ) com.shared.shared_display_information.import_positions; - List.iter (fun (s,p,kind,sev) -> - add kind p sev (JString s) - ) (List.rev com.shared.shared_display_information.diagnostics_messages); - List.iter (fun (s,p,prange) -> - add DKRemovableCode p DiagnosticsSeverity.Warning (JObject ["description",JString s;"range",if prange = null_pos then JNull else Genjson.generate_pos_as_range prange]) - ) dctx.removable_code; - Hashtbl.iter (fun p s -> - add DKDeprecationWarning p DiagnosticsSeverity.Warning (JString s); - ) DeprecationCheck.warned_positions; - Hashtbl.iter (fun file ranges -> - List.iter (fun (p,e) -> - let jo = JObject [ - "expr",JObject [ - "string",JString (Ast.Printer.s_expr e) - ] - ] in - add DKInactiveBlock p DiagnosticsSeverity.Hint jo - ) ranges - ) com.shared.shared_display_information.dead_blocks; - let jl = Hashtbl.fold (fun file diag acc -> - let jl = Hashtbl.fold (fun _ (dk,p,sev,jargs) acc -> - (JObject [ - "kind",JInt (DiagnosticsKind.to_int dk); - "severity",JInt (DiagnosticsSeverity.to_int sev); - "range",Genjson.generate_pos_as_range p; - "args",jargs - ]) :: acc - ) diag [] in - (JObject [ - "file",if file = "?" then JNull else JString file; - "diagnostics",JArray jl - ]) :: acc - ) diag [] in - let js = JArray jl in - string_of_json js -end - -let print com global = - let dctx = prepare com global in - Printer.print_diagnostics dctx com global +let print com = + let dctx = prepare com in + Json.string_of_json (DiagnosticsPrinter.json_of_diagnostics dctx) -let run com global = - DisplayException.raise_diagnostics (print com global) \ No newline at end of file +let run com = + let dctx = prepare com in + DisplayException.raise_diagnostics dctx \ No newline at end of file diff --git a/src/context/display/diagnosticsPrinter.ml b/src/context/display/diagnosticsPrinter.ml new file mode 100644 index 0000000000000000000000000000000000000000..a0561f61dd357dc22ed078d3c9708d1857c00e6d --- /dev/null +++ b/src/context/display/diagnosticsPrinter.ml @@ -0,0 +1,105 @@ +open Globals +open Json +open DisplayTypes +open DiagnosticsKind +open DisplayTypes +open DiagnosticsTypes + +type t = DiagnosticsKind.t * pos + +let is_diagnostics_file file = + let key = Path.UniqueKey.create file in + match (!Parser.display_mode) with + | DMDiagnostics [] -> true + | DMDiagnostics file_keys -> List.exists (fun key' -> key = key') file_keys + | _ -> false + +module UnresolvedIdentifierSuggestion = struct + type t = + | UISImport + | UISTypo + + let to_int = function + | UISImport -> 0 + | UISTypo -> 1 +end + +open UnresolvedIdentifierSuggestion +open CompletionItem +open CompletionModuleType + +let json_of_diagnostics dctx = + let diag = Hashtbl.create 0 in + let add dk p sev args = + let file = if p = null_pos then p.pfile else Path.get_real_path p.pfile in + let diag = try + Hashtbl.find diag file + with Not_found -> + let d = Hashtbl.create 0 in + Hashtbl.add diag file d; + d + in + if not (Hashtbl.mem diag p) then + Hashtbl.add diag p (dk,p,sev,args) + in + let add dk p sev args = + if p = null_pos || is_diagnostics_file p.pfile then add dk p sev args + in + List.iter (fun (s,p,suggestions) -> + let suggestions = ExtList.List.filter_map (fun (s,item,r) -> + match item.ci_kind with + | ITType(t,_) when r = 0 -> + let path = if t.module_name = t.name then (t.pack,t.name) else (t.pack @ [t.module_name],t.name) in + Some (JObject [ + "kind",JInt (to_int UISImport); + "name",JString (s_type_path path); + ]) + | _ when r = 0 -> + (* TODO !!! *) + None + | _ -> + Some (JObject [ + "kind",JInt (to_int UISTypo); + "name",JString s; + ]) + ) suggestions in + add DKUnresolvedIdentifier p DiagnosticsSeverity.Error (JArray suggestions); + ) dctx.unresolved_identifiers; + PMap.iter (fun p r -> + if not !r then add DKUnusedImport p DiagnosticsSeverity.Warning (JArray []) + ) dctx.import_positions; + List.iter (fun (s,p,kind,sev) -> + add kind p sev (JString s) + ) (List.rev dctx.diagnostics_messages); + List.iter (fun (s,p,prange) -> + add DKRemovableCode p DiagnosticsSeverity.Warning (JObject ["description",JString s;"range",if prange = null_pos then JNull else Genjson.generate_pos_as_range prange]) + ) dctx.removable_code; + Hashtbl.iter (fun _ (s,p) -> + add DKDeprecationWarning p DiagnosticsSeverity.Warning (JString s); + ) DeprecationCheck.warned_positions; + Hashtbl.iter (fun file ranges -> + List.iter (fun (p,e) -> + let jo = JObject [ + "expr",JObject [ + "string",JString (Ast.Printer.s_expr e) + ] + ] in + add DKInactiveBlock p DiagnosticsSeverity.Hint jo + ) ranges + ) dctx.dead_blocks; + let jl = Hashtbl.fold (fun file diag acc -> + let jl = Hashtbl.fold (fun _ (dk,p,sev,jargs) acc -> + (JObject [ + "kind",JInt (DiagnosticsKind.to_int dk); + "severity",JInt (DiagnosticsSeverity.to_int sev); + "range",Genjson.generate_pos_as_range p; + "args",jargs + ]) :: acc + ) diag [] in + (JObject [ + "file",if file = "?" then JNull else JString file; + "diagnostics",JArray jl + ]) :: acc + ) diag [] in + let js = JArray jl in + js \ No newline at end of file diff --git a/src/context/display/diagnosticsTypes.ml b/src/context/display/diagnosticsTypes.ml new file mode 100644 index 0000000000000000000000000000000000000000..209b3498867a8ded8fae2c47afc09c64671148a9 --- /dev/null +++ b/src/context/display/diagnosticsTypes.ml @@ -0,0 +1,10 @@ +open Globals +open Ast + +type diagnostics_context = { + mutable removable_code : (string * pos * pos) list; + mutable import_positions : (pos,bool ref) PMap.t; + mutable dead_blocks : (Path.UniqueKey.t,(pos * expr) list) Hashtbl.t; + mutable unresolved_identifiers : (string * pos * (string * CompletionItem.t * int) list) list; + mutable diagnostics_messages : (string * pos * DisplayTypes.DiagnosticsKind.t * DisplayTypes.DiagnosticsSeverity.t) list; +} \ No newline at end of file diff --git a/src/context/display/display.ml b/src/context/display/display.ml index b5aa796ddc67aa994d25701e77465c1838cc42d3..9b7535afc5069e2c1125a0c7b34f4d2ecdcf6d5c 100644 --- a/src/context/display/display.ml +++ b/src/context/display/display.ml @@ -22,8 +22,8 @@ let parse_module ctx m p = display_position#run_outside (fun () -> TypeloadParse.parse_module ctx m p) module ReferencePosition = struct - let reference_position = ref ("",null_pos,KVar) - let set (s,p,k) = reference_position := (s,{p with pfile = Path.unique_full_path p.pfile},k) + let reference_position = ref ("",null_pos,SKOther) + let set (s,p,k) = reference_position := (s,{p with pfile = Path.get_full_path p.pfile},k) let get () = !reference_position end @@ -248,7 +248,7 @@ module ExprPreprocessing = struct let process_expr com e = match com.display.dms_kind with - | DMDefinition | DMTypeDefinition | DMUsage _ | DMHover | DMDefault -> find_before_pos com.display.dms_kind e + | DMDefinition | DMTypeDefinition | DMUsage _ | DMImplementation | DMHover | DMDefault -> find_before_pos com.display.dms_kind e | DMSignature -> find_display_call e | _ -> e end @@ -315,7 +315,7 @@ let sort_fields l with_type tk = let get_import_status ctx path = try - let mt' = ctx.g.do_load_type_def ctx null_pos {tpackage = []; tname = snd path; tparams = []; tsub = None} in + let mt' = ctx.g.do_load_type_def ctx null_pos (mk_type_path ([],snd path)) in if path <> (t_infos mt').mt_path then Shadowed else Imported with _ -> Unimported diff --git a/src/context/display/displayEmitter.ml b/src/context/display/displayEmitter.ml index b74cbde063a2f055ce7190d67e01b4ef275318bb..a820f60f348d6a9c9d40426a7296f63c39bd7171 100644 --- a/src/context/display/displayEmitter.ml +++ b/src/context/display/displayEmitter.ml @@ -13,6 +13,12 @@ open Common open Display open DisplayPosition +let symbol_of_module_type = function + | TClassDecl c -> SKClass c + | TEnumDecl en -> SKEnum en + | TTypeDecl td -> SKTypedef td + | TAbstractDecl a -> SKAbstract a + let display_module_type ctx mt p = match ctx.com.display.dms_kind with | DMDefinition | DMTypeDefinition -> begin match mt with @@ -22,9 +28,9 @@ let display_module_type ctx mt p = match ctx.com.display.dms_kind with | _ -> raise_positions [(t_infos mt).mt_name_pos]; end - | DMUsage _ -> + | DMUsage _ | DMImplementation -> let infos = t_infos mt in - ReferencePosition.set (snd infos.mt_path,infos.mt_name_pos,KModuleType) + ReferencePosition.set (snd infos.mt_path,infos.mt_name_pos,symbol_of_module_type mt) | DMHover -> let t = type_of_module_type mt in let ct = CompletionType.from_type (get_import_status ctx) t in @@ -65,7 +71,7 @@ let raise_position_of_type t = let mt = let rec follow_null t = match t with - | TMono r -> (match !r with None -> raise_positions [null_pos] | Some t -> follow_null t) + | TMono r -> (match r.tm_type with None -> raise_positions [null_pos] | Some t -> follow_null t) | TLazy f -> follow_null (lazy_type f) | TAbstract({a_path = [],"Null"},[t]) -> follow_null t | TDynamic _ -> !t_dynamic_def @@ -81,7 +87,7 @@ let raise_position_of_type t = let display_variable ctx v p = match ctx.com.display.dms_kind with | DMDefinition -> raise_positions [v.v_pos] | DMTypeDefinition -> raise_position_of_type v.v_type - | DMUsage _ -> ReferencePosition.set (v.v_name,v.v_pos,KVar) + | DMUsage _ -> ReferencePosition.set (v.v_name,v.v_pos,SKVariable v) | DMHover -> let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta v.v_meta) v.v_type in raise_hover (make_ci_local v (v.v_type,ct)) None p @@ -90,13 +96,15 @@ let display_variable ctx v p = match ctx.com.display.dms_kind with let display_field ctx origin scope cf p = match ctx.com.display.dms_kind with | DMDefinition -> raise_positions [cf.cf_name_pos] | DMTypeDefinition -> raise_position_of_type cf.cf_type - | DMUsage _ -> + | DMUsage _ | DMImplementation -> let name,kind = match cf.cf_name,origin with | "new",(Self (TClassDecl c) | Parent(TClassDecl c)) -> (* For constructors, we care about the class name so we don't end up looking for "new". *) - snd c.cl_path,KConstructor + snd c.cl_path,SKConstructor cf + | _,(Self (TClassDecl c) | Parent(TClassDecl c)) -> + cf.cf_name,SKField (cf,Some c.cl_path) | _ -> - cf.cf_name,KClassField + cf.cf_name,SKField (cf,None) in ReferencePosition.set (name,cf.cf_name_pos,kind) | DMHover -> @@ -119,7 +127,7 @@ let maybe_display_field ctx origin scope cf p = let display_enum_field ctx en ef p = match ctx.com.display.dms_kind with | DMDefinition -> raise_positions [ef.ef_name_pos] | DMTypeDefinition -> raise_position_of_type ef.ef_type - | DMUsage _ -> ReferencePosition.set (ef.ef_name,ef.ef_name_pos,KEnumField) + | DMUsage _ -> ReferencePosition.set (ef.ef_name,ef.ef_name_pos,SKEnumField ef) | DMHover -> let ct = CompletionType.from_type (get_import_status ctx) ef.ef_type in raise_hover (make_ci_enum_field (CompletionEnumField.make ef (Self (TEnumDecl en)) true) (ef.ef_type,ct)) None p diff --git a/src/context/display/displayException.ml b/src/context/display/displayException.ml index d820c8428e2a7b165bf043c6bee2cd41685026ff..b8224269c150d387366997bca7db99ab5e2482f4 100644 --- a/src/context/display/displayException.ml +++ b/src/context/display/displayException.ml @@ -22,7 +22,7 @@ type signature_kind = | SKArrayAccess type kind = - | Diagnostics of string + | DisplayDiagnostics of DiagnosticsTypes.diagnostics_context | Statistics of string | ModuleSymbols of string | Metadata of string @@ -34,7 +34,7 @@ type kind = exception DisplayException of kind -let raise_diagnostics s = raise (DisplayException(Diagnostics s)) +let raise_diagnostics s = raise (DisplayException(DisplayDiagnostics s)) let raise_statistics s = raise (DisplayException(Statistics s)) let raise_module_symbols s = raise (DisplayException(ModuleSymbols s)) let raise_metadata s = raise (DisplayException(Metadata s)) @@ -50,51 +50,80 @@ let last_completion_pos = ref None let max_completion_items = ref 0 let filter_somehow ctx items kind subj = - let ret = DynArray.create () in - let acc_types = DynArray.create () in let subject = match subj.s_name with | None -> "" | Some name-> String.lowercase name in - let subject_matches s = - let rec loop i o = - if i < String.length subject then begin - let o = String.index_from s o subject.[i] in - loop (i + 1) o + let subject_length = String.length subject in + let determine_cost s = + let get_initial_cost o = + if o = 0 then + 0 (* Term starts with subject - perfect *) + else begin + (* Consider `.` as anchors and determine distance from closest one. Penalize starting distance by factor 2. *) + try + let last_anchor = String.rindex_from s o '.' in + (o - (last_anchor + 1)) * 2 + with Not_found -> + o * 2 end in - try - loop 0 0; - true - with Not_found -> - false + let index_from o c = + let rec loop o cost = + let c' = s.[o] in + if c' = c then + o,cost + else + loop (o + 1) (cost + 3) (* Holes are bad, penalize by 3. *) + in + loop o 0 + in + let rec loop i o cost = + if i < subject_length then begin + let o',new_cost = index_from o subject.[i] in + loop (i + 1) o' (cost + new_cost) + end else + cost + (if o = String.length s - 1 then 0 else 1) (* Slightly penalize for not-exact matches. *) + in + if subject_length = 0 then + 0 + else try + let o = String.index s subject.[0] in + loop 1 o (get_initial_cost o); + with Not_found | Invalid_argument _ -> + -1 in - let rec loop items index = + let rec loop acc items index = match items with - | _ when DynArray.length ret >= !max_completion_items -> - () | item :: items -> let name = String.lowercase (get_filter_name item) in - if subject_matches name then begin - (* Treat types with lowest priority. The assumption is that they are the only kind - which actually causes the limit to be hit, so we show everything else and then - fill in types. *) - match item.ci_kind with - | ITType _ -> - if DynArray.length ret + DynArray.length acc_types < !max_completion_items then - DynArray.add acc_types (item,index); - | _ -> - DynArray.add ret (CompletionItem.to_json ctx (Some index) item); - end; - loop items (index + 1) + let cost = determine_cost name in + let acc = if cost >= 0 then + (item,index,cost) :: acc + else + acc + in + loop acc items (index + 1) | [] -> - () + acc in - loop items 0; - DynArray.iter (fun (item,index) -> - if DynArray.length ret < !max_completion_items then + let acc = loop [] items 0 in + let acc = if subject_length = 0 then + List.rev acc + else + List.sort (fun (_,_,cost1) (_,_,cost2) -> + compare cost1 cost2 + ) acc + in + let ret = DynArray.create () in + let rec loop acc_types = match acc_types with + | (item,index,_) :: acc_types when DynArray.length ret < !max_completion_items -> DynArray.add ret (CompletionItem.to_json ctx (Some index) item); - ) acc_types; + loop acc_types + | _ -> + () + in + loop acc; DynArray.to_list ret,DynArray.length ret let patch_completion_subject subj = @@ -143,18 +172,19 @@ let fields_to_json ctx fields kind subj = let to_json ctx de = match de with - | Diagnostics _ | Statistics _ | ModuleSymbols _ - | Metadata _ -> assert false + | Metadata _ -> die "" __LOC__ | DisplaySignatures None -> jnull + | DisplayDiagnostics dctx -> + DiagnosticsPrinter.json_of_diagnostics dctx | DisplaySignatures Some(sigs,isig,iarg,kind) -> (* We always want full info for signatures *) let ctx = Genjson.create_context GMFull in let fsig ((_,signature),doc) = let fl = CompletionType.generate_function' ctx signature in - let fl = (match doc with None -> fl | Some s -> ("documentation",jstring s) :: fl) in + let fl = (match doc with None -> fl | Some d -> ("documentation",jstring (gen_doc_text d)) :: fl) in jobject fl in let sigkind = match kind with @@ -173,7 +203,7 @@ let to_json ctx de = let named_source_kind = function | WithType.FunctionArgument name -> (0, name) | WithType.StructureField name -> (1, name) - | _ -> assert false + | _ -> die "" __LOC__ in let ctx = Genjson.create_context GMFull in let generate_name kind = @@ -196,7 +226,7 @@ let to_json ctx de = | _ -> jnull in jobject [ - "documentation",jopt jstring (CompletionItem.get_documentation hover.hitem); + "documentation",jopt jstring (gen_doc_text_opt (CompletionItem.get_documentation hover.hitem)); "range",generate_pos_as_range hover.hpos; "item",CompletionItem.to_json ctx None hover.hitem; "expected",expected; diff --git a/src/context/display/displayFields.ml b/src/context/display/displayFields.ml index 0bc069d35cb68a4353ee1df074406106d44ae924..4b8ea68874dcd03687a364ba5cc7d75f8038e199 100644 --- a/src/context/display/displayFields.ml +++ b/src/context/display/displayFields.ml @@ -265,7 +265,7 @@ let collect ctx e_ast e dk with_type p = let items = match fst e_ast with | EConst(String(s,_)) when String.length s = 1 -> let cf = mk_field "code" ctx.t.tint e.epos null_pos in - cf.cf_doc <- Some "The character code of this character (inlined at compile-time)."; + cf.cf_doc <- doc_from_string "The character code of this character (inlined at compile-time)."; cf.cf_kind <- Var { v_read = AccNormal; v_write = AccNever }; let ct = CompletionType.from_type (get_import_status ctx) ~values:(get_value_meta cf.cf_meta) cf.cf_type in let item = make_ci_class_field (CompletionClassField.make cf CFSMember BuiltIn true) (cf.cf_type,ct) in diff --git a/src/context/display/displayJson.ml b/src/context/display/displayJson.ml index b099185add730a0d6c93a823c23954ae93a10cfe..65c7abc840c267012196bebcf8cb4b4ef602a434 100644 --- a/src/context/display/displayJson.ml +++ b/src/context/display/displayJson.ml @@ -55,14 +55,14 @@ class display_handler (jsonrpc : jsonrpc_handler) com (cs : CompilationServer.t) Common.define_value com Define.Display "1" method set_display_file was_auto_triggered requires_offset = - let file = jsonrpc#get_string_param "file" in - let file = Path.unique_full_path file in + let file = jsonrpc#get_opt_param (fun () -> + let file = jsonrpc#get_string_param "file" in + Path.get_full_path file + ) DisplayOutput.file_input_marker in let pos = if requires_offset then jsonrpc#get_int_param "offset" else (-1) in TypeloadParse.current_stdin := jsonrpc#get_opt_param (fun () -> let s = jsonrpc#get_string_param "contents" in Common.define com Define.DisplayStdin; (* TODO: awkward *) - (* Remove our current display file from the cache so the server doesn't pick it up *) - cs#remove_files file; Some s ) None; Parser.was_auto_triggered := was_auto_triggered; @@ -89,7 +89,7 @@ let handler = supports_resolve := hctx.jsonrpc#get_opt_param (fun () -> hctx.jsonrpc#get_bool_param "supportsResolve") false; DisplayException.max_completion_items := hctx.jsonrpc#get_opt_param (fun () -> hctx.jsonrpc#get_int_param "maxCompletionItems") 0; let exclude = hctx.jsonrpc#get_opt_param (fun () -> hctx.jsonrpc#get_array_param "exclude") [] in - DisplayToplevel.exclude := List.map (fun e -> match e with JString s -> s | _ -> assert false) exclude; + DisplayToplevel.exclude := List.map (fun e -> match e with JString s -> s | _ -> die "" __LOC__) exclude; let methods = Hashtbl.fold (fun k _ acc -> (jstring k) :: acc) h [] in hctx.send_result (JObject [ "methods",jarray methods; @@ -102,7 +102,7 @@ let handler = ]; "protocolVersion",jobject [ "major",jint 0; - "minor",jint 3; + "minor",jint 5; "patch",jint 0; ] ]) @@ -126,6 +126,11 @@ let handler = hctx.display#set_display_file false true; hctx.display#enable_display DMDefinition; ); + "display/implementation", (fun hctx -> + Common.define hctx.com Define.NoCOpt; + hctx.display#set_display_file false true; + hctx.display#enable_display (DMImplementation); + ); "display/typeDefinition", (fun hctx -> Common.define hctx.com Define.NoCOpt; hctx.display#set_display_file false true; @@ -134,7 +139,13 @@ let handler = "display/references", (fun hctx -> Common.define hctx.com Define.NoCOpt; hctx.display#set_display_file false true; - hctx.display#enable_display (DMUsage false); + match hctx.jsonrpc#get_opt_param (fun () -> hctx.jsonrpc#get_string_param "kind") "normal" with + | "withBaseAndDescendants" -> + hctx.display#enable_display (DMUsage (false,true,true)); + | "withDescendants" -> + hctx.display#enable_display (DMUsage (false,true,false)); + | _ -> + hctx.display#enable_display (DMUsage (false,false,false)); ); "display/hover", (fun hctx -> Common.define hctx.com Define.NoCOpt; @@ -185,10 +196,11 @@ let handler = ); "server/moduleCreated", (fun hctx -> let file = hctx.jsonrpc#get_string_param "file" in - let file = Path.unique_full_path file in + let file = Path.get_full_path file in + let key = Path.UniqueKey.create file in let cs = hctx.display#get_cs in List.iter (fun cc -> - Hashtbl.replace cc#get_removed_files file () + Hashtbl.replace cc#get_removed_files key file ) cs#get_contexts; hctx.send_result (jstring file); ); @@ -197,9 +209,9 @@ let handler = let cc = hctx.display#get_cs#get_context sign in let files = Hashtbl.fold (fun file cfile acc -> (file,cfile) :: acc) cc#get_files [] in let files = List.sort (fun (file1,_) (file2,_) -> compare file1 file2) files in - let files = List.map (fun (file,cfile) -> + let files = List.map (fun (fkey,cfile) -> jobject [ - "file",jstring file; + "file",jstring cfile.c_file_path; "time",jfloat cfile.c_time; "pack",jstring (String.concat "." cfile.c_package); "moduleName",jopt jstring cfile.c_module_name; @@ -209,10 +221,10 @@ let handler = ); "server/invalidate", (fun hctx -> let file = hctx.jsonrpc#get_string_param "file" in - let file = Path.unique_full_path file in + let fkey = Path.UniqueKey.create file in let cs = hctx.display#get_cs in - cs#taint_modules file; - cs#remove_files file; + cs#taint_modules fkey; + cs#remove_files fkey; hctx.send_result jnull ); "server/configure", (fun hctx -> diff --git a/src/context/display/displayPath.ml b/src/context/display/displayPath.ml index a52c22c2e230e41db9707031fcc76f972dc7564e..21179e69b7402d8e0985d1b38ee0630145ab71ed 100644 --- a/src/context/display/displayPath.ml +++ b/src/context/display/displayPath.ml @@ -183,7 +183,7 @@ let handle_path_display ctx path p = | (IDKPackage sl,p),DMDefault -> let sl = match List.rev sl with | s :: sl -> List.rev sl - | [] -> assert false + | [] -> die "" __LOC__ in raise (Parser.TypePath(sl,None,true,p)) | (IDKPackage _,_),_ -> @@ -214,7 +214,7 @@ let handle_path_display ctx path p = | (IDKModule(sl,s),p),_ -> raise (Parser.TypePath(sl,None,true,p)) | (IDKSubType(sl,sm,st),p),(DMDefinition | DMTypeDefinition) -> - resolve_position_by_path ctx { tpackage = sl; tname = sm; tparams = []; tsub = Some st} p + resolve_position_by_path ctx (Ast.mk_type_path ~sub:st (sl,sm)) p | (IDKSubType(sl,sm,st),p),_ -> raise (Parser.TypePath(sl,Some(sm,false),true,p)) | ((IDKSubTypeField(sl,sm,st,sf) | IDKModuleField(sl,(sm as st),sf)),p),DMDefault -> diff --git a/src/context/display/displayTexpr.ml b/src/context/display/displayTexpr.ml new file mode 100644 index 0000000000000000000000000000000000000000..cfcaebdc95c3ab25aaa5c6b5fc01c6e3535d304f --- /dev/null +++ b/src/context/display/displayTexpr.ml @@ -0,0 +1,160 @@ +open Globals +open Common +open Ast +open Type +open Typecore +open DisplayPosition +open CompletionItem +open CompilationServer +open ClassFieldOrigin + +let find_field_by_position sc p = + List.find (fun cff -> + if pos cff.cff_name = p then true else false + ) sc.d_data + +let find_enum_field_by_position sc p = + List.find (fun eff -> + if pos eff.ec_name = p then true else false + ) sc.d_data + +let find_class_by_position cfile p = + let rec loop dl = match dl with + | (EClass c,_) :: dl when pos c.d_name = p -> c + | _ :: dl -> loop dl + | [] -> raise Not_found + in + loop cfile.c_decls + +let find_enum_by_position cfile p = + let rec loop dl = match dl with + | (EEnum en,_) :: dl when pos en.d_name = p -> en + | _ :: dl -> loop dl + | [] -> raise Not_found + in + loop cfile.c_decls + +let find_typedef_by_position cfile p = + let rec loop dl = match dl with + | (ETypedef td,_) :: dl when pos td.d_name = p -> td + | _ :: dl -> loop dl + | [] -> raise Not_found + in + loop cfile.c_decls + +let find_abstract_by_position cfile p = + let rec loop dl = match dl with + | (EAbstract a,_) :: dl when pos a.d_name = p -> a + | _ :: dl -> loop dl + | [] -> raise Not_found + in + loop cfile.c_decls + +let check_display_field ctx sc c cf = + let cff = find_field_by_position sc cf.cf_name_pos in + let context_init = new TypeloadFields.context_init in + let ctx,cctx = TypeloadFields.create_class_context ctx c context_init cf.cf_pos in + let cff = TypeloadFields.transform_field (ctx,cctx) c cff (ref []) (pos cff.cff_name) in + let ctx,fctx = TypeloadFields.create_field_context (ctx,cctx) c cff in + let cf = TypeloadFields.init_field (ctx,cctx,fctx) cff in + flush_pass ctx PTypeField "check_display_field"; + ignore(follow cf.cf_type) + +let check_display_class ctx cc cfile c = + let check_field sc cf = + if display_position#enclosed_in cf.cf_pos then + check_display_field ctx sc c cf; + DisplayEmitter.check_display_metadata ctx cf.cf_meta + in + match c.cl_kind with + | KAbstractImpl a -> + let sa = find_abstract_by_position cfile c.cl_name_pos in + let check_field = check_field sa in + List.iter check_field c.cl_ordered_statics; + | _ -> + let sc = find_class_by_position cfile c.cl_name_pos in + ignore(Typeload.type_type_params ctx c.cl_path (fun() -> c.cl_params) null_pos sc.d_params); + List.iter (function + | (HExtends(ct,p) | HImplements(ct,p)) when display_position#enclosed_in p -> + ignore(Typeload.load_instance ~allow_display:true ctx (ct,p) false) + | _ -> + () + ) sc.d_flags; + let check_field = check_field sc in + List.iter check_field c.cl_ordered_statics; + List.iter check_field c.cl_ordered_fields; + Option.may check_field c.cl_constructor + +let check_display_enum ctx cc cfile en = + let se = find_enum_by_position cfile en.e_name_pos in + ignore(Typeload.type_type_params ctx en.e_path (fun() -> en.e_params) null_pos se.d_params); + PMap.iter (fun _ ef -> + if display_position#enclosed_in ef.ef_pos then begin + let sef = find_enum_field_by_position se ef.ef_name_pos in + ignore(TypeloadModule.load_enum_field ctx en (TEnum (en,List.map snd en.e_params)) (ref false) (ref 0) sef) + end + ) en.e_constrs + +let check_display_typedef ctx cc cfile td = + let st = find_typedef_by_position cfile td.t_name_pos in + ignore(Typeload.type_type_params ctx td.t_path (fun() -> td.t_params) null_pos st.d_params); + ignore(Typeload.load_complex_type ctx true st.d_data) + +let check_display_abstract ctx cc cfile a = + let sa = find_abstract_by_position cfile a.a_name_pos in + ignore(Typeload.type_type_params ctx a.a_path (fun() -> a.a_params) null_pos sa.d_params); + List.iter (function + | (AbOver(ct,p) | AbFrom(ct,p) | AbTo(ct,p)) when display_position#enclosed_in p -> + ignore(Typeload.load_complex_type ctx true (ct,p)) + | _ -> + () + ) sa.d_flags + +let check_display_module ctx cc cfile m = + let imports = List.filter (function + | (EImport _ | EUsing _),_ -> true + | _ -> false + ) cfile.c_decls in + let imports = TypeloadModule.handle_import_hx ctx m imports null_pos in + let ctx = TypeloadModule.type_types_into_module ctx m imports null_pos in + List.iter (fun md -> + let infos = t_infos md in + if display_position#enclosed_in infos.mt_name_pos then + DisplayEmitter.display_module_type ctx md infos.mt_name_pos; + begin if display_position#enclosed_in infos.mt_pos then match md with + | TClassDecl c -> + check_display_class ctx cc cfile c + | TEnumDecl en -> + check_display_enum ctx cc cfile en + | TTypeDecl td -> + check_display_typedef ctx cc cfile td + | TAbstractDecl a -> + check_display_abstract ctx cc cfile a + end; + DisplayEmitter.check_display_metadata ctx infos.mt_meta + ) m.m_types + +let check_display_file ctx cs = + match ctx.com.cache with + | Some cc -> + begin try + let p = DisplayPosition.display_position#get in + let cfile = cc#find_file (Path.UniqueKey.create p.pfile) in + let path = (cfile.c_package,get_module_name_of_cfile p.pfile cfile) in + TypeloadParse.PdiHandler.handle_pdi ctx.com cfile.c_pdi; + (* We have to go through type_module_hook because one of the module's dependencies could be + invalid (issue #8991). *) + begin match !TypeloadModule.type_module_hook ctx path null_pos with + | None -> raise Not_found + | Some m -> check_display_module ctx cc cfile m + end + with Not_found -> + if ctx.com.display.dms_display then begin + let fkey = DisplayPosition.display_position#get_file_key in + (* force parsing again : if the completion point have been changed *) + cs#remove_files fkey; + cs#taint_modules fkey; + end; + end + | None -> + () \ No newline at end of file diff --git a/src/context/display/displayToplevel.ml b/src/context/display/displayToplevel.ml index 674c4443f244f52fd894b46acb2fd26f49ac0ca1..cb5b337c2d76f2ab4796ad00f5922e5cead3a8c8 100644 --- a/src/context/display/displayToplevel.ml +++ b/src/context/display/displayToplevel.ml @@ -27,48 +27,72 @@ open DisplayTypes open Genjson open Globals +let maybe_resolve_macro_field ctx t c cf = + try + if cf.cf_kind <> Method MethMacro then raise Exit; + let (tl,tr,c,cf) = ctx.g.do_load_macro ctx false c.cl_path cf.cf_name null_pos in + (TFun(tl,tr)),c,cf + with _ -> + t,c,cf + let exclude : string list ref = ref [] -let explore_class_paths com timer class_paths recusive f_pack f_module = - let rec loop dir pack = +class explore_class_path_task cs com recursive f_pack f_module dir pack = object(self) + inherit server_task ["explore";dir] 50 + + method private execute : unit = let dot_path = (String.concat "." (List.rev pack)) in - begin - if (List.mem dot_path !exclude) then - () - else try - let entries = Sys.readdir dir in - Array.iter (fun file -> - match file with - | "." | ".." -> - () - | _ when Sys.is_directory (dir ^ file) && file.[0] >= 'a' && file.[0] <= 'z' -> - begin try - begin match PMap.find file com.package_rules with - | Forbidden | Remap _ -> () - | _ -> raise Not_found - end - with Not_found -> - f_pack (List.rev pack,file); - if recusive then loop (dir ^ file ^ "/") (file :: pack) + if (List.mem dot_path !exclude) then + () + else try + let entries = Sys.readdir dir in + Array.iter (fun file -> + match file with + | "." | ".." -> + () + | _ when Sys.is_directory (dir ^ file) && file.[0] >= 'a' && file.[0] <= 'z' -> + begin try + begin match PMap.find file com.package_rules with + | Forbidden | Remap _ -> () + | _ -> raise Not_found end - | _ -> - let l = String.length file in - if l > 3 && String.sub file (l - 3) 3 = ".hx" then begin - try - let name = String.sub file 0 (l - 3) in - let path = (List.rev pack,name) in - let dot_path = if dot_path = "" then name else dot_path ^ "." ^ name in - if (List.mem dot_path !exclude) then () else f_module (dir ^ file) path; - with _ -> - () + with Not_found -> + f_pack (List.rev pack,file); + if recursive then begin + let task = new explore_class_path_task cs com recursive f_pack f_module (dir ^ file ^ "/") (file :: pack) in + begin match cs with + | None -> task#run + | Some cs' -> cs'#add_task task + end end - ) entries; - with Sys_error _ -> - () - end - in + end + | _ -> + let l = String.length file in + if l > 3 && String.sub file (l - 3) 3 = ".hx" then begin + try + let name = String.sub file 0 (l - 3) in + let path = (List.rev pack,name) in + let dot_path = if dot_path = "" then name else dot_path ^ "." ^ name in + if (List.mem dot_path !exclude) then () else f_module (dir ^ file) path; + with _ -> + () + end + ) entries; + with Sys_error _ -> + () + +end + +let explore_class_paths com timer class_paths recursive f_pack f_module = + let cs = CompilationServer.get() in let t = Timer.timer (timer @ ["class path exploration"]) in - List.iter (fun dir -> loop dir []) class_paths; + let tasks = List.map (fun dir -> + new explore_class_path_task cs com recursive f_pack f_module dir [] + ) class_paths in + begin match cs with + | None -> List.iter (fun task -> task#run) tasks + | Some cs -> List.iter (fun task -> cs#add_task task) tasks + end; t() let read_class_paths com timer = @@ -78,8 +102,8 @@ let read_class_paths com timer = let file,_,pack,_ = Display.parse_module' com path Globals.null_pos in match CompilationServer.get() with | Some cs when pack <> fst path -> - let file = Path.unique_full_path file in - (CommonCache.get_cache cs com)#remove_file_for_real file + let file_key = Path.UniqueKey.create file in + (CommonCache.get_cache cs com)#remove_file_for_real file_key | _ -> () end @@ -91,16 +115,21 @@ let init_or_update_server cs com timer_name = cc#set_initialized true; read_class_paths com timer_name end; + (* Force executing all "explore" tasks here because we need their information. *) + cs#run_tasks true (fun task -> match task#get_id with + | "explore" :: _ -> true + | _ -> false + ); (* Iterate all removed files of the current context. If they aren't part of the context again, re-parse them and remove them from c_removed_files. *) let removed_files = cc#get_removed_files in let removed_removed_files = DynArray.create () in - Hashtbl.iter (fun file () -> - DynArray.add removed_removed_files file; + Hashtbl.iter (fun file_key file_path -> + DynArray.add removed_removed_files file_key; try - ignore(cc#find_file file); + ignore(cc#find_file file_key); with Not_found -> - try ignore(TypeloadParse.parse_module_file com file null_pos) with _ -> () + try ignore(TypeloadParse.parse_module_file com file_path null_pos) with _ -> () ) removed_files; DynArray.iter (Hashtbl.remove removed_files) removed_removed_files @@ -168,7 +197,7 @@ let pack_contains pack1 pack2 = let is_pack_visible pack = not (List.exists (fun s -> String.length s > 0 && s.[0] = '_') pack) -let collect ctx tk with_type = +let collect ctx tk with_type sort = let t = Timer.timer ["display";"toplevel"] in let cctx = CollectionContext.create ctx in let curpack = fst ctx.curclass.cl_path in @@ -247,6 +276,22 @@ let collect ctx tk with_type = ) ctx.locals; let add_field scope origin cf = + let origin,cf = match origin with + | Self (TClassDecl c) -> + let _,c,cf = maybe_resolve_macro_field ctx cf.cf_type c cf in + Self (TClassDecl c),cf + | StaticImport (TClassDecl c) -> + let _,c,cf = maybe_resolve_macro_field ctx cf.cf_type c cf in + StaticImport (TClassDecl c),cf + | Parent (TClassDecl c) -> + let _,c,cf = maybe_resolve_macro_field ctx cf.cf_type c cf in + Parent (TClassDecl c),cf + | StaticExtension (TClassDecl c) -> + let _,c,cf = maybe_resolve_macro_field ctx cf.cf_type c cf in + StaticExtension (TClassDecl c),cf + | _ -> + origin,cf + in let is_qualified = is_qualified cctx cf.cf_name in add (make_ci_class_field (CompletionClassField.make cf scope origin is_qualified) (tpair ~values:(get_value_meta cf.cf_meta) cf.cf_type)) (Some cf.cf_name) in @@ -312,7 +357,7 @@ let collect ctx tk with_type = (* enum constructors of expected type *) begin match with_type with | WithType.WithType(t,_) -> - (try enum_ctors (module_type_of_type t) with Exit -> ()) + (try enum_ctors (module_type_of_type (follow t)) with Exit -> ()) | _ -> () end; @@ -377,7 +422,7 @@ let collect ctx tk with_type = List.iter (fun (s,t) -> match follow t with | TInst(c,_) -> add (make_ci_type_param c (tpair t)) (Some (snd c.cl_path)) - | _ -> assert false + | _ -> die "" __LOC__ ) ctx.type_params; (* module types *) @@ -413,8 +458,8 @@ let collect ctx tk with_type = | [] -> () | s :: sl -> add_package (List.rev sl,s) in - List.iter (fun ((file,cfile),_) -> - let module_name = CompilationServer.get_module_name_of_cfile file cfile in + List.iter (fun ((file_key,cfile),_) -> + let module_name = CompilationServer.get_module_name_of_cfile cfile.c_file_path cfile in let dot_path = s_type_path (cfile.c_package,module_name) in (* In legacy mode we only show toplevel types. *) if is_legacy_completion && cfile.c_package <> [] then begin @@ -425,7 +470,7 @@ let collect ctx tk with_type = end else if (List.exists (fun e -> ExtString.String.starts_with dot_path (e ^ ".")) !exclude) then () else begin - Hashtbl.replace ctx.com.module_to_file (cfile.c_package,module_name) file; + Hashtbl.replace ctx.com.module_to_file (cfile.c_package,module_name) cfile.c_file_path; if process_decls cfile.c_package module_name cfile.c_decls then check_package cfile.c_package; end ) files; @@ -450,8 +495,10 @@ let collect ctx tk with_type = let l = DynArray.to_list cctx.items in let l = if is_legacy_completion then List.sort (fun item1 item2 -> compare (get_name item1) (get_name item2)) l - else + else if sort then Display.sort_fields l with_type tk + else + l in t(); l @@ -461,12 +508,12 @@ let collect_and_raise ctx tk with_type cr (name,pname) pinsert = | Some p' when pname.pmin = p'.pmin -> Array.to_list (!DisplayException.last_completion_result) | _ -> - collect ctx tk with_type + collect ctx tk with_type (name = "") in DisplayException.raise_fields fields cr (make_subject (Some name) ~start_pos:(Some pname) pinsert) let handle_unresolved_identifier ctx i p only_types = - let l = collect ctx (if only_types then TKType else TKExpr p) NoValue in + let l = collect ctx (if only_types then TKType else TKExpr p) NoValue false in let cl = List.map (fun it -> let s = CompletionItem.get_name it in let i = StringError.levenshtein i s in diff --git a/src/context/display/documentSymbols.ml b/src/context/display/documentSymbols.ml index 983c99177711a0746b6340960c2b6e6fb459a4b4..b45c8e7ddc0446c2fb124a16b524078da512e96a 100644 --- a/src/context/display/documentSymbols.ml +++ b/src/context/display/documentSymbols.ml @@ -1,5 +1,5 @@ open Ast - +open Globals open DisplayTypes.SymbolKind let collect_module_symbols with_locals (pack,decls) = @@ -42,40 +42,62 @@ let collect_module_symbols with_locals (pack,decls) = expr_opt parent f.f_expr in let is_deprecated meta = Meta.has Meta.Deprecated meta in - let field parent cff = + let field parent parent_kind cff = let field_parent = parent ^ "." ^ (fst cff.cff_name) in let add_field kind = add (fst cff.cff_name) kind cff.cff_pos parent (is_deprecated cff.cff_meta) in match cff.cff_kind with | FVar(_,eo) -> - add_field Field; + add_field ( + if parent_kind = EnumAbstract && not (List.mem_assoc AStatic cff.cff_access) then EnumMember + else if (List.mem_assoc AInline cff.cff_access) then Constant + else Field + ); if with_locals then expr_opt field_parent eo | FFun f -> - add_field (if fst cff.cff_name = "new" then Constructor else Method); + add_field ( + if fst cff.cff_name = "new" then Constructor + else if ((parent_kind = EnumAbstract or parent_kind = Abstract) && Meta.has_one_of [Meta.Op; Meta.ArrayAccess; Meta.Resolve] cff.cff_meta) then Operator + else Method + ); if with_locals then func field_parent f | FProp(_,_,_,eo) -> add_field Property; if with_locals then expr_opt field_parent eo in - List.iter (fun (td,p) -> match td with + List.iter (fun (td,p) -> + let add_type d kind = + let string_of_path l = String.concat "." l in + let module_name = Path.module_name_of_file p.pfile in + let type_name = fst d.d_name in + let is_primary_type = type_name = module_name in + let type_path = if is_primary_type then pack else pack @ [module_name] in + add type_name kind p (string_of_path type_path) (is_deprecated d.d_meta); + string_of_path (type_path @ [type_name]) + in + match td with | EImport _ | EUsing _ -> - () (* TODO: Can we do anything with these? *) + () | EClass d -> - add (fst d.d_name) (if List.mem HInterface d.d_flags then Interface else Class) p "" (is_deprecated d.d_meta); - List.iter (field (fst d.d_name)) d.d_data + let kind = if List.mem HInterface d.d_flags then Interface else Class in + let parent = add_type d kind in + List.iter (field parent kind) d.d_data | EEnum d -> - add (fst d.d_name) Enum p "" (is_deprecated d.d_meta); + let parent = add_type d Enum in List.iter (fun ef -> - add (fst ef.ec_name) Method ef.ec_pos (fst d.d_name) (is_deprecated ef.ec_meta) + add (fst ef.ec_name) EnumMember ef.ec_pos parent (is_deprecated ef.ec_meta) ) d.d_data | ETypedef d -> - add (fst d.d_name) Typedef p "" (is_deprecated d.d_meta); (match d.d_data with | CTAnonymous fields,_ -> - List.iter (field (fst d.d_name)) fields - | _ -> ()) + let parent = add_type d Struct in + List.iter (field parent Struct) fields + | _ -> + ignore(add_type d TypeAlias) + ) | EAbstract d -> - add (fst d.d_name) Abstract p "" (is_deprecated d.d_meta); - List.iter (field (fst d.d_name)) d.d_data + let kind = if Meta.has Meta.Enum d.d_meta then EnumAbstract else Abstract in + let parent = add_type d kind in + List.iter (field parent kind) d.d_data ) decls; l diff --git a/src/context/display/findReferences.ml b/src/context/display/findReferences.ml index 1621714df68d5035545d4d46c47d4927ee99fa39..7521c8c4cf61ffeb0186e7f503b60919832e1f25 100644 --- a/src/context/display/findReferences.ml +++ b/src/context/display/findReferences.ml @@ -2,177 +2,18 @@ open Globals open Ast open DisplayTypes open Common +open Type open Typecore open CompilationServer open ImportHandling -let find_possible_references kind name (pack,decls) = - (* Employ some heuristics: We know what kind of symbol we are looking for, so let's - filter where we can. *) - let check kind' name' = - if name = name' then match kind',kind with - | KIdent,_ - | KAnyField,(KAnyField | KClassField | KEnumField) - | KClassField,KClassField - | KEnumField,KEnumField - | KModuleType,KModuleType - | KConstructor,(KConstructor | KModuleType) -> - raise Exit - | _ -> - () - in - let rec type_path kind path = - check KModuleType path.tname; - Option.may (check KModuleType) path.tsub; - List.iter (function - | TPType th -> type_hint th - | TPExpr e -> expr e - ) path.tparams - and type_hint th = match fst th with - | CTPath path -> type_path KModuleType path - | CTParent th | CTOptional th | CTNamed(_,th) -> type_hint th - | CTFunction(thl,th) -> - List.iter type_hint thl; - type_hint th; - | CTAnonymous cffl -> - List.iter field cffl - | CTExtend(tl,cffl) -> - List.iter (fun (path,_) -> type_path KModuleType path) tl; - List.iter field cffl; - | CTIntersection tl -> - List.iter type_hint tl - and type_param tp = - List.iter type_param tp.tp_params; - Option.may type_hint tp.tp_constraints - and expr (e,p) = - begin match e with - | EConst(Ident s) -> - check KIdent s - | EField(e1,s) -> - expr e1; - check KAnyField s; - | EVars vl -> - List.iter (fun (_,_,tho,eo) -> - Option.may type_hint tho; - expr_opt eo - ) vl; - | ECast(e1,tho) -> - expr e1; - Option.may type_hint tho; - | ENew((path,_),el) -> - type_path KConstructor path; - List.iter expr el; - | EFunction(_,f) -> - func f - | ETry(e1,catches) -> - expr e1; - List.iter (fun (_,th,e,_) -> - type_hint th; - expr e - ) catches; - | ECheckType(e1,th) -> - expr e1; - type_hint th; - | _ -> - iter_expr expr (e,p) - end - and expr_opt eo = match eo with - | None -> () - | Some e -> expr e - and func f = - List.iter (fun ((s,p),_,_,tho,eo) -> - Option.may type_hint tho; - expr_opt eo - ) f.f_args; - List.iter type_param f.f_params; - Option.may type_hint f.f_type; - expr_opt f.f_expr - and field cff = - check KClassField (fst cff.cff_name); - match cff.cff_kind with - | FVar(tho,eo) -> - Option.may type_hint tho; - expr_opt eo - | FFun f -> - func f - | FProp(_,_,tho,eo) -> - Option.may type_hint tho; - expr_opt eo - in - List.iter (fun (td,p) -> match td with - | EImport(path,_) | EUsing path -> - begin match fst (ImportHandling.convert_import_to_something_usable null_pos path) with - | IDKModule(_,s) -> check KModuleType s - | IDKSubType(_,s1,s2) -> - check KModuleType s1; - check KModuleType s2; - | IDKSubTypeField(_,s1,s2,s3) -> - check KModuleType s1; - check KModuleType s2; - check KAnyField s3; - | IDKModuleField(_,s1,s2) -> - check KModuleType s1; - check KAnyField s2; - | IDKPackage _ | IDK -> - () - end; - | EClass d -> - check KModuleType (fst d.d_name); - List.iter (function - | HExtends(path,_) | HImplements(path,_) -> type_path KModuleType path - | _ -> () - ) d.d_flags; - List.iter type_param d.d_params; - List.iter field d.d_data - | EEnum d -> - check KModuleType (fst d.d_name); - List.iter (fun ef -> - Option.may type_hint ef.ec_type; - check KEnumField (fst ef.ec_name); - List.iter type_param ef.ec_params; - ) d.d_data; - List.iter type_param d.d_params; - | ETypedef d -> - check KModuleType (fst d.d_name); - List.iter type_param d.d_params; - type_hint d.d_data; - | EAbstract d -> - check KModuleType (fst d.d_name); - List.iter field d.d_data; - List.iter type_param d.d_params; - List.iter (function - | AbFrom th | AbTo th | AbOver th -> type_hint th - | _ -> () - ) d.d_flags; - ) decls - let find_possible_references tctx cs = - let name,pos,kind = Display.ReferencePosition.get () in - DisplayToplevel.init_or_update_server cs tctx.com ["display";"references"]; - let cc = CommonCache.get_cache cs tctx.com in - let files = cc#get_files in - let modules = cc#get_modules in - let t = Timer.timer ["display";"references";"candidates"] in - Hashtbl.iter (fun file cfile -> - let module_name = CompilationServer.get_module_name_of_cfile file cfile in - if not (Hashtbl.mem modules (cfile.c_package,module_name)) then try - find_possible_references kind name (cfile.c_package,cfile.c_decls); - with Exit -> - begin try - ignore(tctx.g.do_load_module tctx (cfile.c_package,module_name) null_pos); - (* We have to flush immediately so we catch exceptions from weird modules *) - Typecore.flush_pass tctx Typecore.PFinal "final"; - with _ -> - () - end - ) files; - t(); - () + let name,_,kind = Display.ReferencePosition.get () in + ignore(SyntaxExplorer.explore_uncached_modules tctx cs [name,kind]) -let find_references tctx com with_definition = - let name,pos,kind = Display.ReferencePosition.get () in +let find_references tctx com with_definition name pos kind = let t = Timer.timer ["display";"references";"collect"] in - let symbols,relations = Statistics.collect_statistics tctx (SFPos pos) in + let symbols,relations = Statistics.collect_statistics tctx (SFPos pos) true in t(); let rec loop acc relations = match relations with | (Statistics.Referenced,p) :: relations -> loop (p :: acc) relations @@ -185,10 +26,98 @@ let find_references tctx com with_definition = (try loop acc (Hashtbl.find relations p) with Not_found -> acc) ) symbols [] in + t(); + Display.ReferencePosition.set ("",null_pos,SKOther); + usages + +let collect_reference_positions com = + let name,pos,kind = Display.ReferencePosition.get () in + match kind, com.display.dms_kind with + | SKField (cf,Some cl_path), DMUsage (_,find_descendants,find_base) when find_descendants || find_base -> + let collect() = + let c = + let rec loop = function + | [] -> raise Exit + | TClassDecl c :: _ when c.cl_path = cl_path -> c + | _ :: types -> loop types + in + loop com.types + in + let cf,c = + if find_base then + let rec loop c = + match c.cl_super with + | None -> (PMap.find cf.cf_name c.cl_fields),c + | Some (csup,_) -> + try loop csup + with Not_found -> (PMap.find cf.cf_name c.cl_fields),c + in + try loop c + with Not_found -> cf,c + else + cf,c + in + let full_pos p = { p with pfile = Path.get_full_path p.pfile } in + if find_descendants then + List.fold_left (fun acc t -> + match t with + | TClassDecl child_cls when extends child_cls c -> + (try + let cf = PMap.find cf.cf_name child_cls.cl_fields in + (name,full_pos cf.cf_name_pos,SKField (cf,Some child_cls.cl_path)) :: acc + with Not_found -> acc + ) + | _ -> + acc + ) [] com.types + else + [name,full_pos cf.cf_name_pos,SKField (cf,Some c.cl_path)] + in + (try collect() + with Exit -> [name,pos,kind]) + | _ -> + [name,pos,kind] + +let find_references tctx com with_definition = + let usages = + List.fold_left (fun acc (name,pos,kind) -> + if pos <> null_pos then begin + acc @ (find_references tctx com with_definition name pos kind) + end + else acc + ) [] (collect_reference_positions com) + in + let usages = + List.sort (fun p1 p2 -> + let c = compare p1.pfile p2.pfile in + if c <> 0 then c else compare p1.pmin p2.pmin + ) usages + in + DisplayException.raise_positions usages + +let find_implementations tctx com name pos kind = + let t = Timer.timer ["display";"implementations";"collect"] in + let symbols,relations = Statistics.collect_statistics tctx (SFPos pos) false in + t(); + let rec loop acc relations = match relations with + | ((Statistics.Implemented | Statistics.Overridden | Statistics.Extended),p) :: relations -> loop (p :: acc) relations + | _ :: relations -> loop acc relations + | [] -> acc + in + let t = Timer.timer ["display";"implementations";"filter"] in + let usages = Hashtbl.fold (fun p sym acc -> + (try loop acc (Hashtbl.find relations p) + with Not_found -> acc) + ) symbols [] in let usages = List.sort (fun p1 p2 -> let c = compare p1.pfile p2.pfile in if c <> 0 then c else compare p1.pmin p2.pmin ) usages in t(); - Display.ReferencePosition.set ("",null_pos,KVar); - DisplayException.raise_positions usages \ No newline at end of file + Display.ReferencePosition.set ("",null_pos,SKOther); + DisplayException.raise_positions usages + +let find_implementations tctx com = + let name,pos,kind = Display.ReferencePosition.get () in + if pos <> null_pos then find_implementations tctx com name pos kind + else DisplayException.raise_positions [] \ No newline at end of file diff --git a/src/context/display/importHandling.ml b/src/context/display/importHandling.ml index 14ea6e1021d07a8020e81a4bf8cf8b724ecdb58b..cbc21f8f158947d89ae27a7e411d68bd5de0e0c7 100644 --- a/src/context/display/importHandling.ml +++ b/src/context/display/importHandling.ml @@ -21,7 +21,7 @@ let convert_import_to_something_usable pt path = let is_display_pos = encloses_position pt p in begin match is_lower,m,t with | _,None,Some _ -> - assert false (* impossible, I think *) + die "" __LOC__ (* impossible, I think *) | true,Some m,None -> if is_display_pos then (IDKModuleField(List.rev pack,m,s),p) else (IDK,p) (* assume that we're done *) @@ -43,17 +43,14 @@ let convert_import_to_something_usable pt path = in loop [] None None path -let add_import_position com p path = - let infos = com.shared.shared_display_information in - if not (PMap.mem p infos.import_positions) then - infos.import_positions <- PMap.add p (ref false,path) infos.import_positions +let add_import_position ctx p path = + let infos = ctx.m.curmod.m_extra.m_display in + if not (PMap.mem p infos.m_import_positions) then + infos.m_import_positions <- PMap.add p (ref false) infos.m_import_positions -let mark_import_position com p = +let mark_import_position ctx p = try - let r = fst (PMap.find p com.shared.shared_display_information.import_positions) in + let r = PMap.find p ctx.m.curmod.m_extra.m_display.m_import_positions in r := true with Not_found -> - () - -let maybe_mark_import_position ctx p = - if Diagnostics.is_diagnostics_run p then mark_import_position ctx.com p \ No newline at end of file + () \ No newline at end of file diff --git a/src/context/display/statistics.ml b/src/context/display/statistics.ml index 17a59124953ca0ab55fa136b56103c74f88c5c28..da5e1a8b741eecc4c222aa9c847045a295861ae4 100644 --- a/src/context/display/statistics.ml +++ b/src/context/display/statistics.ml @@ -3,6 +3,7 @@ open Ast open Type open Common open Typecore +open DisplayTypes open ImportHandling @@ -12,40 +13,30 @@ type relation = | Overridden | Referenced -type symbol = - | SKClass of tclass - | SKInterface of tclass - | SKEnum of tenum - | SKTypedef of tdef - | SKAbstract of tabstract - | SKField of tclass_field - | SKEnumField of tenum_field - | SKVariable of tvar - type statistics_filter = | SFNone | SFPos of pos | SFFile of string -let collect_statistics ctx pfilter = +let collect_statistics ctx pfilter with_expressions = let relations = Hashtbl.create 0 in let symbols = Hashtbl.create 0 in let handled_modules = Hashtbl.create 0 in - let full_path = + let path_key = let paths = Hashtbl.create 0 in (fun path -> try Hashtbl.find paths path with Not_found -> - let unique = Path.unique_full_path path in + let unique = Path.UniqueKey.create path in Hashtbl.add paths path unique; unique ) in let check_pos = match pfilter with | SFNone -> (fun p -> p <> null_pos) - | SFPos p -> (fun p' -> p.pmin = p'.pmin && p.pmax = p'.pmax && p.pfile = full_path p'.pfile) - | SFFile s -> (fun p -> full_path p.pfile = s) + | SFPos p -> (fun p' -> p.pmin = p'.pmin && p.pmax = p'.pmax && path_key p.pfile = path_key p'.pfile) + | SFFile s -> (fun p -> path_key p.pfile = path_key s) in let add_relation p r = if check_pos p then try @@ -67,16 +58,36 @@ let collect_statistics ctx pfilter = | Some (c,_) -> begin try let cf' = PMap.find cf.cf_name c.cl_fields in - add_relation cf'.cf_name_pos (Overridden,cf.cf_pos) + add_relation cf'.cf_name_pos (Overridden,cf.cf_name_pos) with Not_found -> - loop c - end + () + end; + loop c | _ -> () in loop c ) c.cl_overrides in + let collect_implementations c = + List.iter (fun cf -> + let rec loop c = + begin try + let cf' = PMap.find cf.cf_name c.cl_fields in + add_relation cf.cf_name_pos (Implemented,cf'.cf_name_pos) + with Not_found -> + () + end; + List.iter loop c.cl_descendants + in + List.iter loop c.cl_descendants + ) c.cl_ordered_fields; + let rec loop c' = + add_relation c.cl_name_pos ((if c'.cl_interface then Extended else Implemented),c'.cl_name_pos); + List.iter loop c'.cl_descendants + in + List.iter loop c.cl_descendants + in let rec find_real_constructor c = match c.cl_constructor,c.cl_super with (* The pos comparison might be a bit weak, not sure... *) | Some cf,_ when not (Meta.has Meta.CompilerGenerated cf.cf_meta) && c.cl_pos <> cf.cf_pos -> cf @@ -85,8 +96,49 @@ let collect_statistics ctx pfilter = in let var_decl v = declare (SKVariable v) v.v_pos in let patch_string_pos p s = { p with pmin = p.pmax - String.length s } in - let field_reference cf p = - add_relation cf.cf_name_pos (Referenced,patch_string_pos p cf.cf_name) + let related_fields = Hashtbl.create 0 in + let field_reference co cf p = + let p' = patch_string_pos p cf.cf_name in + add_relation cf.cf_name_pos (Referenced,p'); + (* extend to related classes for instance fields *) + if check_pos cf.cf_name_pos then match co with + | Some c -> + let id = (c.cl_path,cf.cf_name) in + begin try + let cfl = Hashtbl.find related_fields id in + List.iter (fun cf -> add_relation cf.cf_name_pos (Referenced,p')) cfl + with Not_found -> + let cfl = ref [] in + let check c = + try + let cf = PMap.find cf.cf_name c.cl_fields in + add_relation cf.cf_name_pos (Referenced,p'); + cfl := cf :: !cfl + with Not_found -> + () + in + (* to children *) + let rec loop c = + List.iter (fun c -> + check c; + loop c; + ) c.cl_descendants + in + loop c; + (* to parents *) + let rec loop c = + let f (c,_) = + check c; + loop c; + in + List.iter f c.cl_implements; + Option.may f c.cl_super + in + loop c; + Hashtbl.add related_fields id !cfl + end + | None -> + () in let collect_references c e = let rec loop e = match e.eexpr with @@ -96,11 +148,13 @@ let collect_statistics ctx pfilter = if e1.epos.pmin = e.epos.pmin && e1.epos.pmax <> e.epos.pmax then loop e1; begin match fa with - | FStatic(_,cf) | FInstance(_,_,cf) | FClosure(_,cf) -> - field_reference cf e.epos + | FStatic(_,cf) | FClosure(None,cf) -> + field_reference None cf e.epos + | FInstance(c,_,cf) | FClosure(Some(c,_),cf) -> + field_reference (Some c) cf e.epos | FAnon cf -> - declare (SKField cf) cf.cf_name_pos; - field_reference cf e.epos + declare (SKField (cf,None)) cf.cf_name_pos; + field_reference None cf e.epos | FEnum(_,ef) -> add_relation ef.ef_name_pos (Referenced,patch_string_pos e.epos ef.ef_name) | FDynamic _ -> @@ -144,20 +198,45 @@ let collect_statistics ctx pfilter = List.iter (fun (p,pn) -> add_relation pn (Referenced,p)) m.m_extra.m_display.m_type_hints end in + (* set up descendants *) + let f = function + | TClassDecl c -> + List.iter (fun (iface,_) -> add_descendant iface c) c.cl_implements; + begin match c.cl_super with + | Some (csup,_) -> add_descendant csup c + | None -> () + end; + | _ -> + () + in + let rec loop com = + List.iter f com.types; + Option.may loop (com.get_macros()) + in + loop ctx.com; + (* find things *) let f = function | TClassDecl c -> check_module c.cl_module; declare (if c.cl_interface then (SKInterface c) else (SKClass c)) c.cl_name_pos; - List.iter (fun (c',_) -> add_relation c'.cl_name_pos ((if c.cl_interface then Extended else Implemented),c.cl_name_pos)) c.cl_implements; begin match c.cl_super with | None -> () - | Some (c',_) -> add_relation c'.cl_name_pos (Extended,c.cl_name_pos); + | Some (c',_) -> + let rec loop c' = + add_relation c'.cl_name_pos (Extended,c.cl_name_pos); + Option.may (fun (c',_) -> loop c') c'.cl_super + in + loop c' end; collect_overrides c; + if c.cl_interface then + collect_implementations c; let field cf = - if cf.cf_pos.pmin > c.cl_name_pos.pmin then declare (SKField cf) cf.cf_name_pos; - let _ = follow cf.cf_type in - match cf.cf_expr with None -> () | Some e -> collect_references c e + if cf.cf_pos.pmin > c.cl_name_pos.pmin then declare (SKField (cf,Some c.cl_path)) cf.cf_name_pos; + if with_expressions then begin + let _ = follow cf.cf_type in + match cf.cf_expr with None -> () | Some e -> collect_references c e + end in Option.may field c.cl_constructor; List.iter field c.cl_ordered_fields; @@ -178,11 +257,15 @@ let collect_statistics ctx pfilter = Option.may loop (com.get_macros()) in loop ctx.com; - let l = List.fold_left (fun acc (_,cfi,_,cfo) -> match cfo with - | Some cf -> if List.mem_assoc cf.cf_name_pos acc then acc else (cf.cf_name_pos,cfi.cf_name_pos) :: acc - | None -> acc - ) [] ctx.com.display_information.interface_field_implementations in - List.iter (fun (p,p') -> add_relation p' (Implemented,p)) l; + (* TODO: Using syntax-exploration here is technically fine, but I worry about performance in real codebases. *) + (* let find_symbols = Hashtbl.fold (fun _ kind acc -> + let name = string_of_symbol kind in + (name,kind) :: acc + ) symbols [] in + let additional_modules = SyntaxExplorer.explore_uncached_modules ctx (CompilationServer.force()) find_symbols in + List.iter (fun md -> + List.iter f md.m_types + ) additional_modules; *) (* let deal_with_imports paths = let check_subtype m s p = try @@ -242,8 +325,10 @@ module Printer = struct | SKTypedef _ -> "typedef" | SKAbstract _ -> "abstract" | SKField _ -> "class field" + | SKConstructor _ -> "constructor" | SKEnumField _ -> "enum field" | SKVariable _ -> "variable" + | SKOther -> "other" let print_statistics (kinds,relations) = let files = Hashtbl.create 0 in diff --git a/src/context/display/syntaxExplorer.ml b/src/context/display/syntaxExplorer.ml new file mode 100644 index 0000000000000000000000000000000000000000..d85dfca892b26d9dd7e72e7e9dcae200b6d73da0 --- /dev/null +++ b/src/context/display/syntaxExplorer.ml @@ -0,0 +1,181 @@ +open Globals +open Ast +open DisplayTypes +open Typecore + +type reference_kind = + | KVar + | KIdent + | KAnyField + | KClassField + | KEnumField + | KModuleType + | KConstructor + +let find_in_syntax symbols (pack,decls) = + (* Employ some heuristics: We know what kind of symbol we are looking for, so let's + filter where we can. *) + let check kind' name' = + List.iter (fun (name,kind) -> + if name = name' then match kind',kind with + | KIdent,_ + | KAnyField,(SKField _ | SKConstructor _ | SKEnumField _) + | KClassField,SKField _ + | KEnumField,SKEnumField _ + | KModuleType,(SKClass _ | SKEnum _ | SKTypedef _ | SKAbstract _) + | KConstructor,(SKConstructor _ | SKClass _) -> + raise Exit + | _ -> + () + ) symbols + in + let rec type_path kind path = + check KModuleType path.tname; + Option.may (check KModuleType) path.tsub; + List.iter (function + | TPType th -> type_hint th + | TPExpr e -> expr e + ) path.tparams + and type_hint th = match fst th with + | CTPath path -> type_path KModuleType path + | CTParent th | CTOptional th | CTNamed(_,th) -> type_hint th + | CTFunction(thl,th) -> + List.iter type_hint thl; + type_hint th; + | CTAnonymous cffl -> + List.iter field cffl + | CTExtend(tl,cffl) -> + List.iter (fun (path,_) -> type_path KModuleType path) tl; + List.iter field cffl; + | CTIntersection tl -> + List.iter type_hint tl + and type_param tp = + List.iter type_param tp.tp_params; + Option.may type_hint tp.tp_constraints + and expr (e,p) = + begin match e with + | EConst(Ident s) -> + check KIdent s + | EField(e1,s) -> + expr e1; + check KAnyField s; + | EVars vl -> + List.iter (fun (_,_,tho,eo) -> + Option.may type_hint tho; + expr_opt eo + ) vl; + | ECast(e1,tho) -> + expr e1; + Option.may type_hint tho; + | ENew((path,_),el) -> + type_path KConstructor path; + List.iter expr el; + | EFunction(_,f) -> + func f + | ETry(e1,catches) -> + expr e1; + List.iter (fun (_,th,e,_) -> + Option.may type_hint th; + expr e + ) catches; + | ECheckType(e1,th) -> + expr e1; + type_hint th; + | _ -> + iter_expr expr (e,p) + end + and expr_opt eo = match eo with + | None -> () + | Some e -> expr e + and func f = + List.iter (fun ((s,p),_,_,tho,eo) -> + Option.may type_hint tho; + expr_opt eo + ) f.f_args; + List.iter type_param f.f_params; + Option.may type_hint f.f_type; + expr_opt f.f_expr + and field cff = + check KClassField (fst cff.cff_name); + match cff.cff_kind with + | FVar(tho,eo) -> + Option.may type_hint tho; + expr_opt eo + | FFun f -> + func f + | FProp(_,_,tho,eo) -> + Option.may type_hint tho; + expr_opt eo + in + List.iter (fun (td,p) -> match td with + | EImport(path,_) | EUsing path -> + begin match fst (ImportHandling.convert_import_to_something_usable null_pos path) with + | IDKModule(_,s) -> check KModuleType s + | IDKSubType(_,s1,s2) -> + check KModuleType s1; + check KModuleType s2; + | IDKSubTypeField(_,s1,s2,s3) -> + check KModuleType s1; + check KModuleType s2; + check KAnyField s3; + | IDKModuleField(_,s1,s2) -> + check KModuleType s1; + check KAnyField s2; + | IDKPackage _ | IDK -> + () + end; + | EClass d -> + check KModuleType (fst d.d_name); + List.iter (function + | HExtends(path,_) | HImplements(path,_) -> type_path KModuleType path + | _ -> () + ) d.d_flags; + List.iter type_param d.d_params; + List.iter field d.d_data + | EEnum d -> + check KModuleType (fst d.d_name); + List.iter (fun ef -> + Option.may type_hint ef.ec_type; + check KEnumField (fst ef.ec_name); + List.iter type_param ef.ec_params; + ) d.d_data; + List.iter type_param d.d_params; + | ETypedef d -> + check KModuleType (fst d.d_name); + List.iter type_param d.d_params; + type_hint d.d_data; + | EAbstract d -> + check KModuleType (fst d.d_name); + List.iter field d.d_data; + List.iter type_param d.d_params; + List.iter (function + | AbFrom th | AbTo th | AbOver th -> type_hint th + | _ -> () + ) d.d_flags; + ) decls + +let explore_uncached_modules tctx cs symbols = + DisplayToplevel.init_or_update_server cs tctx.com ["display";"references"]; + let cc = CommonCache.get_cache cs tctx.com in + let files = cc#get_files in + let modules = cc#get_modules in + let t = Timer.timer ["display";"references";"candidates"] in + let acc = Hashtbl.fold (fun file_key cfile acc -> + let module_name = CompilationServer.get_module_name_of_cfile cfile.CompilationServer.c_file_path cfile in + if Hashtbl.mem modules (cfile.c_package,module_name) then + acc + else try + find_in_syntax symbols (cfile.c_package,cfile.c_decls); + acc + with Exit -> + begin try + let m = tctx.g.do_load_module tctx (cfile.c_package,module_name) null_pos in + (* We have to flush immediately so we catch exceptions from weird modules *) + Typecore.flush_pass tctx Typecore.PFinal "final"; + m :: acc + with _ -> + acc + end + ) files [] in + t(); + acc \ No newline at end of file diff --git a/src/context/sourcemaps.ml b/src/context/sourcemaps.ml index 4f48b3b2f9182cea804d625bdd552899e54b1f2c..985770b863a35336acab455853835912ee184ff0 100644 --- a/src/context/sourcemaps.ml +++ b/src/context/sourcemaps.ml @@ -234,7 +234,7 @@ class sourcemap_builder (generated_file:string) = match node with | Some ({ smn_data = SMNil } as node) -> current <- node | Some node -> loop node.smn_left - | None -> assert false + | None -> die "" __LOC__ in loop (Some current) (** @@ -245,7 +245,7 @@ class sourcemap_builder (generated_file:string) = match node.smn_right with | Some { smn_data = SMNil } -> current <- node | Some node -> loop node - | None -> assert false + | None -> die "" __LOC__ in loop current (** diff --git a/src/context/typecore.ml b/src/context/typecore.ml index 97ab818c0f2ac668c9d5cd8dcadbfda528540bf6..96851ce94880b642939e68676f797abf948474ac 100644 --- a/src/context/typecore.ml +++ b/src/context/typecore.ml @@ -88,6 +88,7 @@ type typer_globals = { do_inherit : typer -> Type.tclass -> pos -> (bool * placed_type_path) -> bool; do_create : Common.context -> typer; do_macro : typer -> macro_mode -> path -> string -> expr list -> pos -> expr option; + do_load_macro : typer -> bool -> path -> string -> pos -> ((string * bool * t) list * t * tclass * Type.tclass_field); do_load_module : typer -> path -> pos -> module_def; do_load_type_def : typer -> pos -> type_path -> module_type; do_optimize : typer -> texpr -> texpr; @@ -141,12 +142,12 @@ exception WithTypeError of error_msg * pos let memory_marker = [|Unix.time()|] -let make_call_ref : (typer -> texpr -> texpr list -> t -> ?force_inline:bool -> pos -> texpr) ref = ref (fun _ _ _ _ ?force_inline:bool _ -> assert false) -let type_expr_ref : (?mode:access_mode -> typer -> expr -> WithType.t -> texpr) ref = ref (fun ?(mode=MGet) _ _ _ -> assert false) -let type_block_ref : (typer -> expr list -> WithType.t -> pos -> texpr) ref = ref (fun _ _ _ _ -> assert false) -let unify_min_ref : (typer -> texpr list -> t) ref = ref (fun _ _ -> assert false) -let unify_min_for_type_source_ref : (typer -> texpr list -> WithType.with_type_source option -> t) ref = ref (fun _ _ _ -> assert false) -let analyzer_run_on_expr_ref : (Common.context -> texpr -> texpr) ref = ref (fun _ _ -> assert false) +let make_call_ref : (typer -> texpr -> texpr list -> t -> ?force_inline:bool -> pos -> texpr) ref = ref (fun _ _ _ _ ?force_inline:bool _ -> die "" __LOC__) +let type_expr_ref : (?mode:access_mode -> typer -> expr -> WithType.t -> texpr) ref = ref (fun ?(mode=MGet) _ _ _ -> die "" __LOC__) +let type_block_ref : (typer -> expr list -> WithType.t -> pos -> texpr) ref = ref (fun _ _ _ _ -> die "" __LOC__) +let unify_min_ref : (typer -> texpr list -> t) ref = ref (fun _ _ -> die "" __LOC__) +let unify_min_for_type_source_ref : (typer -> texpr list -> WithType.with_type_source option -> t) ref = ref (fun _ _ _ -> die "" __LOC__) +let analyzer_run_on_expr_ref : (Common.context -> texpr -> texpr) ref = ref (fun _ _ -> die "" __LOC__) let pass_name = function | PBuildModule -> "build-module" @@ -169,7 +170,7 @@ let unify_min ctx el = (!unify_min_ref) ctx el let unify_min_for_type_source ctx el src = (!unify_min_for_type_source_ref) ctx el src let make_static_this c p = - let ta = TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } in + let ta = mk_anon ~fields:c.cl_statics (ref (Statics c)) in mk (TTypeExpr (TClassDecl c)) ta p let make_static_field_access c cf t p = @@ -226,28 +227,32 @@ let add_local ctx k n t p = ctx.locals <- PMap.add n v ctx.locals; v -let check_identifier_name ctx name kind p = +let display_identifier_error ctx ?prepend_msg msg p = + let prepend = match prepend_msg with Some s -> s ^ " " | _ -> "" in + display_error ctx (prepend ^ msg) p + +let check_identifier_name ?prepend_msg ctx name kind p = if starts_with name '$' then - display_error ctx ((StringHelper.capitalize kind) ^ " names starting with a dollar are not allowed: \"" ^ name ^ "\"") p + display_identifier_error ctx ?prepend_msg ((StringHelper.capitalize kind) ^ " names starting with a dollar are not allowed: \"" ^ name ^ "\"") p else if not (Lexer.is_valid_identifier name) then - display_error ctx ("\"" ^ (StringHelper.s_escape name) ^ "\" is not a valid " ^ kind ^ " name") p + display_identifier_error ctx ?prepend_msg ("\"" ^ (StringHelper.s_escape name) ^ "\" is not a valid " ^ kind ^ " name.") p let check_field_name ctx name p = match name with | "new" -> () (* the only keyword allowed in field names *) | _ -> check_identifier_name ctx name "field" p -let check_uppercase_identifier_name ctx name kind p = +let check_uppercase_identifier_name ?prepend_msg ctx name kind p = if String.length name = 0 then - display_error ctx ((StringHelper.capitalize kind) ^ " name must not be empty") p + display_identifier_error ?prepend_msg ctx ((StringHelper.capitalize kind) ^ " name must not be empty.") p else if Ast.is_lower_ident name then - display_error ctx ((StringHelper.capitalize kind) ^ " name should start with an uppercase letter: \"" ^ name ^ "\"") p + display_identifier_error ?prepend_msg ctx ((StringHelper.capitalize kind) ^ " name should start with an uppercase letter: \"" ^ name ^ "\"") p else - check_identifier_name ctx name kind p + check_identifier_name ?prepend_msg ctx name kind p -let check_module_path ctx path p = - check_uppercase_identifier_name ctx (snd path) "module" p; - let pack = fst path in +let check_module_path ctx (pack,name) p = + let full_path = StringHelper.s_escape (if pack = [] then name else (String.concat "." pack) ^ "." ^ name) in + check_uppercase_identifier_name ~prepend_msg:("Module \"" ^ full_path ^ "\" does not have a valid name.") ctx name "module" p; try List.iter (fun part -> Path.check_package_name part) pack; with Failure msg -> @@ -347,15 +352,16 @@ let exc_protect ?(force=true) ctx f (where:string) = let fake_modules = Hashtbl.create 0 let create_fake_module ctx file = - let file = Path.unique_full_path file in - let mdep = (try Hashtbl.find fake_modules file with Not_found -> + let key = Path.UniqueKey.create file in + let file = Path.get_full_path file in + let mdep = (try Hashtbl.find fake_modules key with Not_found -> let mdep = { m_id = alloc_mid(); m_path = (["$DEP"],file); m_types = []; m_extra = module_extra file (Define.get_signature ctx.com.defines) (file_time file) MFake []; } in - Hashtbl.add fake_modules file mdep; + Hashtbl.add fake_modules key mdep; mdep ) in Hashtbl.replace ctx.g.modules mdep.m_path mdep; @@ -382,8 +388,9 @@ let rec can_access ctx ?(in_overload=false) c cf stat = true else if not in_overload && ctx.com.config.pf_overload && Meta.has Meta.Overload cf.cf_meta then true + else if c == ctx.curclass then + true else - (* TODO: should we add a c == ctx.curclass short check here? *) (* has metadata path *) let rec make_path c f = match c.cl_kind with | KAbstractImpl a -> fst a.a_path @ [snd a.a_path; f.cf_name] @@ -447,7 +454,7 @@ let rec can_access ctx ?(in_overload=false) c cf stat = has Meta.Access ctx.curclass ctx.curfield ((make_path c cf), true) || ( (* if our common ancestor declare/override the field, then we can access it *) - let allowed f = is_parent c ctx.curclass || (List.exists (has Meta.Allow c f) !cur_paths) in + let allowed f = extends ctx.curclass c || (List.exists (has Meta.Allow c f) !cur_paths) in if is_constr then (match c.cl_constructor with | Some cf -> @@ -463,16 +470,13 @@ let rec can_access ctx ?(in_overload=false) c cf stat = | None -> false) with Not_found -> false in - let b = loop c + loop c (* access is also allowed of we access a type parameter which is constrained to our (base) class *) || (match c.cl_kind with | KTypeParameter tl -> List.exists (fun t -> match follow t with TInst(c,_) -> loop c | _ -> false) tl | _ -> false) - || (Meta.has Meta.PrivateAccess ctx.meta) in - (* TODO: find out what this does and move it to genas3 *) - if b && Common.defined ctx.com Common.Define.As3 && not (Meta.has Meta.Public cf.cf_meta) then cf.cf_meta <- (Meta.Public,[],cf.cf_pos) :: cf.cf_meta; - b + || (Meta.has Meta.PrivateAccess ctx.meta) (** removes the first argument of the class field's function type and all its overloads *) let prepare_using_field cf = match follow cf.cf_type with diff --git a/src/core/abstract.ml b/src/core/abstract.ml index 11b94dfe671e75ead5c7067bc999d4625d8893ae..5a0070d739b10814c5ead09fa8043d179adf40e9 100644 --- a/src/core/abstract.ml +++ b/src/core/abstract.ml @@ -1,5 +1,8 @@ open Meta -open Type +open TType +open TFunctions +open TPrinting +open TUnification open Error let build_abstract a = match a.a_impl with @@ -53,7 +56,7 @@ let rec get_underlying_type ?(return_first=false) a pl = let maybe_recurse t = let rec loop t = match t with | TMono r -> - (match !r with + (match r.tm_type with | Some t -> loop t | _ -> t) | TLazy f -> @@ -98,5 +101,13 @@ let rec get_underlying_type ?(return_first=false) a pl = let rec follow_with_abstracts t = match follow t with | TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> follow_with_abstracts (get_underlying_type a tl) + | t -> + t + +let rec follow_with_abstracts_without_null t = match follow_without_null t with + | TAbstract({a_path = [],"Null"},_) -> + t + | TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> + follow_with_abstracts_without_null (get_underlying_type a tl) | t -> t \ No newline at end of file diff --git a/src/core/ast.ml b/src/core/ast.ml index 4ddbfe08a0165a5ed74139bc16e5a8ffbb705b0f..73885b78912fdb9324b79b95dd3edb8096d93105 100644 --- a/src/core/ast.ml +++ b/src/core/ast.ml @@ -212,7 +212,7 @@ and expr_def = | EIf of expr * expr * expr option | EWhile of expr * expr * while_flag | ESwitch of expr * (expr list * expr option * expr option * pos) list * (expr option * pos) option - | ETry of expr * (placed_name * type_hint * expr * pos) list + | ETry of expr * (placed_name * type_hint option * expr * pos) list | EReturn of expr option | EBreak | EContinue @@ -234,7 +234,12 @@ and type_param = { tp_meta : metadata; } -and documentation = string option +and doc_block = { + doc_own: string option; + mutable doc_inherited: (unit -> (string option)) list +} + +and documentation = doc_block option and metadata_entry = (Meta.strict_meta * expr list * pos) and metadata = metadata_entry list @@ -323,6 +328,11 @@ type type_decl = type_def * pos type package = string list * type_decl list +let mk_type_path ?(params=[]) ?sub (pack,name) = + if name = "" then + raise (Invalid_argument "Empty module name is not allowed"); + { tpackage = pack; tname = name; tsub = sub; tparams = params; } + let is_lower_ident i = if String.length i = 0 then raise (Invalid_argument "Identifier name must not be empty") @@ -337,6 +347,21 @@ let is_lower_ident i = let pos = snd +let doc_from_string s = Some { doc_own = Some s; doc_inherited = []; } + +let doc_from_string_opt = Option.map (fun s -> { doc_own = Some s; doc_inherited = []; }) + +let gen_doc_text d = + let docs = + match d.doc_own with Some s -> [s] | None -> [] + in + String.concat "\n" docs + + +let gen_doc_text_opt = Option.map gen_doc_text + +let get_own_doc_opt = Option.map_default (fun d -> d.doc_own) None + let rec is_postfix (e,_) op = match op with | Increment | Decrement | Not -> true | Neg | NegBits -> false @@ -672,7 +697,7 @@ let map_expr loop (e,p) = ESwitch (e, cases, def) | ETry (e,catches) -> let e = loop e in - let catches = List.map (fun (n,t,e,p) -> n,type_hint t,loop e,p) catches in + let catches = List.map (fun (n,t,e,p) -> n,Option.map type_hint t,loop e,p) catches in ETry (e,catches) | EReturn e -> EReturn (opt loop e) | EBreak -> EBreak @@ -804,15 +829,35 @@ module Printer = struct | CTExtend (tl, fl) -> "{> " ^ String.concat " >, " (List.map (s_complex_type_path tabs) tl) ^ ", " ^ String.concat ", " (List.map (s_class_field tabs) fl) ^ " }" | CTIntersection tl -> String.concat "&" (List.map (fun (t,_) -> s_complex_type tabs t) tl) and s_class_field tabs f = - match f.cff_doc with - | Some s -> "/**\n\t" ^ tabs ^ s ^ "\n**/\n" - | None -> "" ^ - if List.length f.cff_meta > 0 then String.concat ("\n" ^ tabs) (List.map (s_metadata tabs) f.cff_meta) else "" ^ - if List.length f.cff_access > 0 then String.concat " " (List.map s_placed_access f.cff_access) else "" ^ - match f.cff_kind with - | FVar (t,e) -> "var " ^ (fst f.cff_name) ^ s_opt_type_hint tabs t " : " ^ s_opt_expr tabs e " = " - | FProp ((get,_),(set,_),t,e) -> "var " ^ (fst f.cff_name) ^ "(" ^ get ^ "," ^ set ^ ")" ^ s_opt_type_hint tabs t " : " ^ s_opt_expr tabs e " = " - | FFun func -> "function " ^ (fst f.cff_name) ^ s_func tabs func + let doc = match f.cff_doc with + | Some d -> "/**\n\t" ^ tabs ^ (gen_doc_text d) ^ "\n**/\n" + | None -> "" + in + let s_separated f sep list = + if list <> [] then ((String.concat sep (List.map f list)) ^ sep) else "" + in + let s_meta = s_separated (s_metadata tabs) ("\n" ^ tabs) in + let s_access = s_separated s_placed_access " " in + (match f.cff_kind with + | FVar (t,e) -> + doc ^ + let keyword = ref "var " in + let question = ref "" in + let access = List.filter (fun (a,_) -> if a = AFinal then (keyword := "final "; false) else true) f.cff_access in + let meta = List.filter (fun (m,_,_) -> if m = Meta.Optional then (question := "?"; false) else true) f.cff_meta in + s_meta meta ^ + s_access access ^ + !keyword ^ !question ^ (fst f.cff_name) ^ s_opt_type_hint tabs t " : " ^ s_opt_expr tabs e " = " + | FProp ((get,_),(set,_),t,e) -> + doc ^ + s_meta f.cff_meta ^ + s_access f.cff_access ^ + "var " ^ (fst f.cff_name) ^ "(" ^ get ^ "," ^ set ^ ")" ^ s_opt_type_hint tabs t " : " ^ s_opt_expr tabs e " = " + | FFun func -> + doc ^ + s_meta f.cff_meta ^ + s_access f.cff_access ^ + "function " ^ (fst f.cff_name) ^ s_func tabs func) and s_metadata tabs (s,e,_) = "@" ^ Meta.to_string s ^ if List.length e > 0 then "(" ^ s_expr_list tabs e ", " ^ ")" else "" and s_opt_expr tabs e pre = @@ -845,8 +890,9 @@ module Printer = struct "case " ^ s_expr_list tabs el ", " ^ (match e1 with None -> ":" | Some e -> " if (" ^ s_expr_inner tabs e ^ "):") ^ (match e2 with None -> "" | Some e -> s_expr_omit_block tabs e) - and s_catch tabs ((n,_),(t,_),e,_) = - " catch(" ^ n ^ ":" ^ s_complex_type tabs t ^ ") " ^ s_expr_inner tabs e + and s_catch tabs ((n,_),t,e,_) = + let hint = Option.map_default (fun (t,_) -> ":" ^ s_complex_type tabs t) "" t in + " catch(" ^ n ^ hint ^ ") " ^ s_expr_inner tabs e and s_block tabs el opn nl cls = opn ^ "\n\t" ^ tabs ^ (s_expr_list (tabs ^ "\t") el (";\n\t" ^ tabs)) ^ ";" ^ nl ^ tabs ^ cls and s_expr_omit_block tabs e = @@ -1056,7 +1102,7 @@ module Expr = struct add ("EMeta " ^ fst (Meta.get_info m)); loop e1 | EDisplayNew _ -> - assert false + die "" __LOC__ in loop' "" e; Buffer.contents buf diff --git a/src/core/display/completionItem.ml b/src/core/display/completionItem.ml index b8ed8f54f316f2c8994ffb95740cb45195d817c8..94f7331b4173bf0ffef8b366026bb02e48711465 100644 --- a/src/core/display/completionItem.ml +++ b/src/core/display/completionItem.ml @@ -199,7 +199,7 @@ module CompletionModuleType = struct tp_meta = c.cl_meta } | _ -> - assert false + die "" __LOC__ in { pack = fst infos.mt_path; @@ -235,7 +235,7 @@ module CompletionModuleType = struct ("params",jlist (generate_ast_type_param ctx) cm.params) :: ("isExtern",jbool cm.is_extern) :: ("isFinal",jbool cm.is_final) :: - (if ctx.generation_mode = GMFull then ["doc",jopt jstring cm.doc] else []) + (if ctx.generation_mode = GMFull then ["doc",jopt jstring (gen_doc_text_opt cm.doc)] else []) | GMMinimum -> match generate_minimum_metadata ctx cm.meta with | None -> [] @@ -429,7 +429,7 @@ module CompletionType = struct } and from_type values t = match t with | TMono r -> - begin match !r with + begin match r.tm_type with | None -> CTMono | Some t -> from_type values t end @@ -769,7 +769,7 @@ let to_json ctx index item = "meta",generate_metadata ctx c.cl_meta; "constraints",jlist (generate_type ctx) tl; ] - | _ -> assert false + | _ -> die "" __LOC__ end | ITDefine(n,v) -> "Define",jobject [ "name",jstring n; diff --git a/src/core/display/displayPosition.ml b/src/core/display/displayPosition.ml index f9106064d4f98dc8f4eab5dac80a88d674b34ee9..db9a055abf75637d6de0aab3d72d166c7f16f9b6 100644 --- a/src/core/display/displayPosition.ml +++ b/src/core/display/displayPosition.ml @@ -10,6 +10,7 @@ class display_position_container = object (self) (** Current display position *) val mutable pos = null_pos + val mutable file_key = None (** Display position value which was set with the latest `display_position#set p` call. Kept even after `display_position#reset` call. @@ -20,17 +21,29 @@ class display_position_container = *) method set p = pos <- p; - last_pos <- p + last_pos <- p; + file_key <- None (** Get current display position *) method get = pos + (** + Get current display position + *) + method get_file_key = + match file_key with + | None -> + let key = Path.UniqueKey.create pos.pfile in + file_key <- Some key; + key + | Some key -> key (** Clears current display position. *) method reset = - pos <- null_pos + pos <- null_pos; + file_key <- None (** Check if `p` contains current display position *) @@ -40,7 +53,9 @@ class display_position_container = Check if `file` contains current display position *) method is_in_file file = - file <> "?" && Path.unique_full_path file = pos.pfile + file <> "?" + && pos.pfile <> "?" + && self#get_file_key = Path.UniqueKey.create file (** Cut `p` at the position of the latest `display_position#set pos` call. *) diff --git a/src/core/displayTypes.ml b/src/core/displayTypes.ml index 55028134659bb08502520dafa536d3b2a7a88daf..5b840fd13631e7a8a12a82838f2ce1532887355b 100644 --- a/src/core/displayTypes.ml +++ b/src/core/displayTypes.ml @@ -10,7 +10,7 @@ module SymbolKind = struct | Class | Interface | Enum - | Typedef + | TypeAlias | Abstract | Field | Property @@ -18,12 +18,17 @@ module SymbolKind = struct | Constructor | Function | Variable + | Struct + | EnumAbstract + | Operator + | EnumMember + | Constant let to_int = function | Class -> 1 | Interface -> 2 | Enum -> 3 - | Typedef -> 4 + | TypeAlias -> 4 | Abstract -> 5 | Field -> 6 | Property -> 7 @@ -31,6 +36,11 @@ module SymbolKind = struct | Constructor -> 9 | Function -> 10 | Variable -> 11 + | Struct -> 12 + | EnumAbstract -> 13 + | Operator -> 14 + | EnumMember -> 15 + | Constant -> 16 end module SymbolInformation = struct @@ -180,14 +190,21 @@ module DisplayMode = struct type t = | DMNone | DMDefault - | DMUsage of bool (* true = also report definition *) + (** + Find usages/references of the requested symbol. + @param bool - add symbol definition to the response + @param bool - also find usages of descendants of the symbol (e.g methods, which override the requested one) + @param bool - look for a base method if requested for a method with `override` accessor. + *) + | DMUsage of bool * bool * bool | DMDefinition | DMTypeDefinition + | DMImplementation | DMResolve of string | DMPackage | DMHover | DMModuleSymbols of string option - | DMDiagnostics of bool (* true = global, false = only in display file *) + | DMDiagnostics of Path.UniqueKey.t list | DMStatistics | DMSignature @@ -207,11 +224,11 @@ module DisplayMode = struct dms_full_typing : bool; dms_force_macro_typing : bool; dms_error_policy : error_policy; - dms_collect_data : bool; dms_check_core_api : bool; dms_inline : bool; dms_display_file_policy : display_file_policy; dms_exit_during_typing : bool; + dms_per_file : bool; } let default_display_settings = { @@ -220,11 +237,11 @@ module DisplayMode = struct dms_full_typing = false; dms_force_macro_typing = false; dms_error_policy = EPIgnore; - dms_collect_data = false; dms_check_core_api = false; dms_inline = false; dms_display_file_policy = DFPOnly; dms_exit_during_typing = true; + dms_per_file = false; } let default_compilation_settings = { @@ -233,11 +250,11 @@ module DisplayMode = struct dms_full_typing = true; dms_force_macro_typing = true; dms_error_policy = EPShow; - dms_collect_data = false; dms_check_core_api = true; dms_inline = true; dms_display_file_policy = DFPNo; dms_exit_during_typing = false; + dms_per_file = false; } let create dm = @@ -245,10 +262,9 @@ module DisplayMode = struct match dm with | DMNone -> default_compilation_settings | DMDefault | DMDefinition | DMTypeDefinition | DMResolve _ | DMPackage | DMHover | DMSignature -> settings - | DMUsage _ -> { settings with + | DMUsage _ | DMImplementation -> { settings with dms_full_typing = true; dms_force_macro_typing = true; - dms_collect_data = true; dms_display_file_policy = DFPAlso; dms_exit_during_typing = false } @@ -256,20 +272,21 @@ module DisplayMode = struct dms_display_file_policy = if filter = None then DFPOnly else DFPNo; dms_exit_during_typing = false; dms_force_macro_typing = false; + dms_per_file = true; } - | DMDiagnostics global -> { default_compilation_settings with - dms_kind = DMDiagnostics global; + | DMDiagnostics files -> { default_compilation_settings with + dms_kind = DMDiagnostics files; dms_error_policy = EPCollect; - dms_collect_data = true; - dms_display_file_policy = if global then DFPNo else DFPAlso; + dms_display_file_policy = if files = [] then DFPNo else DFPAlso; + dms_per_file = true; } | DMStatistics -> { settings with dms_full_typing = true; - dms_collect_data = true; dms_inline = false; dms_display_file_policy = DFPAlso; dms_exit_during_typing = false; dms_force_macro_typing = true; + dms_per_file = true; } let to_string = function @@ -277,26 +294,30 @@ module DisplayMode = struct | DMDefault -> "field" | DMDefinition -> "position" | DMTypeDefinition -> "type-definition" + | DMImplementation -> "implementation" | DMResolve s -> "resolve " ^ s | DMPackage -> "package" | DMHover -> "type" - | DMUsage true -> "rename" - | DMUsage false -> "references" + | DMUsage (true,_,_) -> "rename" + | DMUsage (false,_,_) -> "references" | DMModuleSymbols None -> "module-symbols" | DMModuleSymbols (Some s) -> "workspace-symbols " ^ s - | DMDiagnostics b -> (if b then "global " else "") ^ "diagnostics" + | DMDiagnostics _ -> "diagnostics" | DMStatistics -> "statistics" | DMSignature -> "signature" end -type reference_kind = - | KVar - | KIdent - | KAnyField - | KClassField - | KEnumField - | KModuleType - | KConstructor +type symbol = + | SKClass of tclass + | SKInterface of tclass + | SKEnum of tenum + | SKTypedef of tdef + | SKAbstract of tabstract + | SKField of tclass_field * path option (* path - class path *) + | SKConstructor of tclass_field + | SKEnumField of tenum_field + | SKVariable of tvar + | SKOther type completion_subject = { s_name : string option; @@ -308,4 +329,14 @@ let make_subject name ?(start_pos=None) insert_pos = { s_name = name; s_start_pos = (match start_pos with None -> insert_pos | Some p -> p); s_insert_pos = insert_pos; -} \ No newline at end of file +} + +let string_of_symbol = function + | SKClass c | SKInterface c -> snd c.cl_path + | SKEnum en -> snd en.e_path + | SKTypedef td -> snd td.t_path + | SKAbstract a -> snd a.a_path + | SKField (cf,_) | SKConstructor cf -> cf.cf_name + | SKEnumField ef -> ef.ef_name + | SKVariable v -> v.v_name + | SKOther -> "" \ No newline at end of file diff --git a/src/core/ds/priorityQueue.ml b/src/core/ds/priorityQueue.ml new file mode 100644 index 0000000000000000000000000000000000000000..5521f12600f7302b7d0e6128e4453d376b7db459 --- /dev/null +++ b/src/core/ds/priorityQueue.ml @@ -0,0 +1,55 @@ +type priority = int + +type 'a t = +| Empty +| Node of priority * 'a * 'a t * 'a t + +let empty = Empty + +let rec insert queue prio elt = match queue with + | Empty -> Node(prio, elt, Empty, Empty) + | Node(p, e, left, right) -> + if prio <= p then + Node(prio, elt, insert right p e, left) + else + Node(p, e, insert right prio elt, left) + +exception Queue_is_empty + +let rec remove_top = function + | Empty -> raise Queue_is_empty + | Node(prio, elt, left, Empty) -> left + | Node(prio, elt, Empty, right) -> right + | Node(prio, elt, (Node(lprio, lelt, _, _) as left), (Node(rprio, relt, _, _) as right)) -> + if lprio <= rprio then + Node(lprio, lelt, remove_top left, right) + else + Node(rprio, relt, left, remove_top right) + +let extract = function + | Empty -> raise Queue_is_empty + | Node(prio, elt, _, _) as queue -> (prio, elt, remove_top queue) + +let is_empty = function + | Empty -> true + | Node _ -> false + +let fold queue f acc = + let rec loop queue acc = match queue with + | Empty -> acc + | Node(prio, elt, left, Empty) -> loop left (f acc prio elt) + | Node(prio, elt, Empty, right) -> loop right (f acc prio elt) + | Node(prio, elt, (Node(lprio,_,_,_) as left), (Node(rprio,relt,_,_) as right)) -> + let acc = f acc prio elt in + if lprio <= rprio then begin + let acc = loop left acc in + loop right acc + end else begin + let acc = loop right acc in + loop left acc + end + in + loop queue acc + +let merge queue1 queue2 = + fold queue1 insert queue2 \ No newline at end of file diff --git a/src/core/ds/ring.ml b/src/core/ds/ring.ml new file mode 100644 index 0000000000000000000000000000000000000000..a98e7a59529734695e1754f1a06a43aeb22a82d5 --- /dev/null +++ b/src/core/ds/ring.ml @@ -0,0 +1,46 @@ +type 'a t = { + values : 'a array; + mutable index : int; + mutable num_filled : int; +} + +let create len x = { + values = Array.make len x; + index = 0; + num_filled = 0; +} + +let push r x = + r.values.(r.index) <- x; + r.num_filled <- r.num_filled + 1; + if r.index = Array.length r.values - 1 then begin + r.index <- 0; + end else + r.index <- r.index + 1 + +let iter r f = + let len = Array.length r.values in + for i = 0 to len - 1 do + let off = r.index + i in + let off = if off >= len then off - len else off in + f r.values.(off) + done + +let fold r acc f = + let len = Array.length r.values in + let rec loop i acc = + if i = len then + acc + else begin + let off = r.index + i in + let off = if off >= len then off - len else off in + loop (i + 1) (f acc r.values.(off)) + end + in + loop 0 acc + +let is_filled r = + r.num_filled >= Array.length r.values + +let reset_filled r = + r.num_filled <- 0 diff --git a/src/core/dune b/src/core/dune new file mode 100644 index 0000000000000000000000000000000000000000..7218ebea30570a587c0a3ff9454f9ec7a846afeb --- /dev/null +++ b/src/core/dune @@ -0,0 +1,11 @@ +(rule + (targets metaList.ml) + (deps ../../src-json/meta.json) + (action (with-stdout-to metaList.ml (run %{bin:haxe_prebuild} meta ../../src-json/meta.json))) +) + +(rule + (targets defineList.ml) + (deps ../../src-json/define.json) + (action (with-stdout-to defineList.ml (run %{bin:haxe_prebuild} define ../../src-json/define.json))) +) \ No newline at end of file diff --git a/src/core/error.ml b/src/core/error.ml index 0bdff27d74d3a8ef4875806b059b9a49be585c5b..795035d764d085d7ad4af1dbf00ebe8638576ef9 100644 --- a/src/core/error.ml +++ b/src/core/error.ml @@ -1,5 +1,9 @@ open Globals -open Type +open TType +open TUnification +open TFunctions +open TPrinting +open TOther type call_error = | Not_enough_arguments of (string * bool * t) list @@ -9,7 +13,7 @@ type call_error = and error_msg = | Module_not_found of path - | Type_not_found of path * string + | Type_not_found of path * string * type_not_found_reason | Unify of unify_error list | Custom of string | Unknown_ident of string @@ -17,6 +21,10 @@ and error_msg = | Call_error of call_error | No_constructor of module_type +and type_not_found_reason = + | Private_type + | Not_defined + exception Fatal_error of string * Globals.pos exception Error of error_msg * Globals.pos @@ -30,7 +38,7 @@ let short_type ctx t = let tstr = s_type ctx t in if String.length tstr > 150 then String.sub tstr 0 147 ^ "..." else tstr -let unify_error_msg ctx = function +let unify_error_msg ctx err = match err with | Cannot_unify (t1,t2) -> s_type ctx t1 ^ " should be " ^ s_type ctx t2 | Invalid_field_type s -> @@ -85,8 +93,8 @@ module BetterErrors = struct type access = { acc_kind : access_kind; - mutable acc_expected : Type.t; - mutable acc_actual : Type.t; + mutable acc_expected : TType.t; + mutable acc_actual : TType.t; mutable acc_messages : unify_error list; mutable acc_next : access option; } @@ -138,7 +146,7 @@ module BetterErrors = struct let rec s_type ctx t = match t with | TMono r -> - (match !r with + (match r.tm_type with | None -> Printf.sprintf "Unknown<%d>" (try List.assq t (!ctx) with Not_found -> let n = List.length !ctx in ctx := (t,n) :: !ctx; n) | Some t -> s_type ctx t) | TEnum (e,tl) -> @@ -234,7 +242,7 @@ module BetterErrors = struct | TInst({cl_path = path},params) | TEnum({e_path = path},params) | TAbstract({a_path = path},params) | TType({t_path = path},params) -> path,params | _ -> - assert false + die "" __LOC__ in let s1,s2 = loop() in let path1,params1 = get_params access_prev.acc_actual in @@ -256,7 +264,8 @@ end let rec error_msg = function | Module_not_found m -> "Type not found : " ^ s_type_path m - | Type_not_found (m,t) -> "Module " ^ s_type_path m ^ " does not define type " ^ t + | Type_not_found (m,t,Private_type) -> "Cannot access private type " ^ t ^ " in module " ^ s_type_path m + | Type_not_found (m,t,Not_defined) -> "Module " ^ s_type_path m ^ " does not define type " ^ t | Unify l -> BetterErrors.better_error_message l | Unknown_ident s -> "Unknown identifier : " ^ s | Custom s -> s diff --git a/src/core/globals.ml b/src/core/globals.ml index dcaaa80d5bcd76aa8f412c795e901f215e232b53..8b927aef0fe7ab2eab802527c53a1a451e2d3f04 100644 --- a/src/core/globals.ml +++ b/src/core/globals.ml @@ -24,7 +24,7 @@ type platform = | Hl | Eval -let version = 4005 +let version = 4100 let version_major = version / 1000 let version_minor = (version mod 1000) / 100 let version_revision = (version mod 100) @@ -71,7 +71,47 @@ let platform_list_help = function let null_pos = { pfile = "?"; pmin = -1; pmax = -1 } +let mk_zero_range_pos p = { p with pmax = p.pmin } + let s_type_path (p,s) = match p with [] -> s | _ -> String.concat "." p ^ "." ^ s let starts_with s c = - String.length s > 0 && s.[0] = c \ No newline at end of file + String.length s > 0 && s.[0] = c + +let get_error_pos_ref : ((string -> int -> string) -> pos -> string) ref = ref (fun printer p -> + Printf.sprintf "%s: characters %d-%d" p.pfile p.pmin p.pmax +) + +let s_version with_build = + let pre = Option.map_default (fun pre -> "-" ^ pre) "" version_pre in + let build = + match with_build, Version.version_extra with + | true, Some (_,build) -> "+" ^ build + | _, _ -> "" + in + Printf.sprintf "%d.%d.%d%s%s" version_major version_minor version_revision pre build + +(** + Terminates compiler process and prints user-friendly instructions about filing an issue. + Usage: `die message __LOC__`, where `__LOC__` is a built-in ocaml constant +*) +let die ?p msg ml_loc = + let msg = + let str_pos, expr_msg = + match p with + | None -> "", "" + | Some p -> ((!get_error_pos_ref (Printf.sprintf "%s:%d:") p) ^ " "), "the expression example and " + in + str_pos ^ "Compiler failure" ^ (if msg = "" then "" else ": " ^ msg) ^ "\n" + ^ str_pos ^ "Please submit an issue at https://github.com/HaxeFoundation/haxe/issues/new\n" + ^ str_pos ^ "Attach " ^ expr_msg ^ "the following information:" + in + let backtrace = Printexc.raw_backtrace_to_string (Printexc.get_callstack 21) in + let backtrace = + try snd (ExtString.String.split backtrace "\n") + with ExtString.Invalid_string -> backtrace + in + let ver = s_version true + and os_type = if Sys.unix then "unix" else "windows" in + Printf.eprintf "%s\nHaxe: %s; OS type: %s;\n%s\n%s" msg ver os_type ml_loc backtrace; + assert false \ No newline at end of file diff --git a/src/core/json/genjson.ml b/src/core/json/genjson.ml index 27a27a8030a70a757bedc1a5fae9d5c2ba24fa37..eeb15062ba0274903a0199981cdac7b41ea823d0 100644 --- a/src/core/json/genjson.ml +++ b/src/core/json/genjson.ml @@ -72,7 +72,7 @@ let generate_expr_pos ctx p = jtodo let generate_doc ctx d = match ctx.generation_mode with - | GMFull -> jopt jstring d + | GMFull -> jopt jstring (gen_doc_text_opt d) | GMWithoutDoc | GMMinimum -> jnull (** return a range JSON structure for given position @@ -188,7 +188,7 @@ let rec generate_ast_type_param ctx tp = jobject [ let rec generate_type ctx t = let rec loop t = match t with | TMono r -> - begin match !r with + begin match r.tm_type with | None -> "TMono",None | Some t -> loop t end @@ -257,7 +257,7 @@ and generate_type_path_with_params ctx mpath tpath tl = and generate_type_parameter ctx (s,t) = let generate_constraints () = match follow t with | TInst({cl_kind = KTypeParameter tl},_) -> generate_types ctx tl - | _ -> assert false + | _ -> die "" __LOC__ in jobject [ "name",jstring s; @@ -604,6 +604,7 @@ let generate_class ctx c = "init",jopt (generate_texpr ctx) c.cl_init; "overrides",jlist (classfield_ref ctx) c.cl_overrides; "isExtern",jbool c.cl_extern; + "isFinal",jbool c.cl_final; ] let generate_enum ctx e = diff --git a/src/core/meta.ml b/src/core/meta.ml index 6ea21382eefcdd4992b4d9a5649da256e448744f..11e1850d345265a9e304c8fd384251dcfb76880e 100644 --- a/src/core/meta.ml +++ b/src/core/meta.ml @@ -40,7 +40,7 @@ let get_documentation d = | HasParam s -> params := s :: !params | Platforms fl -> pfs := fl @ !pfs | UsedOn ul -> used := ul @ !used - | UsedInternally -> assert false + | UsedInternally -> die "" __LOC__ | Link _ -> () ) flags; let params = (match List.rev !params with @@ -75,3 +75,7 @@ let get_all () = else [] in loop 0 + +let copy_from_to m src dst = + try (get m src) :: dst + with Not_found -> dst \ No newline at end of file diff --git a/src/core/path.ml b/src/core/path.ml index 7c5e3ddbe3c168471668ea1d291e948de53aaf27..d667e9c06a9f14ad4abdfba9129793da065a67d5 100644 --- a/src/core/path.ml +++ b/src/core/path.ml @@ -78,7 +78,7 @@ let normalize_path path = | Str.Text t :: [] -> List.rev (t :: acc) | Str.Text _ :: Str.Text _ :: _ -> - assert false + Globals.die "" __LOC__ in String.concat "/" (normalize [] (Str.full_split path_regex path)) @@ -95,13 +95,34 @@ let get_real_path = else get_full_path -(** Returns absolute path guaranteed to be the same for different letter case. - Use where equality comparison is required, lowercases the path on Windows *) -let unique_full_path = - if Globals.is_windows then - (fun f -> String.lowercase (get_full_path f)) - else - get_full_path +module UniqueKey : sig + type t + (** + Returns absolute path guaranteed to be the same for different letter case. + Use where equality comparison is required, lowercases the path on Windows + *) + val create : string -> t + (** + Check if the first key starts with the second key + *) + val starts_with : t -> t -> bool + (** + Get string representation of a key + *) + val to_string : t -> string +end = struct + type t = string + let create = + if Globals.is_windows then + (fun f -> String.lowercase (get_full_path f)) + else + get_full_path + + let starts_with subj start = + ExtString.String.starts_with subj start + + let to_string k = k +end let add_trailing_slash p = let l = String.length p in @@ -168,10 +189,10 @@ let module_name_of_file file = in s | [] -> - assert false + Globals.die "" __LOC__ let rec create_file bin ext acc = function - | [] -> assert false + | [] -> Globals.die "" __LOC__ | d :: [] -> let d = make_valid_filename d in let maxlen = 200 - String.length ext in @@ -234,8 +255,8 @@ module FilePath = struct | "." | ".." -> create (Some path) None None false | _ -> - let c1 = String.rindex path '/' in - let c2 = String.rindex path '\\' in + let c1 = try String.rindex path '/' with Not_found -> -1 in + let c2 = try String.rindex path '\\' with Not_found -> -1 in let split s at = String.sub s 0 at,String.sub s (at + 1) (String.length s - at - 1) in let dir,path,backslash = if c1 < c2 then begin let dir,path = split path c2 in diff --git a/src/core/tFunctions.ml b/src/core/tFunctions.ml new file mode 100644 index 0000000000000000000000000000000000000000..4daa5c35cda63cfe20ca1df0bc790451201b11b0 --- /dev/null +++ b/src/core/tFunctions.ml @@ -0,0 +1,746 @@ +open Globals +open Ast +open TType + +let monomorph_create_ref : (unit -> tmono) ref = ref (fun _ -> die "" __LOC__) +let monomorph_bind_ref : (tmono -> t -> unit) ref = ref (fun _ _ -> die "" __LOC__) + +let has_meta m ml = List.exists (fun (m2,_,_) -> m = m2) ml +let get_meta m ml = List.find (fun (m2,_,_) -> m = m2) ml + +(* Flags *) + +let has_flag flags flag = + flags land (1 lsl flag) > 0 + +let set_flag flags flag = + flags lor (1 lsl flag) + +let unset_flag flags flag = + flags land (lnot (1 lsl flag)) + +let int_of_class_field_flag (flag : flag_tclass_field) = + Obj.magic flag + +let add_class_field_flag cf (flag : flag_tclass_field) = + cf.cf_flags <- set_flag cf.cf_flags (int_of_class_field_flag flag) + +let remove_class_field_flag cf (flag : flag_tclass_field) = + cf.cf_flags <- unset_flag cf.cf_flags (int_of_class_field_flag flag) + +let has_class_field_flag cf (flag : flag_tclass_field) = + has_flag cf.cf_flags (int_of_class_field_flag flag) + +(* ======= General utility ======= *) + +let alloc_var = + let uid = ref 0 in + (fun kind n t p -> + incr uid; + { + v_kind = kind; + v_name = n; + v_type = t; + v_id = !uid; + v_capture = false; + v_final = (match kind with VUser TVOLocalFunction -> true | _ -> false); + v_extra = None; + v_meta = []; + v_pos = p + } + ) + +let alloc_mid = + let mid = ref 0 in + (fun() -> incr mid; !mid) + +let mk e t p = { eexpr = e; etype = t; epos = p } + +let mk_block e = + match e.eexpr with + | TBlock _ -> e + | _ -> mk (TBlock [e]) e.etype e.epos + +let mk_cast e t p = mk (TCast(e,None)) t p + +let null t p = mk (TConst TNull) t p + +let mk_mono() = TMono (!monomorph_create_ref ()) + +let rec t_dynamic = TDynamic t_dynamic + +let mk_anon ?fields status = + let fields = match fields with Some fields -> fields | None -> PMap.empty in + TAnon { a_fields = fields; a_status = status; } + +(* We use this for display purposes because otherwise we never see the Dynamic type that + is defined in StdTypes.hx. This is set each time a typer is created, but this is fine + because Dynamic is the same in all contexts. If this ever changes we'll have to review + how we handle this. *) +let t_dynamic_def = ref t_dynamic + +let tfun pl r = TFun (List.map (fun t -> "",false,t) pl,r) + +let fun_args l = List.map (fun (a,c,t) -> a, c <> None, t) l + +let mk_class m path pos name_pos = + { + cl_path = path; + cl_module = m; + cl_pos = pos; + cl_name_pos = name_pos; + cl_doc = None; + cl_meta = []; + cl_private = false; + cl_kind = KNormal; + cl_extern = false; + cl_final = false; + cl_interface = false; + cl_params = []; + cl_using = []; + cl_super = None; + cl_implements = []; + cl_fields = PMap.empty; + cl_ordered_statics = []; + cl_ordered_fields = []; + cl_statics = PMap.empty; + cl_dynamic = None; + cl_array_access = None; + cl_constructor = None; + cl_init = None; + cl_overrides = []; + cl_build = (fun() -> Built); + cl_restore = (fun() -> ()); + cl_descendants = []; + } + +let module_extra file sign time kind policy = + { + m_file = file; + m_sign = sign; + m_display = { + m_inline_calls = []; + m_type_hints = []; + m_import_positions = PMap.empty; + }; + m_dirty = None; + m_added = 0; + m_mark = 0; + m_time = time; + m_processed = 0; + m_deps = PMap.empty; + m_kind = kind; + m_binded_res = PMap.empty; + m_if_feature = []; + m_features = Hashtbl.create 0; + m_check_policy = policy; + } + + +let mk_field name ?(public = true) t p name_pos = { + cf_name = name; + cf_type = t; + cf_pos = p; + cf_name_pos = name_pos; + cf_doc = None; + cf_meta = []; + cf_kind = Var { v_read = AccNormal; v_write = AccNormal }; + cf_expr = None; + cf_expr_unoptimized = None; + cf_params = []; + cf_overloads = []; + cf_flags = if public then set_flag 0 (int_of_class_field_flag CfPublic) else 0; +} + +let null_module = { + m_id = alloc_mid(); + m_path = [] , ""; + m_types = []; + m_extra = module_extra "" "" 0. MFake []; + } + +let null_class = + let c = mk_class null_module ([],"") null_pos null_pos in + c.cl_private <- true; + c + +let null_field = mk_field "" t_dynamic null_pos null_pos + +let null_abstract = { + a_path = ([],""); + a_module = null_module; + a_pos = null_pos; + a_name_pos = null_pos; + a_private = true; + a_doc = None; + a_meta = []; + a_params = []; + a_using = []; + a_ops = []; + a_unops = []; + a_impl = None; + a_this = t_dynamic; + a_from = []; + a_from_field = []; + a_to = []; + a_to_field = []; + a_array = []; + a_read = None; + a_write = None; +} + +let add_dependency m mdep = + if m != null_module && m != mdep then m.m_extra.m_deps <- PMap.add mdep.m_id mdep m.m_extra.m_deps + +let arg_name (a,_) = a.v_name + +let t_infos t : tinfos = + match t with + | TClassDecl c -> Obj.magic c + | TEnumDecl e -> Obj.magic e + | TTypeDecl t -> Obj.magic t + | TAbstractDecl a -> Obj.magic a + +let t_path t = (t_infos t).mt_path + +let rec extends c csup = + if c == csup || List.exists (fun (i,_) -> extends i csup) c.cl_implements then + true + else match c.cl_super with + | None -> false + | Some (c,_) -> extends c csup + +let add_descendant c descendant = + c.cl_descendants <- descendant :: c.cl_descendants + +let lazy_type f = + match !f with + | LAvailable t -> t + | LProcessing f | LWait f -> f() + +let lazy_available t = LAvailable t +let lazy_processing f = LProcessing f +let lazy_wait f = LWait f + +let map loop t = + match t with + | TMono r -> + (match r.tm_type with + | None -> t + | Some t -> loop t) (* erase*) + | TEnum (_,[]) | TInst (_,[]) | TType (_,[]) -> + t + | TEnum (e,tl) -> + TEnum (e, List.map loop tl) + | TInst (c,tl) -> + TInst (c, List.map loop tl) + | TType (t2,tl) -> + TType (t2,List.map loop tl) + | TAbstract (a,tl) -> + TAbstract (a,List.map loop tl) + | TFun (tl,r) -> + TFun (List.map (fun (s,o,t) -> s, o, loop t) tl,loop r) + | TAnon a -> + let fields = PMap.map (fun f -> { f with cf_type = loop f.cf_type }) a.a_fields in + begin match !(a.a_status) with + | Opened -> + a.a_fields <- fields; + t + | _ -> + mk_anon ~fields a.a_status + end + | TLazy f -> + let ft = lazy_type f in + let ft2 = loop ft in + if ft == ft2 then t else ft2 + | TDynamic t2 -> + if t == t2 then t else TDynamic (loop t2) + +let duplicate t = + let monos = ref [] in + let rec loop t = + match t with + | TMono { tm_type = None } -> + (try + List.assq t !monos + with Not_found -> + let m = mk_mono() in + monos := (t,m) :: !monos; + m) + | _ -> + map loop t + in + loop t + +exception ApplyParamsRecursion + +(* substitute parameters with other types *) +let apply_params ?stack cparams params t = + match cparams with + | [] -> t + | _ -> + let rec loop l1 l2 = + match l1, l2 with + | [] , [] -> [] + | (x,TLazy f) :: l1, _ -> loop ((x,lazy_type f) :: l1) l2 + | (_,t1) :: l1 , t2 :: l2 -> (t1,t2) :: loop l1 l2 + | _ -> die "" __LOC__ + in + let subst = loop cparams params in + let rec loop t = + try + List.assq t subst + with Not_found -> + match t with + | TMono r -> + (match r.tm_type with + | None -> t + | Some t -> loop t) + | TEnum (e,tl) -> + (match tl with + | [] -> t + | _ -> TEnum (e,List.map loop tl)) + | TType (t2,tl) -> + (match tl with + | [] -> t + | _ -> + let new_applied_params = List.map loop tl in + (match stack with + | None -> () + | Some stack -> + List.iter (fun (subject, old_applied_params) -> + (* + E.g.: + ``` + typedef Rec = { function method():Rec> } + ``` + We need to make sure that we are not applying the result of previous + application to the same place, which would mean the result of current + application would go into `apply_params` again and then again and so on. + + Argument `stack` holds all previous results of `apply_params` to typedefs in current + unification process. + + Imagine we are trying to unify `Rec` with something. + + Once `apply_params Array Int Rec>` is called for the first time the result + will be `Rec< Array >`. Store `Array` into `stack` + + Then the next params application looks like this: + `apply_params Array Array Rec>` + Notice the second argument is actually the result of a previous `apply_params` call. + And the result of the current call is `Rec< Array> >`. + + The third call would be: + `apply_params Array Array> Rec>` + and so on. + + To stop infinite params application we need to check that we are trying to apply params + produced by the previous `apply_params Array _ Rec>` to the same `Rec>` + *) + if + subject == t (* Check the place that we're applying to is the same `Rec>` *) + && old_applied_params == params (* Check that params we're applying are the same params + produced by the previous call to + `apply_params Array _ Rec>` *) + then + raise ApplyParamsRecursion + ) !stack; + stack := (t, new_applied_params) :: !stack; + ); + TType (t2,new_applied_params)) + | TAbstract (a,tl) -> + (match tl with + | [] -> t + | _ -> TAbstract (a,List.map loop tl)) + | TInst (c,tl) -> + (match tl with + | [] -> + t + | [TMono r] -> + (match r.tm_type with + | Some tt when t == tt -> + (* for dynamic *) + let pt = mk_mono() in + let t = TInst (c,[pt]) in + (match pt with TMono r -> !monomorph_bind_ref r t | _ -> die "" __LOC__); + t + | _ -> TInst (c,List.map loop tl)) + | _ -> + TInst (c,List.map loop tl)) + | TFun (tl,r) -> + TFun (List.map (fun (s,o,t) -> s, o, loop t) tl,loop r) + | TAnon a -> + let fields = PMap.map (fun f -> { f with cf_type = loop f.cf_type }) a.a_fields in + begin match !(a.a_status) with + | Opened -> + a.a_fields <- fields; + t + | _ -> + mk_anon ~fields a.a_status + end + | TLazy f -> + let ft = lazy_type f in + let ft2 = loop ft in + if ft == ft2 then + t + else + ft2 + | TDynamic t2 -> + if t == t2 then + t + else + TDynamic (loop t2) + in + loop t + +let monomorphs eparams t = + apply_params eparams (List.map (fun _ -> mk_mono()) eparams) t + +let apply_params_stack = ref [] + +let try_apply_params_rec cparams params t success = + let old_stack = !apply_params_stack in + try + let result = success (apply_params ~stack:apply_params_stack cparams params t) in + apply_params_stack := old_stack; + result + with + | ApplyParamsRecursion -> + apply_params_stack := old_stack; + | err -> + apply_params_stack := old_stack; + raise err + +let rec follow t = + match t with + | TMono r -> + (match r.tm_type with + | Some t -> follow t + | _ -> t) + | TLazy f -> + follow (lazy_type f) + | TType (t,tl) -> + follow (apply_params t.t_params tl t.t_type) + | TAbstract({a_path = [],"Null"},[t]) -> + follow t + | _ -> t + +let follow_once t = + match t with + | TMono r -> + (match r.tm_type with + | None -> t + | Some t -> t) + | TAbstract _ | TEnum _ | TInst _ | TFun _ | TAnon _ | TDynamic _ -> + t + | TType (t,tl) -> + apply_params t.t_params tl t.t_type + | TLazy f -> + lazy_type f + +let rec follow_without_null t = + match t with + | TMono r -> + (match r.tm_type with + | Some t -> follow_without_null t + | _ -> t) + | TLazy f -> + follow_without_null (lazy_type f) + | TType (t,tl) -> + follow_without_null (apply_params t.t_params tl t.t_type) + | _ -> t + +(** Assumes `follow` has already been applied *) +let rec ambiguate_funs t = + match t with + | TFun _ -> TFun ([], t_dynamic) + | TMono r -> + (match r.tm_type with + | Some _ -> die "" __LOC__ + | _ -> t) + | TInst (a, pl) -> + TInst (a, List.map ambiguate_funs pl) + | TEnum (a, pl) -> + TEnum (a, List.map ambiguate_funs pl) + | TAbstract (a, pl) -> + TAbstract (a, List.map ambiguate_funs pl) + | TType (a, pl) -> + TType (a, List.map ambiguate_funs pl) + | TDynamic _ -> t + | TAnon a -> + TAnon { a with a_fields = + PMap.map (fun af -> { af with cf_type = + ambiguate_funs af.cf_type }) a.a_fields } + | TLazy _ -> die "" __LOC__ + +let rec is_nullable = function + | TMono r -> + (match r.tm_type with None -> false | Some t -> is_nullable t) + | TAbstract ({ a_path = ([],"Null") },[_]) -> + true + | TLazy f -> + is_nullable (lazy_type f) + | TType (t,tl) -> + is_nullable (apply_params t.t_params tl t.t_type) + | TFun _ -> + false +(* + Type parameters will most of the time be nullable objects, so we don't want to make it hard for users + to have to specify Null all over the place, so while they could be a basic type, let's assume they will not. + + This will still cause issues with inlining and haxe.rtti.Generic. In that case proper explicit Null is required to + work correctly with basic types. This could still be fixed by redoing a nullability inference on the typed AST. + + | TInst ({ cl_kind = KTypeParameter },_) -> false +*) + | TAbstract (a,_) when Meta.has Meta.CoreType a.a_meta -> + not (Meta.has Meta.NotNull a.a_meta) + | TAbstract (a,tl) -> + not (Meta.has Meta.NotNull a.a_meta) && is_nullable (apply_params a.a_params tl a.a_this) + | _ -> + true + +let rec is_null ?(no_lazy=false) = function + | TMono r -> + (match r.tm_type with None -> false | Some t -> is_null t) + | TAbstract ({ a_path = ([],"Null") },[t]) -> + not (is_nullable (follow t)) + | TLazy f -> + if no_lazy then raise Exit else is_null (lazy_type f) + | TType (t,tl) -> + is_null (apply_params t.t_params tl t.t_type) + | _ -> + false + +(* Determines if we have a Null. Unlike is_null, this returns true even if the wrapped type is nullable itself. *) +let rec is_explicit_null = function + | TMono r -> + (match r.tm_type with None -> false | Some t -> is_explicit_null t) + | TAbstract ({ a_path = ([],"Null") },[t]) -> + true + | TLazy f -> + is_explicit_null (lazy_type f) + | TType (t,tl) -> + is_explicit_null (apply_params t.t_params tl t.t_type) + | _ -> + false + +let rec has_mono t = match t with + | TMono r -> + (match r.tm_type with None -> true | Some t -> has_mono t) + | TInst(_,pl) | TEnum(_,pl) | TAbstract(_,pl) | TType(_,pl) -> + List.exists has_mono pl + | TDynamic _ -> + false + | TFun(args,r) -> + has_mono r || List.exists (fun (_,_,t) -> has_mono t) args + | TAnon a -> + PMap.fold (fun cf b -> has_mono cf.cf_type || b) a.a_fields false + | TLazy f -> + has_mono (lazy_type f) + +let concat e1 e2 = + let e = (match e1.eexpr, e2.eexpr with + | TBlock el1, TBlock el2 -> TBlock (el1@el2) + | TBlock el, _ -> TBlock (el @ [e2]) + | _, TBlock el -> TBlock (e1 :: el) + | _ , _ -> TBlock [e1;e2] + ) in + mk e e2.etype (punion e1.epos e2.epos) + +let is_closed a = !(a.a_status) <> Opened + +let type_of_module_type = function + | TClassDecl c -> TInst (c,List.map snd c.cl_params) + | TEnumDecl e -> TEnum (e,List.map snd e.e_params) + | TTypeDecl t -> TType (t,List.map snd t.t_params) + | TAbstractDecl a -> TAbstract (a,List.map snd a.a_params) + +let rec module_type_of_type = function + | TInst(c,_) -> TClassDecl c + | TEnum(en,_) -> TEnumDecl en + | TType(t,_) -> TTypeDecl t + | TAbstract(a,_) -> TAbstractDecl a + | TLazy f -> module_type_of_type (lazy_type f) + | TMono r -> + (match r.tm_type with + | Some t -> module_type_of_type t + | _ -> raise Exit) + | _ -> + raise Exit + +let tconst_to_const = function + | TInt i -> Int (Int32.to_string i) + | TFloat s -> Float s + | TString s -> String(s,SDoubleQuotes) + | TBool b -> Ident (if b then "true" else "false") + | TNull -> Ident "null" + | TThis -> Ident "this" + | TSuper -> Ident "super" + +let has_ctor_constraint c = match c.cl_kind with + | KTypeParameter tl -> + List.exists (fun t -> match follow t with + | TAnon a when PMap.mem "new" a.a_fields -> true + | TAbstract({a_path=["haxe"],"Constructible"},_) -> true + | _ -> false + ) tl; + | _ -> false + +(* ======= Field utility ======= *) + +let field_name f = + match f with + | FAnon f | FInstance (_,_,f) | FStatic (_,f) | FClosure (_,f) -> f.cf_name + | FEnum (_,f) -> f.ef_name + | FDynamic n -> n + +let extract_field = function + | FAnon f | FInstance (_,_,f) | FStatic (_,f) | FClosure (_,f) -> Some f + | _ -> None + +let is_physical_var_field f = + match f.cf_kind with + | Var { v_read = AccNormal | AccInline | AccNo } | Var { v_write = AccNormal | AccNo } -> true + | Var _ -> Meta.has Meta.IsVar f.cf_meta + | _ -> false + +let is_physical_field f = + match f.cf_kind with + | Method _ -> true + | _ -> is_physical_var_field f + +let field_type f = + match f.cf_params with + | [] -> f.cf_type + | l -> monomorphs l f.cf_type + +let rec raw_class_field build_type c tl i = + let apply = apply_params c.cl_params tl in + try + let f = PMap.find i c.cl_fields in + Some (c,tl), build_type f , f + with Not_found -> try (match c.cl_constructor with + | Some ctor when i = "new" -> Some (c,tl), build_type ctor,ctor + | _ -> raise Not_found) + with Not_found -> try + match c.cl_super with + | None -> + raise Not_found + | Some (c,tl) -> + let c2 , t , f = raw_class_field build_type c (List.map apply tl) i in + c2, apply_params c.cl_params tl t , f + with Not_found -> + match c.cl_kind with + | KTypeParameter tl -> + let rec loop = function + | [] -> + raise Not_found + | t :: ctl -> + match follow t with + | TAnon a -> + (try + let f = PMap.find i a.a_fields in + None, build_type f, f + with + Not_found -> loop ctl) + | TInst (c,tl) -> + (try + let c2, t , f = raw_class_field build_type c (List.map apply tl) i in + c2, apply_params c.cl_params tl t, f + with + Not_found -> loop ctl) + | _ -> + loop ctl + in + loop tl + | _ -> + if not c.cl_interface then raise Not_found; + (* + an interface can implements other interfaces without + having to redeclare its fields + *) + let rec loop = function + | [] -> + raise Not_found + | (c,tl) :: l -> + try + let c2, t , f = raw_class_field build_type c (List.map apply tl) i in + c2, apply_params c.cl_params tl t, f + with + Not_found -> loop l + in + loop c.cl_implements + +let class_field = raw_class_field field_type + +let quick_field t n = + match follow t with + | TInst (c,tl) -> + let c, _, f = raw_class_field (fun f -> f.cf_type) c tl n in + (match c with None -> FAnon f | Some (c,tl) -> FInstance (c,tl,f)) + | TAnon a -> + (match !(a.a_status) with + | EnumStatics e -> + let ef = PMap.find n e.e_constrs in + FEnum(e,ef) + | Statics c -> + FStatic (c,PMap.find n c.cl_statics) + | AbstractStatics a -> + begin match a.a_impl with + | Some c -> + let cf = PMap.find n c.cl_statics in + FStatic(c,cf) (* is that right? *) + | _ -> + raise Not_found + end + | _ -> + FAnon (PMap.find n a.a_fields)) + | TDynamic _ -> + FDynamic n + | TEnum _ | TMono _ | TAbstract _ | TFun _ -> + raise Not_found + | TLazy _ | TType _ -> + die "" __LOC__ + +let quick_field_dynamic t s = + try quick_field t s + with Not_found -> FDynamic s + +let rec get_constructor build_type c = + match c.cl_constructor, c.cl_super with + | Some c, _ -> build_type c, c + | None, None -> raise Not_found + | None, Some (csup,cparams) -> + let t, c = get_constructor build_type csup in + apply_params csup.cl_params cparams t, c + +let has_constructor c = + try + ignore(get_constructor (fun cf -> cf.cf_type) c); + true + with Not_found -> false + +let resolve_typedef t = + match t with + | TClassDecl _ | TEnumDecl _ | TAbstractDecl _ -> t + | TTypeDecl td -> + match follow td.t_type with + | TEnum (e,_) -> TEnumDecl e + | TInst (c,_) -> TClassDecl c + | TAbstract (a,_) -> TAbstractDecl a + | _ -> t + +(** + Check if type `t` has meta `m`. + Does not follow typedefs, monomorphs etc. +*) +let type_has_meta t m = + match t with + | TMono _ | TFun _ | TAnon _ | TDynamic _ | TLazy _ -> false + | TEnum ({ e_meta = metadata }, _) + | TInst ({ cl_meta = metadata }, _) + | TType ({ t_meta = metadata }, _) + | TAbstract ({ a_meta = metadata }, _) -> has_meta m metadata + diff --git a/src/core/tOther.ml b/src/core/tOther.ml new file mode 100644 index 0000000000000000000000000000000000000000..b66cbe15eecd68a31daf2ab13cfa110f3fdd52f9 --- /dev/null +++ b/src/core/tOther.ml @@ -0,0 +1,302 @@ +open Globals +open Ast +open TType +open TFunctions +open TPrinting + +module TExprToExpr = struct + let tpath p mp pl = + if snd mp = snd p then + CTPath (mk_type_path ~params:pl p) + else + CTPath (mk_type_path ~params:pl ~sub:(snd p) mp) + + let rec convert_type = function + | TMono r -> + (match r.tm_type with + | None -> raise Exit + | Some t -> convert_type t) + | TInst ({cl_private = true; cl_path=_,name},tl) + | TEnum ({e_private = true; e_path=_,name},tl) + | TType ({t_private = true; t_path=_,name},tl) + | TAbstract ({a_private = true; a_path=_,name},tl) -> + CTPath (mk_type_path ~params:(List.map tparam tl) ([],name)) + | TEnum (e,pl) -> + tpath e.e_path e.e_module.m_path (List.map tparam pl) + | TInst({cl_kind = KExpr e} as c,pl) -> + tpath ([],snd c.cl_path) ([],snd c.cl_path) (List.map tparam pl) + | TInst({cl_kind = KTypeParameter _} as c,pl) -> + tpath ([],snd c.cl_path) ([],snd c.cl_path) (List.map tparam pl) + | TInst (c,pl) -> + tpath c.cl_path c.cl_module.m_path (List.map tparam pl) + | TType (t,pl) as tf -> + (* recurse on type-type *) + if (snd t.t_path).[0] = '#' then convert_type (follow tf) else tpath t.t_path t.t_module.m_path (List.map tparam pl) + | TAbstract (a,pl) -> + tpath a.a_path a.a_module.m_path (List.map tparam pl) + | TFun (args,ret) -> + CTFunction (List.map (fun (_,_,t) -> convert_type' t) args, (convert_type' ret)) + | TAnon a -> + begin match !(a.a_status) with + | Statics c -> tpath ([],"Class") ([],"Class") [TPType (tpath c.cl_path c.cl_path [],null_pos)] + | EnumStatics e -> tpath ([],"Enum") ([],"Enum") [TPType (tpath e.e_path e.e_path [],null_pos)] + | _ -> + CTAnonymous (PMap.foldi (fun _ f acc -> + { + cff_name = f.cf_name,null_pos; + cff_kind = FVar (mk_type_hint f.cf_type null_pos,None); + cff_pos = f.cf_pos; + cff_doc = f.cf_doc; + cff_meta = f.cf_meta; + cff_access = []; + } :: acc + ) a.a_fields []) + end + | (TDynamic t2) as t -> + tpath ([],"Dynamic") ([],"Dynamic") (if t == t_dynamic then [] else [tparam t2]) + | TLazy f -> + convert_type (lazy_type f) + + and convert_type' t = + convert_type t,null_pos + + and tparam = function + | TInst ({cl_kind = KExpr e}, _) -> TPExpr e + | t -> TPType (convert_type' t) + + and mk_type_hint t p = + match follow t with + | TMono _ -> None + | _ -> (try Some (convert_type t,p) with Exit -> None) + + let rec convert_expr e = + let full_type_path t = + let mp,p = match t with + | TClassDecl c -> c.cl_module.m_path,c.cl_path + | TEnumDecl en -> en.e_module.m_path,en.e_path + | TAbstractDecl a -> a.a_module.m_path,a.a_path + | TTypeDecl t -> t.t_module.m_path,t.t_path + in + if snd mp = snd p then p else (fst mp) @ [snd mp],snd p + in + let mk_path = expr_of_type_path in + let mk_ident = function + | "`trace" -> Ident "trace" + | n -> Ident n + in + let eopt = function None -> None | Some e -> Some (convert_expr e) in + ((match e.eexpr with + | TConst c -> + EConst (tconst_to_const c) + | TLocal v -> EConst (mk_ident v.v_name) + | TArray (e1,e2) -> EArray (convert_expr e1,convert_expr e2) + | TBinop (op,e1,e2) -> EBinop (op, convert_expr e1, convert_expr e2) + | TField (e,f) -> EField (convert_expr e, field_name f) + | TTypeExpr t -> fst (mk_path (full_type_path t) e.epos) + | TParenthesis e -> EParenthesis (convert_expr e) + | TObjectDecl fl -> EObjectDecl (List.map (fun (k,e) -> k, convert_expr e) fl) + | TArrayDecl el -> EArrayDecl (List.map convert_expr el) + | TCall (e,el) -> ECall (convert_expr e,List.map convert_expr el) + | TNew (c,pl,el) -> ENew ((match (try convert_type (TInst (c,pl)) with Exit -> convert_type (TInst (c,[]))) with CTPath p -> p,null_pos | _ -> die "" __LOC__),List.map convert_expr el) + | TUnop (op,p,e) -> EUnop (op,p,convert_expr e) + | TFunction f -> + let arg (v,c) = (v.v_name,v.v_pos), false, v.v_meta, mk_type_hint v.v_type null_pos, (match c with None -> None | Some c -> Some (convert_expr c)) in + EFunction (FKAnonymous,{ f_params = []; f_args = List.map arg f.tf_args; f_type = mk_type_hint f.tf_type null_pos; f_expr = Some (convert_expr f.tf_expr) }) + | TVar (v,eo) -> + EVars ([(v.v_name,v.v_pos), v.v_final, mk_type_hint v.v_type v.v_pos, eopt eo]) + | TBlock el -> EBlock (List.map convert_expr el) + | TFor (v,it,e) -> + let ein = (EBinop (OpIn,(EConst (Ident v.v_name),it.epos),convert_expr it),it.epos) in + EFor (ein,convert_expr e) + | TIf (e,e1,e2) -> EIf (convert_expr e,convert_expr e1,eopt e2) + | TWhile (e1,e2,flag) -> EWhile (convert_expr e1, convert_expr e2, flag) + | TSwitch (e,cases,def) -> + let cases = List.map (fun (vl,e) -> + List.map convert_expr vl,None,(match e.eexpr with TBlock [] -> None | _ -> Some (convert_expr e)),e.epos + ) cases in + let def = match eopt def with None -> None | Some (EBlock [],_) -> Some (None,null_pos) | Some e -> Some (Some e,pos e) in + ESwitch (convert_expr e,cases,def) + | TEnumIndex _ + | TEnumParameter _ -> + (* these are considered complex, so the AST is handled in TMeta(Meta.Ast) *) + die "" __LOC__ + | TTry (e,catches) -> + let e1 = convert_expr e in + let catches = List.map (fun (v,e) -> + let ct = try convert_type v.v_type,null_pos with Exit -> die "" __LOC__ in + let e = convert_expr e in + (v.v_name,v.v_pos),(Some ct),e,(pos e) + ) catches in + ETry (e1,catches) + | TReturn e -> EReturn (eopt e) + | TBreak -> EBreak + | TContinue -> EContinue + | TThrow e -> EThrow (convert_expr e) + | TCast (e,t) -> + let t = (match t with + | None -> None + | Some t -> + let t = (match t with TClassDecl c -> TInst (c,[]) | TEnumDecl e -> TEnum (e,[]) | TTypeDecl t -> TType (t,[]) | TAbstractDecl a -> TAbstract (a,[])) in + Some (try convert_type t,null_pos with Exit -> die "" __LOC__) + ) in + ECast (convert_expr e,t) + | TMeta ((Meta.Ast,[e1,_],_),_) -> e1 + | TMeta (m,e) -> EMeta(m,convert_expr e) + | TIdent s -> EConst (Ident s)) + ,e.epos) + +end + +module ExtType = struct + let is_mono = function + | TMono { tm_type = None } -> true + | _ -> false + + let is_void = function + | TAbstract({a_path=[],"Void"},_) -> true + | _ -> false + + let is_int t = match t with + | TAbstract({a_path=[],"Int"},_) -> true + | _ -> false + + let is_float t = match t with + | TAbstract({a_path=[],"Float"},_) -> true + | _ -> false + + let is_numeric t = match t with + | TAbstract({a_path=[],"Float"},_) -> true + | TAbstract({a_path=[],"Int"},_) -> true + | _ -> false + + let is_string t = match t with + | TInst({cl_path=[],"String"},_) -> true + | _ -> false + + let is_bool t = match t with + | TAbstract({a_path=[],"Bool"},_) -> true + | _ -> false + + type semantics = + | VariableSemantics + | ReferenceSemantics + | ValueSemantics + + let semantics_name = function + | VariableSemantics -> "variable" + | ReferenceSemantics -> "reference" + | ValueSemantics -> "value" + + let has_semantics t sem = + let name = semantics_name sem in + let check meta = + has_meta_option meta Meta.Semantics name + in + let rec loop t = match t with + | TInst(c,_) -> check c.cl_meta + | TEnum(en,_) -> check en.e_meta + | TType(t,tl) -> check t.t_meta || (loop (apply_params t.t_params tl t.t_type)) + | TAbstract(a,_) -> check a.a_meta + | TLazy f -> loop (lazy_type f) + | TMono r -> + (match r.tm_type with + | Some t -> loop t + | _ -> false) + | _ -> + false + in + loop t + + let has_variable_semantics t = has_semantics t VariableSemantics + let has_reference_semantics t = has_semantics t ReferenceSemantics + let has_value_semantics t = has_semantics t ValueSemantics +end + +let no_meta = [] + +let class_module_type c = { + t_path = [],"Class<" ^ (s_type_path c.cl_path) ^ ">" ; + t_module = c.cl_module; + t_doc = None; + t_pos = c.cl_pos; + t_name_pos = null_pos; + t_type = mk_anon ~fields:c.cl_statics (ref (Statics c)); + t_private = true; + t_params = []; + t_using = []; + t_meta = no_meta; +} + +let enum_module_type m path p = { + t_path = [], "Enum<" ^ (s_type_path path) ^ ">"; + t_module = m; + t_doc = None; + t_pos = p; + t_name_pos = null_pos; + t_type = mk_mono(); + t_private = true; + t_params = []; + t_using = []; + t_meta = []; +} + +let abstract_module_type a tl = { + t_path = [],Printf.sprintf "Abstract<%s%s>" (s_type_path a.a_path) (s_type_params (ref []) tl); + t_module = a.a_module; + t_doc = None; + t_pos = a.a_pos; + t_name_pos = null_pos; + t_type = mk_anon (ref (AbstractStatics a)); + t_private = true; + t_params = []; + t_using = []; + t_meta = no_meta; +} + +module TClass = struct + let get_member_fields' self_too c0 tl = + let rec loop acc c tl = + let apply = apply_params c.cl_params tl in + let maybe_add acc cf = + if not (PMap.mem cf.cf_name acc) then begin + let cf = if tl = [] then cf else {cf with cf_type = apply cf.cf_type} in + PMap.add cf.cf_name (c,cf) acc + end else acc + in + let acc = if self_too || c != c0 then List.fold_left maybe_add acc c.cl_ordered_fields else acc in + if c.cl_interface then + List.fold_left (fun acc (i,tl) -> loop acc i (List.map apply tl)) acc c.cl_implements + else + match c.cl_super with + | Some(c,tl) -> loop acc c (List.map apply tl) + | None -> acc + in + loop PMap.empty c0 tl + + let get_all_super_fields c = + get_member_fields' false c (List.map snd c.cl_params) + + let get_all_fields c tl = + get_member_fields' true c tl + + let get_overridden_fields c cf = + let rec loop acc c = match c.cl_super with + | None -> + acc + | Some(c,_) -> + begin try + let cf' = PMap.find cf.cf_name c.cl_fields in + loop (cf' :: acc) c + with Not_found -> + loop acc c + end + in + loop [] c +end + +let s_class_path c = + let path = match c.cl_kind with + | KAbstractImpl a -> a.a_path + | _ -> c.cl_path + in + s_type_path path \ No newline at end of file diff --git a/src/core/tPrinting.ml b/src/core/tPrinting.ml new file mode 100644 index 0000000000000000000000000000000000000000..c8bbdb96fcdd77fd024384252d186d750b8f4bd7 --- /dev/null +++ b/src/core/tPrinting.ml @@ -0,0 +1,655 @@ +open Globals +open Ast +open TType +open TFunctions + +let print_context() = ref [] + +let rec s_type_kind t = + let map tl = String.concat ", " (List.map s_type_kind tl) in + match t with + | TMono r -> + begin match r.tm_type with + | None -> Printf.sprintf "TMono (None)" + | Some t -> "TMono (Some (" ^ (s_type_kind t) ^ "))" + end + | TEnum(en,tl) -> Printf.sprintf "TEnum(%s, [%s])" (s_type_path en.e_path) (map tl) + | TInst(c,tl) -> Printf.sprintf "TInst(%s, [%s])" (s_type_path c.cl_path) (map tl) + | TType(t,tl) -> Printf.sprintf "TType(%s, [%s])" (s_type_path t.t_path) (map tl) + | TAbstract(a,tl) -> Printf.sprintf "TAbstract(%s, [%s])" (s_type_path a.a_path) (map tl) + | TFun(tl,r) -> Printf.sprintf "TFun([%s], %s)" (String.concat ", " (List.map (fun (n,b,t) -> Printf.sprintf "%s%s:%s" (if b then "?" else "") n (s_type_kind t)) tl)) (s_type_kind r) + | TAnon an -> "TAnon" + | TDynamic t2 -> "TDynamic" + | TLazy _ -> "TLazy" + +let s_module_type_kind = function + | TClassDecl c -> "TClassDecl(" ^ (s_type_path c.cl_path) ^ ")" + | TEnumDecl en -> "TEnumDecl(" ^ (s_type_path en.e_path) ^ ")" + | TAbstractDecl a -> "TAbstractDecl(" ^ (s_type_path a.a_path) ^ ")" + | TTypeDecl t -> "TTypeDecl(" ^ (s_type_path t.t_path) ^ ")" + +let rec s_type ctx t = + match t with + | TMono r -> + (match r.tm_type with + | None -> + begin try + let id = List.assq t (!ctx) in + Printf.sprintf "Unknown<%d>" id + with Not_found -> + let id = List.length !ctx in + ctx := (t,id) :: !ctx; + Printf.sprintf "Unknown<%d>" id + end + | Some t -> s_type ctx t) + | TEnum (e,tl) -> + s_type_path e.e_path ^ s_type_params ctx tl + | TInst (c,tl) -> + (match c.cl_kind with + | KExpr e -> Ast.Printer.s_expr e + | _ -> s_type_path c.cl_path ^ s_type_params ctx tl) + | TType ({ t_type = TAnon { a_status = { contents = Statics { cl_kind = KAbstractImpl a }}}}, _) -> + "Abstract<" ^ (s_type_path a.a_path) ^ ">" + | TType (t,tl) -> + s_type_path t.t_path ^ s_type_params ctx tl + | TAbstract (a,tl) -> + s_type_path a.a_path ^ s_type_params ctx tl + | TFun ([],t) -> + "Void -> " ^ s_fun ctx t false + | TFun (l,t) -> + let args = match l with + | [] -> "()" + | ["",b,t] -> Printf.sprintf "%s%s" (if b then "?" else "") (s_fun ctx t true) + | _ -> + let args = String.concat ", " (List.map (fun (s,b,t) -> + (if b then "?" else "") ^ (if s = "" then "" else s ^ " : ") ^ s_fun ctx t true + ) l) in + "(" ^ args ^ ")" + in + Printf.sprintf "%s -> %s" args (s_fun ctx t false) + | TAnon a -> + begin + match !(a.a_status) with + | Statics c -> Printf.sprintf "{ Statics %s }" (s_type_path c.cl_path) + | EnumStatics e -> Printf.sprintf "{ EnumStatics %s }" (s_type_path e.e_path) + | AbstractStatics a -> Printf.sprintf "{ AbstractStatics %s }" (s_type_path a.a_path) + | _ -> + let fl = PMap.fold (fun f acc -> ((if Meta.has Meta.Optional f.cf_meta then " ?" else " ") ^ f.cf_name ^ " : " ^ s_type ctx f.cf_type) :: acc) a.a_fields [] in + "{" ^ (if not (is_closed a) then "+" else "") ^ String.concat "," fl ^ " }" + end + | TDynamic t2 -> + "Dynamic" ^ s_type_params ctx (if t == t2 then [] else [t2]) + | TLazy f -> + s_type ctx (lazy_type f) + +and s_fun ctx t void = + match t with + | TFun _ -> + "(" ^ s_type ctx t ^ ")" + | TAbstract ({ a_path = ([],"Void") },[]) when void -> + "(" ^ s_type ctx t ^ ")" + | TMono r -> + (match r.tm_type with + | None -> s_type ctx t + | Some t -> s_fun ctx t void) + | TLazy f -> + s_fun ctx (lazy_type f) void + | _ -> + s_type ctx t + +and s_type_params ctx = function + | [] -> "" + | l -> "<" ^ String.concat ", " (List.map (s_type ctx) l) ^ ">" + +let s_access is_read = function + | AccNormal -> "default" + | AccNo -> "null" + | AccNever -> "never" + | AccResolve -> "resolve" + | AccCall -> if is_read then "get" else "set" + | AccInline -> "inline" + | AccRequire (n,_) -> "require " ^ n + | AccCtor -> "ctor" + +let s_kind = function + | Var { v_read = AccNormal; v_write = AccNormal } -> "var" + | Var v -> "(" ^ s_access true v.v_read ^ "," ^ s_access false v.v_write ^ ")" + | Method m -> + match m with + | MethNormal -> "method" + | MethDynamic -> "dynamic method" + | MethInline -> "inline method" + | MethMacro -> "macro method" + +let s_expr_kind e = + match e.eexpr with + | TConst _ -> "Const" + | TLocal _ -> "Local" + | TArray (_,_) -> "Array" + | TBinop (_,_,_) -> "Binop" + | TEnumParameter (_,_,_) -> "EnumParameter" + | TEnumIndex _ -> "EnumIndex" + | TField (_,_) -> "Field" + | TTypeExpr _ -> "TypeExpr" + | TParenthesis _ -> "Parenthesis" + | TObjectDecl _ -> "ObjectDecl" + | TArrayDecl _ -> "ArrayDecl" + | TCall (_,_) -> "Call" + | TNew (_,_,_) -> "New" + | TUnop (_,_,_) -> "Unop" + | TFunction _ -> "Function" + | TVar _ -> "Vars" + | TBlock _ -> "Block" + | TFor (_,_,_) -> "For" + | TIf (_,_,_) -> "If" + | TWhile (_,_,_) -> "While" + | TSwitch (_,_,_) -> "Switch" + | TTry (_,_) -> "Try" + | TReturn _ -> "Return" + | TBreak -> "Break" + | TContinue -> "Continue" + | TThrow _ -> "Throw" + | TCast _ -> "Cast" + | TMeta _ -> "Meta" + | TIdent _ -> "Ident" + +let s_const = function + | TInt i -> Int32.to_string i + | TFloat s -> s + | TString s -> Printf.sprintf "\"%s\"" (StringHelper.s_escape s) + | TBool b -> if b then "true" else "false" + | TNull -> "null" + | TThis -> "this" + | TSuper -> "super" + +let s_field_access s_type fa = match fa with + | FStatic (c,f) -> "static(" ^ s_type_path c.cl_path ^ "." ^ f.cf_name ^ ")" + | FInstance (c,_,f) -> "inst(" ^ s_type_path c.cl_path ^ "." ^ f.cf_name ^ " : " ^ s_type f.cf_type ^ ")" + | FClosure (c,f) -> "closure(" ^ (match c with None -> f.cf_name | Some (c,_) -> s_type_path c.cl_path ^ "." ^ f.cf_name) ^ ")" + | FAnon f -> "anon(" ^ f.cf_name ^ ")" + | FEnum (en,f) -> "enum(" ^ s_type_path en.e_path ^ "." ^ f.ef_name ^ ")" + | FDynamic f -> "dynamic(" ^ f ^ ")" + +let rec s_expr s_type e = + let sprintf = Printf.sprintf in + let slist f l = String.concat "," (List.map f l) in + let loop = s_expr s_type in + let s_var v = v.v_name ^ ":" ^ string_of_int v.v_id ^ if v.v_capture then "[c]" else "" in + let str = (match e.eexpr with + | TConst c -> + "Const " ^ s_const c + | TLocal v -> + "Local " ^ s_var v + | TArray (e1,e2) -> + sprintf "%s[%s]" (loop e1) (loop e2) + | TBinop (op,e1,e2) -> + sprintf "(%s %s %s)" (loop e1) (s_binop op) (loop e2) + | TEnumIndex e1 -> + sprintf "EnumIndex %s" (loop e1) + | TEnumParameter (e1,_,i) -> + sprintf "%s[%i]" (loop e1) i + | TField (e,f) -> + let fstr = s_field_access s_type f in + sprintf "%s.%s" (loop e) fstr + | TTypeExpr m -> + sprintf "TypeExpr %s" (s_type_path (t_path m)) + | TParenthesis e -> + sprintf "Parenthesis %s" (loop e) + | TObjectDecl fl -> + sprintf "ObjectDecl {%s}" (slist (fun ((f,_,qs),e) -> sprintf "%s : %s" (s_object_key_name f qs) (loop e)) fl) + | TArrayDecl el -> + sprintf "ArrayDecl [%s]" (slist loop el) + | TCall (e,el) -> + sprintf "Call %s(%s)" (loop e) (slist loop el) + | TNew (c,pl,el) -> + sprintf "New %s%s(%s)" (s_type_path c.cl_path) (match pl with [] -> "" | l -> sprintf "<%s>" (slist s_type l)) (slist loop el) + | TUnop (op,f,e) -> + (match f with + | Prefix -> sprintf "(%s %s)" (s_unop op) (loop e) + | Postfix -> sprintf "(%s %s)" (loop e) (s_unop op)) + | TFunction f -> + let args = slist (fun (v,o) -> sprintf "%s : %s%s" (s_var v) (s_type v.v_type) (match o with None -> "" | Some c -> " = " ^ loop c)) f.tf_args in + sprintf "Function(%s) : %s = %s" args (s_type f.tf_type) (loop f.tf_expr) + | TVar (v,eo) -> + sprintf "Vars %s" (sprintf "%s : %s%s" (s_var v) (s_type v.v_type) (match eo with None -> "" | Some e -> " = " ^ loop e)) + | TBlock el -> + sprintf "Block {\n%s}" (String.concat "" (List.map (fun e -> sprintf "%s;\n" (loop e)) el)) + | TFor (v,econd,e) -> + sprintf "For (%s : %s in %s,%s)" (s_var v) (s_type v.v_type) (loop econd) (loop e) + | TIf (e,e1,e2) -> + sprintf "If (%s,%s%s)" (loop e) (loop e1) (match e2 with None -> "" | Some e -> "," ^ loop e) + | TWhile (econd,e,flag) -> + (match flag with + | NormalWhile -> sprintf "While (%s,%s)" (loop econd) (loop e) + | DoWhile -> sprintf "DoWhile (%s,%s)" (loop e) (loop econd)) + | TSwitch (e,cases,def) -> + sprintf "Switch (%s,(%s)%s)" (loop e) (slist (fun (cl,e) -> sprintf "case %s: %s" (slist loop cl) (loop e)) cases) (match def with None -> "" | Some e -> "," ^ loop e) + | TTry (e,cl) -> + sprintf "Try %s(%s) " (loop e) (slist (fun (v,e) -> sprintf "catch( %s : %s ) %s" (s_var v) (s_type v.v_type) (loop e)) cl) + | TReturn None -> + "Return" + | TReturn (Some e) -> + sprintf "Return %s" (loop e) + | TBreak -> + "Break" + | TContinue -> + "Continue" + | TThrow e -> + "Throw " ^ (loop e) + | TCast (e,t) -> + sprintf "Cast %s%s" (match t with None -> "" | Some t -> s_type_path (t_path t) ^ ": ") (loop e) + | TMeta ((n,el,_),e) -> + sprintf "@%s%s %s" (Meta.to_string n) (match el with [] -> "" | _ -> "(" ^ (String.concat ", " (List.map Ast.Printer.s_expr el)) ^ ")") (loop e) + | TIdent s -> + "Ident " ^ s + ) in + sprintf "(%s : %s)" str (s_type e.etype) + +let rec s_expr_pretty print_var_ids tabs top_level s_type e = + let sprintf = Printf.sprintf in + let loop = s_expr_pretty print_var_ids tabs false s_type in + let slist c f l = String.concat c (List.map f l) in + let clist f l = slist ", " f l in + let local v = if print_var_ids then sprintf "%s<%i>" v.v_name v.v_id else v.v_name in + match e.eexpr with + | TConst c -> s_const c + | TLocal v -> local v + | TArray (e1,e2) -> sprintf "%s[%s]" (loop e1) (loop e2) + | TBinop (op,e1,e2) -> sprintf "%s %s %s" (loop e1) (s_binop op) (loop e2) + | TEnumParameter (e1,_,i) -> sprintf "%s[%i]" (loop e1) i + | TEnumIndex e1 -> sprintf "enumIndex %s" (loop e1) + | TField (e1,s) -> sprintf "%s.%s" (loop e1) (field_name s) + | TTypeExpr mt -> (s_type_path (t_path mt)) + | TParenthesis e1 -> sprintf "(%s)" (loop e1) + | TObjectDecl fl -> sprintf "{%s}" (clist (fun ((f,_,qs),e) -> sprintf "%s : %s" (s_object_key_name f qs) (loop e)) fl) + | TArrayDecl el -> sprintf "[%s]" (clist loop el) + | TCall (e1,el) -> sprintf "%s(%s)" (loop e1) (clist loop el) + | TNew (c,pl,el) -> + sprintf "new %s(%s)" (s_type_path c.cl_path) (clist loop el) + | TUnop (op,f,e) -> + (match f with + | Prefix -> sprintf "%s %s" (s_unop op) (loop e) + | Postfix -> sprintf "%s %s" (loop e) (s_unop op)) + | TFunction f -> + let args = clist (fun (v,o) -> sprintf "%s:%s%s" (local v) (s_type v.v_type) (match o with None -> "" | Some c -> " = " ^ loop c)) f.tf_args in + sprintf "%s(%s) %s" (if top_level then "" else "function") args (loop f.tf_expr) + | TVar (v,eo) -> + sprintf "var %s" (sprintf "%s%s" (local v) (match eo with None -> "" | Some e -> " = " ^ loop e)) + | TBlock el -> + let ntabs = tabs ^ "\t" in + let s = sprintf "{\n%s" (String.concat "" (List.map (fun e -> sprintf "%s%s;\n" ntabs (s_expr_pretty print_var_ids ntabs top_level s_type e)) el)) in + (match el with + | [] -> "{}" + | _ -> s ^ tabs ^ "}") + | TFor (v,econd,e) -> + sprintf "for (%s in %s) %s" (local v) (loop econd) (loop e) + | TIf (e,e1,e2) -> + sprintf "if (%s) %s%s" (loop e) (loop e1) (match e2 with None -> "" | Some e -> " else " ^ loop e) + | TWhile (econd,e,flag) -> + (match flag with + | NormalWhile -> sprintf "while (%s) %s" (loop econd) (loop e) + | DoWhile -> sprintf "do (%s) while(%s)" (loop e) (loop econd)) + | TSwitch (e,cases,def) -> + let ntabs = tabs ^ "\t" in + let s = sprintf "switch (%s) {\n%s%s" (loop e) (slist "" (fun (cl,e) -> sprintf "%scase %s: %s;\n" ntabs (clist loop cl) (s_expr_pretty print_var_ids ntabs top_level s_type e)) cases) (match def with None -> "" | Some e -> ntabs ^ "default: " ^ (s_expr_pretty print_var_ids ntabs top_level s_type e) ^ "\n") in + s ^ tabs ^ "}" + | TTry (e,cl) -> + sprintf "try %s%s" (loop e) (clist (fun (v,e) -> sprintf " catch (%s:%s) %s" (local v) (s_type v.v_type) (loop e)) cl) + | TReturn None -> + "return" + | TReturn (Some e) -> + sprintf "return %s" (loop e) + | TBreak -> + "break" + | TContinue -> + "continue" + | TThrow e -> + "throw " ^ (loop e) + | TCast (e,None) -> + sprintf "cast %s" (loop e) + | TCast (e,Some mt) -> + sprintf "cast (%s,%s)" (loop e) (s_type_path (t_path mt)) + | TMeta ((n,el,_),e) -> + sprintf "@%s%s %s" (Meta.to_string n) (match el with [] -> "" | _ -> "(" ^ (String.concat ", " (List.map Ast.Printer.s_expr el)) ^ ")") (loop e) + | TIdent s -> + s + +let rec s_expr_ast print_var_ids tabs s_type e = + let sprintf = Printf.sprintf in + let loop ?(extra_tabs="") = s_expr_ast print_var_ids (tabs ^ "\t" ^ extra_tabs) s_type in + let tag_args tabs sl = match sl with + | [] -> "" + | [s] when not (String.contains s '\n') -> " " ^ s + | _ -> + let tabs = "\n" ^ tabs ^ "\t" in + tabs ^ (String.concat tabs sl) + in + let tag s ?(t=None) ?(extra_tabs="") sl = + let st = match t with + | None -> s_type e.etype + | Some t -> s_type t + in + sprintf "[%s:%s]%s" s st (tag_args (tabs ^ extra_tabs) sl) + in + let var_id v = if print_var_ids then v.v_id else 0 in + let const c t = tag "Const" ~t [s_const c] in + let local v t = sprintf "[Local %s(%i):%s%s]" v.v_name (var_id v) (s_type v.v_type) (match t with None -> "" | Some t -> ":" ^ (s_type t)) in + let var v sl = sprintf "[Var %s(%i):%s]%s" v.v_name (var_id v) (s_type v.v_type) (tag_args tabs sl) in + let module_type mt = sprintf "[TypeExpr %s:%s]" (s_type_path (t_path mt)) (s_type e.etype) in + match e.eexpr with + | TConst c -> const c (Some e.etype) + | TLocal v -> local v (Some e.etype) + | TArray (e1,e2) -> tag "Array" [loop e1; loop e2] + | TBinop (op,e1,e2) -> tag "Binop" [loop e1; s_binop op; loop e2] + | TUnop (op,flag,e1) -> tag "Unop" [s_unop op; if flag = Postfix then "Postfix" else "Prefix"; loop e1] + | TEnumParameter (e1,ef,i) -> tag "EnumParameter" [loop e1; ef.ef_name; string_of_int i] + | TEnumIndex e1 -> tag "EnumIndex" [loop e1] + | TField (e1,fa) -> + let sfa = match fa with + | FInstance(c,tl,cf) -> tag "FInstance" ~extra_tabs:"\t" [s_type (TInst(c,tl)); Printf.sprintf "%s:%s" cf.cf_name (s_type cf.cf_type)] + | FStatic(c,cf) -> tag "FStatic" ~extra_tabs:"\t" [s_type_path c.cl_path; Printf.sprintf "%s:%s" cf.cf_name (s_type cf.cf_type)] + | FClosure(co,cf) -> tag "FClosure" ~extra_tabs:"\t" [(match co with None -> "None" | Some (c,tl) -> s_type (TInst(c,tl))); Printf.sprintf "%s:%s" cf.cf_name (s_type cf.cf_type)] + | FAnon cf -> tag "FAnon" ~extra_tabs:"\t" [Printf.sprintf "%s:%s" cf.cf_name (s_type cf.cf_type)] + | FDynamic s -> tag "FDynamic" ~extra_tabs:"\t" [s] + | FEnum(en,ef) -> tag "FEnum" ~extra_tabs:"\t" [s_type_path en.e_path; ef.ef_name] + in + tag "Field" [loop e1; sfa] + | TTypeExpr mt -> module_type mt + | TParenthesis e1 -> tag "Parenthesis" [loop e1] + | TObjectDecl fl -> tag "ObjectDecl" (List.map (fun ((s,_,qs),e) -> sprintf "%s: %s" (s_object_key_name s qs) (loop e)) fl) + | TArrayDecl el -> tag "ArrayDecl" (List.map loop el) + | TCall (e1,el) -> tag "Call" (loop e1 :: (List.map loop el)) + | TNew (c,tl,el) -> tag "New" ((s_type (TInst(c,tl))) :: (List.map loop el)) + | TFunction f -> + let arg (v,cto) = + tag "Arg" ~t:(Some v.v_type) ~extra_tabs:"\t" (match cto with None -> [local v None] | Some ct -> [local v None;loop ct]) + in + tag "Function" ((List.map arg f.tf_args) @ [loop f.tf_expr]) + | TVar (v,eo) -> var v (match eo with None -> [] | Some e -> [loop e]) + | TBlock el -> tag "Block" (List.map loop el) + | TIf (e,e1,e2) -> tag "If" (loop e :: (Printf.sprintf "[Then:%s] %s" (s_type e1.etype) (loop e1)) :: (match e2 with None -> [] | Some e -> [Printf.sprintf "[Else:%s] %s" (s_type e.etype) (loop e)])) + | TCast (e1,None) -> tag "Cast" [loop e1] + | TCast (e1,Some mt) -> tag "Cast" [loop e1; module_type mt] + | TThrow e1 -> tag "Throw" [loop e1] + | TBreak -> tag "Break" [] + | TContinue -> tag "Continue" [] + | TReturn None -> tag "Return" [] + | TReturn (Some e1) -> tag "Return" [loop e1] + | TWhile (e1,e2,NormalWhile) -> tag "While" [loop e1; loop e2] + | TWhile (e1,e2,DoWhile) -> tag "Do" [loop e1; loop e2] + | TFor (v,e1,e2) -> tag "For" [local v None; loop e1; loop e2] + | TTry (e1,catches) -> + let sl = List.map (fun (v,e) -> + sprintf "Catch %s%s" (local v None) (tag_args (tabs ^ "\t") [loop ~extra_tabs:"\t" e]); + ) catches in + tag "Try" ((loop e1) :: sl) + | TSwitch (e1,cases,eo) -> + let sl = List.map (fun (el,e) -> + tag "Case" ~t:(Some e.etype) ~extra_tabs:"\t" ((List.map loop el) @ [loop ~extra_tabs:"\t" e]) + ) cases in + let sl = match eo with + | None -> sl + | Some e -> sl @ [tag "Default" ~t:(Some e.etype) ~extra_tabs:"\t" [loop ~extra_tabs:"\t" e]] + in + tag "Switch" ((loop e1) :: sl) + | TMeta ((m,el,_),e1) -> + let s = Meta.to_string m in + let s = match el with + | [] -> s + | _ -> sprintf "%s(%s)" s (String.concat ", " (List.map Ast.Printer.s_expr el)) + in + tag "Meta" [s; loop e1] + | TIdent s -> + tag "Ident" [s] + +(** + Shortcut to pretty-printing expressions for debugging purposes. +*) +let s_expr_debug e = + s_expr_pretty false " " false (s_type (print_context())) e + +let s_types ?(sep = ", ") tl = + let pctx = print_context() in + String.concat sep (List.map (s_type pctx) tl) + +let s_class_kind = function + | KNormal -> + "KNormal" + | KTypeParameter tl -> + Printf.sprintf "KTypeParameter [%s]" (s_types tl) + | KExpr _ -> + "KExpr" + | KGeneric -> + "KGeneric" + | KGenericInstance(c,tl) -> + Printf.sprintf "KGenericInstance %s<%s>" (s_type_path c.cl_path) (s_types tl) + | KMacroType -> + "KMacroType" + | KGenericBuild _ -> + "KGenericBuild" + | KAbstractImpl a -> + Printf.sprintf "KAbstractImpl %s" (s_type_path a.a_path) + +module Printer = struct + + let s_type t = + s_type (print_context()) t + + let s_pair s1 s2 = + Printf.sprintf "(%s,%s)" s1 s2 + + let s_record_field name value = + Printf.sprintf "%s = %s;" name value + + let s_pos p = + Printf.sprintf "%s: %i-%i" p.pfile p.pmin p.pmax + + let s_record_fields tabs fields = + let sl = List.map (fun (name,value) -> s_record_field name value) fields in + Printf.sprintf "{\n%s\t%s\n%s}" tabs (String.concat ("\n\t" ^ tabs) sl) tabs + + let s_list sep f l = + "[" ^ (String.concat sep (List.map f l)) ^ "]" + + let s_opt f o = match o with + | None -> "None" + | Some v -> f v + + let s_pmap fk fv pm = + "{" ^ (String.concat ", " (PMap.foldi (fun k v acc -> (Printf.sprintf "%s = %s" (fk k) (fv v)) :: acc) pm [])) ^ "}" + + let s_doc doc_opt = + match doc_opt with + | None -> "None" + | Some d -> gen_doc_text d + + let s_metadata_entry (s,el,_) = + Printf.sprintf "@%s%s" (Meta.to_string s) (match el with [] -> "" | el -> "(" ^ (String.concat ", " (List.map Ast.Printer.s_expr el)) ^ ")") + + let s_metadata metadata = + s_list " " s_metadata_entry metadata + + let s_type_param (s,t) = match follow t with + | TInst({cl_kind = KTypeParameter tl1},tl2) -> + begin match tl1 with + | [] -> s + | _ -> Printf.sprintf "%s:%s" s (String.concat ", " (List.map s_type tl1)) + end + | _ -> die "" __LOC__ + + let s_type_params tl = + s_list ", " s_type_param tl + + let s_tclass_field tabs cf = + s_record_fields tabs [ + "cf_name",cf.cf_name; + "cf_doc",s_doc cf.cf_doc; + "cf_type",s_type_kind (follow cf.cf_type); + "cf_pos",s_pos cf.cf_pos; + "cf_name_pos",s_pos cf.cf_name_pos; + "cf_meta",s_metadata cf.cf_meta; + "cf_kind",s_kind cf.cf_kind; + "cf_params",s_type_params cf.cf_params; + "cf_expr",s_opt (s_expr_ast true "\t\t" s_type) cf.cf_expr; + ] + + let s_tclass tabs c = + s_record_fields tabs [ + "cl_path",s_type_path c.cl_path; + "cl_module",s_type_path c.cl_module.m_path; + "cl_pos",s_pos c.cl_pos; + "cl_name_pos",s_pos c.cl_name_pos; + "cl_private",string_of_bool c.cl_private; + "cl_doc",s_doc c.cl_doc; + "cl_meta",s_metadata c.cl_meta; + "cl_params",s_type_params c.cl_params; + "cl_kind",s_class_kind c.cl_kind; + "cl_extern",string_of_bool c.cl_extern; + "cl_final",string_of_bool c.cl_final; + "cl_interface",string_of_bool c.cl_interface; + "cl_super",s_opt (fun (c,tl) -> s_type (TInst(c,tl))) c.cl_super; + "cl_implements",s_list ", " (fun (c,tl) -> s_type (TInst(c,tl))) c.cl_implements; + "cl_array_access",s_opt s_type c.cl_array_access; + "cl_overrides",s_list "," (fun cf -> cf.cf_name) c.cl_overrides; + "cl_init",s_opt (s_expr_ast true "" s_type) c.cl_init; + "cl_constructor",s_opt (s_tclass_field (tabs ^ "\t")) c.cl_constructor; + "cl_ordered_fields",s_list "\n\t" (s_tclass_field (tabs ^ "\t")) c.cl_ordered_fields; + "cl_ordered_statics",s_list "\n\t" (s_tclass_field (tabs ^ "\t")) c.cl_ordered_statics; + ] + + let s_tdef tabs t = + s_record_fields tabs [ + "t_path",s_type_path t.t_path; + "t_module",s_type_path t.t_module.m_path; + "t_pos",s_pos t.t_pos; + "t_name_pos",s_pos t.t_name_pos; + "t_private",string_of_bool t.t_private; + "t_doc",s_doc t.t_doc; + "t_meta",s_metadata t.t_meta; + "t_params",s_type_params t.t_params; + "t_type",s_type_kind t.t_type + ] + + let s_tenum_field tabs ef = + s_record_fields tabs [ + "ef_name",ef.ef_name; + "ef_doc",s_doc ef.ef_doc; + "ef_pos",s_pos ef.ef_pos; + "ef_name_pos",s_pos ef.ef_name_pos; + "ef_type",s_type_kind ef.ef_type; + "ef_index",string_of_int ef.ef_index; + "ef_params",s_type_params ef.ef_params; + "ef_meta",s_metadata ef.ef_meta + ] + + let s_tenum tabs en = + s_record_fields tabs [ + "e_path",s_type_path en.e_path; + "e_module",s_type_path en.e_module.m_path; + "e_pos",s_pos en.e_pos; + "e_name_pos",s_pos en.e_name_pos; + "e_private",string_of_bool en.e_private; + "d_doc",s_doc en.e_doc; + "e_meta",s_metadata en.e_meta; + "e_params",s_type_params en.e_params; + "e_type",s_tdef "\t" en.e_type; + "e_extern",string_of_bool en.e_extern; + "e_constrs",s_list "\n\t" (s_tenum_field (tabs ^ "\t")) (PMap.fold (fun ef acc -> ef :: acc) en.e_constrs []); + "e_names",String.concat ", " en.e_names + ] + + let s_tabstract tabs a = + s_record_fields tabs [ + "a_path",s_type_path a.a_path; + "a_modules",s_type_path a.a_module.m_path; + "a_pos",s_pos a.a_pos; + "a_name_pos",s_pos a.a_name_pos; + "a_private",string_of_bool a.a_private; + "a_doc",s_doc a.a_doc; + "a_meta",s_metadata a.a_meta; + "a_params",s_type_params a.a_params; + "a_ops",s_list ", " (fun (op,cf) -> Printf.sprintf "%s: %s" (s_binop op) cf.cf_name) a.a_ops; + "a_unops",s_list ", " (fun (op,flag,cf) -> Printf.sprintf "%s (%s): %s" (s_unop op) (if flag = Postfix then "postfix" else "prefix") cf.cf_name) a.a_unops; + "a_impl",s_opt (fun c -> s_type_path c.cl_path) a.a_impl; + "a_this",s_type_kind a.a_this; + "a_from",s_list ", " s_type_kind a.a_from; + "a_to",s_list ", " s_type_kind a.a_to; + "a_from_field",s_list ", " (fun (t,cf) -> Printf.sprintf "%s: %s" (s_type_kind t) cf.cf_name) a.a_from_field; + "a_to_field",s_list ", " (fun (t,cf) -> Printf.sprintf "%s: %s" (s_type_kind t) cf.cf_name) a.a_to_field; + "a_array",s_list ", " (fun cf -> cf.cf_name) a.a_array; + "a_read",s_opt (fun cf -> cf.cf_name) a.a_read; + "a_write",s_opt (fun cf -> cf.cf_name) a.a_write; + ] + + let s_tvar_extra (tl,eo) = + Printf.sprintf "Some(%s, %s)" (s_type_params tl) (s_opt (s_expr_ast true "" s_type) eo) + + let s_tvar v = + s_record_fields "" [ + "v_id",string_of_int v.v_id; + "v_name",v.v_name; + "v_type",s_type v.v_type; + "v_capture",string_of_bool v.v_capture; + "v_extra",s_opt s_tvar_extra v.v_extra; + "v_meta",s_metadata v.v_meta; + "v_pos",s_pos v.v_pos; + ] + + let s_module_kind = function + | MCode -> "MCode" + | MMacro -> "MMacro" + | MFake -> "MFake" + | MExtern -> "MExtern" + | MImport -> "MImport" + + let s_module_def_extra tabs me = + s_record_fields tabs [ + "m_file",me.m_file; + "m_sign",me.m_sign; + "m_time",string_of_float me.m_time; + "m_dirty",s_opt s_type_path me.m_dirty; + "m_added",string_of_int me.m_added; + "m_mark",string_of_int me.m_mark; + "m_deps",s_pmap string_of_int (fun m -> snd m.m_path) me.m_deps; + "m_processed",string_of_int me.m_processed; + "m_kind",s_module_kind me.m_kind; + "m_binded_res",""; (* TODO *) + "m_if_feature",""; (* TODO *) + "m_features",""; (* TODO *) + ] + + let s_module_def m = + s_record_fields "" [ + "m_id",string_of_int m.m_id; + "m_path",s_type_path m.m_path; + "m_extra",s_module_def_extra "\t" m.m_extra + ] + + let s_type_path tp = + s_record_fields "" [ + "tpackage",s_list "." (fun s -> s) tp.tpackage; + "tname",tp.tname; + "tparams",""; + "tsub",s_opt (fun s -> s) tp.tsub; + ] + + let s_class_flag = function + | HInterface -> "HInterface" + | HExtern -> "HExtern" + | HPrivate -> "HPrivate" + | HExtends tp -> "HExtends " ^ (s_type_path (fst tp)) + | HImplements tp -> "HImplements " ^ (s_type_path (fst tp)) + | HFinal -> "HFinal" + + let s_placed f (x,p) = + s_pair (f x) (s_pos p) + + let s_class_field cff = + s_record_fields "" [ + "cff_name",s_placed (fun s -> s) cff.cff_name; + "cff_doc",s_doc cff.cff_doc; + "cff_pos",s_pos cff.cff_pos; + "cff_meta",s_metadata cff.cff_meta; + "cff_access",s_list ", " Ast.s_placed_access cff.cff_access; + ] +end diff --git a/src/core/tType.ml b/src/core/tType.ml new file mode 100644 index 0000000000000000000000000000000000000000..6ac3a81c6e6e29ee0e1833e69e0895529fc4d75c --- /dev/null +++ b/src/core/tType.ml @@ -0,0 +1,372 @@ +open Ast +open Globals + +type field_kind = + | Var of var_kind + | Method of method_kind + +and var_kind = { + v_read : var_access; + v_write : var_access; +} + +and var_access = + | AccNormal + | AccNo (* can't be accessed outside of the class itself and its subclasses *) + | AccNever (* can't be accessed, even in subclasses *) + | AccCtor (* can only be accessed from the constructor *) + | AccResolve (* call resolve("field") when accessed *) + | AccCall (* perform a method call when accessed *) + | AccInline (* similar to Normal but inline when accessed *) + | AccRequire of string * string option (* set when @:require(cond) fails *) + +and method_kind = + | MethNormal + | MethInline + | MethDynamic + | MethMacro + +type module_check_policy = + | NoCheckFileTimeModification + | CheckFileContentModification + | NoCheckDependencies + | NoCheckShadowing + +type t = + | TMono of tmono + | TEnum of tenum * tparams + | TInst of tclass * tparams + | TType of tdef * tparams + | TFun of tsignature + | TAnon of tanon + | TDynamic of t + | TLazy of tlazy ref + | TAbstract of tabstract * tparams + +and tmono = { + mutable tm_type : t option; +} + +and tlazy = + | LAvailable of t + | LProcessing of (unit -> t) + | LWait of (unit -> t) + +and tsignature = (string * bool * t) list * t + +and tparams = t list + +and type_params = (string * t) list + +and tconstant = + | TInt of int32 + | TFloat of string + | TString of string + | TBool of bool + | TNull + | TThis + | TSuper + +and tvar_extra = (type_params * texpr option) option + +and tvar_origin = + | TVOLocalVariable + | TVOArgument + | TVOForVariable + | TVOPatternVariable + | TVOCatchVariable + | TVOLocalFunction + +and tvar_kind = + | VUser of tvar_origin + | VGenerated + | VInlined + | VInlinedConstructorVariable + | VExtractorVariable + +and tvar = { + mutable v_id : int; + mutable v_name : string; + mutable v_type : t; + mutable v_kind : tvar_kind; + mutable v_capture : bool; + mutable v_final : bool; + mutable v_extra : tvar_extra; + mutable v_meta : metadata; + v_pos : pos; +} + +and tfunc = { + tf_args : (tvar * texpr option) list; + tf_type : t; + tf_expr : texpr; +} + +and anon_status = + | Closed + | Opened + | Const + | Extend of t list + | Statics of tclass + | EnumStatics of tenum + | AbstractStatics of tabstract + +and tanon = { + mutable a_fields : (string, tclass_field) PMap.t; + a_status : anon_status ref; +} + +and texpr_expr = + | TConst of tconstant + | TLocal of tvar + | TArray of texpr * texpr + | TBinop of Ast.binop * texpr * texpr + | TField of texpr * tfield_access + | TTypeExpr of module_type + | TParenthesis of texpr + | TObjectDecl of ((string * pos * quote_status) * texpr) list + | TArrayDecl of texpr list + | TCall of texpr * texpr list + | TNew of tclass * tparams * texpr list + | TUnop of Ast.unop * Ast.unop_flag * texpr + | TFunction of tfunc + | TVar of tvar * texpr option + | TBlock of texpr list + | TFor of tvar * texpr * texpr + | TIf of texpr * texpr * texpr option + | TWhile of texpr * texpr * Ast.while_flag + | TSwitch of texpr * (texpr list * texpr) list * texpr option + | TTry of texpr * (tvar * texpr) list + | TReturn of texpr option + | TBreak + | TContinue + | TThrow of texpr + | TCast of texpr * module_type option + | TMeta of metadata_entry * texpr + | TEnumParameter of texpr * tenum_field * int + | TEnumIndex of texpr + | TIdent of string + +and tfield_access = + | FInstance of tclass * tparams * tclass_field + | FStatic of tclass * tclass_field + | FAnon of tclass_field + | FDynamic of string + | FClosure of (tclass * tparams) option * tclass_field (* None class = TAnon *) + | FEnum of tenum * tenum_field + +and texpr = { + eexpr : texpr_expr; + etype : t; + epos : pos; +} + +and tclass_field = { + mutable cf_name : string; + mutable cf_type : t; + cf_pos : pos; + cf_name_pos : pos; + mutable cf_doc : Ast.documentation; + mutable cf_meta : metadata; + mutable cf_kind : field_kind; + mutable cf_params : type_params; + mutable cf_expr : texpr option; + mutable cf_expr_unoptimized : tfunc option; + mutable cf_overloads : tclass_field list; + mutable cf_flags : int; +} + +and tclass_kind = + | KNormal + | KTypeParameter of t list + | KExpr of Ast.expr + | KGeneric + | KGenericInstance of tclass * tparams + | KMacroType + | KGenericBuild of class_field list + | KAbstractImpl of tabstract + +and metadata = Ast.metadata + +and tinfos = { + mutable mt_path : path; + mt_module : module_def; + mt_pos : pos; + mt_name_pos : pos; + mt_private : bool; + mt_doc : Ast.documentation; + mutable mt_meta : metadata; + mt_params : type_params; + mutable mt_using : (tclass * pos) list; +} + +and tclass = { + mutable cl_path : path; + mutable cl_module : module_def; + mutable cl_pos : pos; + mutable cl_name_pos : pos; + mutable cl_private : bool; + mutable cl_doc : Ast.documentation; + mutable cl_meta : metadata; + mutable cl_params : type_params; + mutable cl_using : (tclass * pos) list; + (* do not insert any fields above *) + mutable cl_kind : tclass_kind; + mutable cl_extern : bool; + mutable cl_final : bool; + mutable cl_interface : bool; + mutable cl_super : (tclass * tparams) option; + mutable cl_implements : (tclass * tparams) list; + mutable cl_fields : (string, tclass_field) PMap.t; + mutable cl_statics : (string, tclass_field) PMap.t; + mutable cl_ordered_statics : tclass_field list; + mutable cl_ordered_fields : tclass_field list; + mutable cl_dynamic : t option; + mutable cl_array_access : t option; + mutable cl_constructor : tclass_field option; + mutable cl_init : texpr option; + mutable cl_overrides : tclass_field list; + + mutable cl_build : unit -> build_state; + mutable cl_restore : unit -> unit; + (* + These are classes which directly extend or directly implement this class. + Populated automatically in post-processing step (Filters.run) + *) + mutable cl_descendants : tclass list; +} + +and tenum_field = { + ef_name : string; + mutable ef_type : t; + ef_pos : pos; + ef_name_pos : pos; + ef_doc : Ast.documentation; + ef_index : int; + mutable ef_params : type_params; + mutable ef_meta : metadata; +} + +and tenum = { + mutable e_path : path; + e_module : module_def; + e_pos : pos; + e_name_pos : pos; + e_private : bool; + e_doc : Ast.documentation; + mutable e_meta : metadata; + mutable e_params : type_params; + mutable e_using : (tclass * pos) list; + (* do not insert any fields above *) + e_type : tdef; + mutable e_extern : bool; + mutable e_constrs : (string , tenum_field) PMap.t; + mutable e_names : string list; +} + +and tdef = { + mutable t_path : path; + t_module : module_def; + t_pos : pos; + t_name_pos : pos; + t_private : bool; + t_doc : Ast.documentation; + mutable t_meta : metadata; + mutable t_params : type_params; + mutable t_using : (tclass * pos) list; + (* do not insert any fields above *) + mutable t_type : t; +} + +and tabstract = { + mutable a_path : path; + a_module : module_def; + a_pos : pos; + a_name_pos : pos; + a_private : bool; + a_doc : Ast.documentation; + mutable a_meta : metadata; + mutable a_params : type_params; + mutable a_using : (tclass * pos) list; + (* do not insert any fields above *) + mutable a_ops : (Ast.binop * tclass_field) list; + mutable a_unops : (Ast.unop * unop_flag * tclass_field) list; + mutable a_impl : tclass option; + mutable a_this : t; + mutable a_from : t list; + mutable a_from_field : (t * tclass_field) list; + mutable a_to : t list; + mutable a_to_field : (t * tclass_field) list; + mutable a_array : tclass_field list; + mutable a_read : tclass_field option; + mutable a_write : tclass_field option; +} + +and module_type = + | TClassDecl of tclass + | TEnumDecl of tenum + | TTypeDecl of tdef + | TAbstractDecl of tabstract + +and module_def = { + m_id : int; + m_path : path; + mutable m_types : module_type list; + m_extra : module_def_extra; +} + +and module_def_display = { + mutable m_inline_calls : (pos * pos) list; (* calls whatever is at pos1 from pos2 *) + mutable m_type_hints : (pos * pos) list; + mutable m_import_positions : (pos,bool ref) PMap.t; +} + +and module_def_extra = { + m_file : string; + m_sign : string; + m_display : module_def_display; + mutable m_check_policy : module_check_policy list; + mutable m_time : float; + mutable m_dirty : path option; + mutable m_added : int; + mutable m_mark : int; + mutable m_deps : (int,module_def) PMap.t; + mutable m_processed : int; + mutable m_kind : module_kind; + mutable m_binded_res : (string, string) PMap.t; + mutable m_if_feature : (string *(tclass * tclass_field * bool)) list; + mutable m_features : (string,bool) Hashtbl.t; +} + +and module_kind = + | MCode + | MMacro + | MFake + | MExtern + | MImport + +and build_state = + | Built + | Building of tclass list + | BuildMacro of (unit -> unit) list ref + +type basic_types = { + mutable tvoid : t; + mutable tint : t; + mutable tfloat : t; + mutable tbool : t; + mutable tnull : t -> t; + mutable tstring : t; + mutable tarray : t -> t; +} + +type class_field_scope = + | CFSStatic + | CFSMember + | CFSConstructor + +type flag_tclass_field = + | CfPublic + | CfExtern (* This is only set if the field itself is extern, not just the class. *) + | CfFinal + | CfModifiesThis (* This is set for methods which reassign `this`. E.g. `this = value` *) \ No newline at end of file diff --git a/src/core/tUnification.ml b/src/core/tUnification.ml new file mode 100644 index 0000000000000000000000000000000000000000..1bb7d8f7274a94a419662a69f75962bd3a2830fc --- /dev/null +++ b/src/core/tUnification.ml @@ -0,0 +1,853 @@ +open Globals +open TType +open TFunctions +open TPrinting + +module Monomorph = struct + let create () = { + tm_type = None; + } + + let do_bind m t = + (* assert(m.tm_type = None); *) (* TODO: should be here, but matcher.ml does some weird bind handling at the moment. *) + m.tm_type <- Some t + + let rec bind m t = + m.tm_type <- Some t + + let unbind m = + m.tm_type <- None +end + +let rec link e a b = + (* tell if setting a == b will create a type-loop *) + let rec loop t = + if t == a then + true + else match t with + | TMono t -> (match t.tm_type with None -> false | Some t -> loop t) + | TEnum (_,tl) -> List.exists loop tl + | TInst (_,tl) | TType (_,tl) | TAbstract (_,tl) -> List.exists loop tl + | TFun (tl,t) -> List.exists (fun (_,_,t) -> loop t) tl || loop t + | TDynamic t2 -> + if t == t2 then + false + else + loop t2 + | TLazy f -> + loop (lazy_type f) + | TAnon a -> + try + PMap.iter (fun _ f -> if loop f.cf_type then raise Exit) a.a_fields; + false + with + Exit -> true + in + (* tell is already a ~= b *) + if loop b then + (follow b) == a + else if b == t_dynamic then + true + else begin + Monomorph.bind e b; + true + end + +let would_produce_recursive_anon field_acceptor field_donor = + try + (match !(field_acceptor.a_status) with + | Opened -> + PMap.iter (fun n field -> + match follow field.cf_type with + | TAnon a when field_acceptor == a -> raise Exit + | _ -> () + ) field_donor.a_fields; + | _ -> ()); + false + with Exit -> true + +let link_dynamic a b = match follow a,follow b with + | TMono r,TDynamic _ -> Monomorph.bind r b + | TDynamic _,TMono r -> Monomorph.bind r a + | _ -> () + +let fast_eq_check type_param_check a b = + if a == b then + true + else match a , b with + | TFun (l1,r1) , TFun (l2,r2) when List.length l1 = List.length l2 -> + List.for_all2 (fun (_,_,t1) (_,_,t2) -> type_param_check t1 t2) l1 l2 && type_param_check r1 r2 + | TType (t1,l1), TType (t2,l2) -> + t1 == t2 && List.for_all2 type_param_check l1 l2 + | TEnum (e1,l1), TEnum (e2,l2) -> + e1 == e2 && List.for_all2 type_param_check l1 l2 + | TInst (c1,l1), TInst (c2,l2) -> + c1 == c2 && List.for_all2 type_param_check l1 l2 + | TAbstract (a1,l1), TAbstract (a2,l2) -> + a1 == a2 && List.for_all2 type_param_check l1 l2 + | _ , _ -> + false + +let rec fast_eq a b = fast_eq_check fast_eq a b + +let rec fast_eq_mono ml a b = + if fast_eq_check (fast_eq_mono ml) a b then + true + else match a , b with + | TMono _, _ -> + List.memq a ml + | _ , _ -> + false + +let rec shallow_eq a b = + a == b + || begin + let a = follow a + and b = follow b in + fast_eq_check shallow_eq a b + || match a , b with + | t, TMono { tm_type = None } when t == t_dynamic -> true + | TMono { tm_type = None }, t when t == t_dynamic -> true + | TMono { tm_type = None }, TMono { tm_type = None } -> true + | TAnon a1, TAnon a2 -> + let fields_eq() = + let rec loop fields1 fields2 = + match fields1, fields2 with + | [], [] -> true + | _, [] | [], _ -> false + | f1 :: rest1, f2 :: rest2 -> + f1.cf_name = f2.cf_name + && (try shallow_eq f1.cf_type f2.cf_type with Not_found -> false) + && loop rest1 rest2 + in + let fields1 = PMap.fold (fun field fields -> field :: fields) a1.a_fields [] + and fields2 = PMap.fold (fun field fields -> field :: fields) a2.a_fields [] + and sort_compare f1 f2 = compare f1.cf_name f2.cf_name in + loop (List.sort sort_compare fields1) (List.sort sort_compare fields2) + in + (match !(a2.a_status), !(a1.a_status) with + | Statics c, Statics c2 -> c == c2 + | EnumStatics e, EnumStatics e2 -> e == e2 + | AbstractStatics a, AbstractStatics a2 -> a == a2 + | Extend tl1, Extend tl2 -> fields_eq() && List.for_all2 shallow_eq tl1 tl2 + | Closed, Closed -> fields_eq() + | Opened, Opened -> fields_eq() + | Const, Const -> fields_eq() + | _ -> false + ) + | _ , _ -> + false + end + +(* perform unification with subtyping. + the first type is always the most down in the class hierarchy + it's also the one that is pointed by the position. + It's actually a typecheck of A :> B where some mutations can happen *) + +type unify_error = + | Cannot_unify of t * t + | Invalid_field_type of string + | Has_no_field of t * string + | Has_no_runtime_field of t * string + | Has_extra_field of t * string + | Invalid_kind of string * field_kind * field_kind + | Invalid_visibility of string + | Not_matching_optional of string + | Cant_force_optional + | Invariant_parameter of int + | Constraint_failure of string + | Missing_overload of tclass_field * t + | FinalInvariance (* nice band name *) + | Invalid_function_argument of int (* index *) * int (* total *) + | Invalid_return_type + | Unify_custom of string + +exception Unify_error of unify_error list + +let cannot_unify a b = Cannot_unify (a,b) +let invalid_field n = Invalid_field_type n +let invalid_kind n a b = Invalid_kind (n,a,b) +let invalid_visibility n = Invalid_visibility n +let has_no_field t n = Has_no_field (t,n) +let has_extra_field t n = Has_extra_field (t,n) +let error l = raise (Unify_error l) + +(* + we can restrict access as soon as both are runtime-compatible +*) +let unify_access a1 a2 = + a1 = a2 || match a1, a2 with + | _, AccNo | _, AccNever -> true + | AccInline, AccNormal -> true + | _ -> false + +let direct_access = function + | AccNo | AccNever | AccNormal | AccInline | AccRequire _ | AccCtor -> true + | AccResolve | AccCall -> false + +let unify_kind k1 k2 = + k1 = k2 || match k1, k2 with + | Var v1, Var v2 -> unify_access v1.v_read v2.v_read && unify_access v1.v_write v2.v_write + | Var v, Method m -> + (match v.v_read, v.v_write, m with + | AccNormal, _, MethNormal -> true + | AccNormal, AccNormal, MethDynamic -> true + | _ -> false) + | Method m, Var v -> + (match m with + | MethDynamic -> direct_access v.v_read && direct_access v.v_write + | MethMacro -> false + | MethNormal | MethInline -> + match v.v_read,v.v_write with + | AccNormal,(AccNo | AccNever) -> true + | _ -> false) + | Method m1, Method m2 -> + match m1,m2 with + | MethInline, MethNormal + | MethDynamic, MethNormal -> true + | _ -> false + +type 'a rec_stack = { + mutable rec_stack : 'a list; +} + +let new_rec_stack() = { rec_stack = [] } +let rec_stack_exists f s = List.exists f s.rec_stack +let rec_stack_memq v s = List.memq v s.rec_stack +let rec_stack_loop stack value f arg = + stack.rec_stack <- value :: stack.rec_stack; + try + let r = f arg in + stack.rec_stack <- List.tl stack.rec_stack; + r + with e -> + stack.rec_stack <- List.tl stack.rec_stack; + raise e + +let eq_stack = new_rec_stack() + +let rec_stack stack value fcheck frun ferror = + if not (rec_stack_exists fcheck stack) then begin + try + stack.rec_stack <- value :: stack.rec_stack; + let v = frun() in + stack.rec_stack <- List.tl stack.rec_stack; + v + with + Unify_error l -> + stack.rec_stack <- List.tl stack.rec_stack; + ferror l + | e -> + stack.rec_stack <- List.tl stack.rec_stack; + raise e + end + +let rec_stack_default stack value fcheck frun def = + if not (rec_stack_exists fcheck stack) then rec_stack_loop stack value frun () else def + +let rec_stack_bool stack value fcheck frun = + if (rec_stack_exists fcheck stack) then false else begin + try + stack.rec_stack <- value :: stack.rec_stack; + frun(); + stack.rec_stack <- List.tl stack.rec_stack; + true + with + Unify_error l -> + stack.rec_stack <- List.tl stack.rec_stack; + false + | e -> + stack.rec_stack <- List.tl stack.rec_stack; + raise e + end + +type eq_kind = + | EqStrict + | EqCoreType + | EqRightDynamic + | EqBothDynamic + | EqDoNotFollowNull (* like EqStrict, but does not follow Null *) + +let rec type_eq param a b = + let can_follow t = match param with + | EqCoreType -> false + | EqDoNotFollowNull -> not (is_explicit_null t) + | _ -> true + in + if a == b then + () + else match a , b with + | TLazy f , _ -> type_eq param (lazy_type f) b + | _ , TLazy f -> type_eq param a (lazy_type f) + | TMono t , _ -> + (match t.tm_type with + | None -> if param = EqCoreType || not (link t a b) then error [cannot_unify a b] + | Some t -> type_eq param t b) + | _ , TMono t -> + (match t.tm_type with + | None -> if param = EqCoreType || not (link t b a) then error [cannot_unify a b] + | Some t -> type_eq param a t) + | TAbstract ({a_path=[],"Null"},[t1]),TAbstract ({a_path=[],"Null"},[t2]) -> + type_eq param t1 t2 + | TAbstract ({a_path=[],"Null"},[t]),_ when param <> EqDoNotFollowNull -> + type_eq param t b + | _,TAbstract ({a_path=[],"Null"},[t]) when param <> EqDoNotFollowNull -> + type_eq param a t + | TType (t1,tl1), TType (t2,tl2) when (t1 == t2 || (param = EqCoreType && t1.t_path = t2.t_path)) && List.length tl1 = List.length tl2 -> + type_eq_params param a b tl1 tl2 + | TType (t,tl) , _ when can_follow a -> + type_eq param (apply_params t.t_params tl t.t_type) b + | _ , TType (t,tl) when can_follow b -> + rec_stack eq_stack (a,b) + (fun (a2,b2) -> fast_eq a a2 && fast_eq b b2) + (fun() -> type_eq param a (apply_params t.t_params tl t.t_type)) + (fun l -> error (cannot_unify a b :: l)) + | TEnum (e1,tl1) , TEnum (e2,tl2) -> + if e1 != e2 && not (param = EqCoreType && e1.e_path = e2.e_path) then error [cannot_unify a b]; + type_eq_params param a b tl1 tl2 + | TInst (c1,tl1) , TInst (c2,tl2) -> + if c1 != c2 && not (param = EqCoreType && c1.cl_path = c2.cl_path) && (match c1.cl_kind, c2.cl_kind with KExpr _, KExpr _ -> false | _ -> true) then error [cannot_unify a b]; + type_eq_params param a b tl1 tl2 + | TFun (l1,r1) , TFun (l2,r2) when List.length l1 = List.length l2 -> + let i = ref 0 in + (try + type_eq param r1 r2; + List.iter2 (fun (n,o1,t1) (_,o2,t2) -> + incr i; + if o1 <> o2 then error [Not_matching_optional n]; + type_eq param t1 t2 + ) l1 l2 + with + Unify_error l -> + let msg = if !i = 0 then Invalid_return_type else Invalid_function_argument(!i,List.length l1) in + error (cannot_unify a b :: msg :: l) + ) + | TDynamic a , TDynamic b -> + type_eq param a b + | TAbstract (a1,tl1) , TAbstract (a2,tl2) -> + if a1 != a2 && not (param = EqCoreType && a1.a_path = a2.a_path) then error [cannot_unify a b]; + type_eq_params param a b tl1 tl2 + | TAnon a1, TAnon a2 -> + (try + (match !(a2.a_status) with + | Statics c -> (match !(a1.a_status) with Statics c2 when c == c2 -> () | _ -> error []) + | EnumStatics e -> (match !(a1.a_status) with EnumStatics e2 when e == e2 -> () | _ -> error []) + | AbstractStatics a -> (match !(a1.a_status) with AbstractStatics a2 when a == a2 -> () | _ -> error []) + | _ -> () + ); + if would_produce_recursive_anon a1 a2 || would_produce_recursive_anon a2 a1 then error [cannot_unify a b]; + PMap.iter (fun n f1 -> + try + let f2 = PMap.find n a2.a_fields in + if f1.cf_kind <> f2.cf_kind && (param = EqStrict || param = EqCoreType || not (unify_kind f1.cf_kind f2.cf_kind)) then error [invalid_kind n f1.cf_kind f2.cf_kind]; + let a = f1.cf_type and b = f2.cf_type in + (try type_eq param a b with Unify_error l -> error (invalid_field n :: l)); + if (has_class_field_flag f1 CfPublic) != (has_class_field_flag f2 CfPublic) then error [invalid_visibility n]; + with + Not_found -> + if is_closed a2 then error [has_no_field b n]; + if not (link (Monomorph.create()) b f1.cf_type) then error [cannot_unify a b]; + a2.a_fields <- PMap.add n f1 a2.a_fields + ) a1.a_fields; + PMap.iter (fun n f2 -> + if not (PMap.mem n a1.a_fields) then begin + if is_closed a1 then error [has_no_field a n]; + if not (link (Monomorph.create()) a f2.cf_type) then error [cannot_unify a b]; + a1.a_fields <- PMap.add n f2 a1.a_fields + end; + ) a2.a_fields; + with + Unify_error l -> error (cannot_unify a b :: l)) + | _ , _ -> + if b == t_dynamic && (param = EqRightDynamic || param = EqBothDynamic) then + () + else if a == t_dynamic && param = EqBothDynamic then + () + else + error [cannot_unify a b] + +and type_eq_params param a b tl1 tl2 = + let i = ref 0 in + List.iter2 (fun t1 t2 -> + incr i; + try + type_eq param t1 t2 + with Unify_error l -> + let err = cannot_unify a b in + error (err :: (Invariant_parameter !i) :: l) + ) tl1 tl2 + +let type_iseq a b = + try + type_eq EqStrict a b; + true + with + Unify_error _ -> false + +let type_iseq_strict a b = + try + type_eq EqDoNotFollowNull a b; + true + with Unify_error _ -> + false + +let unify_stack = new_rec_stack() +let abstract_cast_stack = new_rec_stack() +let unify_new_monos = new_rec_stack() + +let print_stacks() = + let ctx = print_context() in + let st = s_type ctx in + print_endline "unify_stack"; + List.iter (fun (a,b) -> Printf.printf "\t%s , %s\n" (st a) (st b)) unify_stack.rec_stack; + print_endline "monos"; + List.iter (fun m -> print_endline ("\t" ^ st m)) unify_new_monos.rec_stack; + print_endline "abstract_cast_stack"; + List.iter (fun (a,b) -> Printf.printf "\t%s , %s\n" (st a) (st b)) abstract_cast_stack.rec_stack + +let rec unify a b = + if a == b then + () + else match a, b with + | TLazy f , _ -> unify (lazy_type f) b + | _ , TLazy f -> unify a (lazy_type f) + | TMono t , _ -> + (match t.tm_type with + | None -> if not (link t a b) then error [cannot_unify a b] + | Some t -> unify t b) + | _ , TMono t -> + (match t.tm_type with + | None -> if not (link t b a) then error [cannot_unify a b] + | Some t -> unify a t) + | TType (t,tl) , _ -> + rec_stack unify_stack (a,b) + (fun(a2,b2) -> fast_eq a a2 && fast_eq b b2) + (fun() -> try_apply_params_rec t.t_params tl t.t_type (fun a -> unify a b)) + (fun l -> error (cannot_unify a b :: l)) + | _ , TType (t,tl) -> + rec_stack unify_stack (a,b) + (fun(a2,b2) -> fast_eq a a2 && fast_eq b b2) + (fun() -> try_apply_params_rec t.t_params tl t.t_type (unify a)) + (fun l -> error (cannot_unify a b :: l)) + | TEnum (ea,tl1) , TEnum (eb,tl2) -> + if ea != eb then error [cannot_unify a b]; + unify_type_params a b tl1 tl2 + | TAbstract ({a_path=[],"Null"},[t]),_ -> + begin try unify t b + with Unify_error l -> error (cannot_unify a b :: l) end + | _,TAbstract ({a_path=[],"Null"},[t]) -> + begin try unify a t + with Unify_error l -> error (cannot_unify a b :: l) end + | TAbstract (a1,tl1) , TAbstract (a2,tl2) when a1 == a2 -> + begin try + unify_type_params a b tl1 tl2 + with Unify_error _ as err -> + (* the type could still have a from/to relation to itself (issue #3494) *) + begin try + unify_abstracts a b a1 tl1 a2 tl2 + with Unify_error _ -> + raise err + end + end + | TAbstract ({a_path=[],"Void"},_) , _ + | _ , TAbstract ({a_path=[],"Void"},_) -> + error [cannot_unify a b] + | TAbstract ({ a_path = ["haxe"],"NotVoid" },[]), _ + | _, TAbstract ({ a_path = ["haxe"],"NotVoid" },[]) -> + () + | TAbstract (a1,tl1) , TAbstract (a2,tl2) -> + unify_abstracts a b a1 tl1 a2 tl2 + | TInst (c1,tl1) , TInst (c2,tl2) -> + let rec loop c tl = + if c == c2 then begin + unify_type_params a b tl tl2; + true + end else (match c.cl_super with + | None -> false + | Some (cs,tls) -> + loop cs (List.map (apply_params c.cl_params tl) tls) + ) || List.exists (fun (cs,tls) -> + loop cs (List.map (apply_params c.cl_params tl) tls) + ) c.cl_implements + || (match c.cl_kind with + | KTypeParameter pl -> List.exists (fun t -> + match follow t with + | TInst (cs,tls) -> loop cs (List.map (apply_params c.cl_params tl) tls) + | TAbstract(aa,tl) -> List.exists (unify_to aa tl b) aa.a_to + | _ -> false + ) pl + | _ -> false) + in + if not (loop c1 tl1) then error [cannot_unify a b] + | TFun (l1,r1) , TFun (l2,r2) when List.length l1 = List.length l2 -> + let i = ref 0 in + (try + (match follow r2 with + | TAbstract ({a_path=[],"Void"},_) -> incr i + | _ -> unify r1 r2; incr i); + List.iter2 (fun (_,o1,t1) (_,o2,t2) -> + if o1 && not o2 then error [Cant_force_optional]; + unify t1 t2; + incr i + ) l2 l1 (* contravariance *) + with + Unify_error l -> + let msg = if !i = 0 then Invalid_return_type else Invalid_function_argument(!i,List.length l1) in + error (cannot_unify a b :: msg :: l)) + | TInst (c,tl) , TAnon an -> + if PMap.is_empty an.a_fields then (match c.cl_kind with + | KTypeParameter pl -> + (* one of the constraints must unify with { } *) + if not (List.exists (fun t -> match follow t with TInst _ | TAnon _ -> true | _ -> false) pl) then error [cannot_unify a b] + | _ -> ()); + (try + PMap.iter (fun n f2 -> + (* + introducing monomorphs while unifying might create infinite loops - see #2315 + let's store these monomorphs and make sure we reach a fixed point + *) + let monos = ref [] in + let make_type f = + match f.cf_params with + | [] -> f.cf_type + | l -> + let ml = List.map (fun _ -> mk_mono()) l in + monos := ml; + apply_params f.cf_params ml f.cf_type + in + let _, ft, f1 = (try raw_class_field make_type c tl n with Not_found -> error [has_no_field a n]) in + let ft = apply_params c.cl_params tl ft in + if not (unify_kind f1.cf_kind f2.cf_kind) then error [invalid_kind n f1.cf_kind f2.cf_kind]; + if (has_class_field_flag f2 CfPublic) && not (has_class_field_flag f1 CfPublic) then error [invalid_visibility n]; + + (match f2.cf_kind with + | Var { v_read = AccNo } | Var { v_read = AccNever } -> + (* we will do a recursive unification, so let's check for possible recursion *) + let old_monos = unify_new_monos.rec_stack in + unify_new_monos.rec_stack <- !monos @ unify_new_monos.rec_stack; + rec_stack unify_stack (ft,f2.cf_type) + (fun (a2,b2) -> fast_eq b2 f2.cf_type && fast_eq_mono unify_new_monos.rec_stack ft a2) + (fun() -> try unify_with_access f1 ft f2 with e -> unify_new_monos.rec_stack <- old_monos; raise e) + (fun l -> error (invalid_field n :: l)); + unify_new_monos.rec_stack <- old_monos; + | Method MethNormal | Method MethInline | Var { v_write = AccNo } | Var { v_write = AccNever } -> + (* same as before, but unification is reversed (read-only var) *) + let old_monos = unify_new_monos.rec_stack in + unify_new_monos.rec_stack <- !monos @ unify_new_monos.rec_stack; + rec_stack unify_stack (f2.cf_type,ft) + (fun(a2,b2) -> fast_eq_mono unify_new_monos.rec_stack b2 ft && fast_eq f2.cf_type a2) + (fun() -> try unify_with_access f1 ft f2 with e -> unify_new_monos.rec_stack <- old_monos; raise e) + (fun l -> error (invalid_field n :: l)); + unify_new_monos.rec_stack <- old_monos; + | _ -> + (* will use fast_eq, which have its own stack *) + try + unify_with_access f1 ft f2 + with + Unify_error l -> + error (invalid_field n :: l)); + + List.iter (fun f2o -> + if not (List.exists (fun f1o -> type_iseq f1o.cf_type f2o.cf_type) (f1 :: f1.cf_overloads)) + then error [Missing_overload (f1, f2o.cf_type)] + ) f2.cf_overloads; + (* we mark the field as :?used because it might be used through the structure *) + if not (Meta.has Meta.MaybeUsed f1.cf_meta) then begin + f1.cf_meta <- (Meta.MaybeUsed,[],f1.cf_pos) :: f1.cf_meta; + match f2.cf_kind with + | Var vk -> + let check name = + try + let _,_,cf = raw_class_field make_type c tl name in + if not (Meta.has Meta.MaybeUsed cf.cf_meta) then + cf.cf_meta <- (Meta.MaybeUsed,[],f1.cf_pos) :: cf.cf_meta + with Not_found -> + () + in + (match vk.v_read with AccCall -> check ("get_" ^ f1.cf_name) | _ -> ()); + (match vk.v_write with AccCall -> check ("set_" ^ f1.cf_name) | _ -> ()); + | _ -> () + end; + (match f1.cf_kind with + | Method MethInline -> + if (c.cl_extern || has_class_field_flag f1 CfExtern) && not (Meta.has Meta.Runtime f1.cf_meta) then error [Has_no_runtime_field (a,n)]; + | _ -> ()); + ) an.a_fields; + (match !(an.a_status) with + | Opened -> an.a_status := Closed; + | Statics _ | EnumStatics _ | AbstractStatics _ -> error [] + | Closed | Extend _ | Const -> ()) + with + Unify_error l -> error (cannot_unify a b :: l)) + | TAnon a1, TAnon a2 -> + unify_anons a b a1 a2 + | TAnon an, TAbstract ({ a_path = [],"Class" },[pt]) -> + (match !(an.a_status) with + | Statics cl -> unify (TInst (cl,List.map (fun _ -> mk_mono()) cl.cl_params)) pt + | _ -> error [cannot_unify a b]) + | TAnon an, TAbstract ({ a_path = [],"Enum" },[pt]) -> + (match !(an.a_status) with + | EnumStatics e -> unify (TEnum (e,List.map (fun _ -> mk_mono()) e.e_params)) pt + | _ -> error [cannot_unify a b]) + | TEnum _, TAbstract ({ a_path = [],"EnumValue" },[]) -> + () + | TEnum(en,_), TAbstract ({ a_path = ["haxe"],"FlatEnum" },[]) when Meta.has Meta.FlatEnum en.e_meta -> + () + | TFun _, TAbstract ({ a_path = ["haxe"],"Function" },[]) -> + () + | TInst(c,tl),TAbstract({a_path = ["haxe"],"Constructible"},[t1]) -> + begin try + begin match c.cl_kind with + | KTypeParameter tl -> + (* type parameters require an equal Constructible constraint *) + if not (List.exists (fun t -> match follow t with TAbstract({a_path = ["haxe"],"Constructible"},[t2]) -> type_iseq t1 t2 | _ -> false) tl) then error [cannot_unify a b] + | _ -> + let _,t,cf = class_field c tl "new" in + if not (has_class_field_flag cf CfPublic) then error [invalid_visibility "new"]; + begin try unify t t1 + with Unify_error l -> error (cannot_unify a b :: l) end + end + with Not_found -> + error [has_no_field a "new"] + end + | TDynamic t , _ -> + if t == a then + () + else (match b with + | TDynamic t2 -> + if t2 != b then + (try + type_eq EqRightDynamic t t2 + with + Unify_error l -> error (cannot_unify a b :: l)); + | TAbstract(bb,tl) when (List.exists (unify_from bb tl a b) bb.a_from) -> + () + | _ -> + error [cannot_unify a b]) + | _ , TDynamic t -> + if t == b then + () + else (match a with + | TDynamic t2 -> + if t2 != a then + (try + type_eq EqRightDynamic t t2 + with + Unify_error l -> error (cannot_unify a b :: l)); + | TAnon an -> + (try + (match !(an.a_status) with + | Statics _ | EnumStatics _ -> error [] + | Opened -> an.a_status := Closed + | _ -> ()); + PMap.iter (fun _ f -> + try + type_eq EqStrict (field_type f) t + with Unify_error l -> + error (invalid_field f.cf_name :: l) + ) an.a_fields + with Unify_error l -> + error (cannot_unify a b :: l)) + | TAbstract(aa,tl) when (List.exists (unify_to aa tl b) aa.a_to) -> + () + | _ -> + error [cannot_unify a b]) + | TAbstract (aa,tl), _ -> + if not (List.exists (unify_to aa tl b) aa.a_to) then error [cannot_unify a b]; + | TInst ({ cl_kind = KTypeParameter ctl } as c,pl), TAbstract (bb,tl) -> + (* one of the constraints must satisfy the abstract *) + if not (List.exists (fun t -> + let t = apply_params c.cl_params pl t in + try unify t b; true with Unify_error _ -> false + ) ctl) && not (List.exists (unify_from bb tl a b) bb.a_from) then error [cannot_unify a b]; + | _, TAbstract (bb,tl) -> + if not (List.exists (unify_from bb tl a b) bb.a_from) then error [cannot_unify a b] + | _ , _ -> + error [cannot_unify a b] + +and unify_abstracts a b a1 tl1 a2 tl2 = + let f1 = unify_to a1 tl1 b in + let f2 = unify_from a2 tl2 a b in + if (List.exists (f1 ~allow_transitive_cast:false) a1.a_to) + || (List.exists (f2 ~allow_transitive_cast:false) a2.a_from) + || (((Meta.has Meta.CoreType a1.a_meta) || (Meta.has Meta.CoreType a2.a_meta)) + && ((List.exists f1 a1.a_to) || (List.exists f2 a2.a_from))) then + () + else + error [cannot_unify a b] + +and unify_anons a b a1 a2 = + if would_produce_recursive_anon a1 a2 then error [cannot_unify a b]; + (try + PMap.iter (fun n f2 -> + try + let f1 = PMap.find n a1.a_fields in + if not (unify_kind f1.cf_kind f2.cf_kind) then + (match !(a1.a_status), f1.cf_kind, f2.cf_kind with + | Opened, Var { v_read = AccNormal; v_write = AccNo }, Var { v_read = AccNormal; v_write = AccNormal } -> + f1.cf_kind <- f2.cf_kind; + | _ -> error [invalid_kind n f1.cf_kind f2.cf_kind]); + if (has_class_field_flag f2 CfPublic) && not (has_class_field_flag f1 CfPublic) then error [invalid_visibility n]; + try + let f1_type = + if fast_eq f1.cf_type f2.cf_type then f1.cf_type + else field_type f1 + in + unify_with_access f1 f1_type f2; + (match !(a1.a_status) with + | Statics c when not (Meta.has Meta.MaybeUsed f1.cf_meta) -> f1.cf_meta <- (Meta.MaybeUsed,[],f1.cf_pos) :: f1.cf_meta + | _ -> ()); + with + Unify_error l -> error (invalid_field n :: l) + with + Not_found -> + match !(a1.a_status) with + | Opened -> + if not (link (Monomorph.create()) a f2.cf_type) then error []; + a1.a_fields <- PMap.add n f2 a1.a_fields + | Const when Meta.has Meta.Optional f2.cf_meta -> + () + | _ -> + error [has_no_field a n]; + ) a2.a_fields; + (match !(a1.a_status) with + | Const when not (PMap.is_empty a2.a_fields) -> + PMap.iter (fun n _ -> if not (PMap.mem n a2.a_fields) then error [has_extra_field a n]) a1.a_fields; + | Opened -> + a1.a_status := Closed + | _ -> ()); + (match !(a2.a_status) with + | Statics c -> (match !(a1.a_status) with Statics c2 when c == c2 -> () | _ -> error []) + | EnumStatics e -> (match !(a1.a_status) with EnumStatics e2 when e == e2 -> () | _ -> error []) + | AbstractStatics a -> (match !(a1.a_status) with AbstractStatics a2 when a == a2 -> () | _ -> error []) + | Opened -> a2.a_status := Closed + | Const | Extend _ | Closed -> ()) + with + Unify_error l -> error (cannot_unify a b :: l)) + +and unify_from ab tl a b ?(allow_transitive_cast=true) t = + rec_stack_bool abstract_cast_stack (a,b) + (fun (a2,b2) -> fast_eq a a2 && fast_eq b b2) + (fun() -> + let t = apply_params ab.a_params tl t in + let unify_func = if allow_transitive_cast then unify else type_eq EqRightDynamic in + unify_func a t) + +and unify_to ab tl b ?(allow_transitive_cast=true) t = + let t = apply_params ab.a_params tl t in + let unify_func = if allow_transitive_cast then unify else type_eq EqStrict in + try + unify_func t b; + true + with Unify_error _ -> + false + +and unify_from_field ab tl a b ?(allow_transitive_cast=true) (t,cf) = + rec_stack_bool abstract_cast_stack (a,b) + (fun (a2,b2) -> fast_eq a a2 && fast_eq b b2) + (fun() -> + let unify_func = if allow_transitive_cast then unify else type_eq EqStrict in + match follow cf.cf_type with + | TFun(_,r) -> + let monos = List.map (fun _ -> mk_mono()) cf.cf_params in + let map t = apply_params ab.a_params tl (apply_params cf.cf_params monos t) in + unify_func a (map t); + List.iter2 (fun m (name,t) -> match follow t with + | TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] -> + List.iter (fun tc -> match follow m with TMono _ -> raise (Unify_error []) | _ -> unify m (map tc) ) constr + | _ -> () + ) monos cf.cf_params; + unify_func (map r) b; + true + | _ -> die "" __LOC__) + +and unify_to_field ab tl b ?(allow_transitive_cast=true) (t,cf) = + let a = TAbstract(ab,tl) in + rec_stack_bool abstract_cast_stack (b,a) + (fun (b2,a2) -> fast_eq a a2 && fast_eq b b2) + (fun() -> + let unify_func = if allow_transitive_cast then unify else type_eq EqStrict in + match follow cf.cf_type with + | TFun((_,_,ta) :: _,_) -> + let monos = List.map (fun _ -> mk_mono()) cf.cf_params in + let map t = apply_params ab.a_params tl (apply_params cf.cf_params monos t) in + let athis = map ab.a_this in + (* we cannot allow implicit casts when the this type is not completely known yet *) + (* if has_mono athis then raise (Unify_error []); *) + with_variance (type_eq EqStrict) athis (map ta); + (* immediate constraints checking is ok here because we know there are no monomorphs *) + List.iter2 (fun m (name,t) -> match follow t with + | TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] -> + List.iter (fun tc -> match follow m with TMono _ -> raise (Unify_error []) | _ -> unify m (map tc) ) constr + | _ -> () + ) monos cf.cf_params; + unify_func (map t) b; + | _ -> die "" __LOC__) + +and unify_with_variance f t1 t2 = + let allows_variance_to t tf = type_iseq tf t in + match follow t1,follow t2 with + | TInst(c1,tl1),TInst(c2,tl2) when c1 == c2 -> + List.iter2 f tl1 tl2 + | TEnum(en1,tl1),TEnum(en2,tl2) when en1 == en2 -> + List.iter2 f tl1 tl2 + | TAbstract(a1,tl1),TAbstract(a2,tl2) when a1 == a2 && Meta.has Meta.CoreType a1.a_meta -> + List.iter2 f tl1 tl2 + | TAbstract(a1,pl1),TAbstract(a2,pl2) -> + if (Meta.has Meta.CoreType a1.a_meta) && (Meta.has Meta.CoreType a2.a_meta) then begin + let ta1 = apply_params a1.a_params pl1 a1.a_this in + let ta2 = apply_params a2.a_params pl2 a2.a_this in + type_eq EqStrict ta1 ta2; + end; + if not (List.exists (allows_variance_to t2) a1.a_to) && not (List.exists (allows_variance_to t1) a2.a_from) then + error [cannot_unify t1 t2] + | TAbstract(a,pl),t -> + type_eq EqBothDynamic (apply_params a.a_params pl a.a_this) t; + if not (List.exists (fun t2 -> allows_variance_to t (apply_params a.a_params pl t2)) a.a_to) then error [cannot_unify t1 t2] + | t,TAbstract(a,pl) -> + type_eq EqBothDynamic t (apply_params a.a_params pl a.a_this); + if not (List.exists (fun t2 -> allows_variance_to t (apply_params a.a_params pl t2)) a.a_from) then error [cannot_unify t1 t2] + | (TAnon a1 as t1), (TAnon a2 as t2) -> + rec_stack unify_stack (t1,t2) + (fun (a,b) -> fast_eq a t1 && fast_eq b t2) + (fun() -> unify_anons t1 t2 a1 a2) + (fun l -> error l) + | _ -> + error [cannot_unify t1 t2] + +and unify_type_params a b tl1 tl2 = + let i = ref 0 in + List.iter2 (fun t1 t2 -> + incr i; + try + with_variance (type_eq EqRightDynamic) t1 t2 + with Unify_error l -> + let err = cannot_unify a b in + error (err :: (Invariant_parameter !i) :: l) + ) tl1 tl2 + +and with_variance f t1 t2 = + try + f t1 t2 + with Unify_error l -> try + unify_with_variance (with_variance f) t1 t2 + with Unify_error _ -> + raise (Unify_error l) + +and unify_with_access f1 t1 f2 = + match f2.cf_kind with + (* write only *) + | Var { v_read = AccNo } | Var { v_read = AccNever } -> unify f2.cf_type t1 + (* read only *) + | Method MethNormal | Method MethInline | Var { v_write = AccNo } | Var { v_write = AccNever } -> + if (has_class_field_flag f1 CfFinal) <> (has_class_field_flag f2 CfFinal) then raise (Unify_error [FinalInvariance]); + unify t1 f2.cf_type + (* read/write *) + | _ -> with_variance (type_eq EqBothDynamic) t1 f2.cf_type + +let does_unify a b = + try + unify a b; + true + with Unify_error _ -> + false diff --git a/src/core/texpr.ml b/src/core/texpr.ml index 200a1ea3a790ed7f1ad8aba1e4593e809b4f54be..ffa9937a6bb93522140efd666e031fe9bcd8bb68 100644 --- a/src/core/texpr.ml +++ b/src/core/texpr.ml @@ -1,8 +1,255 @@ open Globals open Ast -open Type +open TType +open TFunctions +open TUnification +open TPrinting open Error +let iter f e = + match e.eexpr with + | TConst _ + | TLocal _ + | TBreak + | TContinue + | TTypeExpr _ + | TIdent _ -> + () + | TArray (e1,e2) + | TBinop (_,e1,e2) + | TFor (_,e1,e2) + | TWhile (e1,e2,_) -> + f e1; + f e2; + | TThrow e + | TField (e,_) + | TEnumParameter (e,_,_) + | TEnumIndex e + | TParenthesis e + | TCast (e,_) + | TUnop (_,_,e) + | TMeta(_,e) -> + f e + | TArrayDecl el + | TNew (_,_,el) + | TBlock el -> + List.iter f el + | TObjectDecl fl -> + List.iter (fun (_,e) -> f e) fl + | TCall (e,el) -> + f e; + List.iter f el + | TVar (v,eo) -> + (match eo with None -> () | Some e -> f e) + | TFunction fu -> + f fu.tf_expr + | TIf (e,e1,e2) -> + f e; + f e1; + (match e2 with None -> () | Some e -> f e) + | TSwitch (e,cases,def) -> + f e; + List.iter (fun (el,e2) -> List.iter f el; f e2) cases; + (match def with None -> () | Some e -> f e) + | TTry (e,catches) -> + f e; + List.iter (fun (_,e) -> f e) catches + | TReturn eo -> + (match eo with None -> () | Some e -> f e) + +(** + Returns `true` if `predicate` is evaluated to `true` for at least one of sub-expressions. + Returns `false` otherwise. + Does not evaluate `predicate` for the `e` expression. +*) +let check_expr predicate e = + match e.eexpr with + | TConst _ | TLocal _ | TBreak | TContinue | TTypeExpr _ | TIdent _ -> + false + | TArray (e1,e2) | TBinop (_,e1,e2) | TFor (_,e1,e2) | TWhile (e1,e2,_) -> + predicate e1 || predicate e2; + | TThrow e | TField (e,_) | TEnumParameter (e,_,_) | TEnumIndex e | TParenthesis e + | TCast (e,_) | TUnop (_,_,e) | TMeta(_,e) -> + predicate e + | TArrayDecl el | TNew (_,_,el) | TBlock el -> + List.exists predicate el + | TObjectDecl fl -> + List.exists (fun (_,e) -> predicate e) fl + | TCall (e,el) -> + predicate e || List.exists predicate el + | TVar (_,eo) | TReturn eo -> + (match eo with None -> false | Some e -> predicate e) + | TFunction fu -> + predicate fu.tf_expr + | TIf (e,e1,e2) -> + predicate e || predicate e1 || (match e2 with None -> false | Some e -> predicate e) + | TSwitch (e,cases,def) -> + predicate e + || List.exists (fun (el,e2) -> List.exists predicate el || predicate e2) cases + || (match def with None -> false | Some e -> predicate e) + | TTry (e,catches) -> + predicate e || List.exists (fun (_,e) -> predicate e) catches + +let map_expr f e = + match e.eexpr with + | TConst _ + | TLocal _ + | TBreak + | TContinue + | TTypeExpr _ + | TIdent _ -> + e + | TArray (e1,e2) -> + let e1 = f e1 in + { e with eexpr = TArray (e1,f e2) } + | TBinop (op,e1,e2) -> + let e1 = f e1 in + { e with eexpr = TBinop (op,e1,f e2) } + | TFor (v,e1,e2) -> + let e1 = f e1 in + { e with eexpr = TFor (v,e1,f e2) } + | TWhile (e1,e2,flag) -> + let e1 = f e1 in + { e with eexpr = TWhile (e1,f e2,flag) } + | TThrow e1 -> + { e with eexpr = TThrow (f e1) } + | TEnumParameter (e1,ef,i) -> + { e with eexpr = TEnumParameter(f e1,ef,i) } + | TEnumIndex e1 -> + { e with eexpr = TEnumIndex (f e1) } + | TField (e1,v) -> + { e with eexpr = TField (f e1,v) } + | TParenthesis e1 -> + { e with eexpr = TParenthesis (f e1) } + | TUnop (op,pre,e1) -> + { e with eexpr = TUnop (op,pre,f e1) } + | TArrayDecl el -> + { e with eexpr = TArrayDecl (List.map f el) } + | TNew (t,pl,el) -> + { e with eexpr = TNew (t,pl,List.map f el) } + | TBlock el -> + { e with eexpr = TBlock (List.map f el) } + | TObjectDecl el -> + { e with eexpr = TObjectDecl (List.map (fun (v,e) -> v, f e) el) } + | TCall (e1,el) -> + let e1 = f e1 in + { e with eexpr = TCall (e1, List.map f el) } + | TVar (v,eo) -> + { e with eexpr = TVar (v, match eo with None -> None | Some e -> Some (f e)) } + | TFunction fu -> + { e with eexpr = TFunction { fu with tf_expr = f fu.tf_expr } } + | TIf (ec,e1,e2) -> + let ec = f ec in + let e1 = f e1 in + { e with eexpr = TIf (ec,e1,match e2 with None -> None | Some e -> Some (f e)) } + | TSwitch (e1,cases,def) -> + let e1 = f e1 in + let cases = List.map (fun (el,e2) -> List.map f el, f e2) cases in + { e with eexpr = TSwitch (e1, cases, match def with None -> None | Some e -> Some (f e)) } + | TTry (e1,catches) -> + let e1 = f e1 in + { e with eexpr = TTry (e1, List.map (fun (v,e) -> v, f e) catches) } + | TReturn eo -> + { e with eexpr = TReturn (match eo with None -> None | Some e -> Some (f e)) } + | TCast (e1,t) -> + { e with eexpr = TCast (f e1,t) } + | TMeta (m,e1) -> + {e with eexpr = TMeta(m,f e1)} + +let map_expr_type f ft fv e = + match e.eexpr with + | TConst _ + | TBreak + | TContinue + | TTypeExpr _ + | TIdent _ -> + { e with etype = ft e.etype } + | TLocal v -> + { e with eexpr = TLocal (fv v); etype = ft e.etype } + | TArray (e1,e2) -> + let e1 = f e1 in + { e with eexpr = TArray (e1,f e2); etype = ft e.etype } + | TBinop (op,e1,e2) -> + let e1 = f e1 in + { e with eexpr = TBinop (op,e1,f e2); etype = ft e.etype } + | TFor (v,e1,e2) -> + let v = fv v in + let e1 = f e1 in + { e with eexpr = TFor (v,e1,f e2); etype = ft e.etype } + | TWhile (e1,e2,flag) -> + let e1 = f e1 in + { e with eexpr = TWhile (e1,f e2,flag); etype = ft e.etype } + | TThrow e1 -> + { e with eexpr = TThrow (f e1); etype = ft e.etype } + | TEnumParameter (e1,ef,i) -> + { e with eexpr = TEnumParameter (f e1,ef,i); etype = ft e.etype } + | TEnumIndex e1 -> + { e with eexpr = TEnumIndex (f e1); etype = ft e.etype } + | TField (e1,v) -> + let e1 = f e1 in + let v = try + let n = match v with + | FClosure _ -> raise Not_found + | FAnon f | FInstance (_,_,f) | FStatic (_,f) -> f.cf_name + | FEnum (_,f) -> f.ef_name + | FDynamic n -> n + in + quick_field e1.etype n + with Not_found -> + v + in + { e with eexpr = TField (e1,v); etype = ft e.etype } + | TParenthesis e1 -> + { e with eexpr = TParenthesis (f e1); etype = ft e.etype } + | TUnop (op,pre,e1) -> + { e with eexpr = TUnop (op,pre,f e1); etype = ft e.etype } + | TArrayDecl el -> + { e with eexpr = TArrayDecl (List.map f el); etype = ft e.etype } + | TNew (c,pl,el) -> + let et = ft e.etype in + (* make sure that we use the class corresponding to the replaced type *) + let t = match c.cl_kind with + | KTypeParameter _ | KGeneric -> + et + | _ -> + ft (TInst(c,pl)) + in + let c, pl = (match follow t with TInst (c,pl) -> (c,pl) | TAbstract({a_impl = Some c},pl) -> c,pl | t -> TUnification.error [has_no_field t "new"]) in + { e with eexpr = TNew (c,pl,List.map f el); etype = et } + | TBlock el -> + { e with eexpr = TBlock (List.map f el); etype = ft e.etype } + | TObjectDecl el -> + { e with eexpr = TObjectDecl (List.map (fun (v,e) -> v, f e) el); etype = ft e.etype } + | TCall (e1,el) -> + let e1 = f e1 in + { e with eexpr = TCall (e1, List.map f el); etype = ft e.etype } + | TVar (v,eo) -> + { e with eexpr = TVar (fv v, match eo with None -> None | Some e -> Some (f e)); etype = ft e.etype } + | TFunction fu -> + let fu = { + tf_expr = f fu.tf_expr; + tf_args = List.map (fun (v,o) -> fv v, o) fu.tf_args; + tf_type = ft fu.tf_type; + } in + { e with eexpr = TFunction fu; etype = ft e.etype } + | TIf (ec,e1,e2) -> + let ec = f ec in + let e1 = f e1 in + { e with eexpr = TIf (ec,e1,match e2 with None -> None | Some e -> Some (f e)); etype = ft e.etype } + | TSwitch (e1,cases,def) -> + let e1 = f e1 in + let cases = List.map (fun (el,e2) -> List.map f el, f e2) cases in + { e with eexpr = TSwitch (e1, cases, match def with None -> None | Some e -> Some (f e)); etype = ft e.etype } + | TTry (e1,catches) -> + let e1 = f e1 in + { e with eexpr = TTry (e1, List.map (fun (v,e) -> fv v, f e) catches); etype = ft e.etype } + | TReturn eo -> + { e with eexpr = TReturn (match eo with None -> None | Some e -> Some (f e)); etype = ft e.etype } + | TCast (e1,t) -> + { e with eexpr = TCast (f e1,t); etype = ft e.etype } + | TMeta (m,e1) -> + {e with eexpr = TMeta(m, f e1); etype = ft e.etype } + let equal_fa fa1 fa2 = match fa1,fa2 with | FStatic(c1,cf1),FStatic(c2,cf2) -> c1 == c2 && cf1.cf_name == cf2.cf_name | FInstance(c1,tl1,cf1),FInstance(c2,tl2,cf2) -> c1 == c2 && safe_for_all2 type_iseq tl1 tl2 && cf1.cf_name == cf2.cf_name @@ -214,16 +461,16 @@ let foldmap f acc e = (* Collection of functions that return expressions *) module Builder = struct let make_static_this c p = - let ta = TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } in + let ta = mk_anon ~fields:c.cl_statics (ref (Statics c)) in mk (TTypeExpr (TClassDecl c)) ta p let make_typeexpr mt pos = let t = match resolve_typedef mt with - | TClassDecl c -> TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } - | TEnumDecl e -> TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics e) } - | TAbstractDecl a -> TAnon { a_fields = PMap.empty; a_status = ref (AbstractStatics a) } - | _ -> assert false + | TClassDecl c -> mk_anon ~fields:c.cl_statics (ref (Statics c)) + | TEnumDecl e -> mk_anon (ref (EnumStatics e)) + | TAbstractDecl a -> mk_anon (ref (AbstractStatics a)) + | _ -> die "" __LOC__ in mk (TTypeExpr mt) t pos @@ -261,7 +508,14 @@ module Builder = struct | _ -> error "Unsupported constant" p let field e name t p = - mk (TField (e,try quick_field e.etype name with Not_found -> assert false)) t p + let f = + try + quick_field e.etype name + with Not_found -> + let field = (s_type (print_context()) e.etype) ^ "." ^ name in + die ("Field " ^ field ^ " requested but not found") __LOC__ + in + mk (TField (e,f)) t p let fcall e name el ret p = let ft = tfun (List.map (fun e -> e.etype) el) ret in @@ -270,6 +524,11 @@ module Builder = struct let mk_parent e = mk (TParenthesis e) e.etype e.epos + let ensure_parent e = + match e.eexpr with + | TParenthesis _ -> e + | _ -> mk_parent e + let mk_return e = mk (TReturn (Some e)) t_dynamic e.epos @@ -302,7 +561,7 @@ let rec constructor_side_effects e = | TParenthesis _ | TTypeExpr _ | TLocal _ | TMeta _ | TConst _ | TContinue | TBreak | TCast _ | TIdent _ -> try - Type.iter (fun e -> if constructor_side_effects e then raise Exit) e; + iter (fun e -> if constructor_side_effects e then raise Exit) e; false; with Exit -> true @@ -328,7 +587,7 @@ let rec type_constant_value basic (e,p) = | EParenthesis e -> type_constant_value basic e | EObjectDecl el -> - mk (TObjectDecl (List.map (fun (k,e) -> k,type_constant_value basic e) el)) (TAnon { a_fields = PMap.empty; a_status = ref Closed }) p + mk (TObjectDecl (List.map (fun (k,e) -> k,type_constant_value basic e) el)) (mk_anon (ref Closed)) p | EArrayDecl el -> mk (TArrayDecl (List.map (type_constant_value basic) el)) (basic.tarray t_dynamic) p | _ -> @@ -343,7 +602,7 @@ let for_remap basic v e1 e2 p = let enext = mk (TField(ev',quick_field t1 "next")) (tfun [] v.v_type) e1.epos in let enext = mk (TCall(enext,[])) v.v_type e1.epos in let eassign = mk (TVar(v,Some enext)) basic.tvoid p in - let ebody = Type.concat eassign e2 in + let ebody = concat eassign e2 in mk (TBlock [ mk (TVar (v',Some e1)) basic.tvoid e1.epos; mk (TWhile((mk (TParenthesis ehasnext) ehasnext.etype ehasnext.epos),ebody,NormalWhile)) basic.tvoid e1.epos; @@ -529,7 +788,7 @@ let collect_captured_vars e = loop e; ) catches | _ -> - Type.iter loop e + iter loop e in loop e; List.rev !unknown,!accesses_this diff --git a/src/core/timer.ml b/src/core/timer.ml index 8abd752a3d62538c169b93a77a5e39fa9a2e7710..7335cfc3df677c56068e511b3274c2a22ae399cc 100644 --- a/src/core/timer.ml +++ b/src/core/timer.ml @@ -25,6 +25,8 @@ type timer_infos = { mutable calls : int; } +let measure_times = ref false + let get_time = Extc.time let htimers = Hashtbl.create 0 @@ -61,16 +63,24 @@ let rec close now t = | current :: _ -> match current.pauses with | pauses :: rest -> current.pauses <- (dt +. pauses) :: rest - | _ -> assert false + | _ -> Globals.die "" __LOC__ ) - | _ -> assert false + | _ -> Globals.die "" __LOC__ end else close now tt let timer id = - let t = new_timer id in - curtime := t :: !curtime; - (function() -> close (get_time()) t) + if !measure_times then ( + let t = new_timer id in + curtime := t :: !curtime; + (function() -> close (get_time()) t) + ) else + (fun() -> ()) + +let current_id() = + match !curtime with + | [] -> None + | t :: _ -> Some t.id let rec close_times() = let now = get_time() in @@ -105,7 +115,7 @@ let build_times_tree () = } in Hashtbl.iter (fun _ timer -> let rec loop parent sl = match sl with - | [] -> assert false + | [] -> Globals.die "" __LOC__ | s :: sl -> let path = (match parent.path with "" -> "" | _ -> parent.path ^ ".") ^ s in let node = try diff --git a/src/core/type.ml b/src/core/type.ml index 3102b95775a3ba914d863a76fa742b9f18bd065a..3606ee9715682f5d7937eac0897488090f857f8d 100644 --- a/src/core/type.ml +++ b/src/core/type.ml @@ -17,3113 +17,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *) -open Ast -open Globals - -type field_kind = - | Var of var_kind - | Method of method_kind - -and var_kind = { - v_read : var_access; - v_write : var_access; -} - -and var_access = - | AccNormal - | AccNo (* can't be accessed outside of the class itself and its subclasses *) - | AccNever (* can't be accessed, even in subclasses *) - | AccCtor (* can only be accessed from the constructor *) - | AccResolve (* call resolve("field") when accessed *) - | AccCall (* perform a method call when accessed *) - | AccInline (* similar to Normal but inline when accessed *) - | AccRequire of string * string option (* set when @:require(cond) fails *) - -and method_kind = - | MethNormal - | MethInline - | MethDynamic - | MethMacro - -type module_check_policy = - | NoCheckFileTimeModification - | CheckFileContentModification - | NoCheckDependencies - | NoCheckShadowing - -type t = - | TMono of t option ref - | TEnum of tenum * tparams - | TInst of tclass * tparams - | TType of tdef * tparams - | TFun of tsignature - | TAnon of tanon - | TDynamic of t - | TLazy of tlazy ref - | TAbstract of tabstract * tparams - -and tlazy = - | LAvailable of t - | LProcessing of (unit -> t) - | LWait of (unit -> t) - -and tsignature = (string * bool * t) list * t - -and tparams = t list - -and type_params = (string * t) list - -and tconstant = - | TInt of int32 - | TFloat of string - | TString of string - | TBool of bool - | TNull - | TThis - | TSuper - -and tvar_extra = (type_params * texpr option) option - -and tvar_origin = - | TVOLocalVariable - | TVOArgument - | TVOForVariable - | TVOPatternVariable - | TVOCatchVariable - | TVOLocalFunction - -and tvar_kind = - | VUser of tvar_origin - | VGenerated - | VInlined - | VInlinedConstructorVariable - | VExtractorVariable - -and tvar = { - mutable v_id : int; - mutable v_name : string; - mutable v_type : t; - mutable v_kind : tvar_kind; - mutable v_capture : bool; - mutable v_final : bool; - mutable v_extra : tvar_extra; - mutable v_meta : metadata; - v_pos : pos; -} - -and tfunc = { - tf_args : (tvar * texpr option) list; - tf_type : t; - tf_expr : texpr; -} - -and anon_status = - | Closed - | Opened - | Const - | Extend of t list - | Statics of tclass - | EnumStatics of tenum - | AbstractStatics of tabstract - -and tanon = { - mutable a_fields : (string, tclass_field) PMap.t; - a_status : anon_status ref; -} - -and texpr_expr = - | TConst of tconstant - | TLocal of tvar - | TArray of texpr * texpr - | TBinop of Ast.binop * texpr * texpr - | TField of texpr * tfield_access - | TTypeExpr of module_type - | TParenthesis of texpr - | TObjectDecl of ((string * pos * quote_status) * texpr) list - | TArrayDecl of texpr list - | TCall of texpr * texpr list - | TNew of tclass * tparams * texpr list - | TUnop of Ast.unop * Ast.unop_flag * texpr - | TFunction of tfunc - | TVar of tvar * texpr option - | TBlock of texpr list - | TFor of tvar * texpr * texpr - | TIf of texpr * texpr * texpr option - | TWhile of texpr * texpr * Ast.while_flag - | TSwitch of texpr * (texpr list * texpr) list * texpr option - | TTry of texpr * (tvar * texpr) list - | TReturn of texpr option - | TBreak - | TContinue - | TThrow of texpr - | TCast of texpr * module_type option - | TMeta of metadata_entry * texpr - | TEnumParameter of texpr * tenum_field * int - | TEnumIndex of texpr - | TIdent of string - -and tfield_access = - | FInstance of tclass * tparams * tclass_field - | FStatic of tclass * tclass_field - | FAnon of tclass_field - | FDynamic of string - | FClosure of (tclass * tparams) option * tclass_field (* None class = TAnon *) - | FEnum of tenum * tenum_field - -and texpr = { - eexpr : texpr_expr; - etype : t; - epos : pos; -} - -and tclass_field = { - mutable cf_name : string; - mutable cf_type : t; - cf_pos : pos; - cf_name_pos : pos; - mutable cf_doc : Ast.documentation; - mutable cf_meta : metadata; - mutable cf_kind : field_kind; - mutable cf_params : type_params; - mutable cf_expr : texpr option; - mutable cf_expr_unoptimized : tfunc option; - mutable cf_overloads : tclass_field list; - mutable cf_flags : int; -} - -and tclass_kind = - | KNormal - | KTypeParameter of t list - | KExpr of Ast.expr - | KGeneric - | KGenericInstance of tclass * tparams - | KMacroType - | KGenericBuild of class_field list - | KAbstractImpl of tabstract - -and metadata = Ast.metadata - -and tinfos = { - mt_path : path; - mt_module : module_def; - mt_pos : pos; - mt_name_pos : pos; - mt_private : bool; - mt_doc : Ast.documentation; - mutable mt_meta : metadata; - mt_params : type_params; - mutable mt_using : (tclass * pos) list; -} - -and tclass = { - mutable cl_path : path; - mutable cl_module : module_def; - mutable cl_pos : pos; - mutable cl_name_pos : pos; - mutable cl_private : bool; - mutable cl_doc : Ast.documentation; - mutable cl_meta : metadata; - mutable cl_params : type_params; - mutable cl_using : (tclass * pos) list; - (* do not insert any fields above *) - mutable cl_kind : tclass_kind; - mutable cl_extern : bool; - mutable cl_final : bool; - mutable cl_interface : bool; - mutable cl_super : (tclass * tparams) option; - mutable cl_implements : (tclass * tparams) list; - mutable cl_fields : (string, tclass_field) PMap.t; - mutable cl_statics : (string, tclass_field) PMap.t; - mutable cl_ordered_statics : tclass_field list; - mutable cl_ordered_fields : tclass_field list; - mutable cl_dynamic : t option; - mutable cl_array_access : t option; - mutable cl_constructor : tclass_field option; - mutable cl_init : texpr option; - mutable cl_overrides : tclass_field list; - - mutable cl_build : unit -> build_state; - mutable cl_restore : unit -> unit; - (* - These are classes which directly extend or directly implement this class. - Populated automatically in post-processing step (Filters.run) - *) - mutable cl_descendants : tclass list; -} - -and tenum_field = { - ef_name : string; - mutable ef_type : t; - ef_pos : pos; - ef_name_pos : pos; - ef_doc : Ast.documentation; - ef_index : int; - mutable ef_params : type_params; - mutable ef_meta : metadata; -} - -and tenum = { - mutable e_path : path; - e_module : module_def; - e_pos : pos; - e_name_pos : pos; - e_private : bool; - e_doc : Ast.documentation; - mutable e_meta : metadata; - mutable e_params : type_params; - mutable e_using : (tclass * pos) list; - (* do not insert any fields above *) - e_type : tdef; - mutable e_extern : bool; - mutable e_constrs : (string , tenum_field) PMap.t; - mutable e_names : string list; -} - -and tdef = { - t_path : path; - t_module : module_def; - t_pos : pos; - t_name_pos : pos; - t_private : bool; - t_doc : Ast.documentation; - mutable t_meta : metadata; - mutable t_params : type_params; - mutable t_using : (tclass * pos) list; - (* do not insert any fields above *) - mutable t_type : t; -} - -and tabstract = { - mutable a_path : path; - a_module : module_def; - a_pos : pos; - a_name_pos : pos; - a_private : bool; - a_doc : Ast.documentation; - mutable a_meta : metadata; - mutable a_params : type_params; - mutable a_using : (tclass * pos) list; - (* do not insert any fields above *) - mutable a_ops : (Ast.binop * tclass_field) list; - mutable a_unops : (Ast.unop * unop_flag * tclass_field) list; - mutable a_impl : tclass option; - mutable a_this : t; - mutable a_from : t list; - mutable a_from_field : (t * tclass_field) list; - mutable a_to : t list; - mutable a_to_field : (t * tclass_field) list; - mutable a_array : tclass_field list; - mutable a_read : tclass_field option; - mutable a_write : tclass_field option; -} - -and module_type = - | TClassDecl of tclass - | TEnumDecl of tenum - | TTypeDecl of tdef - | TAbstractDecl of tabstract - -and module_def = { - m_id : int; - m_path : path; - mutable m_types : module_type list; - m_extra : module_def_extra; -} - -and module_def_display = { - mutable m_inline_calls : (pos * pos) list; (* calls whatever is at pos1 from pos2 *) - mutable m_type_hints : (pos * pos) list; -} - -and module_def_extra = { - m_file : string; - m_sign : string; - m_display : module_def_display; - mutable m_check_policy : module_check_policy list; - mutable m_time : float; - mutable m_dirty : path option; - mutable m_added : int; - mutable m_mark : int; - mutable m_deps : (int,module_def) PMap.t; - mutable m_processed : int; - mutable m_kind : module_kind; - mutable m_binded_res : (string, string) PMap.t; - mutable m_if_feature : (string *(tclass * tclass_field * bool)) list; - mutable m_features : (string,bool) Hashtbl.t; -} - -and module_kind = - | MCode - | MMacro - | MFake - | MExtern - | MImport - -and build_state = - | Built - | Building of tclass list - | BuildMacro of (unit -> unit) list ref - -type basic_types = { - mutable tvoid : t; - mutable tint : t; - mutable tfloat : t; - mutable tbool : t; - mutable tnull : t -> t; - mutable tstring : t; - mutable tarray : t -> t; -} - -type class_field_scope = - | CFSStatic - | CFSMember - | CFSConstructor - -type flag_tclass_field = - | CfPublic - | CfExtern (* This is only set if the field itself is extern, not just the class. *) - | CfFinal - | CfModifiesThis (* This is set for methods which reassign `this`. E.g. `this = value` *) - -(* Flags *) - -let has_flag flags flag = - flags land (1 lsl flag) > 0 - -let set_flag flags flag = - flags lor (1 lsl flag) - -let unset_flag flags flag = - flags land (lnot (1 lsl flag)) - -let int_of_class_field_flag (flag : flag_tclass_field) = - Obj.magic flag - -let add_class_field_flag cf (flag : flag_tclass_field) = - cf.cf_flags <- set_flag cf.cf_flags (int_of_class_field_flag flag) - -let remove_class_field_flag cf (flag : flag_tclass_field) = - cf.cf_flags <- unset_flag cf.cf_flags (int_of_class_field_flag flag) - -let has_class_field_flag cf (flag : flag_tclass_field) = - has_flag cf.cf_flags (int_of_class_field_flag flag) - -(* ======= General utility ======= *) - -let alloc_var = - let uid = ref 0 in - (fun kind n t p -> - incr uid; - { - v_kind = kind; - v_name = n; - v_type = t; - v_id = !uid; - v_capture = false; - v_final = (match kind with VUser TVOLocalFunction -> true | _ -> false); - v_extra = None; - v_meta = []; - v_pos = p - } - ) - -let alloc_mid = - let mid = ref 0 in - (fun() -> incr mid; !mid) - -let mk e t p = { eexpr = e; etype = t; epos = p } - -let mk_block e = - match e.eexpr with - | TBlock _ -> e - | _ -> mk (TBlock [e]) e.etype e.epos - -let mk_cast e t p = mk (TCast(e,None)) t p - -let null t p = mk (TConst TNull) t p - -let mk_mono() = TMono (ref None) - -let rec t_dynamic = TDynamic t_dynamic - -let mk_anon fl = TAnon { a_fields = fl; a_status = ref Closed; } - -(* We use this for display purposes because otherwise we never see the Dynamic type that - is defined in StdTypes.hx. This is set each time a typer is created, but this is fine - because Dynamic is the same in all contexts. If this ever changes we'll have to review - how we handle this. *) -let t_dynamic_def = ref t_dynamic - -let tfun pl r = TFun (List.map (fun t -> "",false,t) pl,r) - -let fun_args l = List.map (fun (a,c,t) -> a, c <> None, t) l - -let mk_class m path pos name_pos = - { - cl_path = path; - cl_module = m; - cl_pos = pos; - cl_name_pos = name_pos; - cl_doc = None; - cl_meta = []; - cl_private = false; - cl_kind = KNormal; - cl_extern = false; - cl_final = false; - cl_interface = false; - cl_params = []; - cl_using = []; - cl_super = None; - cl_implements = []; - cl_fields = PMap.empty; - cl_ordered_statics = []; - cl_ordered_fields = []; - cl_statics = PMap.empty; - cl_dynamic = None; - cl_array_access = None; - cl_constructor = None; - cl_init = None; - cl_overrides = []; - cl_build = (fun() -> Built); - cl_restore = (fun() -> ()); - cl_descendants = []; - } - -let module_extra file sign time kind policy = - { - m_file = file; - m_sign = sign; - m_display = { - m_inline_calls = []; - m_type_hints = []; - }; - m_dirty = None; - m_added = 0; - m_mark = 0; - m_time = time; - m_processed = 0; - m_deps = PMap.empty; - m_kind = kind; - m_binded_res = PMap.empty; - m_if_feature = []; - m_features = Hashtbl.create 0; - m_check_policy = policy; - } - - -let mk_field name ?(public = true) t p name_pos = { - cf_name = name; - cf_type = t; - cf_pos = p; - cf_name_pos = name_pos; - cf_doc = None; - cf_meta = []; - cf_kind = Var { v_read = AccNormal; v_write = AccNormal }; - cf_expr = None; - cf_expr_unoptimized = None; - cf_params = []; - cf_overloads = []; - cf_flags = if public then set_flag 0 (int_of_class_field_flag CfPublic) else 0; -} - -let null_module = { - m_id = alloc_mid(); - m_path = [] , ""; - m_types = []; - m_extra = module_extra "" "" 0. MFake []; - } - -let null_class = - let c = mk_class null_module ([],"") null_pos null_pos in - c.cl_private <- true; - c - -let null_field = mk_field "" t_dynamic null_pos null_pos - -let null_abstract = { - a_path = ([],""); - a_module = null_module; - a_pos = null_pos; - a_name_pos = null_pos; - a_private = true; - a_doc = None; - a_meta = []; - a_params = []; - a_using = []; - a_ops = []; - a_unops = []; - a_impl = None; - a_this = t_dynamic; - a_from = []; - a_from_field = []; - a_to = []; - a_to_field = []; - a_array = []; - a_read = None; - a_write = None; -} - -let add_dependency m mdep = - if m != null_module && m != mdep then m.m_extra.m_deps <- PMap.add mdep.m_id mdep m.m_extra.m_deps - -let arg_name (a,_) = a.v_name - -let t_infos t : tinfos = - match t with - | TClassDecl c -> Obj.magic c - | TEnumDecl e -> Obj.magic e - | TTypeDecl t -> Obj.magic t - | TAbstractDecl a -> Obj.magic a - -let t_path t = (t_infos t).mt_path - -let rec is_parent csup c = - if c == csup || List.exists (fun (i,_) -> is_parent csup i) c.cl_implements then - true - else match c.cl_super with - | None -> false - | Some (c,_) -> is_parent csup c - -let add_descendant c descendant = - c.cl_descendants <- descendant :: c.cl_descendants - -let lazy_type f = - match !f with - | LAvailable t -> t - | LProcessing f | LWait f -> f() - -let lazy_available t = LAvailable t -let lazy_processing f = LProcessing f -let lazy_wait f = LWait f - -let map loop t = - match t with - | TMono r -> - (match !r with - | None -> t - | Some t -> loop t) (* erase*) - | TEnum (_,[]) | TInst (_,[]) | TType (_,[]) -> - t - | TEnum (e,tl) -> - TEnum (e, List.map loop tl) - | TInst (c,tl) -> - TInst (c, List.map loop tl) - | TType (t2,tl) -> - TType (t2,List.map loop tl) - | TAbstract (a,tl) -> - TAbstract (a,List.map loop tl) - | TFun (tl,r) -> - TFun (List.map (fun (s,o,t) -> s, o, loop t) tl,loop r) - | TAnon a -> - let fields = PMap.map (fun f -> { f with cf_type = loop f.cf_type }) a.a_fields in - begin match !(a.a_status) with - | Opened -> - a.a_fields <- fields; - t - | _ -> - TAnon { - a_fields = fields; - a_status = a.a_status; - } - end - | TLazy f -> - let ft = lazy_type f in - let ft2 = loop ft in - if ft == ft2 then t else ft2 - | TDynamic t2 -> - if t == t2 then t else TDynamic (loop t2) - -let duplicate t = - let monos = ref [] in - let rec loop t = - match t with - | TMono { contents = None } -> - (try - List.assq t !monos - with Not_found -> - let m = mk_mono() in - monos := (t,m) :: !monos; - m) - | _ -> - map loop t - in - loop t - -exception ApplyParamsRecursion - -(* substitute parameters with other types *) -let apply_params ?stack cparams params t = - match cparams with - | [] -> t - | _ -> - let rec loop l1 l2 = - match l1, l2 with - | [] , [] -> [] - | (x,TLazy f) :: l1, _ -> loop ((x,lazy_type f) :: l1) l2 - | (_,t1) :: l1 , t2 :: l2 -> (t1,t2) :: loop l1 l2 - | _ -> assert false - in - let subst = loop cparams params in - let rec loop t = - try - List.assq t subst - with Not_found -> - match t with - | TMono r -> - (match !r with - | None -> t - | Some t -> loop t) - | TEnum (e,tl) -> - (match tl with - | [] -> t - | _ -> TEnum (e,List.map loop tl)) - | TType (t2,tl) -> - (match tl with - | [] -> t - | _ -> - let new_applied_params = List.map loop tl in - (match stack with - | None -> () - | Some stack -> - List.iter (fun (subject, old_applied_params) -> - (* - E.g.: - ``` - typedef Rec = { function method():Rec> } - ``` - We need to make sure that we are not applying the result of previous - application to the same place, which would mean the result of current - application would go into `apply_params` again and then again and so on. - - Argument `stack` holds all previous results of `apply_params` to typedefs in current - unification process. - - Imagine we are trying to unify `Rec` with something. - - Once `apply_params Array Int Rec>` is called for the first time the result - will be `Rec< Array >`. Store `Array` into `stack` - - Then the next params application looks like this: - `apply_params Array Array Rec>` - Notice the second argument is actually the result of a previous `apply_params` call. - And the result of the current call is `Rec< Array> >`. - - The third call would be: - `apply_params Array Array> Rec>` - and so on. - - To stop infinite params application we need to check that we are trying to apply params - produced by the previous `apply_params Array _ Rec>` to the same `Rec>` - *) - if - subject == t (* Check the place that we're applying to is the same `Rec>` *) - && old_applied_params == params (* Check that params we're applying are the same params - produced by the previous call to - `apply_params Array _ Rec>` *) - then - raise ApplyParamsRecursion - ) !stack; - stack := (t, new_applied_params) :: !stack; - ); - TType (t2,new_applied_params)) - | TAbstract (a,tl) -> - (match tl with - | [] -> t - | _ -> TAbstract (a,List.map loop tl)) - | TInst (c,tl) -> - (match tl with - | [] -> - t - | [TMono r] -> - (match !r with - | Some tt when t == tt -> - (* for dynamic *) - let pt = mk_mono() in - let t = TInst (c,[pt]) in - (match pt with TMono r -> r := Some t | _ -> assert false); - t - | _ -> TInst (c,List.map loop tl)) - | _ -> - TInst (c,List.map loop tl)) - | TFun (tl,r) -> - TFun (List.map (fun (s,o,t) -> s, o, loop t) tl,loop r) - | TAnon a -> - let fields = PMap.map (fun f -> { f with cf_type = loop f.cf_type }) a.a_fields in - begin match !(a.a_status) with - | Opened -> - a.a_fields <- fields; - t - | _ -> - TAnon { - a_fields = fields; - a_status = a.a_status; - } - end - | TLazy f -> - let ft = lazy_type f in - let ft2 = loop ft in - if ft == ft2 then - t - else - ft2 - | TDynamic t2 -> - if t == t2 then - t - else - TDynamic (loop t2) - in - loop t - -let monomorphs eparams t = - apply_params eparams (List.map (fun _ -> mk_mono()) eparams) t - -let apply_params_stack = ref [] - -let try_apply_params_rec cparams params t success = - let old_stack = !apply_params_stack in - try - let result = success (apply_params ~stack:apply_params_stack cparams params t) in - apply_params_stack := old_stack; - result - with - | ApplyParamsRecursion -> - apply_params_stack := old_stack; - | err -> - apply_params_stack := old_stack; - raise err - -let rec follow t = - match t with - | TMono r -> - (match !r with - | Some t -> follow t - | _ -> t) - | TLazy f -> - follow (lazy_type f) - | TType (t,tl) -> - follow (apply_params t.t_params tl t.t_type) - | TAbstract({a_path = [],"Null"},[t]) -> - follow t - | _ -> t - -let rec follow_without_null t = - match t with - | TMono r -> - (match !r with - | Some t -> follow_without_null t - | _ -> t) - | TLazy f -> - follow_without_null (lazy_type f) - | TType (t,tl) -> - follow_without_null (apply_params t.t_params tl t.t_type) - | _ -> t - -(** Assumes `follow` has already been applied *) -let rec ambiguate_funs t = - match t with - | TFun _ -> TFun ([], t_dynamic) - | TMono r -> - (match !r with - | Some _ -> assert false - | _ -> t) - | TInst (a, pl) -> - TInst (a, List.map ambiguate_funs pl) - | TEnum (a, pl) -> - TEnum (a, List.map ambiguate_funs pl) - | TAbstract (a, pl) -> - TAbstract (a, List.map ambiguate_funs pl) - | TType (a, pl) -> - TType (a, List.map ambiguate_funs pl) - | TDynamic _ -> t - | TAnon a -> - TAnon { a with a_fields = - PMap.map (fun af -> { af with cf_type = - ambiguate_funs af.cf_type }) a.a_fields } - | TLazy _ -> assert false - -let rec is_nullable = function - | TMono r -> - (match !r with None -> false | Some t -> is_nullable t) - | TAbstract ({ a_path = ([],"Null") },[_]) -> - true - | TLazy f -> - is_nullable (lazy_type f) - | TType (t,tl) -> - is_nullable (apply_params t.t_params tl t.t_type) - | TFun _ -> - false -(* - Type parameters will most of the time be nullable objects, so we don't want to make it hard for users - to have to specify Null all over the place, so while they could be a basic type, let's assume they will not. - - This will still cause issues with inlining and haxe.rtti.Generic. In that case proper explicit Null is required to - work correctly with basic types. This could still be fixed by redoing a nullability inference on the typed AST. - - | TInst ({ cl_kind = KTypeParameter },_) -> false -*) - | TAbstract (a,_) when Meta.has Meta.CoreType a.a_meta -> - not (Meta.has Meta.NotNull a.a_meta) - | TAbstract (a,tl) -> - not (Meta.has Meta.NotNull a.a_meta) && is_nullable (apply_params a.a_params tl a.a_this) - | _ -> - true - -let rec is_null ?(no_lazy=false) = function - | TMono r -> - (match !r with None -> false | Some t -> is_null t) - | TAbstract ({ a_path = ([],"Null") },[t]) -> - not (is_nullable (follow t)) - | TLazy f -> - if no_lazy then raise Exit else is_null (lazy_type f) - | TType (t,tl) -> - is_null (apply_params t.t_params tl t.t_type) - | _ -> - false - -(* Determines if we have a Null. Unlike is_null, this returns true even if the wrapped type is nullable itself. *) -let rec is_explicit_null = function - | TMono r -> - (match !r with None -> false | Some t -> is_explicit_null t) - | TAbstract ({ a_path = ([],"Null") },[t]) -> - true - | TLazy f -> - is_explicit_null (lazy_type f) - | TType (t,tl) -> - is_explicit_null (apply_params t.t_params tl t.t_type) - | _ -> - false - -let rec has_mono t = match t with - | TMono r -> - (match !r with None -> true | Some t -> has_mono t) - | TInst(_,pl) | TEnum(_,pl) | TAbstract(_,pl) | TType(_,pl) -> - List.exists has_mono pl - | TDynamic _ -> - false - | TFun(args,r) -> - has_mono r || List.exists (fun (_,_,t) -> has_mono t) args - | TAnon a -> - PMap.fold (fun cf b -> has_mono cf.cf_type || b) a.a_fields false - | TLazy f -> - has_mono (lazy_type f) - -let concat e1 e2 = - let e = (match e1.eexpr, e2.eexpr with - | TBlock el1, TBlock el2 -> TBlock (el1@el2) - | TBlock el, _ -> TBlock (el @ [e2]) - | _, TBlock el -> TBlock (e1 :: el) - | _ , _ -> TBlock [e1;e2] - ) in - mk e e2.etype (punion e1.epos e2.epos) - -let is_closed a = !(a.a_status) <> Opened - -let type_of_module_type = function - | TClassDecl c -> TInst (c,List.map snd c.cl_params) - | TEnumDecl e -> TEnum (e,List.map snd e.e_params) - | TTypeDecl t -> TType (t,List.map snd t.t_params) - | TAbstractDecl a -> TAbstract (a,List.map snd a.a_params) - -let rec module_type_of_type = function - | TInst(c,_) -> TClassDecl c - | TEnum(en,_) -> TEnumDecl en - | TType(t,_) -> TTypeDecl t - | TAbstract(a,_) -> TAbstractDecl a - | TLazy f -> module_type_of_type (lazy_type f) - | TMono r -> - (match !r with - | Some t -> module_type_of_type t - | _ -> raise Exit) - | _ -> - raise Exit - -let tconst_to_const = function - | TInt i -> Int (Int32.to_string i) - | TFloat s -> Float s - | TString s -> String(s,SDoubleQuotes) - | TBool b -> Ident (if b then "true" else "false") - | TNull -> Ident "null" - | TThis -> Ident "this" - | TSuper -> Ident "super" - -let has_ctor_constraint c = match c.cl_kind with - | KTypeParameter tl -> - List.exists (fun t -> match follow t with - | TAnon a when PMap.mem "new" a.a_fields -> true - | TAbstract({a_path=["haxe"],"Constructible"},_) -> true - | _ -> false - ) tl; - | _ -> false - -(* ======= Field utility ======= *) - -let field_name f = - match f with - | FAnon f | FInstance (_,_,f) | FStatic (_,f) | FClosure (_,f) -> f.cf_name - | FEnum (_,f) -> f.ef_name - | FDynamic n -> n - -let extract_field = function - | FAnon f | FInstance (_,_,f) | FStatic (_,f) | FClosure (_,f) -> Some f - | _ -> None - -let is_physical_var_field f = - match f.cf_kind with - | Var { v_read = AccNormal | AccInline | AccNo } | Var { v_write = AccNormal | AccNo } -> true - | Var _ -> Meta.has Meta.IsVar f.cf_meta - | _ -> false - -let is_physical_field f = - match f.cf_kind with - | Method _ -> true - | _ -> is_physical_var_field f - -let field_type f = - match f.cf_params with - | [] -> f.cf_type - | l -> monomorphs l f.cf_type - -let rec raw_class_field build_type c tl i = - let apply = apply_params c.cl_params tl in - try - let f = PMap.find i c.cl_fields in - Some (c,tl), build_type f , f - with Not_found -> try (match c.cl_constructor with - | Some ctor when i = "new" -> Some (c,tl), build_type ctor,ctor - | _ -> raise Not_found) - with Not_found -> try - match c.cl_super with - | None -> - raise Not_found - | Some (c,tl) -> - let c2 , t , f = raw_class_field build_type c (List.map apply tl) i in - c2, apply_params c.cl_params tl t , f - with Not_found -> - match c.cl_kind with - | KTypeParameter tl -> - let rec loop = function - | [] -> - raise Not_found - | t :: ctl -> - match follow t with - | TAnon a -> - (try - let f = PMap.find i a.a_fields in - None, build_type f, f - with - Not_found -> loop ctl) - | TInst (c,tl) -> - (try - let c2, t , f = raw_class_field build_type c (List.map apply tl) i in - c2, apply_params c.cl_params tl t, f - with - Not_found -> loop ctl) - | _ -> - loop ctl - in - loop tl - | _ -> - if not c.cl_interface then raise Not_found; - (* - an interface can implements other interfaces without - having to redeclare its fields - *) - let rec loop = function - | [] -> - raise Not_found - | (c,tl) :: l -> - try - let c2, t , f = raw_class_field build_type c (List.map apply tl) i in - c2, apply_params c.cl_params tl t, f - with - Not_found -> loop l - in - loop c.cl_implements - -let class_field = raw_class_field field_type - -let quick_field t n = - match follow t with - | TInst (c,tl) -> - let c, _, f = raw_class_field (fun f -> f.cf_type) c tl n in - (match c with None -> FAnon f | Some (c,tl) -> FInstance (c,tl,f)) - | TAnon a -> - (match !(a.a_status) with - | EnumStatics e -> - let ef = PMap.find n e.e_constrs in - FEnum(e,ef) - | Statics c -> - FStatic (c,PMap.find n c.cl_statics) - | AbstractStatics a -> - begin match a.a_impl with - | Some c -> - let cf = PMap.find n c.cl_statics in - FStatic(c,cf) (* is that right? *) - | _ -> - raise Not_found - end - | _ -> - FAnon (PMap.find n a.a_fields)) - | TDynamic _ -> - FDynamic n - | TEnum _ | TMono _ | TAbstract _ | TFun _ -> - raise Not_found - | TLazy _ | TType _ -> - assert false - -let quick_field_dynamic t s = - try quick_field t s - with Not_found -> FDynamic s - -let rec get_constructor build_type c = - match c.cl_constructor, c.cl_super with - | Some c, _ -> build_type c, c - | None, None -> raise Not_found - | None, Some (csup,cparams) -> - let t, c = get_constructor build_type csup in - apply_params csup.cl_params cparams t, c - -let has_constructor c = - try - ignore(get_constructor (fun cf -> cf.cf_type) c); - true - with Not_found -> false - -(* ======= Printing ======= *) - -let print_context() = ref [] - -let rec s_type_kind t = - let map tl = String.concat ", " (List.map s_type_kind tl) in - match t with - | TMono r -> - begin match !r with - | None -> "TMono (None)" - | Some t -> "TMono (Some (" ^ (s_type_kind t) ^ "))" - end - | TEnum(en,tl) -> Printf.sprintf "TEnum(%s, [%s])" (s_type_path en.e_path) (map tl) - | TInst(c,tl) -> Printf.sprintf "TInst(%s, [%s])" (s_type_path c.cl_path) (map tl) - | TType(t,tl) -> Printf.sprintf "TType(%s, [%s])" (s_type_path t.t_path) (map tl) - | TAbstract(a,tl) -> Printf.sprintf "TAbstract(%s, [%s])" (s_type_path a.a_path) (map tl) - | TFun(tl,r) -> Printf.sprintf "TFun([%s], %s)" (String.concat ", " (List.map (fun (n,b,t) -> Printf.sprintf "%s%s:%s" (if b then "?" else "") n (s_type_kind t)) tl)) (s_type_kind r) - | TAnon an -> "TAnon" - | TDynamic t2 -> "TDynamic" - | TLazy _ -> "TLazy" - -let s_module_type_kind = function - | TClassDecl c -> "TClassDecl(" ^ (s_type_path c.cl_path) ^ ")" - | TEnumDecl en -> "TEnumDecl(" ^ (s_type_path en.e_path) ^ ")" - | TAbstractDecl a -> "TAbstractDecl(" ^ (s_type_path a.a_path) ^ ")" - | TTypeDecl t -> "TTypeDecl(" ^ (s_type_path t.t_path) ^ ")" - -let rec s_type ctx t = - match t with - | TMono r -> - (match !r with - | None -> Printf.sprintf "Unknown<%d>" (try List.assq t (!ctx) with Not_found -> let n = List.length !ctx in ctx := (t,n) :: !ctx; n) - | Some t -> s_type ctx t) - | TEnum (e,tl) -> - s_type_path e.e_path ^ s_type_params ctx tl - | TInst (c,tl) -> - (match c.cl_kind with - | KExpr e -> Ast.Printer.s_expr e - | _ -> s_type_path c.cl_path ^ s_type_params ctx tl) - | TType (t,tl) -> - s_type_path t.t_path ^ s_type_params ctx tl - | TAbstract (a,tl) -> - s_type_path a.a_path ^ s_type_params ctx tl - | TFun ([],t) -> - "Void -> " ^ s_fun ctx t false - | TFun (l,t) -> - let args = match l with - | [] -> "()" - | ["",b,t] -> Printf.sprintf "%s%s" (if b then "?" else "") (s_fun ctx t true) - | _ -> - let args = String.concat ", " (List.map (fun (s,b,t) -> - (if b then "?" else "") ^ (if s = "" then "" else s ^ " : ") ^ s_fun ctx t true - ) l) in - "(" ^ args ^ ")" - in - Printf.sprintf "%s -> %s" args (s_fun ctx t false) - | TAnon a -> - begin - match !(a.a_status) with - | Statics c -> Printf.sprintf "{ Statics %s }" (s_type_path c.cl_path) - | EnumStatics e -> Printf.sprintf "{ EnumStatics %s }" (s_type_path e.e_path) - | AbstractStatics a -> Printf.sprintf "{ AbstractStatics %s }" (s_type_path a.a_path) - | _ -> - let fl = PMap.fold (fun f acc -> ((if Meta.has Meta.Optional f.cf_meta then " ?" else " ") ^ f.cf_name ^ " : " ^ s_type ctx f.cf_type) :: acc) a.a_fields [] in - "{" ^ (if not (is_closed a) then "+" else "") ^ String.concat "," fl ^ " }" - end - | TDynamic t2 -> - "Dynamic" ^ s_type_params ctx (if t == t2 then [] else [t2]) - | TLazy f -> - s_type ctx (lazy_type f) - -and s_fun ctx t void = - match t with - | TFun _ -> - "(" ^ s_type ctx t ^ ")" - | TAbstract ({ a_path = ([],"Void") },[]) when void -> - "(" ^ s_type ctx t ^ ")" - | TMono r -> - (match !r with - | None -> s_type ctx t - | Some t -> s_fun ctx t void) - | TLazy f -> - s_fun ctx (lazy_type f) void - | _ -> - s_type ctx t - -and s_type_params ctx = function - | [] -> "" - | l -> "<" ^ String.concat ", " (List.map (s_type ctx) l) ^ ">" - -let s_access is_read = function - | AccNormal -> "default" - | AccNo -> "null" - | AccNever -> "never" - | AccResolve -> "resolve" - | AccCall -> if is_read then "get" else "set" - | AccInline -> "inline" - | AccRequire (n,_) -> "require " ^ n - | AccCtor -> "ctor" - -let s_kind = function - | Var { v_read = AccNormal; v_write = AccNormal } -> "var" - | Var v -> "(" ^ s_access true v.v_read ^ "," ^ s_access false v.v_write ^ ")" - | Method m -> - match m with - | MethNormal -> "method" - | MethDynamic -> "dynamic method" - | MethInline -> "inline method" - | MethMacro -> "macro method" - -let s_expr_kind e = - match e.eexpr with - | TConst _ -> "Const" - | TLocal _ -> "Local" - | TArray (_,_) -> "Array" - | TBinop (_,_,_) -> "Binop" - | TEnumParameter (_,_,_) -> "EnumParameter" - | TEnumIndex _ -> "EnumIndex" - | TField (_,_) -> "Field" - | TTypeExpr _ -> "TypeExpr" - | TParenthesis _ -> "Parenthesis" - | TObjectDecl _ -> "ObjectDecl" - | TArrayDecl _ -> "ArrayDecl" - | TCall (_,_) -> "Call" - | TNew (_,_,_) -> "New" - | TUnop (_,_,_) -> "Unop" - | TFunction _ -> "Function" - | TVar _ -> "Vars" - | TBlock _ -> "Block" - | TFor (_,_,_) -> "For" - | TIf (_,_,_) -> "If" - | TWhile (_,_,_) -> "While" - | TSwitch (_,_,_) -> "Switch" - | TTry (_,_) -> "Try" - | TReturn _ -> "Return" - | TBreak -> "Break" - | TContinue -> "Continue" - | TThrow _ -> "Throw" - | TCast _ -> "Cast" - | TMeta _ -> "Meta" - | TIdent _ -> "Ident" - -let s_const = function - | TInt i -> Int32.to_string i - | TFloat s -> s - | TString s -> Printf.sprintf "\"%s\"" (StringHelper.s_escape s) - | TBool b -> if b then "true" else "false" - | TNull -> "null" - | TThis -> "this" - | TSuper -> "super" - -let s_field_access s_type fa = match fa with - | FStatic (c,f) -> "static(" ^ s_type_path c.cl_path ^ "." ^ f.cf_name ^ ")" - | FInstance (c,_,f) -> "inst(" ^ s_type_path c.cl_path ^ "." ^ f.cf_name ^ " : " ^ s_type f.cf_type ^ ")" - | FClosure (c,f) -> "closure(" ^ (match c with None -> f.cf_name | Some (c,_) -> s_type_path c.cl_path ^ "." ^ f.cf_name) ^ ")" - | FAnon f -> "anon(" ^ f.cf_name ^ ")" - | FEnum (en,f) -> "enum(" ^ s_type_path en.e_path ^ "." ^ f.ef_name ^ ")" - | FDynamic f -> "dynamic(" ^ f ^ ")" - -let rec s_expr s_type e = - let sprintf = Printf.sprintf in - let slist f l = String.concat "," (List.map f l) in - let loop = s_expr s_type in - let s_var v = v.v_name ^ ":" ^ string_of_int v.v_id ^ if v.v_capture then "[c]" else "" in - let str = (match e.eexpr with - | TConst c -> - "Const " ^ s_const c - | TLocal v -> - "Local " ^ s_var v - | TArray (e1,e2) -> - sprintf "%s[%s]" (loop e1) (loop e2) - | TBinop (op,e1,e2) -> - sprintf "(%s %s %s)" (loop e1) (s_binop op) (loop e2) - | TEnumIndex e1 -> - sprintf "EnumIndex %s" (loop e1) - | TEnumParameter (e1,_,i) -> - sprintf "%s[%i]" (loop e1) i - | TField (e,f) -> - let fstr = s_field_access s_type f in - sprintf "%s.%s" (loop e) fstr - | TTypeExpr m -> - sprintf "TypeExpr %s" (s_type_path (t_path m)) - | TParenthesis e -> - sprintf "Parenthesis %s" (loop e) - | TObjectDecl fl -> - sprintf "ObjectDecl {%s}" (slist (fun ((f,_,qs),e) -> sprintf "%s : %s" (s_object_key_name f qs) (loop e)) fl) - | TArrayDecl el -> - sprintf "ArrayDecl [%s]" (slist loop el) - | TCall (e,el) -> - sprintf "Call %s(%s)" (loop e) (slist loop el) - | TNew (c,pl,el) -> - sprintf "New %s%s(%s)" (s_type_path c.cl_path) (match pl with [] -> "" | l -> sprintf "<%s>" (slist s_type l)) (slist loop el) - | TUnop (op,f,e) -> - (match f with - | Prefix -> sprintf "(%s %s)" (s_unop op) (loop e) - | Postfix -> sprintf "(%s %s)" (loop e) (s_unop op)) - | TFunction f -> - let args = slist (fun (v,o) -> sprintf "%s : %s%s" (s_var v) (s_type v.v_type) (match o with None -> "" | Some c -> " = " ^ loop c)) f.tf_args in - sprintf "Function(%s) : %s = %s" args (s_type f.tf_type) (loop f.tf_expr) - | TVar (v,eo) -> - sprintf "Vars %s" (sprintf "%s : %s%s" (s_var v) (s_type v.v_type) (match eo with None -> "" | Some e -> " = " ^ loop e)) - | TBlock el -> - sprintf "Block {\n%s}" (String.concat "" (List.map (fun e -> sprintf "%s;\n" (loop e)) el)) - | TFor (v,econd,e) -> - sprintf "For (%s : %s in %s,%s)" (s_var v) (s_type v.v_type) (loop econd) (loop e) - | TIf (e,e1,e2) -> - sprintf "If (%s,%s%s)" (loop e) (loop e1) (match e2 with None -> "" | Some e -> "," ^ loop e) - | TWhile (econd,e,flag) -> - (match flag with - | NormalWhile -> sprintf "While (%s,%s)" (loop econd) (loop e) - | DoWhile -> sprintf "DoWhile (%s,%s)" (loop e) (loop econd)) - | TSwitch (e,cases,def) -> - sprintf "Switch (%s,(%s)%s)" (loop e) (slist (fun (cl,e) -> sprintf "case %s: %s" (slist loop cl) (loop e)) cases) (match def with None -> "" | Some e -> "," ^ loop e) - | TTry (e,cl) -> - sprintf "Try %s(%s) " (loop e) (slist (fun (v,e) -> sprintf "catch( %s : %s ) %s" (s_var v) (s_type v.v_type) (loop e)) cl) - | TReturn None -> - "Return" - | TReturn (Some e) -> - sprintf "Return %s" (loop e) - | TBreak -> - "Break" - | TContinue -> - "Continue" - | TThrow e -> - "Throw " ^ (loop e) - | TCast (e,t) -> - sprintf "Cast %s%s" (match t with None -> "" | Some t -> s_type_path (t_path t) ^ ": ") (loop e) - | TMeta ((n,el,_),e) -> - sprintf "@%s%s %s" (Meta.to_string n) (match el with [] -> "" | _ -> "(" ^ (String.concat ", " (List.map Ast.Printer.s_expr el)) ^ ")") (loop e) - | TIdent s -> - "Ident " ^ s - ) in - sprintf "(%s : %s)" str (s_type e.etype) - -let rec s_expr_pretty print_var_ids tabs top_level s_type e = - let sprintf = Printf.sprintf in - let loop = s_expr_pretty print_var_ids tabs false s_type in - let slist c f l = String.concat c (List.map f l) in - let clist f l = slist ", " f l in - let local v = if print_var_ids then sprintf "%s<%i>" v.v_name v.v_id else v.v_name in - match e.eexpr with - | TConst c -> s_const c - | TLocal v -> local v - | TArray (e1,e2) -> sprintf "%s[%s]" (loop e1) (loop e2) - | TBinop (op,e1,e2) -> sprintf "%s %s %s" (loop e1) (s_binop op) (loop e2) - | TEnumParameter (e1,_,i) -> sprintf "%s[%i]" (loop e1) i - | TEnumIndex e1 -> sprintf "enumIndex %s" (loop e1) - | TField (e1,s) -> sprintf "%s.%s" (loop e1) (field_name s) - | TTypeExpr mt -> (s_type_path (t_path mt)) - | TParenthesis e1 -> sprintf "(%s)" (loop e1) - | TObjectDecl fl -> sprintf "{%s}" (clist (fun ((f,_,qs),e) -> sprintf "%s : %s" (s_object_key_name f qs) (loop e)) fl) - | TArrayDecl el -> sprintf "[%s]" (clist loop el) - | TCall (e1,el) -> sprintf "%s(%s)" (loop e1) (clist loop el) - | TNew (c,pl,el) -> - sprintf "new %s(%s)" (s_type_path c.cl_path) (clist loop el) - | TUnop (op,f,e) -> - (match f with - | Prefix -> sprintf "%s %s" (s_unop op) (loop e) - | Postfix -> sprintf "%s %s" (loop e) (s_unop op)) - | TFunction f -> - let args = clist (fun (v,o) -> sprintf "%s:%s%s" (local v) (s_type v.v_type) (match o with None -> "" | Some c -> " = " ^ loop c)) f.tf_args in - sprintf "%s(%s) %s" (if top_level then "" else "function") args (loop f.tf_expr) - | TVar (v,eo) -> - sprintf "var %s" (sprintf "%s%s" (local v) (match eo with None -> "" | Some e -> " = " ^ loop e)) - | TBlock el -> - let ntabs = tabs ^ "\t" in - let s = sprintf "{\n%s" (String.concat "" (List.map (fun e -> sprintf "%s%s;\n" ntabs (s_expr_pretty print_var_ids ntabs top_level s_type e)) el)) in - (match el with - | [] -> "{}" - | _ -> s ^ tabs ^ "}") - | TFor (v,econd,e) -> - sprintf "for (%s in %s) %s" (local v) (loop econd) (loop e) - | TIf (e,e1,e2) -> - sprintf "if (%s) %s%s" (loop e) (loop e1) (match e2 with None -> "" | Some e -> " else " ^ loop e) - | TWhile (econd,e,flag) -> - (match flag with - | NormalWhile -> sprintf "while (%s) %s" (loop econd) (loop e) - | DoWhile -> sprintf "do (%s) while(%s)" (loop e) (loop econd)) - | TSwitch (e,cases,def) -> - let ntabs = tabs ^ "\t" in - let s = sprintf "switch (%s) {\n%s%s" (loop e) (slist "" (fun (cl,e) -> sprintf "%scase %s: %s;\n" ntabs (clist loop cl) (s_expr_pretty print_var_ids ntabs top_level s_type e)) cases) (match def with None -> "" | Some e -> ntabs ^ "default: " ^ (s_expr_pretty print_var_ids ntabs top_level s_type e) ^ "\n") in - s ^ tabs ^ "}" - | TTry (e,cl) -> - sprintf "try %s%s" (loop e) (clist (fun (v,e) -> sprintf " catch (%s:%s) %s" (local v) (s_type v.v_type) (loop e)) cl) - | TReturn None -> - "return" - | TReturn (Some e) -> - sprintf "return %s" (loop e) - | TBreak -> - "break" - | TContinue -> - "continue" - | TThrow e -> - "throw " ^ (loop e) - | TCast (e,None) -> - sprintf "cast %s" (loop e) - | TCast (e,Some mt) -> - sprintf "cast (%s,%s)" (loop e) (s_type_path (t_path mt)) - | TMeta ((n,el,_),e) -> - sprintf "@%s%s %s" (Meta.to_string n) (match el with [] -> "" | _ -> "(" ^ (String.concat ", " (List.map Ast.Printer.s_expr el)) ^ ")") (loop e) - | TIdent s -> - s - -let rec s_expr_ast print_var_ids tabs s_type e = - let sprintf = Printf.sprintf in - let loop ?(extra_tabs="") = s_expr_ast print_var_ids (tabs ^ "\t" ^ extra_tabs) s_type in - let tag_args tabs sl = match sl with - | [] -> "" - | [s] when not (String.contains s '\n') -> " " ^ s - | _ -> - let tabs = "\n" ^ tabs ^ "\t" in - tabs ^ (String.concat tabs sl) - in - let tag s ?(t=None) ?(extra_tabs="") sl = - let st = match t with - | None -> s_type e.etype - | Some t -> s_type t - in - sprintf "[%s:%s]%s" s st (tag_args (tabs ^ extra_tabs) sl) - in - let var_id v = if print_var_ids then v.v_id else 0 in - let const c t = tag "Const" ~t [s_const c] in - let local v t = sprintf "[Local %s(%i):%s%s]" v.v_name (var_id v) (s_type v.v_type) (match t with None -> "" | Some t -> ":" ^ (s_type t)) in - let var v sl = sprintf "[Var %s(%i):%s]%s" v.v_name (var_id v) (s_type v.v_type) (tag_args tabs sl) in - let module_type mt = sprintf "[TypeExpr %s:%s]" (s_type_path (t_path mt)) (s_type e.etype) in - match e.eexpr with - | TConst c -> const c (Some e.etype) - | TLocal v -> local v (Some e.etype) - | TArray (e1,e2) -> tag "Array" [loop e1; loop e2] - | TBinop (op,e1,e2) -> tag "Binop" [loop e1; s_binop op; loop e2] - | TUnop (op,flag,e1) -> tag "Unop" [s_unop op; if flag = Postfix then "Postfix" else "Prefix"; loop e1] - | TEnumParameter (e1,ef,i) -> tag "EnumParameter" [loop e1; ef.ef_name; string_of_int i] - | TEnumIndex e1 -> tag "EnumIndex" [loop e1] - | TField (e1,fa) -> - let sfa = match fa with - | FInstance(c,tl,cf) -> tag "FInstance" ~extra_tabs:"\t" [s_type (TInst(c,tl)); Printf.sprintf "%s:%s" cf.cf_name (s_type cf.cf_type)] - | FStatic(c,cf) -> tag "FStatic" ~extra_tabs:"\t" [s_type_path c.cl_path; Printf.sprintf "%s:%s" cf.cf_name (s_type cf.cf_type)] - | FClosure(co,cf) -> tag "FClosure" ~extra_tabs:"\t" [(match co with None -> "None" | Some (c,tl) -> s_type (TInst(c,tl))); Printf.sprintf "%s:%s" cf.cf_name (s_type cf.cf_type)] - | FAnon cf -> tag "FAnon" ~extra_tabs:"\t" [Printf.sprintf "%s:%s" cf.cf_name (s_type cf.cf_type)] - | FDynamic s -> tag "FDynamic" ~extra_tabs:"\t" [s] - | FEnum(en,ef) -> tag "FEnum" ~extra_tabs:"\t" [s_type_path en.e_path; ef.ef_name] - in - tag "Field" [loop e1; sfa] - | TTypeExpr mt -> module_type mt - | TParenthesis e1 -> tag "Parenthesis" [loop e1] - | TObjectDecl fl -> tag "ObjectDecl" (List.map (fun ((s,_,qs),e) -> sprintf "%s: %s" (s_object_key_name s qs) (loop e)) fl) - | TArrayDecl el -> tag "ArrayDecl" (List.map loop el) - | TCall (e1,el) -> tag "Call" (loop e1 :: (List.map loop el)) - | TNew (c,tl,el) -> tag "New" ((s_type (TInst(c,tl))) :: (List.map loop el)) - | TFunction f -> - let arg (v,cto) = - tag "Arg" ~t:(Some v.v_type) ~extra_tabs:"\t" (match cto with None -> [local v None] | Some ct -> [local v None;loop ct]) - in - tag "Function" ((List.map arg f.tf_args) @ [loop f.tf_expr]) - | TVar (v,eo) -> var v (match eo with None -> [] | Some e -> [loop e]) - | TBlock el -> tag "Block" (List.map loop el) - | TIf (e,e1,e2) -> tag "If" (loop e :: (Printf.sprintf "[Then:%s] %s" (s_type e1.etype) (loop e1)) :: (match e2 with None -> [] | Some e -> [Printf.sprintf "[Else:%s] %s" (s_type e.etype) (loop e)])) - | TCast (e1,None) -> tag "Cast" [loop e1] - | TCast (e1,Some mt) -> tag "Cast" [loop e1; module_type mt] - | TThrow e1 -> tag "Throw" [loop e1] - | TBreak -> tag "Break" [] - | TContinue -> tag "Continue" [] - | TReturn None -> tag "Return" [] - | TReturn (Some e1) -> tag "Return" [loop e1] - | TWhile (e1,e2,NormalWhile) -> tag "While" [loop e1; loop e2] - | TWhile (e1,e2,DoWhile) -> tag "Do" [loop e1; loop e2] - | TFor (v,e1,e2) -> tag "For" [local v None; loop e1; loop e2] - | TTry (e1,catches) -> - let sl = List.map (fun (v,e) -> - sprintf "Catch %s%s" (local v None) (tag_args (tabs ^ "\t") [loop ~extra_tabs:"\t" e]); - ) catches in - tag "Try" ((loop e1) :: sl) - | TSwitch (e1,cases,eo) -> - let sl = List.map (fun (el,e) -> - tag "Case" ~t:(Some e.etype) ~extra_tabs:"\t" ((List.map loop el) @ [loop ~extra_tabs:"\t" e]) - ) cases in - let sl = match eo with - | None -> sl - | Some e -> sl @ [tag "Default" ~t:(Some e.etype) ~extra_tabs:"\t" [loop ~extra_tabs:"\t" e]] - in - tag "Switch" ((loop e1) :: sl) - | TMeta ((m,el,_),e1) -> - let s = Meta.to_string m in - let s = match el with - | [] -> s - | _ -> sprintf "%s(%s)" s (String.concat ", " (List.map Ast.Printer.s_expr el)) - in - tag "Meta" [s; loop e1] - | TIdent s -> - tag "Ident" [s] - -let s_types ?(sep = ", ") tl = - let pctx = print_context() in - String.concat sep (List.map (s_type pctx) tl) - -let s_class_kind = function - | KNormal -> - "KNormal" - | KTypeParameter tl -> - Printf.sprintf "KTypeParameter [%s]" (s_types tl) - | KExpr _ -> - "KExpr" - | KGeneric -> - "KGeneric" - | KGenericInstance(c,tl) -> - Printf.sprintf "KGenericInstance %s<%s>" (s_type_path c.cl_path) (s_types tl) - | KMacroType -> - "KMacroType" - | KGenericBuild _ -> - "KGenericBuild" - | KAbstractImpl a -> - Printf.sprintf "KAbstractImpl %s" (s_type_path a.a_path) - -module Printer = struct - - let s_type t = - s_type (print_context()) t - - let s_pair s1 s2 = - Printf.sprintf "(%s,%s)" s1 s2 - - let s_record_field name value = - Printf.sprintf "%s = %s;" name value - - let s_pos p = - Printf.sprintf "%s: %i-%i" p.pfile p.pmin p.pmax - - let s_record_fields tabs fields = - let sl = List.map (fun (name,value) -> s_record_field name value) fields in - Printf.sprintf "{\n%s\t%s\n%s}" tabs (String.concat ("\n\t" ^ tabs) sl) tabs - - let s_list sep f l = - "[" ^ (String.concat sep (List.map f l)) ^ "]" - - let s_opt f o = match o with - | None -> "None" - | Some v -> f v - - let s_pmap fk fv pm = - "{" ^ (String.concat ", " (PMap.foldi (fun k v acc -> (Printf.sprintf "%s = %s" (fk k) (fv v)) :: acc) pm [])) ^ "}" - - let s_doc = s_opt (fun s -> s) - - let s_metadata_entry (s,el,_) = - Printf.sprintf "@%s%s" (Meta.to_string s) (match el with [] -> "" | el -> "(" ^ (String.concat ", " (List.map Ast.Printer.s_expr el)) ^ ")") - - let s_metadata metadata = - s_list " " s_metadata_entry metadata - - let s_type_param (s,t) = match follow t with - | TInst({cl_kind = KTypeParameter tl1},tl2) -> - begin match tl1 with - | [] -> s - | _ -> Printf.sprintf "%s:%s" s (String.concat ", " (List.map s_type tl1)) - end - | _ -> assert false - - let s_type_params tl = - s_list ", " s_type_param tl - - let s_tclass_field tabs cf = - s_record_fields tabs [ - "cf_name",cf.cf_name; - "cf_doc",s_doc cf.cf_doc; - "cf_type",s_type_kind (follow cf.cf_type); - "cf_pos",s_pos cf.cf_pos; - "cf_name_pos",s_pos cf.cf_name_pos; - "cf_meta",s_metadata cf.cf_meta; - "cf_kind",s_kind cf.cf_kind; - "cf_params",s_type_params cf.cf_params; - "cf_expr",s_opt (s_expr_ast true "\t\t" s_type) cf.cf_expr; - ] - - let s_tclass tabs c = - s_record_fields tabs [ - "cl_path",s_type_path c.cl_path; - "cl_module",s_type_path c.cl_module.m_path; - "cl_pos",s_pos c.cl_pos; - "cl_name_pos",s_pos c.cl_name_pos; - "cl_private",string_of_bool c.cl_private; - "cl_doc",s_doc c.cl_doc; - "cl_meta",s_metadata c.cl_meta; - "cl_params",s_type_params c.cl_params; - "cl_kind",s_class_kind c.cl_kind; - "cl_extern",string_of_bool c.cl_extern; - "cl_final",string_of_bool c.cl_final; - "cl_interface",string_of_bool c.cl_interface; - "cl_super",s_opt (fun (c,tl) -> s_type (TInst(c,tl))) c.cl_super; - "cl_implements",s_list ", " (fun (c,tl) -> s_type (TInst(c,tl))) c.cl_implements; - "cl_array_access",s_opt s_type c.cl_array_access; - "cl_overrides",s_list "," (fun cf -> cf.cf_name) c.cl_overrides; - "cl_init",s_opt (s_expr_ast true "" s_type) c.cl_init; - "cl_constructor",s_opt (s_tclass_field (tabs ^ "\t")) c.cl_constructor; - "cl_ordered_fields",s_list "\n\t" (s_tclass_field (tabs ^ "\t")) c.cl_ordered_fields; - "cl_ordered_statics",s_list "\n\t" (s_tclass_field (tabs ^ "\t")) c.cl_ordered_statics; - ] - - let s_tdef tabs t = - s_record_fields tabs [ - "t_path",s_type_path t.t_path; - "t_module",s_type_path t.t_module.m_path; - "t_pos",s_pos t.t_pos; - "t_name_pos",s_pos t.t_name_pos; - "t_private",string_of_bool t.t_private; - "t_doc",s_doc t.t_doc; - "t_meta",s_metadata t.t_meta; - "t_params",s_type_params t.t_params; - "t_type",s_type_kind t.t_type - ] - - let s_tenum_field tabs ef = - s_record_fields tabs [ - "ef_name",ef.ef_name; - "ef_doc",s_doc ef.ef_doc; - "ef_pos",s_pos ef.ef_pos; - "ef_name_pos",s_pos ef.ef_name_pos; - "ef_type",s_type_kind ef.ef_type; - "ef_index",string_of_int ef.ef_index; - "ef_params",s_type_params ef.ef_params; - "ef_meta",s_metadata ef.ef_meta - ] - - let s_tenum tabs en = - s_record_fields tabs [ - "e_path",s_type_path en.e_path; - "e_module",s_type_path en.e_module.m_path; - "e_pos",s_pos en.e_pos; - "e_name_pos",s_pos en.e_name_pos; - "e_private",string_of_bool en.e_private; - "d_doc",s_doc en.e_doc; - "e_meta",s_metadata en.e_meta; - "e_params",s_type_params en.e_params; - "e_type",s_tdef "\t" en.e_type; - "e_extern",string_of_bool en.e_extern; - "e_constrs",s_list "\n\t" (s_tenum_field (tabs ^ "\t")) (PMap.fold (fun ef acc -> ef :: acc) en.e_constrs []); - "e_names",String.concat ", " en.e_names - ] - - let s_tabstract tabs a = - s_record_fields tabs [ - "a_path",s_type_path a.a_path; - "a_modules",s_type_path a.a_module.m_path; - "a_pos",s_pos a.a_pos; - "a_name_pos",s_pos a.a_name_pos; - "a_private",string_of_bool a.a_private; - "a_doc",s_doc a.a_doc; - "a_meta",s_metadata a.a_meta; - "a_params",s_type_params a.a_params; - "a_ops",s_list ", " (fun (op,cf) -> Printf.sprintf "%s: %s" (s_binop op) cf.cf_name) a.a_ops; - "a_unops",s_list ", " (fun (op,flag,cf) -> Printf.sprintf "%s (%s): %s" (s_unop op) (if flag = Postfix then "postfix" else "prefix") cf.cf_name) a.a_unops; - "a_impl",s_opt (fun c -> s_type_path c.cl_path) a.a_impl; - "a_this",s_type_kind a.a_this; - "a_from",s_list ", " s_type_kind a.a_from; - "a_to",s_list ", " s_type_kind a.a_to; - "a_from_field",s_list ", " (fun (t,cf) -> Printf.sprintf "%s: %s" (s_type_kind t) cf.cf_name) a.a_from_field; - "a_to_field",s_list ", " (fun (t,cf) -> Printf.sprintf "%s: %s" (s_type_kind t) cf.cf_name) a.a_to_field; - "a_array",s_list ", " (fun cf -> cf.cf_name) a.a_array; - "a_read",s_opt (fun cf -> cf.cf_name) a.a_read; - "a_write",s_opt (fun cf -> cf.cf_name) a.a_write; - ] - - let s_tvar_extra (tl,eo) = - Printf.sprintf "Some(%s, %s)" (s_type_params tl) (s_opt (s_expr_ast true "" s_type) eo) - - let s_tvar v = - s_record_fields "" [ - "v_id",string_of_int v.v_id; - "v_name",v.v_name; - "v_type",s_type v.v_type; - "v_capture",string_of_bool v.v_capture; - "v_extra",s_opt s_tvar_extra v.v_extra; - "v_meta",s_metadata v.v_meta; - ] - - let s_module_kind = function - | MCode -> "MCode" - | MMacro -> "MMacro" - | MFake -> "MFake" - | MExtern -> "MExtern" - | MImport -> "MImport" - - let s_module_def_extra tabs me = - s_record_fields tabs [ - "m_file",me.m_file; - "m_sign",me.m_sign; - "m_time",string_of_float me.m_time; - "m_dirty",s_opt s_type_path me.m_dirty; - "m_added",string_of_int me.m_added; - "m_mark",string_of_int me.m_mark; - "m_deps",s_pmap string_of_int (fun m -> snd m.m_path) me.m_deps; - "m_processed",string_of_int me.m_processed; - "m_kind",s_module_kind me.m_kind; - "m_binded_res",""; (* TODO *) - "m_if_feature",""; (* TODO *) - "m_features",""; (* TODO *) - ] - - let s_module_def m = - s_record_fields "" [ - "m_id",string_of_int m.m_id; - "m_path",s_type_path m.m_path; - "m_extra",s_module_def_extra "\t" m.m_extra - ] - - let s_type_path tp = - s_record_fields "" [ - "tpackage",s_list "." (fun s -> s) tp.tpackage; - "tname",tp.tname; - "tparams",""; - "tsub",s_opt (fun s -> s) tp.tsub; - ] - - let s_class_flag = function - | HInterface -> "HInterface" - | HExtern -> "HExtern" - | HPrivate -> "HPrivate" - | HExtends tp -> "HExtends " ^ (s_type_path (fst tp)) - | HImplements tp -> "HImplements " ^ (s_type_path (fst tp)) - | HFinal -> "HFinal" - - let s_placed f (x,p) = - s_pair (f x) (s_pos p) - - let s_class_field cff = - s_record_fields "" [ - "cff_name",s_placed (fun s -> s) cff.cff_name; - "cff_doc",s_opt (fun s -> s) cff.cff_doc; - "cff_pos",s_pos cff.cff_pos; - "cff_meta",s_metadata cff.cff_meta; - "cff_access",s_list ", " Ast.s_placed_access cff.cff_access; - ] -end - -(* ======= Unification ======= *) - -let rec link e a b = - (* tell if setting a == b will create a type-loop *) - let rec loop t = - if t == a then - true - else match t with - | TMono t -> (match !t with None -> false | Some t -> loop t) - | TEnum (_,tl) -> List.exists loop tl - | TInst (_,tl) | TType (_,tl) | TAbstract (_,tl) -> List.exists loop tl - | TFun (tl,t) -> List.exists (fun (_,_,t) -> loop t) tl || loop t - | TDynamic t2 -> - if t == t2 then - false - else - loop t2 - | TLazy f -> - loop (lazy_type f) - | TAnon a -> - try - PMap.iter (fun _ f -> if loop f.cf_type then raise Exit) a.a_fields; - false - with - Exit -> true - in - (* tell is already a ~= b *) - if loop b then - (follow b) == a - else if b == t_dynamic then - true - else begin - e := Some b; - true - end - -let would_produce_recursive_anon field_acceptor field_donor = - try - (match !(field_acceptor.a_status) with - | Opened -> - PMap.iter (fun n field -> - match follow field.cf_type with - | TAnon a when field_acceptor == a -> raise Exit - | _ -> () - ) field_donor.a_fields; - | _ -> ()); - false - with Exit -> true - -let link_dynamic a b = match follow a,follow b with - | TMono r,TDynamic _ -> r := Some b - | TDynamic _,TMono r -> r := Some a - | _ -> () - -let fast_eq_check type_param_check a b = - if a == b then - true - else match a , b with - | TFun (l1,r1) , TFun (l2,r2) when List.length l1 = List.length l2 -> - List.for_all2 (fun (_,_,t1) (_,_,t2) -> type_param_check t1 t2) l1 l2 && type_param_check r1 r2 - | TType (t1,l1), TType (t2,l2) -> - t1 == t2 && List.for_all2 type_param_check l1 l2 - | TEnum (e1,l1), TEnum (e2,l2) -> - e1 == e2 && List.for_all2 type_param_check l1 l2 - | TInst (c1,l1), TInst (c2,l2) -> - c1 == c2 && List.for_all2 type_param_check l1 l2 - | TAbstract (a1,l1), TAbstract (a2,l2) -> - a1 == a2 && List.for_all2 type_param_check l1 l2 - | _ , _ -> - false - -let rec fast_eq a b = fast_eq_check fast_eq a b - -let rec fast_eq_mono ml a b = - if fast_eq_check (fast_eq_mono ml) a b then - true - else match a , b with - | TMono _, _ -> - List.memq a ml - | _ , _ -> - false - -let rec shallow_eq a b = - a == b - || begin - let a = follow a - and b = follow b in - fast_eq_check shallow_eq a b - || match a , b with - | t, TMono { contents = None } when t == t_dynamic -> true - | TMono { contents = None }, t when t == t_dynamic -> true - | TMono { contents = None }, TMono { contents = None } -> true - | TAnon a1, TAnon a2 -> - let fields_eq() = - let rec loop fields1 fields2 = - match fields1, fields2 with - | [], [] -> true - | _, [] | [], _ -> false - | f1 :: rest1, f2 :: rest2 -> - f1.cf_name = f2.cf_name - && (try shallow_eq f1.cf_type f2.cf_type with Not_found -> false) - && loop rest1 rest2 - in - let fields1 = PMap.fold (fun field fields -> field :: fields) a1.a_fields [] - and fields2 = PMap.fold (fun field fields -> field :: fields) a2.a_fields [] - and sort_compare f1 f2 = compare f1.cf_name f2.cf_name in - loop (List.sort sort_compare fields1) (List.sort sort_compare fields2) - in - (match !(a2.a_status), !(a1.a_status) with - | Statics c, Statics c2 -> c == c2 - | EnumStatics e, EnumStatics e2 -> e == e2 - | AbstractStatics a, AbstractStatics a2 -> a == a2 - | Extend tl1, Extend tl2 -> fields_eq() && List.for_all2 shallow_eq tl1 tl2 - | Closed, Closed -> fields_eq() - | Opened, Opened -> fields_eq() - | Const, Const -> fields_eq() - | _ -> false - ) - | _ , _ -> - false - end - -(* perform unification with subtyping. - the first type is always the most down in the class hierarchy - it's also the one that is pointed by the position. - It's actually a typecheck of A :> B where some mutations can happen *) - -type unify_error = - | Cannot_unify of t * t - | Invalid_field_type of string - | Has_no_field of t * string - | Has_no_runtime_field of t * string - | Has_extra_field of t * string - | Invalid_kind of string * field_kind * field_kind - | Invalid_visibility of string - | Not_matching_optional of string - | Cant_force_optional - | Invariant_parameter of int - | Constraint_failure of string - | Missing_overload of tclass_field * t - | FinalInvariance (* nice band name *) - | Invalid_function_argument of int (* index *) * int (* total *) - | Invalid_return_type - | Unify_custom of string - -exception Unify_error of unify_error list - -let cannot_unify a b = Cannot_unify (a,b) -let invalid_field n = Invalid_field_type n -let invalid_kind n a b = Invalid_kind (n,a,b) -let invalid_visibility n = Invalid_visibility n -let has_no_field t n = Has_no_field (t,n) -let has_extra_field t n = Has_extra_field (t,n) -let error l = raise (Unify_error l) -let has_meta m ml = List.exists (fun (m2,_,_) -> m = m2) ml -let get_meta m ml = List.find (fun (m2,_,_) -> m = m2) ml -let no_meta = [] - -(* - we can restrict access as soon as both are runtime-compatible -*) -let unify_access a1 a2 = - a1 = a2 || match a1, a2 with - | _, AccNo | _, AccNever -> true - | AccInline, AccNormal -> true - | _ -> false - -let direct_access = function - | AccNo | AccNever | AccNormal | AccInline | AccRequire _ | AccCtor -> true - | AccResolve | AccCall -> false - -let unify_kind k1 k2 = - k1 = k2 || match k1, k2 with - | Var v1, Var v2 -> unify_access v1.v_read v2.v_read && unify_access v1.v_write v2.v_write - | Var v, Method m -> - (match v.v_read, v.v_write, m with - | AccNormal, _, MethNormal -> true - | AccNormal, AccNormal, MethDynamic -> true - | _ -> false) - | Method m, Var v -> - (match m with - | MethDynamic -> direct_access v.v_read && direct_access v.v_write - | MethMacro -> false - | MethNormal | MethInline -> - match v.v_read,v.v_write with - | AccNormal,(AccNo | AccNever) -> true - | _ -> false) - | Method m1, Method m2 -> - match m1,m2 with - | MethInline, MethNormal - | MethDynamic, MethNormal -> true - | _ -> false - -type 'a rec_stack = { - mutable rec_stack : 'a list; -} - -let new_rec_stack() = { rec_stack = [] } -let rec_stack_exists f s = List.exists f s.rec_stack -let rec_stack_memq v s = List.memq v s.rec_stack -let rec_stack_loop stack value f arg = - stack.rec_stack <- value :: stack.rec_stack; - try - let r = f arg in - stack.rec_stack <- List.tl stack.rec_stack; - r - with e -> - stack.rec_stack <- List.tl stack.rec_stack; - raise e - -let eq_stack = new_rec_stack() - -let rec_stack stack value fcheck frun ferror = - if not (rec_stack_exists fcheck stack) then begin - try - stack.rec_stack <- value :: stack.rec_stack; - let v = frun() in - stack.rec_stack <- List.tl stack.rec_stack; - v - with - Unify_error l -> - stack.rec_stack <- List.tl stack.rec_stack; - ferror l - | e -> - stack.rec_stack <- List.tl stack.rec_stack; - raise e - end - -let rec_stack_default stack value fcheck frun def = - if not (rec_stack_exists fcheck stack) then rec_stack_loop stack value frun () else def - -let rec_stack_bool stack value fcheck frun = - if (rec_stack_exists fcheck stack) then false else begin - try - stack.rec_stack <- value :: stack.rec_stack; - frun(); - stack.rec_stack <- List.tl stack.rec_stack; - true - with - Unify_error l -> - stack.rec_stack <- List.tl stack.rec_stack; - false - | e -> - stack.rec_stack <- List.tl stack.rec_stack; - raise e - end - -type eq_kind = - | EqStrict - | EqCoreType - | EqRightDynamic - | EqBothDynamic - | EqDoNotFollowNull (* like EqStrict, but does not follow Null *) - -let rec type_eq param a b = - let can_follow t = match param with - | EqCoreType -> false - | EqDoNotFollowNull -> not (is_explicit_null t) - | _ -> true - in - if a == b then - () - else match a , b with - | TLazy f , _ -> type_eq param (lazy_type f) b - | _ , TLazy f -> type_eq param a (lazy_type f) - | TMono t , _ -> - (match !t with - | None -> if param = EqCoreType || not (link t a b) then error [cannot_unify a b] - | Some t -> type_eq param t b) - | _ , TMono t -> - (match !t with - | None -> if param = EqCoreType || not (link t b a) then error [cannot_unify a b] - | Some t -> type_eq param a t) - | TAbstract ({a_path=[],"Null"},[t1]),TAbstract ({a_path=[],"Null"},[t2]) -> - type_eq param t1 t2 - | TAbstract ({a_path=[],"Null"},[t]),_ when param <> EqDoNotFollowNull -> - type_eq param t b - | _,TAbstract ({a_path=[],"Null"},[t]) when param <> EqDoNotFollowNull -> - type_eq param a t - | TType (t1,tl1), TType (t2,tl2) when (t1 == t2 || (param = EqCoreType && t1.t_path = t2.t_path)) && List.length tl1 = List.length tl2 -> - type_eq_params param a b tl1 tl2 - | TType (t,tl) , _ when can_follow a -> - type_eq param (apply_params t.t_params tl t.t_type) b - | _ , TType (t,tl) when can_follow b -> - rec_stack eq_stack (a,b) - (fun (a2,b2) -> fast_eq a a2 && fast_eq b b2) - (fun() -> type_eq param a (apply_params t.t_params tl t.t_type)) - (fun l -> error (cannot_unify a b :: l)) - | TEnum (e1,tl1) , TEnum (e2,tl2) -> - if e1 != e2 && not (param = EqCoreType && e1.e_path = e2.e_path) then error [cannot_unify a b]; - type_eq_params param a b tl1 tl2 - | TInst (c1,tl1) , TInst (c2,tl2) -> - if c1 != c2 && not (param = EqCoreType && c1.cl_path = c2.cl_path) && (match c1.cl_kind, c2.cl_kind with KExpr _, KExpr _ -> false | _ -> true) then error [cannot_unify a b]; - type_eq_params param a b tl1 tl2 - | TFun (l1,r1) , TFun (l2,r2) when List.length l1 = List.length l2 -> - let i = ref 0 in - (try - type_eq param r1 r2; - List.iter2 (fun (n,o1,t1) (_,o2,t2) -> - incr i; - if o1 <> o2 then error [Not_matching_optional n]; - type_eq param t1 t2 - ) l1 l2 - with - Unify_error l -> - let msg = if !i = 0 then Invalid_return_type else Invalid_function_argument(!i,List.length l1) in - error (cannot_unify a b :: msg :: l) - ) - | TDynamic a , TDynamic b -> - type_eq param a b - | TAbstract (a1,tl1) , TAbstract (a2,tl2) -> - if a1 != a2 && not (param = EqCoreType && a1.a_path = a2.a_path) then error [cannot_unify a b]; - type_eq_params param a b tl1 tl2 - | TAnon a1, TAnon a2 -> - (try - (match !(a2.a_status) with - | Statics c -> (match !(a1.a_status) with Statics c2 when c == c2 -> () | _ -> error []) - | EnumStatics e -> (match !(a1.a_status) with EnumStatics e2 when e == e2 -> () | _ -> error []) - | AbstractStatics a -> (match !(a1.a_status) with AbstractStatics a2 when a == a2 -> () | _ -> error []) - | _ -> () - ); - if would_produce_recursive_anon a1 a2 || would_produce_recursive_anon a2 a1 then error [cannot_unify a b]; - PMap.iter (fun n f1 -> - try - let f2 = PMap.find n a2.a_fields in - if f1.cf_kind <> f2.cf_kind && (param = EqStrict || param = EqCoreType || not (unify_kind f1.cf_kind f2.cf_kind)) then error [invalid_kind n f1.cf_kind f2.cf_kind]; - let a = f1.cf_type and b = f2.cf_type in - (try type_eq param a b with Unify_error l -> error (invalid_field n :: l)); - if (has_class_field_flag f1 CfPublic) != (has_class_field_flag f2 CfPublic) then error [invalid_visibility n]; - with - Not_found -> - if is_closed a2 then error [has_no_field b n]; - if not (link (ref None) b f1.cf_type) then error [cannot_unify a b]; - a2.a_fields <- PMap.add n f1 a2.a_fields - ) a1.a_fields; - PMap.iter (fun n f2 -> - if not (PMap.mem n a1.a_fields) then begin - if is_closed a1 then error [has_no_field a n]; - if not (link (ref None) a f2.cf_type) then error [cannot_unify a b]; - a1.a_fields <- PMap.add n f2 a1.a_fields - end; - ) a2.a_fields; - with - Unify_error l -> error (cannot_unify a b :: l)) - | _ , _ -> - if b == t_dynamic && (param = EqRightDynamic || param = EqBothDynamic) then - () - else if a == t_dynamic && param = EqBothDynamic then - () - else - error [cannot_unify a b] - -and type_eq_params param a b tl1 tl2 = - let i = ref 0 in - List.iter2 (fun t1 t2 -> - incr i; - try - type_eq param t1 t2 - with Unify_error l -> - let err = cannot_unify a b in - error (err :: (Invariant_parameter !i) :: l) - ) tl1 tl2 - -let type_iseq a b = - try - type_eq EqStrict a b; - true - with - Unify_error _ -> false - -let type_iseq_strict a b = - try - type_eq EqDoNotFollowNull a b; - true - with Unify_error _ -> - false - -let unify_stack = new_rec_stack() -let abstract_cast_stack = new_rec_stack() -let unify_new_monos = new_rec_stack() - -let print_stacks() = - let ctx = print_context() in - let st = s_type ctx in - print_endline "unify_stack"; - List.iter (fun (a,b) -> Printf.printf "\t%s , %s\n" (st a) (st b)) unify_stack.rec_stack; - print_endline "monos"; - List.iter (fun m -> print_endline ("\t" ^ st m)) unify_new_monos.rec_stack; - print_endline "abstract_cast_stack"; - List.iter (fun (a,b) -> Printf.printf "\t%s , %s\n" (st a) (st b)) abstract_cast_stack.rec_stack - -let rec unify a b = - if a == b then - () - else match a, b with - | TLazy f , _ -> unify (lazy_type f) b - | _ , TLazy f -> unify a (lazy_type f) - | TMono t , _ -> - (match !t with - | None -> if not (link t a b) then error [cannot_unify a b] - | Some t -> unify t b) - | _ , TMono t -> - (match !t with - | None -> if not (link t b a) then error [cannot_unify a b] - | Some t -> unify a t) - | TType (t,tl) , _ -> - rec_stack unify_stack (a,b) - (fun(a2,b2) -> fast_eq a a2 && fast_eq b b2) - (fun() -> try_apply_params_rec t.t_params tl t.t_type (fun a -> unify a b)) - (fun l -> error (cannot_unify a b :: l)) - | _ , TType (t,tl) -> - rec_stack unify_stack (a,b) - (fun(a2,b2) -> fast_eq a a2 && fast_eq b b2) - (fun() -> try_apply_params_rec t.t_params tl t.t_type (unify a)) - (fun l -> error (cannot_unify a b :: l)) - | TEnum (ea,tl1) , TEnum (eb,tl2) -> - if ea != eb then error [cannot_unify a b]; - unify_type_params a b tl1 tl2 - | TAbstract ({a_path=[],"Null"},[t]),_ -> - begin try unify t b - with Unify_error l -> error (cannot_unify a b :: l) end - | _,TAbstract ({a_path=[],"Null"},[t]) -> - begin try unify a t - with Unify_error l -> error (cannot_unify a b :: l) end - | TAbstract (a1,tl1) , TAbstract (a2,tl2) when a1 == a2 -> - begin try - unify_type_params a b tl1 tl2 - with Unify_error _ as err -> - (* the type could still have a from/to relation to itself (issue #3494) *) - begin try - unify_abstracts a b a1 tl1 a2 tl2 - with Unify_error _ -> - raise err - end - end - | TAbstract ({a_path=[],"Void"},_) , _ - | _ , TAbstract ({a_path=[],"Void"},_) -> - error [cannot_unify a b] - | TAbstract (a1,tl1) , TAbstract (a2,tl2) -> - unify_abstracts a b a1 tl1 a2 tl2 - | TInst (c1,tl1) , TInst (c2,tl2) -> - let rec loop c tl = - if c == c2 then begin - unify_type_params a b tl tl2; - true - end else (match c.cl_super with - | None -> false - | Some (cs,tls) -> - loop cs (List.map (apply_params c.cl_params tl) tls) - ) || List.exists (fun (cs,tls) -> - loop cs (List.map (apply_params c.cl_params tl) tls) - ) c.cl_implements - || (match c.cl_kind with - | KTypeParameter pl -> List.exists (fun t -> - match follow t with - | TInst (cs,tls) -> loop cs (List.map (apply_params c.cl_params tl) tls) - | TAbstract(aa,tl) -> List.exists (unify_to aa tl b) aa.a_to - | _ -> false - ) pl - | _ -> false) - in - if not (loop c1 tl1) then error [cannot_unify a b] - | TFun (l1,r1) , TFun (l2,r2) when List.length l1 = List.length l2 -> - let i = ref 0 in - (try - (match follow r2 with - | TAbstract ({a_path=[],"Void"},_) -> incr i - | _ -> unify r1 r2; incr i); - List.iter2 (fun (_,o1,t1) (_,o2,t2) -> - if o1 && not o2 then error [Cant_force_optional]; - unify t1 t2; - incr i - ) l2 l1 (* contravariance *) - with - Unify_error l -> - let msg = if !i = 0 then Invalid_return_type else Invalid_function_argument(!i,List.length l1) in - error (cannot_unify a b :: msg :: l)) - | TInst (c,tl) , TAnon an -> - if PMap.is_empty an.a_fields then (match c.cl_kind with - | KTypeParameter pl -> - (* one of the constraints must unify with { } *) - if not (List.exists (fun t -> match follow t with TInst _ | TAnon _ -> true | _ -> false) pl) then error [cannot_unify a b] - | _ -> ()); - (try - PMap.iter (fun n f2 -> - (* - introducing monomorphs while unifying might create infinite loops - see #2315 - let's store these monomorphs and make sure we reach a fixed point - *) - let monos = ref [] in - let make_type f = - match f.cf_params with - | [] -> f.cf_type - | l -> - let ml = List.map (fun _ -> mk_mono()) l in - monos := ml; - apply_params f.cf_params ml f.cf_type - in - let _, ft, f1 = (try raw_class_field make_type c tl n with Not_found -> error [has_no_field a n]) in - let ft = apply_params c.cl_params tl ft in - if not (unify_kind f1.cf_kind f2.cf_kind) then error [invalid_kind n f1.cf_kind f2.cf_kind]; - if (has_class_field_flag f2 CfPublic) && not (has_class_field_flag f1 CfPublic) then error [invalid_visibility n]; - - (match f2.cf_kind with - | Var { v_read = AccNo } | Var { v_read = AccNever } -> - (* we will do a recursive unification, so let's check for possible recursion *) - let old_monos = unify_new_monos.rec_stack in - unify_new_monos.rec_stack <- !monos @ unify_new_monos.rec_stack; - rec_stack unify_stack (ft,f2.cf_type) - (fun (a2,b2) -> fast_eq b2 f2.cf_type && fast_eq_mono unify_new_monos.rec_stack ft a2) - (fun() -> try unify_with_access f1 ft f2 with e -> unify_new_monos.rec_stack <- old_monos; raise e) - (fun l -> error (invalid_field n :: l)); - unify_new_monos.rec_stack <- old_monos; - | Method MethNormal | Method MethInline | Var { v_write = AccNo } | Var { v_write = AccNever } -> - (* same as before, but unification is reversed (read-only var) *) - let old_monos = unify_new_monos.rec_stack in - unify_new_monos.rec_stack <- !monos @ unify_new_monos.rec_stack; - rec_stack unify_stack (f2.cf_type,ft) - (fun(a2,b2) -> fast_eq_mono unify_new_monos.rec_stack b2 ft && fast_eq f2.cf_type a2) - (fun() -> try unify_with_access f1 ft f2 with e -> unify_new_monos.rec_stack <- old_monos; raise e) - (fun l -> error (invalid_field n :: l)); - unify_new_monos.rec_stack <- old_monos; - | _ -> - (* will use fast_eq, which have its own stack *) - try - unify_with_access f1 ft f2 - with - Unify_error l -> - error (invalid_field n :: l)); - - List.iter (fun f2o -> - if not (List.exists (fun f1o -> type_iseq f1o.cf_type f2o.cf_type) (f1 :: f1.cf_overloads)) - then error [Missing_overload (f1, f2o.cf_type)] - ) f2.cf_overloads; - (* we mark the field as :?used because it might be used through the structure *) - if not (Meta.has Meta.MaybeUsed f1.cf_meta) then begin - f1.cf_meta <- (Meta.MaybeUsed,[],f1.cf_pos) :: f1.cf_meta; - match f2.cf_kind with - | Var vk -> - let check name = - try - let _,_,cf = raw_class_field make_type c tl name in - if not (Meta.has Meta.MaybeUsed cf.cf_meta) then - cf.cf_meta <- (Meta.MaybeUsed,[],f1.cf_pos) :: cf.cf_meta - with Not_found -> - () - in - (match vk.v_read with AccCall -> check ("get_" ^ f1.cf_name) | _ -> ()); - (match vk.v_write with AccCall -> check ("set_" ^ f1.cf_name) | _ -> ()); - | _ -> () - end; - (match f1.cf_kind with - | Method MethInline -> - if (c.cl_extern || has_class_field_flag f1 CfExtern) && not (Meta.has Meta.Runtime f1.cf_meta) then error [Has_no_runtime_field (a,n)]; - | _ -> ()); - ) an.a_fields; - (match !(an.a_status) with - | Opened -> an.a_status := Closed; - | Statics _ | EnumStatics _ | AbstractStatics _ -> error [] - | Closed | Extend _ | Const -> ()) - with - Unify_error l -> error (cannot_unify a b :: l)) - | TAnon a1, TAnon a2 -> - unify_anons a b a1 a2 - | TAnon an, TAbstract ({ a_path = [],"Class" },[pt]) -> - (match !(an.a_status) with - | Statics cl -> unify (TInst (cl,List.map (fun _ -> mk_mono()) cl.cl_params)) pt - | _ -> error [cannot_unify a b]) - | TAnon an, TAbstract ({ a_path = [],"Enum" },[pt]) -> - (match !(an.a_status) with - | EnumStatics e -> unify (TEnum (e,List.map (fun _ -> mk_mono()) e.e_params)) pt - | _ -> error [cannot_unify a b]) - | TEnum _, TAbstract ({ a_path = [],"EnumValue" },[]) -> - () - | TEnum(en,_), TAbstract ({ a_path = ["haxe"],"FlatEnum" },[]) when Meta.has Meta.FlatEnum en.e_meta -> - () - | TFun _, TAbstract ({ a_path = ["haxe"],"Function" },[]) -> - () - | TInst(c,tl),TAbstract({a_path = ["haxe"],"Constructible"},[t1]) -> - begin try - begin match c.cl_kind with - | KTypeParameter tl -> - (* type parameters require an equal Constructible constraint *) - if not (List.exists (fun t -> match follow t with TAbstract({a_path = ["haxe"],"Constructible"},[t2]) -> type_iseq t1 t2 | _ -> false) tl) then error [cannot_unify a b] - | _ -> - let _,t,cf = class_field c tl "new" in - if not (has_class_field_flag cf CfPublic) then error [invalid_visibility "new"]; - begin try unify t t1 - with Unify_error l -> error (cannot_unify a b :: l) end - end - with Not_found -> - error [has_no_field a "new"] - end - | TDynamic t , _ -> - if t == a then - () - else (match b with - | TDynamic t2 -> - if t2 != b then - (try - type_eq EqRightDynamic t t2 - with - Unify_error l -> error (cannot_unify a b :: l)); - | TAbstract(bb,tl) when (List.exists (unify_from bb tl a b) bb.a_from) -> - () - | _ -> - error [cannot_unify a b]) - | _ , TDynamic t -> - if t == b then - () - else (match a with - | TDynamic t2 -> - if t2 != a then - (try - type_eq EqRightDynamic t t2 - with - Unify_error l -> error (cannot_unify a b :: l)); - | TAnon an -> - (try - (match !(an.a_status) with - | Statics _ | EnumStatics _ -> error [] - | Opened -> an.a_status := Closed - | _ -> ()); - PMap.iter (fun _ f -> - try - type_eq EqStrict (field_type f) t - with Unify_error l -> - error (invalid_field f.cf_name :: l) - ) an.a_fields - with Unify_error l -> - error (cannot_unify a b :: l)) - | TAbstract(aa,tl) when (List.exists (unify_to aa tl b) aa.a_to) -> - () - | _ -> - error [cannot_unify a b]) - | TAbstract (aa,tl), _ -> - if not (List.exists (unify_to aa tl b) aa.a_to) then error [cannot_unify a b]; - | TInst ({ cl_kind = KTypeParameter ctl } as c,pl), TAbstract (bb,tl) -> - (* one of the constraints must satisfy the abstract *) - if not (List.exists (fun t -> - let t = apply_params c.cl_params pl t in - try unify t b; true with Unify_error _ -> false - ) ctl) && not (List.exists (unify_from bb tl a b) bb.a_from) then error [cannot_unify a b]; - | _, TAbstract (bb,tl) -> - if not (List.exists (unify_from bb tl a b) bb.a_from) then error [cannot_unify a b] - | _ , _ -> - error [cannot_unify a b] - -and unify_abstracts a b a1 tl1 a2 tl2 = - let f1 = unify_to a1 tl1 b in - let f2 = unify_from a2 tl2 a b in - if (List.exists (f1 ~allow_transitive_cast:false) a1.a_to) - || (List.exists (f2 ~allow_transitive_cast:false) a2.a_from) - || (((Meta.has Meta.CoreType a1.a_meta) || (Meta.has Meta.CoreType a2.a_meta)) - && ((List.exists f1 a1.a_to) || (List.exists f2 a2.a_from))) then - () - else - error [cannot_unify a b] - -and unify_anons a b a1 a2 = - if would_produce_recursive_anon a1 a2 then error [cannot_unify a b]; - (try - PMap.iter (fun n f2 -> - try - let f1 = PMap.find n a1.a_fields in - if not (unify_kind f1.cf_kind f2.cf_kind) then - (match !(a1.a_status), f1.cf_kind, f2.cf_kind with - | Opened, Var { v_read = AccNormal; v_write = AccNo }, Var { v_read = AccNormal; v_write = AccNormal } -> - f1.cf_kind <- f2.cf_kind; - | _ -> error [invalid_kind n f1.cf_kind f2.cf_kind]); - if (has_class_field_flag f2 CfPublic) && not (has_class_field_flag f1 CfPublic) then error [invalid_visibility n]; - try - let f1_type = - if fast_eq f1.cf_type f2.cf_type then f1.cf_type - else field_type f1 - in - unify_with_access f1 f1_type f2; - (match !(a1.a_status) with - | Statics c when not (Meta.has Meta.MaybeUsed f1.cf_meta) -> f1.cf_meta <- (Meta.MaybeUsed,[],f1.cf_pos) :: f1.cf_meta - | _ -> ()); - with - Unify_error l -> error (invalid_field n :: l) - with - Not_found -> - match !(a1.a_status) with - | Opened -> - if not (link (ref None) a f2.cf_type) then error []; - a1.a_fields <- PMap.add n f2 a1.a_fields - | Const when Meta.has Meta.Optional f2.cf_meta -> - () - | _ -> - error [has_no_field a n]; - ) a2.a_fields; - (match !(a1.a_status) with - | Const when not (PMap.is_empty a2.a_fields) -> - PMap.iter (fun n _ -> if not (PMap.mem n a2.a_fields) then error [has_extra_field a n]) a1.a_fields; - | Opened -> - a1.a_status := Closed - | _ -> ()); - (match !(a2.a_status) with - | Statics c -> (match !(a1.a_status) with Statics c2 when c == c2 -> () | _ -> error []) - | EnumStatics e -> (match !(a1.a_status) with EnumStatics e2 when e == e2 -> () | _ -> error []) - | AbstractStatics a -> (match !(a1.a_status) with AbstractStatics a2 when a == a2 -> () | _ -> error []) - | Opened -> a2.a_status := Closed - | Const | Extend _ | Closed -> ()) - with - Unify_error l -> error (cannot_unify a b :: l)) - -and unify_from ab tl a b ?(allow_transitive_cast=true) t = - rec_stack_bool abstract_cast_stack (a,b) - (fun (a2,b2) -> fast_eq a a2 && fast_eq b b2) - (fun() -> - let t = apply_params ab.a_params tl t in - let unify_func = if allow_transitive_cast then unify else type_eq EqRightDynamic in - unify_func a t) - -and unify_to ab tl b ?(allow_transitive_cast=true) t = - let t = apply_params ab.a_params tl t in - let unify_func = if allow_transitive_cast then unify else type_eq EqStrict in - try - unify_func t b; - true - with Unify_error _ -> - false - -and unify_from_field ab tl a b ?(allow_transitive_cast=true) (t,cf) = - rec_stack_bool abstract_cast_stack (a,b) - (fun (a2,b2) -> fast_eq a a2 && fast_eq b b2) - (fun() -> - let unify_func = if allow_transitive_cast then unify else type_eq EqStrict in - match follow cf.cf_type with - | TFun(_,r) -> - let monos = List.map (fun _ -> mk_mono()) cf.cf_params in - let map t = apply_params ab.a_params tl (apply_params cf.cf_params monos t) in - unify_func a (map t); - List.iter2 (fun m (name,t) -> match follow t with - | TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] -> - List.iter (fun tc -> match follow m with TMono _ -> raise (Unify_error []) | _ -> unify m (map tc) ) constr - | _ -> () - ) monos cf.cf_params; - unify_func (map r) b; - true - | _ -> assert false) - -and unify_to_field ab tl b ?(allow_transitive_cast=true) (t,cf) = - let a = TAbstract(ab,tl) in - rec_stack_bool abstract_cast_stack (b,a) - (fun (b2,a2) -> fast_eq a a2 && fast_eq b b2) - (fun() -> - let unify_func = if allow_transitive_cast then unify else type_eq EqStrict in - match follow cf.cf_type with - | TFun((_,_,ta) :: _,_) -> - let monos = List.map (fun _ -> mk_mono()) cf.cf_params in - let map t = apply_params ab.a_params tl (apply_params cf.cf_params monos t) in - let athis = map ab.a_this in - (* we cannot allow implicit casts when the this type is not completely known yet *) - (* if has_mono athis then raise (Unify_error []); *) - with_variance (type_eq EqStrict) athis (map ta); - (* immediate constraints checking is ok here because we know there are no monomorphs *) - List.iter2 (fun m (name,t) -> match follow t with - | TInst ({ cl_kind = KTypeParameter constr },_) when constr <> [] -> - List.iter (fun tc -> match follow m with TMono _ -> raise (Unify_error []) | _ -> unify m (map tc) ) constr - | _ -> () - ) monos cf.cf_params; - unify_func (map t) b; - | _ -> assert false) - -and unify_with_variance f t1 t2 = - let allows_variance_to t tf = type_iseq tf t in - match follow t1,follow t2 with - | TInst(c1,tl1),TInst(c2,tl2) when c1 == c2 -> - List.iter2 f tl1 tl2 - | TEnum(en1,tl1),TEnum(en2,tl2) when en1 == en2 -> - List.iter2 f tl1 tl2 - | TAbstract(a1,tl1),TAbstract(a2,tl2) when a1 == a2 && Meta.has Meta.CoreType a1.a_meta -> - List.iter2 f tl1 tl2 - | TAbstract(a1,pl1),TAbstract(a2,pl2) -> - if (Meta.has Meta.CoreType a1.a_meta) && (Meta.has Meta.CoreType a2.a_meta) then begin - let ta1 = apply_params a1.a_params pl1 a1.a_this in - let ta2 = apply_params a2.a_params pl2 a2.a_this in - type_eq EqStrict ta1 ta2; - end; - if not (List.exists (allows_variance_to t2) a1.a_to) && not (List.exists (allows_variance_to t1) a2.a_from) then - error [cannot_unify t1 t2] - | TAbstract(a,pl),t -> - type_eq EqBothDynamic (apply_params a.a_params pl a.a_this) t; - if not (List.exists (fun t2 -> allows_variance_to t (apply_params a.a_params pl t2)) a.a_to) then error [cannot_unify t1 t2] - | t,TAbstract(a,pl) -> - type_eq EqBothDynamic t (apply_params a.a_params pl a.a_this); - if not (List.exists (fun t2 -> allows_variance_to t (apply_params a.a_params pl t2)) a.a_from) then error [cannot_unify t1 t2] - | (TAnon a1 as t1), (TAnon a2 as t2) -> - rec_stack unify_stack (t1,t2) - (fun (a,b) -> fast_eq a t1 && fast_eq b t2) - (fun() -> unify_anons t1 t2 a1 a2) - (fun l -> error l) - | _ -> - error [cannot_unify t1 t2] - -and unify_type_params a b tl1 tl2 = - let i = ref 0 in - List.iter2 (fun t1 t2 -> - incr i; - try - with_variance (type_eq EqRightDynamic) t1 t2 - with Unify_error l -> - let err = cannot_unify a b in - error (err :: (Invariant_parameter !i) :: l) - ) tl1 tl2 - -and with_variance f t1 t2 = - try - f t1 t2 - with Unify_error l -> try - unify_with_variance (with_variance f) t1 t2 - with Unify_error _ -> - raise (Unify_error l) - -and unify_with_access f1 t1 f2 = - match f2.cf_kind with - (* write only *) - | Var { v_read = AccNo } | Var { v_read = AccNever } -> unify f2.cf_type t1 - (* read only *) - | Method MethNormal | Method MethInline | Var { v_write = AccNo } | Var { v_write = AccNever } -> - if (has_class_field_flag f1 CfFinal) <> (has_class_field_flag f2 CfFinal) then raise (Unify_error [FinalInvariance]); - unify t1 f2.cf_type - (* read/write *) - | _ -> with_variance (type_eq EqBothDynamic) t1 f2.cf_type - -let does_unify a b = - try - unify a b; - true - with Unify_error _ -> - false - -(* ======= Mapping and iterating ======= *) - -let iter f e = - match e.eexpr with - | TConst _ - | TLocal _ - | TBreak - | TContinue - | TTypeExpr _ - | TIdent _ -> - () - | TArray (e1,e2) - | TBinop (_,e1,e2) - | TFor (_,e1,e2) - | TWhile (e1,e2,_) -> - f e1; - f e2; - | TThrow e - | TField (e,_) - | TEnumParameter (e,_,_) - | TEnumIndex e - | TParenthesis e - | TCast (e,_) - | TUnop (_,_,e) - | TMeta(_,e) -> - f e - | TArrayDecl el - | TNew (_,_,el) - | TBlock el -> - List.iter f el - | TObjectDecl fl -> - List.iter (fun (_,e) -> f e) fl - | TCall (e,el) -> - f e; - List.iter f el - | TVar (v,eo) -> - (match eo with None -> () | Some e -> f e) - | TFunction fu -> - f fu.tf_expr - | TIf (e,e1,e2) -> - f e; - f e1; - (match e2 with None -> () | Some e -> f e) - | TSwitch (e,cases,def) -> - f e; - List.iter (fun (el,e2) -> List.iter f el; f e2) cases; - (match def with None -> () | Some e -> f e) - | TTry (e,catches) -> - f e; - List.iter (fun (_,e) -> f e) catches - | TReturn eo -> - (match eo with None -> () | Some e -> f e) - -(** - Returns `true` if `predicate` is evaluated to `true` for at least one of sub-expressions. - Returns `false` otherwise. - Does not evaluate `predicate` for the `e` expression. -*) -let check_expr predicate e = - match e.eexpr with - | TConst _ | TLocal _ | TBreak | TContinue | TTypeExpr _ | TIdent _ -> - false - | TArray (e1,e2) | TBinop (_,e1,e2) | TFor (_,e1,e2) | TWhile (e1,e2,_) -> - predicate e1 || predicate e2; - | TThrow e | TField (e,_) | TEnumParameter (e,_,_) | TEnumIndex e | TParenthesis e - | TCast (e,_) | TUnop (_,_,e) | TMeta(_,e) -> - predicate e - | TArrayDecl el | TNew (_,_,el) | TBlock el -> - List.exists predicate el - | TObjectDecl fl -> - List.exists (fun (_,e) -> predicate e) fl - | TCall (e,el) -> - predicate e || List.exists predicate el - | TVar (_,eo) | TReturn eo -> - (match eo with None -> false | Some e -> predicate e) - | TFunction fu -> - predicate fu.tf_expr - | TIf (e,e1,e2) -> - predicate e || predicate e1 || (match e2 with None -> false | Some e -> predicate e) - | TSwitch (e,cases,def) -> - predicate e - || List.exists (fun (el,e2) -> List.exists predicate el || predicate e2) cases - || (match def with None -> false | Some e -> predicate e) - | TTry (e,catches) -> - predicate e || List.exists (fun (_,e) -> predicate e) catches - -let map_expr f e = - match e.eexpr with - | TConst _ - | TLocal _ - | TBreak - | TContinue - | TTypeExpr _ - | TIdent _ -> - e - | TArray (e1,e2) -> - let e1 = f e1 in - { e with eexpr = TArray (e1,f e2) } - | TBinop (op,e1,e2) -> - let e1 = f e1 in - { e with eexpr = TBinop (op,e1,f e2) } - | TFor (v,e1,e2) -> - let e1 = f e1 in - { e with eexpr = TFor (v,e1,f e2) } - | TWhile (e1,e2,flag) -> - let e1 = f e1 in - { e with eexpr = TWhile (e1,f e2,flag) } - | TThrow e1 -> - { e with eexpr = TThrow (f e1) } - | TEnumParameter (e1,ef,i) -> - { e with eexpr = TEnumParameter(f e1,ef,i) } - | TEnumIndex e1 -> - { e with eexpr = TEnumIndex (f e1) } - | TField (e1,v) -> - { e with eexpr = TField (f e1,v) } - | TParenthesis e1 -> - { e with eexpr = TParenthesis (f e1) } - | TUnop (op,pre,e1) -> - { e with eexpr = TUnop (op,pre,f e1) } - | TArrayDecl el -> - { e with eexpr = TArrayDecl (List.map f el) } - | TNew (t,pl,el) -> - { e with eexpr = TNew (t,pl,List.map f el) } - | TBlock el -> - { e with eexpr = TBlock (List.map f el) } - | TObjectDecl el -> - { e with eexpr = TObjectDecl (List.map (fun (v,e) -> v, f e) el) } - | TCall (e1,el) -> - let e1 = f e1 in - { e with eexpr = TCall (e1, List.map f el) } - | TVar (v,eo) -> - { e with eexpr = TVar (v, match eo with None -> None | Some e -> Some (f e)) } - | TFunction fu -> - { e with eexpr = TFunction { fu with tf_expr = f fu.tf_expr } } - | TIf (ec,e1,e2) -> - let ec = f ec in - let e1 = f e1 in - { e with eexpr = TIf (ec,e1,match e2 with None -> None | Some e -> Some (f e)) } - | TSwitch (e1,cases,def) -> - let e1 = f e1 in - let cases = List.map (fun (el,e2) -> List.map f el, f e2) cases in - { e with eexpr = TSwitch (e1, cases, match def with None -> None | Some e -> Some (f e)) } - | TTry (e1,catches) -> - let e1 = f e1 in - { e with eexpr = TTry (e1, List.map (fun (v,e) -> v, f e) catches) } - | TReturn eo -> - { e with eexpr = TReturn (match eo with None -> None | Some e -> Some (f e)) } - | TCast (e1,t) -> - { e with eexpr = TCast (f e1,t) } - | TMeta (m,e1) -> - {e with eexpr = TMeta(m,f e1)} - -let map_expr_type f ft fv e = - match e.eexpr with - | TConst _ - | TBreak - | TContinue - | TTypeExpr _ - | TIdent _ -> - { e with etype = ft e.etype } - | TLocal v -> - { e with eexpr = TLocal (fv v); etype = ft e.etype } - | TArray (e1,e2) -> - let e1 = f e1 in - { e with eexpr = TArray (e1,f e2); etype = ft e.etype } - | TBinop (op,e1,e2) -> - let e1 = f e1 in - { e with eexpr = TBinop (op,e1,f e2); etype = ft e.etype } - | TFor (v,e1,e2) -> - let v = fv v in - let e1 = f e1 in - { e with eexpr = TFor (v,e1,f e2); etype = ft e.etype } - | TWhile (e1,e2,flag) -> - let e1 = f e1 in - { e with eexpr = TWhile (e1,f e2,flag); etype = ft e.etype } - | TThrow e1 -> - { e with eexpr = TThrow (f e1); etype = ft e.etype } - | TEnumParameter (e1,ef,i) -> - { e with eexpr = TEnumParameter (f e1,ef,i); etype = ft e.etype } - | TEnumIndex e1 -> - { e with eexpr = TEnumIndex (f e1); etype = ft e.etype } - | TField (e1,v) -> - let e1 = f e1 in - let v = try - let n = match v with - | FClosure _ -> raise Not_found - | FAnon f | FInstance (_,_,f) | FStatic (_,f) -> f.cf_name - | FEnum (_,f) -> f.ef_name - | FDynamic n -> n - in - quick_field e1.etype n - with Not_found -> - v - in - { e with eexpr = TField (e1,v); etype = ft e.etype } - | TParenthesis e1 -> - { e with eexpr = TParenthesis (f e1); etype = ft e.etype } - | TUnop (op,pre,e1) -> - { e with eexpr = TUnop (op,pre,f e1); etype = ft e.etype } - | TArrayDecl el -> - { e with eexpr = TArrayDecl (List.map f el); etype = ft e.etype } - | TNew (c,pl,el) -> - let et = ft e.etype in - (* make sure that we use the class corresponding to the replaced type *) - let t = match c.cl_kind with - | KTypeParameter _ | KGeneric -> - et - | _ -> - ft (TInst(c,pl)) - in - let c, pl = (match follow t with TInst (c,pl) -> (c,pl) | TAbstract({a_impl = Some c},pl) -> c,pl | t -> error [has_no_field t "new"]) in - { e with eexpr = TNew (c,pl,List.map f el); etype = et } - | TBlock el -> - { e with eexpr = TBlock (List.map f el); etype = ft e.etype } - | TObjectDecl el -> - { e with eexpr = TObjectDecl (List.map (fun (v,e) -> v, f e) el); etype = ft e.etype } - | TCall (e1,el) -> - let e1 = f e1 in - { e with eexpr = TCall (e1, List.map f el); etype = ft e.etype } - | TVar (v,eo) -> - { e with eexpr = TVar (fv v, match eo with None -> None | Some e -> Some (f e)); etype = ft e.etype } - | TFunction fu -> - let fu = { - tf_expr = f fu.tf_expr; - tf_args = List.map (fun (v,o) -> fv v, o) fu.tf_args; - tf_type = ft fu.tf_type; - } in - { e with eexpr = TFunction fu; etype = ft e.etype } - | TIf (ec,e1,e2) -> - let ec = f ec in - let e1 = f e1 in - { e with eexpr = TIf (ec,e1,match e2 with None -> None | Some e -> Some (f e)); etype = ft e.etype } - | TSwitch (e1,cases,def) -> - let e1 = f e1 in - let cases = List.map (fun (el,e2) -> List.map f el, f e2) cases in - { e with eexpr = TSwitch (e1, cases, match def with None -> None | Some e -> Some (f e)); etype = ft e.etype } - | TTry (e1,catches) -> - let e1 = f e1 in - { e with eexpr = TTry (e1, List.map (fun (v,e) -> fv v, f e) catches); etype = ft e.etype } - | TReturn eo -> - { e with eexpr = TReturn (match eo with None -> None | Some e -> Some (f e)); etype = ft e.etype } - | TCast (e1,t) -> - { e with eexpr = TCast (f e1,t); etype = ft e.etype } - | TMeta (m,e1) -> - {e with eexpr = TMeta(m, f e1); etype = ft e.etype } - -let resolve_typedef t = - match t with - | TClassDecl _ | TEnumDecl _ | TAbstractDecl _ -> t - | TTypeDecl td -> - match follow td.t_type with - | TEnum (e,_) -> TEnumDecl e - | TInst (c,_) -> TClassDecl c - | TAbstract (a,_) -> TAbstractDecl a - | _ -> t - -module TExprToExpr = struct - let tpath p mp pl = - if snd mp = snd p then - CTPath { - tpackage = fst p; - tname = snd p; - tparams = pl; - tsub = None; - } - else CTPath { - tpackage = fst mp; - tname = snd mp; - tparams = pl; - tsub = Some (snd p); - } - - let rec convert_type = function - | TMono r -> - (match !r with - | None -> raise Exit - | Some t -> convert_type t) - | TInst ({cl_private = true; cl_path=_,name},tl) - | TEnum ({e_private = true; e_path=_,name},tl) - | TType ({t_private = true; t_path=_,name},tl) - | TAbstract ({a_private = true; a_path=_,name},tl) -> - CTPath { - tpackage = []; - tname = name; - tparams = List.map tparam tl; - tsub = None; - } - | TEnum (e,pl) -> - tpath e.e_path e.e_module.m_path (List.map tparam pl) - | TInst({cl_kind = KExpr e} as c,pl) -> - tpath ([],snd c.cl_path) ([],snd c.cl_path) (List.map tparam pl) - | TInst({cl_kind = KTypeParameter _} as c,pl) -> - tpath ([],snd c.cl_path) ([],snd c.cl_path) (List.map tparam pl) - | TInst (c,pl) -> - tpath c.cl_path c.cl_module.m_path (List.map tparam pl) - | TType (t,pl) as tf -> - (* recurse on type-type *) - if (snd t.t_path).[0] = '#' then convert_type (follow tf) else tpath t.t_path t.t_module.m_path (List.map tparam pl) - | TAbstract (a,pl) -> - tpath a.a_path a.a_module.m_path (List.map tparam pl) - | TFun (args,ret) -> - CTFunction (List.map (fun (_,_,t) -> convert_type' t) args, (convert_type' ret)) - | TAnon a -> - begin match !(a.a_status) with - | Statics c -> tpath ([],"Class") ([],"Class") [TPType (tpath c.cl_path c.cl_path [],null_pos)] - | EnumStatics e -> tpath ([],"Enum") ([],"Enum") [TPType (tpath e.e_path e.e_path [],null_pos)] - | _ -> - CTAnonymous (PMap.foldi (fun _ f acc -> - { - cff_name = f.cf_name,null_pos; - cff_kind = FVar (mk_type_hint f.cf_type null_pos,None); - cff_pos = f.cf_pos; - cff_doc = f.cf_doc; - cff_meta = f.cf_meta; - cff_access = []; - } :: acc - ) a.a_fields []) - end - | (TDynamic t2) as t -> - tpath ([],"Dynamic") ([],"Dynamic") (if t == t_dynamic then [] else [tparam t2]) - | TLazy f -> - convert_type (lazy_type f) - - and convert_type' t = - convert_type t,null_pos - - and tparam = function - | TInst ({cl_kind = KExpr e}, _) -> TPExpr e - | t -> TPType (convert_type' t) - - and mk_type_hint t p = - match follow t with - | TMono _ -> None - | _ -> (try Some (convert_type t,p) with Exit -> None) - - let rec convert_expr e = - let full_type_path t = - let mp,p = match t with - | TClassDecl c -> c.cl_module.m_path,c.cl_path - | TEnumDecl en -> en.e_module.m_path,en.e_path - | TAbstractDecl a -> a.a_module.m_path,a.a_path - | TTypeDecl t -> t.t_module.m_path,t.t_path - in - if snd mp = snd p then p else (fst mp) @ [snd mp],snd p - in - let mk_path = expr_of_type_path in - let mk_ident = function - | "`trace" -> Ident "trace" - | n -> Ident n - in - let eopt = function None -> None | Some e -> Some (convert_expr e) in - ((match e.eexpr with - | TConst c -> - EConst (tconst_to_const c) - | TLocal v -> EConst (mk_ident v.v_name) - | TArray (e1,e2) -> EArray (convert_expr e1,convert_expr e2) - | TBinop (op,e1,e2) -> EBinop (op, convert_expr e1, convert_expr e2) - | TField (e,f) -> EField (convert_expr e, field_name f) - | TTypeExpr t -> fst (mk_path (full_type_path t) e.epos) - | TParenthesis e -> EParenthesis (convert_expr e) - | TObjectDecl fl -> EObjectDecl (List.map (fun (k,e) -> k, convert_expr e) fl) - | TArrayDecl el -> EArrayDecl (List.map convert_expr el) - | TCall (e,el) -> ECall (convert_expr e,List.map convert_expr el) - | TNew (c,pl,el) -> ENew ((match (try convert_type (TInst (c,pl)) with Exit -> convert_type (TInst (c,[]))) with CTPath p -> p,null_pos | _ -> assert false),List.map convert_expr el) - | TUnop (op,p,e) -> EUnop (op,p,convert_expr e) - | TFunction f -> - let arg (v,c) = (v.v_name,v.v_pos), false, v.v_meta, mk_type_hint v.v_type null_pos, (match c with None -> None | Some c -> Some (convert_expr c)) in - EFunction (FKAnonymous,{ f_params = []; f_args = List.map arg f.tf_args; f_type = mk_type_hint f.tf_type null_pos; f_expr = Some (convert_expr f.tf_expr) }) - | TVar (v,eo) -> - EVars ([(v.v_name,v.v_pos), v.v_final, mk_type_hint v.v_type v.v_pos, eopt eo]) - | TBlock el -> EBlock (List.map convert_expr el) - | TFor (v,it,e) -> - let ein = (EBinop (OpIn,(EConst (Ident v.v_name),it.epos),convert_expr it),it.epos) in - EFor (ein,convert_expr e) - | TIf (e,e1,e2) -> EIf (convert_expr e,convert_expr e1,eopt e2) - | TWhile (e1,e2,flag) -> EWhile (convert_expr e1, convert_expr e2, flag) - | TSwitch (e,cases,def) -> - let cases = List.map (fun (vl,e) -> - List.map convert_expr vl,None,(match e.eexpr with TBlock [] -> None | _ -> Some (convert_expr e)),e.epos - ) cases in - let def = match eopt def with None -> None | Some (EBlock [],_) -> Some (None,null_pos) | Some e -> Some (Some e,pos e) in - ESwitch (convert_expr e,cases,def) - | TEnumIndex _ - | TEnumParameter _ -> - (* these are considered complex, so the AST is handled in TMeta(Meta.Ast) *) - assert false - | TTry (e,catches) -> - let e1 = convert_expr e in - let catches = List.map (fun (v,e) -> - let ct = try convert_type v.v_type,null_pos with Exit -> assert false in - let e = convert_expr e in - (v.v_name,v.v_pos),ct,e,(pos e) - ) catches in - ETry (e1,catches) - | TReturn e -> EReturn (eopt e) - | TBreak -> EBreak - | TContinue -> EContinue - | TThrow e -> EThrow (convert_expr e) - | TCast (e,t) -> - let t = (match t with - | None -> None - | Some t -> - let t = (match t with TClassDecl c -> TInst (c,[]) | TEnumDecl e -> TEnum (e,[]) | TTypeDecl t -> TType (t,[]) | TAbstractDecl a -> TAbstract (a,[])) in - Some (try convert_type t,null_pos with Exit -> assert false) - ) in - ECast (convert_expr e,t) - | TMeta ((Meta.Ast,[e1,_],_),_) -> e1 - | TMeta (m,e) -> EMeta(m,convert_expr e) - | TIdent s -> EConst (Ident s)) - ,e.epos) - -end - -module ExtType = struct - let is_mono = function - | TMono { contents = None } -> true - | _ -> false - - let is_void = function - | TAbstract({a_path=[],"Void"},_) -> true - | _ -> false - - let is_int t = match t with - | TAbstract({a_path=[],"Int"},_) -> true - | _ -> false - - let is_float t = match t with - | TAbstract({a_path=[],"Float"},_) -> true - | _ -> false - - let is_numeric t = match t with - | TAbstract({a_path=[],"Float"},_) -> true - | TAbstract({a_path=[],"Int"},_) -> true - | _ -> false - - let is_string t = match t with - | TInst({cl_path=[],"String"},_) -> true - | _ -> false - - let is_bool t = match t with - | TAbstract({a_path=[],"Bool"},_) -> true - | _ -> false - - type semantics = - | VariableSemantics - | ReferenceSemantics - | ValueSemantics - - let semantics_name = function - | VariableSemantics -> "variable" - | ReferenceSemantics -> "reference" - | ValueSemantics -> "value" - - let has_semantics t sem = - let name = semantics_name sem in - let check meta = - has_meta_option meta Meta.Semantics name - in - let rec loop t = match t with - | TInst(c,_) -> check c.cl_meta - | TEnum(en,_) -> check en.e_meta - | TType(t,tl) -> check t.t_meta || (loop (apply_params t.t_params tl t.t_type)) - | TAbstract(a,_) -> check a.a_meta - | TLazy f -> loop (lazy_type f) - | TMono r -> - (match !r with - | Some t -> loop t - | _ -> false) - | _ -> - false - in - loop t - - let has_variable_semantics t = has_semantics t VariableSemantics - let has_reference_semantics t = has_semantics t ReferenceSemantics - let has_value_semantics t = has_semantics t ValueSemantics -end - -let class_module_type c = { - t_path = [],"Class<" ^ (s_type_path c.cl_path) ^ ">" ; - t_module = c.cl_module; - t_doc = None; - t_pos = c.cl_pos; - t_name_pos = null_pos; - t_type = TAnon { - a_fields = c.cl_statics; - a_status = ref (Statics c); - }; - t_private = true; - t_params = []; - t_using = []; - t_meta = no_meta; -} - -let enum_module_type m path p = { - t_path = [], "Enum<" ^ (s_type_path path) ^ ">"; - t_module = m; - t_doc = None; - t_pos = p; - t_name_pos = null_pos; - t_type = mk_mono(); - t_private = true; - t_params = []; - t_using = []; - t_meta = []; -} - -let abstract_module_type a tl = { - t_path = [],Printf.sprintf "Abstract<%s%s>" (s_type_path a.a_path) (s_type_params (ref []) tl); - t_module = a.a_module; - t_doc = None; - t_pos = a.a_pos; - t_name_pos = null_pos; - t_type = TAnon { - a_fields = PMap.empty; - a_status = ref (AbstractStatics a); - }; - t_private = true; - t_params = []; - t_using = []; - t_meta = no_meta; -} - -module TClass = struct - let get_member_fields' self_too c0 tl = - let rec loop acc c tl = - let apply = apply_params c.cl_params tl in - let maybe_add acc cf = - if not (PMap.mem cf.cf_name acc) then begin - let cf = if tl = [] then cf else {cf with cf_type = apply cf.cf_type} in - PMap.add cf.cf_name (c,cf) acc - end else acc - in - let acc = if self_too || c != c0 then List.fold_left maybe_add acc c.cl_ordered_fields else acc in - if c.cl_interface then - List.fold_left (fun acc (i,tl) -> loop acc i (List.map apply tl)) acc c.cl_implements - else - match c.cl_super with - | Some(c,tl) -> loop acc c (List.map apply tl) - | None -> acc - in - loop PMap.empty c0 tl - - let get_all_super_fields c = - get_member_fields' false c (List.map snd c.cl_params) - - let get_all_fields c tl = - get_member_fields' true c tl - - let get_overridden_fields c cf = - let rec loop acc c = match c.cl_super with - | None -> - acc - | Some(c,_) -> - begin try - let cf' = PMap.find cf.cf_name c.cl_fields in - loop (cf' :: acc) c - with Not_found -> - loop acc c - end - in - loop [] c -end - -let s_class_path c = - let path = match c.cl_kind with - | KAbstractImpl a -> a.a_path - | _ -> c.cl_path - in - s_type_path path +include TType +include TFunctions +include TPrinting +include TUnification +include Texpr +include TOther + +;; +monomorph_bind_ref := Monomorph.bind;; +monomorph_create_ref := Monomorph.create;; \ No newline at end of file diff --git a/src/dune b/src/dune new file mode 100644 index 0000000000000000000000000000000000000000..dcb3496c3664e0d7ffb25e1cc9426551628c6a9b --- /dev/null +++ b/src/dune @@ -0,0 +1,33 @@ +(include_subdirs unqualified) + +(env + (_ + (flags (:standard -w -3 -thread)) + ) +) + +(library + (name haxe) + (libraries + extc extproc extlib_leftovers ilib javalib mbedtls neko objsize pcre swflib ttflib ziplib + json + unix str threads dynlink + xml-light extlib ptmap sha + ) + (modules (:standard \ haxe)) + (preprocess (per_module + ((pps sedlex.ppx) json lexer) + )) + (wrapped false) +) + +(executable + (name haxe) + (public_name haxe) + (package haxe) + (libraries haxe) + (modules haxe) + (link_flags (:include ../lib.sexp)) + ; Uncomment to enable bytecode output for ocamldebug support + ; (modes byte) +) \ No newline at end of file diff --git a/src/filters/ES6Ctors.ml b/src/filters/ES6Ctors.ml index 766cbbb5de308204af225455927b0aed3c849016..b9725c60b3bd62952fcb08cc93cc9c72a22ee8d5 100644 --- a/src/filters/ES6Ctors.ml +++ b/src/filters/ES6Ctors.ml @@ -36,6 +36,9 @@ let rec replace_super_call e = | _ -> map_expr replace_super_call e +let remove_default_arg_values args = + List.map (fun (v,_) -> v,None) args + exception Accessed_this of texpr (* return whether given expression has `this` access before calling `super` *) @@ -59,7 +62,7 @@ let has_this_before_super e = let get_num_args cf = match follow cf.cf_type with | TFun (args, _) -> List.length args - | _ -> assert false + | _ -> die "" __LOC__ (* the filter works in two passes: @@ -202,7 +205,10 @@ let rewrite_ctors com = ] } in - cf_ctor.cf_expr <- Some { ctor_expr with eexpr = TFunction { tf_ctor with tf_expr = e_ctor_replaced } }; + cf_ctor.cf_expr <- Some { ctor_expr with eexpr = TFunction { tf_ctor with + tf_args = remove_default_arg_values tf_ctor.tf_args; + tf_expr = e_ctor_replaced + } }; end; if cl == root then begin @@ -224,7 +230,10 @@ let rewrite_ctors com = make_hx_ctor_call e_skip_flag ] } in - cf_ctor.cf_expr <- Some { ctor_expr with eexpr = TFunction { tf_ctor with tf_expr = e_ctor_replaced } }; + cf_ctor.cf_expr <- Some { ctor_expr with eexpr = TFunction { tf_ctor with + tf_args = remove_default_arg_values tf_ctor.tf_args; + tf_expr = e_ctor_replaced + } }; | None -> ()) ) @@ -239,5 +248,5 @@ let rewrite_ctors com = | { cl_constructor = Some ({ cf_expr = Some ({ eexpr = TFunction tf } as e_ctor) } as cf_ctor); cl_super = Some (cl_super,_) } -> cl.cl_constructor <- Some { cf_ctor with cf_expr = Some { e_ctor with eexpr = TFunction { tf with tf_expr = { tf.tf_expr with eexpr = TBlock [e_empty_super_call; tf.tf_expr] } } } }; | _ -> - assert false + die "" __LOC__ ) inject_super; diff --git a/src/filters/capturedVars.ml b/src/filters/capturedVars.ml index b8396312a1cf2909b174729830372cdd99fba0ab..890e359d5e8ea96688907fad841f0a514608ac55 100644 --- a/src/filters/capturedVars.ml +++ b/src/filters/capturedVars.ml @@ -50,7 +50,7 @@ let captured_vars com e = | TClassDecl ({ cl_path = ["cs"|"java"],"NativeArray" }) -> true | _ -> false ) com.types) - with TClassDecl cl -> cl | _ -> assert false + with TClassDecl cl -> cl | _ -> die "" __LOC__ in object @@ -60,7 +60,7 @@ let captured_vars com e = match ve with | None -> let eone = mk (TConst (TInt (Int32.of_int 1))) t.tint p in - let t = match v.v_type with TInst (_, [t]) -> t | _ -> assert false in + let t = match v.v_type with TInst (_, [t]) -> t | _ -> die "" __LOC__ in mk (TNew (cnativearray,[t],[eone])) v.v_type p | Some e -> { (Inline.mk_untyped_call "__array__" p [e]) with etype = v.v_type } diff --git a/src/filters/defaultArguments.ml b/src/filters/defaultArguments.ml index bf8379ed83c5407eaeba1d922a01bca51c7686b4..c660a690510f490d7ee32be37449cf433e9fd96a 100644 --- a/src/filters/defaultArguments.ml +++ b/src/filters/defaultArguments.ml @@ -127,7 +127,7 @@ let rec change_func com cl cf = in let args = List.map replace_args args in { tf.tf_expr with eexpr = TBlock ((if !found then { super with eexpr = TCall (e1, args) } else super) :: !block @ tl) } - | _ -> assert false) + | _ -> Globals.die "" __LOC__) with Not_found -> Type.concat { tf.tf_expr with eexpr = TBlock !block; etype = basic.tvoid } tf.tf_expr in @@ -146,7 +146,7 @@ let rec change_func com cl cf = | _ -> ()); (if !found then cf.cf_type <- TFun(!args, ret)) - | _, _ -> assert false + | _, _ -> Globals.die "" __LOC__ let run com md = match md with diff --git a/src/filters/exceptions.ml b/src/filters/exceptions.ml new file mode 100644 index 0000000000000000000000000000000000000000..60e67de0c26c55194e1581e9f928b5c79a5e60f1 --- /dev/null +++ b/src/filters/exceptions.ml @@ -0,0 +1,541 @@ +open Globals +open Ast +open Type +open Common +open Typecore +open TyperBase +open Fields +open Error + +let haxe_exception_type_path = (["haxe"],"Exception") + +type context = { + typer : typer; + basic : basic_types; + config : exceptions_config; + wildcard_catch_type : Type.t; + base_throw_type : Type.t; + haxe_exception_class : tclass; + haxe_exception_type : Type.t; + haxe_native_stack_trace : tclass; +} + +let is_dynamic t = + match Abstract.follow_with_abstracts t with + | TAbstract({ a_path = [],"Dynamic" }, _) -> true + | t -> t == t_dynamic + +(** + Generate `haxe.Exception.method_name(args)` +*) +let haxe_exception_static_call ctx method_name args p = + let method_field = + try PMap.find method_name ctx.haxe_exception_class.cl_statics + with Not_found -> error ("haxe.Exception has no field " ^ method_name) p + in + let return_type = + match follow method_field.cf_type with + | TFun(_,t) -> t + | _ -> error ("haxe.Exception." ^ method_name ^ " is not a function and cannot be called") p + in + make_static_call ctx.typer ctx.haxe_exception_class method_field (fun t -> t) args return_type p + +(** + Generate `haxe_exception.method_name(args)` +*) +let haxe_exception_instance_call ctx haxe_exception method_name args p = + match quick_field haxe_exception.etype method_name with + | FInstance (_,_,cf) as faccess -> + let efield = { eexpr = TField(haxe_exception,faccess); etype = cf.cf_type; epos = p } in + let rt = + match follow cf.cf_type with + | TFun(_,t) -> t + | _ -> + error ((s_type (print_context()) haxe_exception.etype) ^ "." ^ method_name ^ " is not a function and cannot be called") p + in + make_call ctx.typer efield args rt p + | _ -> error ((s_type (print_context()) haxe_exception.etype) ^ "." ^ method_name ^ " is expected to be an instance method") p + +(** + Generate `Std.isOfType(e, t)` +*) +let std_is ctx e t p = + let t = follow t in + let std_cls = + match Typeload.load_type_raise ctx.typer ([],"Std") "Std" p with + | TClassDecl cls -> cls + | _ -> error "Std is expected to be a class" p + in + let isOfType_field = + try PMap.find "isOfType" std_cls.cl_statics + with Not_found -> error ("Std has no field isOfType") p + in + let return_type = + match follow isOfType_field.cf_type with + | TFun(_,t) -> t + | _ -> error ("Std.isOfType is not a function and cannot be called") p + in + let type_expr = { eexpr = TTypeExpr(module_type_of_type t); etype = t; epos = null_pos } in + make_static_call ctx.typer std_cls isOfType_field (fun t -> t) [e; type_expr] return_type p + +(** + Check if type path of `t` exists in `lst` +*) +let is_in_list t lst = + match Abstract.follow_with_abstracts t with + | TInst(cls,_) -> + let rec check cls = + List.mem cls.cl_path lst + || List.exists (fun (cls,_) -> check cls) cls.cl_implements + || Option.map_default (fun (cls,_) -> check cls) false cls.cl_super + in + (match follow t with + | TInst (cls, _) -> check cls + | _ -> false + ) + | TAbstract({ a_path = path },_) + | TEnum({ e_path = path },_) -> + List.mem path lst + | _ -> false + +(** + Check if `t` can be thrown without wrapping. +*) +let rec is_native_throw cfg t = + is_in_list t cfg.ec_native_throws + +(** + Check if `t` can be caught without wrapping. +*) +let rec is_native_catch cfg t = + is_in_list t cfg.ec_native_catches + +(** + Check if `cls` is or extends (if `check_parent=true`) `haxe.Exception` +*) +let rec is_haxe_exception_class ?(check_parent=true) cls = + cls.cl_path = haxe_exception_type_path + || (check_parent && match cls.cl_super with + | None -> false + | Some (cls, _) -> is_haxe_exception_class ~check_parent cls + ) + +(** + Check if `t` is or extends `haxe.Exception` +*) +let is_haxe_exception ?(check_parent=true) (t:Type.t) = + match Abstract.follow_with_abstracts t with + | TInst (cls, _) -> is_haxe_exception_class ~check_parent cls + | _ -> false + +(** + Check if `v` variable is used in `e` expression +*) +let rec is_var_used v e = + match e.eexpr with + | TLocal v2 -> v == v2 + | _ -> check_expr (is_var_used v) e + +(** + Check if `e` contains any throws or try..catches. +*) +let rec contains_throw_or_try e = + match e.eexpr with + | TThrow _ | TTry _ -> true + | _ -> check_expr contains_throw_or_try e + +(** + Returns `true` if `e` has to be wrapped with `haxe.Exception.thrown(e)` + to be thrown. +*) +let requires_wrapped_throw cfg e = + (* + Check if `e` is of `haxe.Exception` type directly (not a descendant), + but not a `new haxe.Exception(...)` expression. + In this case we delegate the decision to `haxe.Exception.thrown(e)`. + Because it could happen to be a wrapper for a wildcard catch. + *) + let is_stored_haxe_exception() = + is_haxe_exception ~check_parent:false e.etype + && match e.eexpr with + | TNew(_,_,_) -> false + | _ -> true + in + is_stored_haxe_exception() + || (not (is_native_throw cfg e.etype) && not (is_haxe_exception e.etype)) + +(** + Generate a throw of a native exception. +*) +let throw_native ctx e_thrown t p = + let e_native = + if requires_wrapped_throw ctx.config e_thrown then + let thrown = haxe_exception_static_call ctx "thrown" [e_thrown] p in + if is_dynamic ctx.base_throw_type then thrown + else mk_cast thrown ctx.base_throw_type p + else + e_thrown + in + mk (TThrow e_native) t p + +let set_needs_exception_stack v = + if not (Meta.has Meta.NeedsExceptionStack v.v_meta) then + v.v_meta <- (Meta.NeedsExceptionStack,[],null_pos) :: v.v_meta + +(** + Transform user-written `catches` to a set of catches, which would not require + special handling in the target generator. + + For example: + ``` + } catch(e:SomeNativeError) { + doStuff(); + } catch(e:String) { + trace(e); + } + ``` + is transformed into + ``` + } catch(e:SomeNativeError) { + doStuff(); + } catch(etmp:WildCardNativeException) { + var ehx:haxe.Exception = haxe.Exception.caught(etmp); + if(Std.isOfType(ehx.unwrap(), String)) { + var e:String = ehx.unwrap(); + trace(e); + } else { + throw etmp; + } + } + ``` +*) +let catch_native ctx catches t p = + let rec transform = function + | [] -> [] + (* Keep catches for native exceptions intact *) + | (v,_) as current :: rest when (is_native_catch ctx.config v.v_type) + (* + In case haxe.Exception extends native exception on current target. + We don't want it to be generated as a native catch. + *) + && not (fast_eq ctx.haxe_exception_type (follow v.v_type)) -> + current :: (transform rest) + (* Everything else falls into `if(Std.is(e, ExceptionType)`-fest *) + | rest -> + let catch_var = gen_local ctx.typer ctx.wildcard_catch_type null_pos in + let catch_local = mk (TLocal catch_var) catch_var.v_type null_pos in + let body = + let haxe_exception_var = gen_local ctx.typer ctx.haxe_exception_type null_pos in + let haxe_exception_local = mk (TLocal haxe_exception_var) haxe_exception_var.v_type null_pos in + let unwrapped_var = gen_local ctx.typer t_dynamic null_pos in + let unwrapped_local = mk (TLocal unwrapped_var) unwrapped_var.v_type null_pos in + let needs_haxe_exception = ref false + and needs_unwrap = ref false in + let get_haxe_exception() = + needs_haxe_exception := true; + haxe_exception_local + and unwrap() = + needs_haxe_exception := true; + needs_unwrap := true; + unwrapped_local; + in + let catch_var_used = ref false in + let rec transform = function + | (v, body) :: rest -> + let current_t = Abstract.follow_with_abstracts v.v_type in + let var_used = is_var_used v body in + (* catch(e:ExtendsHaxeError) *) + if is_haxe_exception current_t then + let condition = + (* catch(e:haxe.Exception) is a wildcard catch *) + if fast_eq ctx.haxe_exception_type current_t then + mk (TConst (TBool true)) ctx.basic.tbool v.v_pos + else begin + std_is ctx (get_haxe_exception()) v.v_type v.v_pos + end + in + let body = + if var_used then + mk (TBlock [ + (* var v:ExceptionType = cast haxe_exception_local; *) + mk (TVar (v, Some (mk_cast (get_haxe_exception()) v.v_type null_pos))) ctx.basic.tvoid null_pos; + body + ]) body.etype body.epos + else + body + in + compose condition body rest + (* catch(e:Dynamic) *) + else if current_t == t_dynamic then + begin + set_needs_exception_stack catch_var; + (* this is a wildcard catch *) + let condition = mk (TConst (TBool true)) ctx.basic.tbool v.v_pos in + let body = + mk (TBlock [ + (* var v:Dynamic = haxe_exception_local.unwrap(); *) + if var_used then + mk (TVar (v, Some (unwrap()))) ctx.basic.tvoid null_pos + else + mk (TBlock[]) ctx.basic.tvoid null_pos; + body + ]) body.etype body.epos + in + compose condition body rest + end + (* catch(e:NativeWildcardException) *) + else if fast_eq ctx.wildcard_catch_type current_t then + begin + set_needs_exception_stack catch_var; + (* this is a wildcard catch *) + let condition = mk (TConst (TBool true)) ctx.basic.tbool v.v_pos in + let body = + mk (TBlock [ + (* var v:NativeWildcardException = catch_var; *) + if var_used then + mk (TVar (v, Some catch_local)) ctx.basic.tvoid null_pos + else + mk (TBlock[]) ctx.basic.tvoid null_pos; + body + ]) body.etype body.epos + in + compose condition body rest + end + (* catch(e:AnythingElse) *) + else begin + set_needs_exception_stack catch_var; + let condition = + catch_var_used := true; + (* Std.isOfType(haxe_exception_local.unwrap(), ExceptionType) *) + std_is ctx (unwrap()) v.v_type v.v_pos + in + let body = + mk (TBlock [ + (* var v:ExceptionType = cast haxe_exception_local.unwrap() *) + if var_used then + mk (TVar (v, Some (mk_cast (unwrap()) v.v_type null_pos))) ctx.basic.tvoid null_pos + else + mk (TBlock[]) ctx.basic.tvoid null_pos; + body + ]) body.etype body.epos + in + compose condition body rest + end + | [] -> mk (TThrow catch_local) t p + and compose condition body rest_catches = + let else_body = + match rest_catches with + | [] -> mk (TThrow catch_local) (mk_mono()) p + | _ -> transform rest_catches + in + mk (TIf(condition, body, Some else_body)) t p + in + let transformed_catches = transform rest in + (* haxe.Exception.caught(catch_var) *) + let caught = haxe_exception_static_call ctx "caught" [catch_local] null_pos in + let exprs = [ + (* var haxe_exception_local = haxe.Exception.caught(catch_var); *) + if !needs_haxe_exception then + (mk (TVar (haxe_exception_var, Some caught)) ctx.basic.tvoid null_pos) + else + mk (TBlock[]) ctx.basic.tvoid null_pos; + (* var unwrapped_local = haxe_exception_local.unwrap(); *) + if !needs_unwrap then + let unwrap = haxe_exception_instance_call ctx haxe_exception_local "unwrap" [] null_pos in + mk (TVar (unwrapped_var, Some unwrap)) ctx.basic.tvoid null_pos + else + mk (TBlock[]) ctx.basic.tvoid null_pos; + transformed_catches + ] in + mk (TBlock exprs) t p + in (* let body = *) + [(catch_var,body)] + in + transform catches + +(** + Transform `throw` and `try..catch` expressions. + `rename_locals` is required to deal with the names of temp vars. +*) +let filter tctx = + let stub e = e in + match tctx.com.platform with (* TODO: implement for all targets *) + | Php | Js | Java | Cs | Python | Lua | Eval | Neko | Flash | Hl | Cpp -> + let config = tctx.com.config.pf_exceptions in + let tp (pack,name) = + match List.rev pack with + | module_name :: pack_rev when not (Ast.is_lower_ident module_name) -> + (mk_type_path ~sub:name (List.rev pack_rev,module_name), null_pos) + | _ -> + (mk_type_path (pack,name), null_pos) + in + let wildcard_catch_type = + let t = Typeload.load_instance tctx (tp config.ec_wildcard_catch) true in + if is_dynamic t then t_dynamic + else t + and base_throw_type = + let t = Typeload.load_instance tctx (tp config.ec_base_throw) true in + if is_dynamic t then t_dynamic + else t + and haxe_exception_type, haxe_exception_class = + match Typeload.load_instance tctx (tp haxe_exception_type_path) true with + | TInst(cls,_) as t -> t,cls + | _ -> error "haxe.Exception is expected to be a class" null_pos + and haxe_native_stack_trace = + match Typeload.load_instance tctx (tp (["haxe"],"NativeStackTrace")) true with + | TInst(cls,_) -> cls + | TAbstract({ a_impl = Some cls },_) -> cls + | _ -> error "haxe.NativeStackTrace is expected to be a class or an abstract" null_pos + in + let ctx = { + typer = tctx; + basic = tctx.t; + config = config; + wildcard_catch_type = wildcard_catch_type; + base_throw_type = base_throw_type; + haxe_exception_class = haxe_exception_class; + haxe_exception_type = haxe_exception_type; + haxe_native_stack_trace = haxe_native_stack_trace; + } in + let rec run e = + match e.eexpr with + | TThrow e1 -> + { e with eexpr = TThrow (throw_native ctx (run e1) e.etype e.epos) } + | TTry(e1,catches) -> + let catches = + let catches = List.map (fun (v,e) -> (v,run e)) catches in + (catch_native ctx catches e.etype e.epos) + in + { e with eexpr = TTry(run e1,catches) } + | _ -> + map_expr run e + in + (fun e -> + if contains_throw_or_try e then run e + else stub e + ) + | Cross -> stub + +(** + Inserts `haxe.NativeStackTrace.saveStack(e)` in non-haxe.Exception catches. +*) +let insert_save_stacks tctx = + if not (has_feature tctx.com "haxe.NativeStackTrace.exceptionStack") then + (fun e -> e) + else + let native_stack_trace_cls = + let tp = mk_type_path (["haxe"],"NativeStackTrace") in + match Typeload.load_type_def tctx null_pos tp with + | TClassDecl cls -> cls + | TAbstractDecl { a_impl = Some cls } -> cls + | _ -> error "haxe.NativeStackTrace is expected to be a class or an abstract" null_pos + in + let rec contains_insertion_points e = + match e.eexpr with + | TTry (e, catches) -> + List.exists (fun (v, _) -> Meta.has Meta.NeedsExceptionStack v.v_meta) catches + || contains_insertion_points e + || List.exists (fun (_, e) -> contains_insertion_points e) catches + | _ -> + check_expr contains_insertion_points e + in + let save_exception_stack catch_var = + (* GOTCHA: `has_feature` always returns `true` if executed before DCE filters *) + if has_feature tctx.com "haxe.NativeStackTrace.exceptionStack" then + let method_field = + try PMap.find "saveStack" native_stack_trace_cls.cl_statics + with Not_found -> error ("haxe.NativeStackTrace has no field saveStack") null_pos + in + let return_type = + match follow method_field.cf_type with + | TFun(_,t) -> t + | _ -> error ("haxe.NativeStackTrace." ^ method_field.cf_name ^ " is not a function and cannot be called") null_pos + in + let catch_local = mk (TLocal catch_var) catch_var.v_type null_pos in + make_static_call tctx native_stack_trace_cls method_field (fun t -> t) [catch_local] return_type null_pos + else + mk (TBlock[]) tctx.t.tvoid null_pos + in + let rec run e = + match e.eexpr with + | TTry (e1, catches) -> + let e1 = map_expr run e1 in + let catches = + List.map (fun ((v, body) as catch) -> + if Meta.has Meta.NeedsExceptionStack v.v_meta then + let exprs = + match body.eexpr with + | TBlock exprs -> + save_exception_stack v :: exprs + | _ -> + [save_exception_stack v; body] + in + (v, { body with eexpr = TBlock exprs }) + else + catch + ) catches + in + { e with eexpr = TTry (e1, catches) } + | _ -> + map_expr run e + in + (fun e -> + if contains_insertion_points e then run e + else e + ) + +(** + Adds `this.__shiftStack()` calls to constructors of classes which extend `haxe.Exception` +*) +let patch_constructors tctx = + let tp = (mk_type_path haxe_exception_type_path, null_pos) in + match Typeload.load_instance tctx tp true with + (* Add only if `__shiftStack` method exists *) + | TInst(cls,_) when PMap.mem "__shiftStack" cls.cl_fields -> + (fun mt -> + match mt with + | TClassDecl cls when not cls.cl_extern && cls.cl_path <> haxe_exception_type_path && is_haxe_exception_class cls -> + let shift_stack p = + let t = type_of_module_type mt in + let this = { eexpr = TConst(TThis); etype = t; epos = p } in + let faccess = + try quick_field t "__shiftStack" + with Not_found -> error "haxe.Exception has no field __shiftStack" p + in + match faccess with + | FInstance (_,_,cf) -> + let efield = { eexpr = TField(this,faccess); etype = cf.cf_type; epos = p } in + let rt = + match follow cf.cf_type with + | TFun(_,t) -> t + | _ -> + error "haxe.Exception.__shiftStack is not a function and cannot be called" cf.cf_name_pos + in + make_call tctx efield [] rt p + | _ -> error "haxe.Exception.__shiftStack is expected to be an instance method" p + in + TypeloadFunction.add_constructor tctx cls true cls.cl_name_pos; + Option.may (fun cf -> ignore(follow cf.cf_type)) cls.cl_constructor; + (match cls.cl_constructor with + | Some ({ cf_expr = Some e_ctor } as ctor) -> + let rec add e = + match e.eexpr with + | TFunction _ -> e + | TReturn _ -> mk (TBlock [shift_stack e.epos; e]) e.etype e.epos + | _ -> map_expr add e + in + (ctor.cf_expr <- match e_ctor.eexpr with + | TFunction fn -> + Some { e_ctor with + eexpr = TFunction { fn with + tf_expr = mk (TBlock [add fn.tf_expr; shift_stack fn.tf_expr.epos]) tctx.t.tvoid fn.tf_expr.epos + } + } + | _ -> die "" __LOC__ + ) + | None -> die "" __LOC__ + | _ -> () + ) + | _ -> () + ) + | _ -> (fun _ -> ()) \ No newline at end of file diff --git a/src/filters/filters.ml b/src/filters/filters.ml index bc80bfc9d0ad5284f137516e93b7624cff69e746..9ae20430c342493b2db4385d9ec2e48da54fcee1 100644 --- a/src/filters/filters.ml +++ b/src/filters/filters.ml @@ -69,7 +69,7 @@ let rec add_final_return e = (* -------------------------------------------------------------------------- *) (* CHECK LOCAL VARS INIT *) -let check_local_vars_init e = +let check_local_vars_init com e = let intersect vl1 vl2 = PMap.mapi (fun v t -> t && PMap.find v vl2) vl1 in @@ -88,9 +88,13 @@ let check_local_vars_init e = match e.eexpr with | TLocal v -> let init = (try PMap.find v.v_id !vars with Not_found -> true) in - if not init && not (IntMap.mem v.v_id !outside_vars) then begin - if v.v_name = "this" then error "Missing this = value" e.epos - else error ("Local variable " ^ v.v_name ^ " used without being initialized") e.epos + if not init then begin + if IntMap.mem v.v_id !outside_vars then + if v.v_name = "this" then com.warning "this might be used before assigning a value to it" e.epos + else com.warning ("Local variable " ^ v.v_name ^ " might be used before being initialized") e.epos + else + if v.v_name = "this" then error "Missing this = value" e.epos + else error ("Local variable " ^ v.v_name ^ " used without being initialized") e.epos end | TVar (v,eo) -> begin @@ -188,110 +192,6 @@ let check_local_vars_init e = loop (ref PMap.empty) e; e -(* -------------------------------------------------------------------------- *) -(* RENAME LOCAL VARS *) - -let collect_reserved_local_names com = - match com.platform with - | Js -> - let h = ref StringMap.empty in - let add name = h := StringMap.add name true !h in - List.iter (fun mt -> - let tinfos = t_infos mt in - let native_name = try fst (get_native_name tinfos.mt_meta) with Not_found -> Path.flat_path tinfos.mt_path in - if native_name = "" then - match mt with - | TClassDecl c -> - List.iter (fun cf -> - let native_name = try fst (get_native_name cf.cf_meta) with Not_found -> cf.cf_name in - add native_name - ) c.cl_ordered_statics; - | _ -> () - else - add native_name - ) com.types; - !h - | _ -> StringMap.empty - -let rename_local_vars ctx reserved e = - let vars = ref [] in - let declare v = - vars := v :: !vars - in - let reserved = ref reserved in - let reserve name = - reserved := StringMap.add name true !reserved - in - let check t = - match (t_infos t).mt_path with - | [], name | name :: _, _ -> reserve name - in - let check_type t = - match follow t with - | TInst (c,_) -> check (TClassDecl c) - | TEnum (e,_) -> check (TEnumDecl e) - | TType (t,_) -> check (TTypeDecl t) - | TAbstract (a,_) -> check (TAbstractDecl a) - | TMono _ | TLazy _ | TAnon _ | TDynamic _ | TFun _ -> () - in - let rec collect e = match e.eexpr with - | TVar(v,eo) -> - declare v; - (match eo with None -> () | Some e -> collect e) - | TFor(v,e1,e2) -> - declare v; - collect e1; - collect e2; - | TTry(e1,catches) -> - collect e1; - List.iter (fun (v,e) -> - declare v; - check_type v.v_type; - collect e - ) catches - | TFunction tf -> - List.iter (fun (v,_) -> declare v) tf.tf_args; - collect tf.tf_expr - | TTypeExpr t -> - check t - | TNew (c,_,_) -> - Type.iter collect e; - check (TClassDecl c); - | TCast (e,Some t) -> - collect e; - check t; - | TConst TSuper -> - check_type e.etype - | _ -> - Type.iter collect e - in - (* Pass 1: Collect used identifiers and variables. *) - reserve "this"; - if ctx.com.platform = Java then reserve "_"; - begin match ctx.curclass.cl_path with - | s :: _,_ | [],s -> reserve s - end; - collect e; - (* Pass 2: Check and rename variables. *) - let count_table = Hashtbl.create 0 in - let maybe_rename v = - (* chop escape char for all local variables generated *) - if is_gen_local v then v.v_name <- "_g" ^ String.sub v.v_name 1 (String.length v.v_name - 1); - let name = ref v.v_name in - let count = ref (try Hashtbl.find count_table v.v_name with Not_found -> 0) in - while StringMap.mem !name !reserved do - incr count; - name := v.v_name ^ (string_of_int !count); - done; - reserve !name; - Hashtbl.replace count_table v.v_name !count; - if not (Meta.has Meta.RealPath v.v_meta) then - v.v_meta <- (Meta.RealPath,[EConst (String(v.v_name,SDoubleQuotes)),e.epos],e.epos) :: v.v_meta; - v.v_name <- !name; - in - List.iter maybe_rename (List.rev !vars); - e - let mark_switch_break_loops e = let add_loop_label n e = { e with eexpr = TMeta ((Meta.LoopLabel,[(EConst(Int(string_of_int n)),e.epos)],e.epos), e) } @@ -544,8 +444,7 @@ let add_rtti ctx t = () (* Adds member field initializations as assignments to the constructor *) -let add_field_inits reserved ctx t = - let is_as3 = Common.defined ctx.com Define.As3 && not ctx.in_macro in +let add_field_inits locals ctx t = let apply c = let ethis = mk (TConst TThis) (TInst (c,List.map snd c.cl_params)) c.cl_pos in (* TODO: we have to find a variable name which is not used in any of the functions *) @@ -553,28 +452,7 @@ let add_field_inits reserved ctx t = let need_this = ref false in let inits,fields = List.fold_left (fun (inits,fields) cf -> match cf.cf_kind,cf.cf_expr with - | Var _, Some _ -> - if is_as3 then (inits, cf :: fields) else (cf :: inits, cf :: fields) - | Method MethDynamic, Some e when is_as3 -> - (* TODO : this would have a better place in genSWF9 I think - NC *) - (* we move the initialization of dynamic functions to the constructor and also solve the - 'this' problem along the way *) - let rec use_this v e = match e.eexpr with - | TConst TThis -> - need_this := true; - mk (TLocal v) v.v_type e.epos - | _ -> Type.map_expr (use_this v) e - in - let e = Type.map_expr (use_this v) e in - let cf2 = {cf with cf_expr = Some e} in - (* if the method is an override, we have to remove the class field to not get invalid overrides *) - let fields = if List.memq cf c.cl_overrides then begin - c.cl_fields <- PMap.remove cf.cf_name c.cl_fields; - fields - end else - cf2 :: fields - in - (cf2 :: inits, fields) + | Var _, Some _ -> (cf :: inits, cf :: fields) | _ -> (inits, cf :: fields) ) ([],[]) c.cl_ordered_fields in c.cl_ordered_fields <- (List.rev fields); @@ -583,16 +461,11 @@ let add_field_inits reserved ctx t = | _ -> let el = List.map (fun cf -> match cf.cf_expr with - | None -> assert false + | None -> die "" __LOC__ | Some e -> let lhs = mk (TField({ ethis with epos = cf.cf_pos },FInstance (c,List.map snd c.cl_params,cf))) cf.cf_type cf.cf_pos in cf.cf_expr <- None; - let eassign = mk (TBinop(OpAssign,lhs,e)) cf.cf_type e.epos in - if is_as3 then begin - let echeck = mk (TBinop(OpEq,lhs,(mk (TConst TNull) lhs.etype e.epos))) ctx.com.basic.tbool e.epos in - mk (TIf(echeck,eassign,None)) eassign.etype e.epos - end else - eassign; + mk (TBinop(OpAssign,lhs,e)) cf.cf_type e.epos ) inits in let el = if !need_this then (mk (TVar((v, Some ethis))) ethis.etype ethis.epos) :: el else el in let cf = match c.cl_constructor with @@ -613,14 +486,14 @@ let add_field_inits reserved ctx t = let ce = mk (TFunction {f with tf_expr = mk (TBlock (el @ bl)) ctx.com.basic.tvoid c.cl_pos }) cf.cf_type cf.cf_pos in {cf with cf_expr = Some ce }; | _ -> - assert false + die "" __LOC__ in let config = AnalyzerConfig.get_field_config ctx.com c cf in Analyzer.Run.run_on_field ctx config c cf; (match cf.cf_expr with | Some e -> (* This seems a bit expensive, but hopefully constructor expressions aren't that massive. *) - let e = rename_local_vars ctx reserved e in + let e = RenameVars.run ctx locals e in let e = Optimizer.sanitize ctx.com e in cf.cf_expr <- Some e | _ -> @@ -643,7 +516,6 @@ let add_meta_field ctx t = match t with let cf = mk_field "__meta__" e.etype e.epos null_pos in cf.cf_expr <- Some e; let can_deal_with_interface_metadata () = match ctx.com.platform with - | Flash when Common.defined ctx.com Define.As3 -> false | Cs | Java -> false | _ -> true in @@ -699,7 +571,7 @@ let check_cs_events com t = match t with (* add @:keep to event methods if the event is kept *) if Meta.has Meta.Keep f.cf_meta && not (Meta.has Meta.Keep m.cf_meta) then - m.cf_meta <- (Meta.Keep,[],f.cf_pos) :: m.cf_meta; + m.cf_meta <- (Dce.mk_keep_meta f.cf_pos) :: m.cf_meta; in process_event_method ("add_" ^ f.cf_name); process_event_method ("remove_" ^ f.cf_name) @@ -809,7 +681,7 @@ module ForRemap = struct end let run com tctx main = - let detail_times = Common.raw_defined com "filter-times" in + let detail_times = Common.defined com DefineList.FilterTimes in let new_types = List.filter (fun t -> let cached = is_cached t in begin match t with @@ -837,7 +709,7 @@ let run com tctx main = NullSafety.run com new_types; (* PASS 1: general expression filters *) let filters = [ - (* ForRemap.apply tctx; *) + ForRemap.apply tctx; VarLazifier.apply com; AbstractCast.handle_abstract_casts tctx; ] in @@ -846,26 +718,22 @@ let run com tctx main = t(); let filters = [ fix_return_dynamic_from_void_function tctx true; - check_local_vars_init; + check_local_vars_init tctx.com; check_abstract_as_value; - if Common.defined com Define.OldConstructorInline then Optimizer.inline_constructors tctx else InlineConstructors.inline_constructors tctx; + if defined com Define.AnalyzerOptimize then Tre.run tctx else (fun e -> e); Optimizer.reduce_expression tctx; + if Common.defined com Define.OldConstructorInline then Optimizer.inline_constructors tctx else InlineConstructors.inline_constructors tctx; + Exceptions.filter tctx; CapturedVars.captured_vars com; ] in let filters = match com.platform with | Cs -> SetHXGen.run_filter com new_types; - filters @ [ - TryCatchWrapper.configure_cs com - ] + filters | Java when not (Common.defined com Jvm)-> SetHXGen.run_filter com new_types; - filters @ [ - TryCatchWrapper.configure_java com - ] - | Js -> - filters @ [JsExceptions.init tctx]; + filters | _ -> filters in let t = filter_timer detail_times ["expr 1"] in @@ -892,13 +760,13 @@ let run com tctx main = com.stage <- CAnalyzerStart; if com.platform <> Cross then Analyzer.Run.run_on_types tctx new_types; com.stage <- CAnalyzerDone; - let reserved = collect_reserved_local_names com in + let locals = RenameVars.init com in let filters = [ Optimizer.sanitize com; if com.config.pf_add_final_return then add_final_return else (fun e -> e); (match com.platform with | Eval -> (fun e -> e) - | _ -> rename_local_vars tctx reserved); + | _ -> RenameVars.run tctx locals); mark_switch_break_loops; ] in let t = filter_timer detail_times ["expr 2"] in @@ -929,11 +797,7 @@ let run com tctx main = com.stage <- CDceStart; let t = filter_timer detail_times ["dce"] in (* DCE *) - let dce_mode = if Common.defined com Define.As3 then - "no" - else - (try Common.defined_value com Define.Dce with _ -> "no") - in + let dce_mode = try Common.defined_value com Define.Dce with _ -> "no" in let dce_mode = match dce_mode with | "full" -> if Common.defined com Define.Interp then Dce.DceNo else DceFull | "std" -> DceStd @@ -944,11 +808,13 @@ let run com tctx main = t(); com.stage <- CDceDone; (* PASS 3: type filters post-DCE *) + List.iter (run_expression_filters tctx [Exceptions.insert_save_stacks tctx]) new_types; let type_filters = [ + Exceptions.patch_constructors; check_private_path; apply_native_paths; add_rtti; - (match com.platform with | Java | Cs -> (fun _ _ -> ()) | _ -> add_field_inits reserved); + (match com.platform with | Java | Cs -> (fun _ _ -> ()) | _ -> add_field_inits locals); (match com.platform with Hl -> (fun _ _ -> ()) | _ -> add_meta_field); check_void_field; (match com.platform with | Cpp -> promote_first_interface_to_super | _ -> (fun _ _ -> ()) ); @@ -957,7 +823,6 @@ let run com tctx main = ] in let type_filters = match com.platform with | Cs -> type_filters @ [ fun _ t -> InterfaceProps.run t ] - | Js -> JsExceptions.inject_callstack com type_filters | _ -> type_filters in let t = filter_timer detail_times ["type 3"] in diff --git a/src/filters/filtersCommon.ml b/src/filters/filtersCommon.ml index fc31b179382746d91acbe6872de51b5105b73157..6d9bad46751b814fd04c8f7ce7d261fb5a865f8e 100644 --- a/src/filters/filtersCommon.ml +++ b/src/filters/filtersCommon.ml @@ -38,6 +38,16 @@ let rec is_removable_class c = | _ -> false +(** + Check if `field` is overridden in subclasses +*) +let is_overridden cls field = + let rec loop_inheritance c = + (PMap.mem field.cf_name c.cl_fields) + || List.exists (fun d -> loop_inheritance d) c.cl_descendants; + in + List.exists (fun d -> loop_inheritance d) cls.cl_descendants + let run_expression_filters ctx filters t = let run e = List.fold_left (fun e f -> f e) e filters diff --git a/src/filters/jsExceptions.ml b/src/filters/jsExceptions.ml deleted file mode 100644 index c7f537d63601459698162442f9e1ec42b4925ea1..0000000000000000000000000000000000000000 --- a/src/filters/jsExceptions.ml +++ /dev/null @@ -1,212 +0,0 @@ -(* - The Haxe Compiler - Copyright (C) 2005-2019 Haxe Foundation - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - *) - -(* - This filter handles everything related to exceptions for the JavaScript target: - - - wrapping non-js.Error types in HaxeError on throwing - - unwrapping HaxeError on catch - - transforming series of catches into a single catch with Std.is checks (optimized) - - re-throwing caught exception with js.Lib.rethrow - - storing caught exception in haxe.CallStack.lastException (if haxe.CallStack is used) - - Basically it translates this: - - try throw "fail" - catch (e:String) { trace(e); js.Lib.rethrow(); } - catch (e:Bool) {} - - into something like this (JS): - - try { - throw new HaxeError("fail"); - } catch (e) { - haxe.CallStack.lastException = e; - var e1 = (e instanceof HaxeError) e.val : e; - if (typeof e1 == "string") { - trace(e1); - throw e; - } else if (typeof e1 == "boolean") { - } else { - throw e; - } - } -*) - -open Common -open Type -open Typecore -open Texpr.Builder - -let follow = Abstract.follow_with_abstracts - -let rec is_js_error c = - match c with - | { cl_path = ["js";"lib"],"Error" } -> true - | { cl_super = Some (csup,_) } -> is_js_error csup - | _ -> false - -let find_cl com path = - ExtList.List.find_map (function - | TClassDecl c when c.cl_path = path -> Some c - | _ -> None - ) com.types - -let init ctx = - let cJsError = find_cl ctx.com (["js";"lib"],"Error") in - let cHaxeError = find_cl ctx.com (["js";"_Boot"],"HaxeError") in - let cStd = find_cl ctx.com ([],"Std") in - let cBoot = find_cl ctx.com (["js"],"Boot") in - let cSyntax = find_cl ctx.com (["js"],"Syntax") in - - let dynamic_wrap e = - let eHaxeError = make_static_this cHaxeError e.epos in - fcall eHaxeError "wrap" [e] (TInst (cJsError, [])) e.epos - in - - let static_wrap e = - { e with eexpr = TNew (cHaxeError,[],[e]); etype = TInst (cHaxeError,[]) } - in - - let rec loop vrethrow e = - match e.eexpr with - | TThrow eexc -> - let eexc = loop vrethrow eexc in - let eexc = - match follow eexc.etype with - | TDynamic _ | TMono _ -> - (match eexc.eexpr with - | TConst (TInt _ | TFloat _ | TString _ | TBool _ | TNull) -> static_wrap eexc - | _ -> dynamic_wrap eexc) - | TInst (c,_) when (is_js_error c) -> - eexc - | _ -> - static_wrap eexc - in - { e with eexpr = TThrow eexc } - - | TCall ({ eexpr = TField (_, FStatic ({ cl_path = ["js"],"Lib" }, { cf_name = "getOriginalException" })) }, _) -> - (match vrethrow with - | Some erethrowvar -> erethrowvar - | None -> abort "js.Lib.getOriginalException can only be called inside a catch block" e.epos) - - | TCall ({ eexpr = TField (_, FStatic ({ cl_path = ["js"],"Lib" }, { cf_name = "rethrow" })) }, _) -> - (match vrethrow with - | Some erethrowvar -> { e with eexpr = TThrow erethrowvar } - | None -> abort "js.Lib.rethrow can only be called inside a catch block" e.epos) - - | TTry (etry, catches) -> - let etry = loop vrethrow etry in - - let catchall_name, catchall_kind = match catches with [(v,_)] -> v.v_name, (VUser TVOCatchVariable) | _ -> "e", VGenerated in - let vcatchall = alloc_var catchall_kind catchall_name t_dynamic e.epos in - let ecatchall = make_local vcatchall e.epos in - let erethrow = mk (TThrow ecatchall) t_dynamic e.epos in - - let eSyntax = make_static_this cSyntax e.epos in - let eHaxeError = make_static_this cHaxeError e.epos in - let eInstanceof = fcall eSyntax "instanceof" [ecatchall;eHaxeError] ctx.com.basic.tbool e.epos in - let eVal = field { ecatchall with etype = TInst (cHaxeError,[]) } "val" t_dynamic e.epos in - let eunwrap = mk (TIf (eInstanceof, eVal, Some (ecatchall))) t_dynamic e.epos in - - let vunwrapped = alloc_var catchall_kind catchall_name t_dynamic e.epos in - vunwrapped.v_kind <- VGenerated; - let eunwrapped = make_local vunwrapped e.epos in - - let ecatch = List.fold_left (fun acc (v,ecatch) -> - let ecatch = loop (Some ecatchall) ecatch in - - (* it's not really compiler-generated, but it kind of is, since it was used as catch identifier and we add a TVar for it *) - v.v_kind <- VGenerated; - - match follow v.v_type with - | TDynamic _ -> - { ecatch with - eexpr = TBlock [ - mk (TVar (v, Some eunwrapped)) ctx.com.basic.tvoid ecatch.epos; - ecatch; - ] - } - | t -> - let etype = make_typeexpr (module_type_of_type t) e.epos in - let args = [eunwrapped;etype] in - let echeck = - match Inline.api_inline ctx cStd "is" args e.epos with - | Some e -> e - | None -> - let eBoot = make_static_this cBoot e.epos in - fcall eBoot "__instanceof" [eunwrapped;etype] ctx.com.basic.tbool e.epos - in - let ecatch = { ecatch with - eexpr = TBlock [ - mk (TVar (v, Some eunwrapped)) ctx.com.basic.tvoid ecatch.epos; - ecatch; - ] - } in - mk (TIf (echeck, ecatch, Some acc)) e.etype e.epos - ) erethrow (List.rev catches) in - - let ecatch = { ecatch with - eexpr = TBlock [ - mk (TVar (vunwrapped, Some eunwrap)) ctx.com.basic.tvoid e.epos; - ecatch; - ] - } in - { e with eexpr = TTry (etry, [(vcatchall,ecatch)]) } - | _ -> - Type.map_expr (loop vrethrow) e - in - loop None - -let inject_callstack com type_filters = - let cCallStack = - if Common.has_dce com then - if Common.has_feature com "haxe.CallStack.lastException" then - Some (find_cl com (["haxe"],"CallStack")) - else - None - else - try Some (find_cl com (["haxe"],"CallStack")) with Not_found -> None - in - match cCallStack with - | Some cCallStack -> - let run mt e = - let rec loop e = - match e.eexpr with - | TTry (etry,[(v,ecatch)]) -> - let etry = loop etry in - let ecatch = loop ecatch in - add_dependency (t_infos mt).mt_module cCallStack.cl_module; - let eCallStack = make_static_this cCallStack ecatch.epos in - let elastException = field eCallStack "lastException" t_dynamic ecatch.epos in - let elocal = make_local v ecatch.epos in - let eStoreException = mk (TBinop (Ast.OpAssign, elastException, elocal)) ecatch.etype ecatch.epos in - let ecatch = Type.concat eStoreException ecatch in - { e with eexpr = TTry (etry,[(v,ecatch)]) } - | TTry _ -> - (* this should be handled by the filter above *) - assert false - | _ -> - Type.map_expr loop e - in - loop e - in - type_filters @ [ fun ctx t -> FiltersCommon.run_expression_filters ctx [run t] t ] - | None -> - type_filters diff --git a/src/filters/renameVars.ml b/src/filters/renameVars.ml new file mode 100644 index 0000000000000000000000000000000000000000..f55ed3ef7b6fed661933ee5c831286a0311ba0c2 --- /dev/null +++ b/src/filters/renameVars.ml @@ -0,0 +1,318 @@ +open Globals +open Type +open Typecore +open Common +open Ast + +type rename_init = { + mutable ri_scope : var_scope; + mutable ri_hoisting : bool; + mutable ri_no_shadowing : bool; + mutable ri_switch_cases_no_blocks : bool; + mutable ri_reserved : bool StringMap.t; + mutable ri_reserve_current_top_level_symbol : bool; +} + +(** + For initialization. + Make the `name` a reserved word. + No local variable will be allowed to have such name. +*) +let reserve_init ri name = + ri.ri_reserved <- StringMap.add name true ri.ri_reserved + +(** + Make all class names reserved names. + No local variable will have a name matching a class. +*) +let reserve_all_types ri com path_to_name = + List.iter (fun mt -> + let tinfos = t_infos mt in + let native_name = try fst (TypeloadCheck.get_native_name tinfos.mt_meta) with Not_found -> path_to_name tinfos.mt_path in + if native_name = "" then + match mt with + | TClassDecl c -> + List.iter (fun cf -> + let native_name = try fst (TypeloadCheck.get_native_name cf.cf_meta) with Not_found -> cf.cf_name in + reserve_init ri native_name + ) c.cl_ordered_statics; + | _ -> () + else + reserve_init ri native_name + ) com.types + +(** + Initialize the context for local variables renaming +*) +let init com = + let ri = { + ri_scope = com.config.pf_scoping.vs_scope; + ri_reserved = StringMap.empty; + ri_hoisting = false; + ri_no_shadowing = false; + ri_switch_cases_no_blocks = false; + ri_reserve_current_top_level_symbol = false; + } in + reserve_init ri "this"; + List.iter (fun flag -> + match flag with + | VarHoisting -> + ri.ri_hoisting <- true; + | NoShadowing -> + ri.ri_no_shadowing <- true; + | SwitchCasesNoBlocks -> + ri.ri_switch_cases_no_blocks <- true; + | ReserveNames names -> + List.iter (reserve_init ri) names + | ReserveAllTopLevelSymbols -> + reserve_all_types ri com (fun (pack,name) -> if pack = [] then name else List.hd pack) + | ReserveAllTypesFlat -> + reserve_all_types ri com Path.flat_path + | ReserveCurrentTopLevelSymbol -> ri.ri_reserve_current_top_level_symbol <- true + ) com.config.pf_scoping.vs_flags; + ri + +type scope = { + (** Parent scope *) + parent : scope option; + (** Child scopes *) + mutable children : scope list; + (** + Pairs of "variable declared => the list of variables it overlaps with". + That list contains variables, which were declared _before_ the current one, but + used _after_ the current one was declared. + Example: + ``` + var a = 123; + var b = 324; + trace(a); + ``` + in this example `b` overlaps with `a`. + *) + mutable own_vars : (tvar * (tvar IntMap.t ref)) list; + (** Variables declared outside of this scope, but used inside of it *) + mutable foreign_vars : tvar IntMap.t; + (** List of variables used in current loop *) + loop_vars : tvar IntMap.t ref; + (** Current loops depth *) + mutable loop_count : int; +} + +type rename_context = { + rc_hoisting : bool; + rc_no_shadowing : bool; + rc_switch_cases_no_blocks : bool; + rc_scope : var_scope; + mutable rc_reserved : bool StringMap.t; +} + +(** + Make `name` a reserved word. + No local variable will be allowed to have such name. +*) +let reserve_ctx rc name = + rc.rc_reserved <- StringMap.add name true rc.rc_reserved + +(** + Make `name` a reserved word. + No local variable will be allowed to have such name. +*) +let reserve reserved name = + reserved := StringMap.add name true !reserved + +let create_scope parent = + let scope = { + parent = parent; + children = []; + own_vars = []; + foreign_vars = IntMap.empty; + loop_vars = ref IntMap.empty; + loop_count = 0; + } in + Option.may (fun p -> p.children <- scope :: p.children) parent; + scope + +(** + Invoked for each `TVar v` texpr_expr +*) +let declare_var rc scope v = + let overlaps = + if not rc.rc_hoisting || IntMap.is_empty scope.foreign_vars then + if scope.loop_count = 0 then IntMap.empty + else !(scope.loop_vars) + else + if scope.loop_count = 0 then + scope.foreign_vars + else begin + let overlaps = ref !(scope.loop_vars) in + IntMap.iter (fun i o -> + if not (IntMap.mem i !overlaps) then + overlaps := IntMap.add i o !overlaps + ) scope.foreign_vars; + !overlaps + end + in + scope.own_vars <- (v, ref overlaps) :: scope.own_vars; + if scope.loop_count > 0 then + scope.loop_vars := IntMap.add v.v_id v !(scope.loop_vars) + +(** + Invoked for each `TLocal v` texr_expr +*) +let rec use_var rc scope v = + let rec loop declarations = + match declarations with + | [] -> + if (rc.rc_no_shadowing || rc.rc_hoisting) && not (IntMap.mem v.v_id scope.foreign_vars) then + scope.foreign_vars <- IntMap.add v.v_id v scope.foreign_vars; + (match scope.parent with + | Some parent -> use_var rc parent v + | None -> raise (Failure "Failed to locate variable declaration") + ) + | (d, _) :: _ when d == v -> () + | (d, overlaps) :: rest -> + if not (IntMap.mem v.v_id !overlaps) then + overlaps := IntMap.add v.v_id v !overlaps; + loop rest + in + loop scope.own_vars; + if scope.loop_count > 0 && not (IntMap.mem v.v_id !(scope.loop_vars)) then + scope.loop_vars := IntMap.add v.v_id v !(scope.loop_vars) + +let collect_loop scope fn = + scope.loop_count <- scope.loop_count + 1; + fn(); + scope.loop_count <- scope.loop_count - 1; + if scope.loop_count < 0 then + raise (Failure "Unexpected loop count"); + if scope.loop_count = 0 then + scope.loop_vars := IntMap.empty + +(** + Collect all the variables declared and used in `e` expression. +*) +let rec collect_vars ?(in_block=false) rc scope e = + let collect_vars = + match e.eexpr with + | TBlock _ | TFunction _ -> collect_vars ~in_block:true rc + | _ -> collect_vars ~in_block:false rc + in + match e.eexpr with + | TVar (v, e_opt) when rc.rc_hoisting || (match e_opt with Some { eexpr = TFunction _ } -> true | _ -> false) -> + declare_var rc scope v; + Option.may (collect_vars scope) e_opt + | TVar (v, e_opt) -> + Option.may (collect_vars scope) e_opt; + declare_var rc scope v + | TLocal v -> + use_var rc scope v + | TFunction fn -> + let scope = create_scope (Some scope) in + List.iter (fun (v,_) -> declare_var rc scope v) fn.tf_args; + List.iter (fun (v,_) -> use_var rc scope v) fn.tf_args; + (match fn.tf_expr.eexpr with + | TBlock exprs -> List.iter (collect_vars scope) exprs + | _ -> collect_vars scope fn.tf_expr + ) + | TTry (try_expr, catches) -> + collect_vars scope try_expr; + List.iter (fun (v, catch_expr) -> + declare_var rc scope v; + collect_vars scope catch_expr + ) catches + | TSwitch (target, cases, default_opt) when rc.rc_switch_cases_no_blocks -> + collect_vars scope target; + List.iter (fun (el,e) -> + List.iter (collect_vars scope) el; + collect_ignore_block ~in_block:true rc scope e + ) cases; + Option.may (collect_ignore_block ~in_block:true rc scope) default_opt + | TBlock exprs when rc.rc_scope = BlockScope && not in_block -> + let scope = create_scope (Some scope) in + List.iter (collect_vars scope) exprs + | TWhile (condition, body, flag) -> + collect_loop scope (fun() -> + if flag = NormalWhile then + collect_vars scope condition; + collect_vars scope body; + if flag = DoWhile then + collect_vars scope condition; + ) + (* + This only happens for `cross` target, because for real targets all loops are converted to `while` at this point + Idk if this works correctly. + *) + | TFor (v, iterator, body) -> + collect_loop scope (fun() -> + if rc.rc_hoisting then + declare_var rc scope v; + collect_vars scope iterator; + if not rc.rc_hoisting then + declare_var rc scope v; + collect_vars scope body + ) + | _ -> + iter (collect_vars scope) e + +and collect_ignore_block ?(in_block=false) rc scope e = + match e.eexpr with + | TBlock el -> List.iter (collect_vars ~in_block rc scope) el + | _ -> collect_vars ~in_block rc scope e + +let trailing_numbers = Str.regexp "[0-9]+$" + +(** + Rename `v` if needed +*) +let maybe_rename_var rc reserved (v,overlaps) = + (* chop escape char for all local variables generated *) + if is_gen_local v then begin + let name = String.sub v.v_name 1 (String.length v.v_name - 1) in + v.v_name <- "_g" ^ (Str.replace_first trailing_numbers "" name) + end; + let name = ref v.v_name in + let count = ref 0 in + let same_name _ o = !name = o.v_name in + while ( + StringMap.mem !name !reserved + || IntMap.exists same_name !overlaps + ) do + incr count; + name := v.v_name ^ (string_of_int !count); + done; + v.v_name <- !name; + if rc.rc_no_shadowing || (v.v_capture && rc.rc_hoisting) then reserve reserved v.v_name + +(** + Rename variables found in `scope` +*) +let rec rename_vars rc scope = + let reserved = ref rc.rc_reserved in + if (rc.rc_hoisting || rc.rc_no_shadowing) && not (IntMap.is_empty scope.foreign_vars) then + IntMap.iter (fun _ v -> reserve reserved v.v_name) scope.foreign_vars; + List.iter (maybe_rename_var rc reserved) (List.rev scope.own_vars); + List.iter (rename_vars rc) scope.children + +(** + Rename local variables in `e` expression if needed. +*) +let run ctx ri e = + (try + let rc = { + rc_scope = ri.ri_scope; + rc_hoisting = ri.ri_hoisting; + rc_no_shadowing = ri.ri_no_shadowing; + rc_switch_cases_no_blocks = ri.ri_switch_cases_no_blocks; + rc_reserved = ri.ri_reserved; + } in + if ri.ri_reserve_current_top_level_symbol then begin + match ctx.curclass.cl_path with + | s :: _,_ | [],s -> reserve_ctx rc s + end; + let scope = create_scope None in + collect_vars rc scope e; + rename_vars rc scope; + with Failure msg -> + die ~p:e.epos msg __LOC__ + ); + e \ No newline at end of file diff --git a/src/filters/tre.ml b/src/filters/tre.ml new file mode 100644 index 0000000000000000000000000000000000000000..14f1756fbac43439fcc574c193d7882822909ebf --- /dev/null +++ b/src/filters/tre.ml @@ -0,0 +1,227 @@ +open Type +open Typecore +open Globals + +let rec collect_new_args_values ctx args declarations values n = + match args with + | [] -> declarations, values + | arg :: rest -> + let v = alloc_var VGenerated ("`tmp" ^ (string_of_int n)) arg.etype arg.epos in + let decl = { eexpr = TVar (v, Some arg); etype = ctx.t.tvoid; epos = v.v_pos } + and value = { arg with eexpr = TLocal v } in + collect_new_args_values ctx rest (decl :: declarations) (value :: values) (n + 1) + +let rec assign_args vars exprs = + match vars, exprs with + | [], [] -> [] + | (v, _) :: rest_vars, e :: rest_exprs + | (v, Some e) :: rest_vars, rest_exprs -> + let arg = { e with eexpr = TLocal v } in + { e with eexpr = TBinop (OpAssign, arg, e) } :: assign_args rest_vars rest_exprs + | _ -> die "" __LOC__ + +let replacement_for_TReturn ctx fn args p = + let temps_rev, args_rev = collect_new_args_values ctx args [] [] 0 + and continue = mk TContinue ctx.t.tvoid Globals.null_pos in + { + etype = ctx.t.tvoid; + epos = p; + eexpr = TMeta ((Meta.TailRecursion, [], null_pos), { + eexpr = TBlock ((List.rev temps_rev) @ (assign_args fn.tf_args (List.rev args_rev)) @ [continue]); + etype = ctx.t.tvoid; + epos = p; + }); + } + +let collect_captured_args args e = + let result = ref [] in + let rec loop in_closure e = + match e.eexpr with + | TLocal ({ v_kind = VUser TVOArgument } as v) when in_closure && not (List.memq v !result) && List.memq v args -> + result := v :: !result + | TFunction { tf_expr = e } -> + loop true e + | _ -> + iter (loop in_closure) e + in + loop false e; + !result + +let rec redeclare_vars ctx vars declarations replace_list = + match vars with + | [] -> declarations, replace_list + | v :: rest -> + let new_v = alloc_var VGenerated ("`" ^ v.v_name) v.v_type v.v_pos in + let decl = + { + eexpr = TVar (new_v, Some { eexpr = TLocal v; etype = v.v_type; epos = v.v_pos; }); + etype = ctx.t.tvoid; + epos = v.v_pos; + } + in + redeclare_vars ctx rest (decl :: declarations) ((v, new_v) :: replace_list) + +let rec replace_vars replace_list in_tail_recursion e = + match e.eexpr with + | TBinop (OpAssign, ({ eexpr = TLocal { v_kind = VUser TVOArgument } } as arg), value) when in_tail_recursion -> + let value = replace_vars replace_list in_tail_recursion value in + { e with eexpr = TBinop (OpAssign, arg, value) } + | TLocal v -> + (try + let v = List.assq v replace_list in + { e with eexpr = TLocal v } + with Not_found -> + e + ) + | TMeta ((Meta.TailRecursion, _, _), _) -> map_expr (replace_vars replace_list true) e + | _ -> map_expr (replace_vars replace_list in_tail_recursion) e + +let wrap_loop ctx args body = + let wrap e = + let cond = mk (TConst (TBool true)) ctx.t.tbool Globals.null_pos in + { e with eexpr = TWhile (cond, e, Ast.NormalWhile) } + in + match collect_captured_args args body with + | [] -> wrap body + | captured_args -> + let declarations, replace_list = redeclare_vars ctx captured_args [] [] in + wrap { body with eexpr = TBlock (declarations @ [replace_vars replace_list false body]) } + +let fn_args_vars fn = List.map (fun (v,_) -> v) fn.tf_args + +let is_recursive_named_local_call fn_var callee args = + match callee.eexpr with + (* named local function*) + | TLocal v -> + v == fn_var + | _ -> false + +let is_recursive_method_call cls field callee args = + match callee.eexpr, args with + (* member abstract function*) + | TField (_, FStatic (_, cf)), { eexpr = TLocal v } :: _ when has_meta Meta.Impl cf.cf_meta -> + cf == field && has_meta Meta.This v.v_meta + (* static method *) + | TField (_, FStatic (_, cf)), _ -> + cf == field + | _ -> false + +let rec transform_function ctx is_recursive_call fn = + let add_loop = ref false in + let rec transform_expr cancel_tre function_end e = + match e.eexpr with + (* cancel tre inside of loops bodies *) + | TWhile _ | TFor _ -> + map_expr (transform_expr true false) e + (* cancel tre inside of try blocks *) + | TTry (e_try, catches) -> + let e_try = transform_expr true function_end e_try in + let catches = List.map (fun (v, e) -> v, transform_expr cancel_tre function_end e) catches in + { e with eexpr = TTry (e_try, catches) } + (* named local function *) + | TBinop (OpAssign, ({ eexpr = TLocal ({ v_kind = VUser TVOLocalFunction } as v) } as e_var), ({ eexpr = TFunction fn } as e_fn)) -> + let fn = transform_function ctx (is_recursive_named_local_call v) fn in + { e with eexpr = TBinop (OpAssign, e_var, { e_fn with eexpr = TFunction fn }) } + (* anonymous function *) + | TFunction _ -> + e + (* return a recursive call to current function *) + | TReturn (Some { eexpr = TCall (callee, args) }) when not cancel_tre && is_recursive_call callee args -> + add_loop := true; + replacement_for_TReturn ctx fn args e.epos + | TReturn (Some e_return) -> + { e with eexpr = TReturn (Some (transform_expr cancel_tre function_end e_return)) } + | TBlock exprs -> + let rec loop exprs = + match exprs with + | [] -> [] + | [{ eexpr = TCall (callee, args) } as e] when not cancel_tre && function_end && is_recursive_call callee args -> + add_loop := true; + [replacement_for_TReturn ctx fn args e.epos] + | { eexpr = TCall (callee, args) } :: [{ eexpr = TReturn None }] when not cancel_tre && is_recursive_call callee args -> + add_loop := true; + [replacement_for_TReturn ctx fn args e.epos] + | e :: rest -> + let function_end = function_end && rest = [] in + transform_expr cancel_tre function_end e :: loop rest + in + { e with eexpr = TBlock (loop exprs) } + | _ -> + map_expr (transform_expr cancel_tre function_end) e + in + let body = transform_expr false true fn.tf_expr in + let body = + if !add_loop then + let body = + if ExtType.is_void (follow fn.tf_type) then + mk (TBlock [body; mk (TReturn None) ctx.t.tvoid null_pos]) ctx.t.tvoid null_pos + else + body + in + wrap_loop ctx (fn_args_vars fn) body + else + body + in + { fn with tf_expr = body } + +let rec has_tail_recursion is_recursive_call cancel_tre function_end e = + match e.eexpr with + (* cancel tre inside of loops bodies *) + | TFor _ | TWhile _ -> + check_expr (has_tail_recursion is_recursive_call true false) e + (* cancel tre inside of try blocks *) + | TTry (e, catches) -> + has_tail_recursion is_recursive_call true function_end e + || List.exists (fun (_, e) -> has_tail_recursion is_recursive_call cancel_tre function_end e) catches + (* named local function *) + | TBinop (OpAssign, { eexpr = TLocal ({ v_kind = VUser TVOLocalFunction } as v) }, { eexpr = TFunction fn }) -> + has_tail_recursion (is_recursive_named_local_call v) false true fn.tf_expr + (* anonymous function *) + | TFunction _ -> + false + | TReturn (Some { eexpr = TCall (callee, args)}) -> + not cancel_tre && is_recursive_call callee args + | TBlock exprs -> + let rec loop exprs = + match exprs with + | [] -> false + | [{ eexpr = TCall (callee, args) }] when not cancel_tre && function_end -> + is_recursive_call callee args + | { eexpr = TCall (callee, args) } :: [{ eexpr = TReturn None }] when not cancel_tre -> + is_recursive_call callee args + | e :: rest -> + let function_end = function_end && rest = [] in + has_tail_recursion is_recursive_call cancel_tre function_end e + || loop rest + in + loop exprs + | _ -> + check_expr (has_tail_recursion is_recursive_call cancel_tre function_end) e + +let run ctx = + if Common.defined ctx.com Define.NoTre then + (fun e -> e) + else + (fun e -> + match e.eexpr with + | TFunction fn -> + let is_tre_eligible = + match ctx.curfield.cf_kind with + | Method MethDynamic -> false + | Method MethInline -> true + | Method MethNormal -> + PMap.mem ctx.curfield.cf_name ctx.curclass.cl_statics + | _ -> + has_class_field_flag ctx.curfield CfFinal + in + let is_recursive_call callee args = + is_tre_eligible && is_recursive_method_call ctx.curclass ctx.curfield callee args + in + if has_tail_recursion is_recursive_call false true fn.tf_expr then + (* print_endline ("TRE: " ^ ctx.curfield.cf_pos.pfile ^ ": " ^ ctx.curfield.cf_name); *) + let fn = transform_function ctx is_recursive_call fn in + { e with eexpr = TFunction fn } + else + e + | _ -> e + ) \ No newline at end of file diff --git a/src/filters/tryCatchWrapper.ml b/src/filters/tryCatchWrapper.ml deleted file mode 100644 index e7e4e4c92c5a7bdcc6590e8b565acb74db116ccf..0000000000000000000000000000000000000000 --- a/src/filters/tryCatchWrapper.ml +++ /dev/null @@ -1,187 +0,0 @@ -(* - The Haxe Compiler - Copyright (C) 2005-2019 Haxe Foundation - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*) -open Globals -open Common -open Ast -open Type -open Codegen -open Texpr.Builder - -(* ******************************************* *) -(* Try / Catch + throw native types handling *) -(* ******************************************* *) -(* - Some languages/vm's do not support throwing any kind of value. For them, only - special kinds of objects can be thrown. Because of this, we must wrap some throw - statements with an expression, and also we must unwrap it on the catch() phase, and - maybe manually test with Std.is() -*) - -(* - should_wrap : does the type should be wrapped? This of course works on the reverse way, so it tells us if the type should be unwrapped as well - wrap_throw : the wrapper for throw (throw expr->returning wrapped expression) - unwrap_expr : the other way around : given the catch var (maybe will need casting to wrapper_type) , return the unwrap expr - rethrow_expr : how to rethrow ane exception in the platform - catchall_type : the class used for catchall (e:Dynamic) - wrapper_type : the wrapper type, so we can test if exception is of type 'wrapper' - catch_map : maps the catch expression to include some intialization code (e.g. setting up Stack.exceptionStack) - gen_typecheck : generate Std.is (or similar) check expression for given expression and type -*) -let init com (should_wrap:t->bool) (wrap_throw:texpr->texpr) (unwrap_expr:texpr->texpr) (rethrow_expr:texpr->texpr) (catchall_type:t) (wrapper_type:t) (catch_map:tvar->texpr->texpr) (gen_typecheck:texpr->t->pos->texpr) = - let rec run e = - match e.eexpr with - | TThrow texpr when should_wrap texpr.etype -> - wrap_throw (run texpr) - | TTry (ttry, catches) -> - let nowrap_catches, must_wrap_catches, catchall = List.fold_left (fun (nowrap_catches, must_wrap_catches, catchall) (v, catch) -> - (* first we'll see if the type is Dynamic (catchall) *) - match follow v.v_type with - | TDynamic _ -> - assert (Option.is_none catchall); - (nowrap_catches, must_wrap_catches, Some(v, run catch)) - (* see if we should unwrap it *) - | _ when should_wrap (follow v.v_type) -> - (nowrap_catches, (v,run catch) :: must_wrap_catches, catchall) - | _ -> - ((v,catch_map v (run catch)) :: nowrap_catches, must_wrap_catches, catchall) - ) ([], [], None) catches in - - (* temp (?) fix for https://github.com/HaxeFoundation/haxe/issues/4134 *) - let must_wrap_catches = List.rev must_wrap_catches in - - (* - 1st catch all nowrap "the easy way" - 2nd see if there are any must_wrap or catchall. If there is, - do a catchall first with a temp var. - then get catchall var (as dynamic) (or create one), and declare it = catchall exception - then test if it is of type wrapper_type. If it is, unwrap it - then start doing Std.is() tests for each catch type - if there is a catchall in the end, end with it. If there isn't, rethrow - *) - let dyn_catch = match catchall, must_wrap_catches with - | Some (v,c), _ - | _, (v, c) :: _ -> - let pos = c.epos in - - let temp_var = alloc_var VGenerated "catchallException" catchall_type pos in - let temp_local = make_local temp_var pos in - let catchall_var = alloc_var VGenerated "realException" t_dynamic pos in - let catchall_local = make_local catchall_var pos in - - (* if it is of type wrapper_type, unwrap it *) - let catchall_expr = mk (TIf (gen_typecheck temp_local wrapper_type pos, unwrap_expr temp_local, Some temp_local)) t_dynamic pos in - let catchall_decl = mk (TVar (catchall_var, Some catchall_expr)) com.basic.tvoid pos in - - let rec loop must_wrap_catches = - match must_wrap_catches with - | (vcatch,catch) :: tl -> - mk (TIf (gen_typecheck catchall_local vcatch.v_type catch.epos, - mk (TBlock [(mk (TVar (vcatch, Some(mk_cast (* TODO: this should be a fast non-dynamic cast *) catchall_local vcatch.v_type pos))) com.basic.tvoid catch.epos); catch]) catch.etype catch.epos, - Some (loop tl)) - ) catch.etype catch.epos - | [] -> - match catchall with - | Some (v,s) -> - Type.concat (mk (TVar (v, Some catchall_local)) com.basic.tvoid pos) s - | None -> - mk_block (rethrow_expr temp_local) - in - [(temp_var, catch_map temp_var { e with eexpr = TBlock [catchall_decl; loop must_wrap_catches] })] - | _ -> - [] - in - { e with eexpr = TTry(run ttry, (List.rev nowrap_catches) @ dyn_catch) } - | _ -> - Type.map_expr run e - in - run - -let find_class com path = - let mt = List.find (fun mt -> match mt with TClassDecl c -> c.cl_path = path | _ -> false) com.types in - match mt with TClassDecl c -> c | _ -> assert false - -let configure_cs com = - let base_exception = find_class com (["cs";"system"], "Exception") in - let base_exception_t = TInst(base_exception, []) in - let hx_exception = find_class com (["cs";"internal";"_Exceptions"], "HaxeException") in - let hx_exception_t = TInst (hx_exception, []) in - let exc_cl = find_class com (["cs";"internal"],"Exceptions") in - let rec is_exception t = - match follow t with - | TInst (cl,_) -> is_parent base_exception cl - | _ -> false - in - let e_rethrow = mk (TIdent "__rethrow__") t_dynamic null_pos in - let should_wrap t = not (is_exception t) in - let wrap_throw expr = - match expr.eexpr with - | TIdent "__rethrow__" -> - make_throw expr expr.epos - | _ -> - let e_hxexception = make_static_this hx_exception expr.epos in - let e_wrap = fcall e_hxexception "wrap" [expr] base_exception_t expr.epos in - make_throw e_wrap expr.epos - in - let unwrap_expr local_to_unwrap = field (mk_cast local_to_unwrap hx_exception_t local_to_unwrap.epos) "obj" t_dynamic local_to_unwrap.epos in - let rethrow_expr rethrow = make_throw e_rethrow rethrow.epos in - let catch_map v e = - let e_exc = make_static_this exc_cl e.epos in - let e_field = field e_exc "exception" base_exception_t e.epos in - let e_setstack = binop OpAssign e_field (make_local v e.epos) v.v_type e.epos in - Type.concat e_setstack e - in - let std_cl = find_class com ([],"Std") in - let gen_typecheck e t pos = - let std = make_static_this std_cl pos in - let e_type = make_typeexpr (module_type_of_type t) pos in - fcall std "is" [e; e_type] com.basic.tbool pos - in - init com should_wrap wrap_throw unwrap_expr rethrow_expr base_exception_t hx_exception_t catch_map gen_typecheck - -let configure_java com = - let base_exception = find_class com (["java"; "lang"], "Throwable") in - let base_exception_t = TInst (base_exception, []) in - let hx_exception = find_class com (["java";"internal";"_Exceptions"], "HaxeException") in - let hx_exception_t = TInst (hx_exception, []) in - let exc_cl = find_class com (["java";"internal"],"Exceptions") in - let rec is_exception t = - match follow t with - | TInst (cl,_) -> is_parent base_exception cl - | _ -> false - in - let should_wrap t = not (is_exception t) in - let wrap_throw expr = - let e_hxexception = make_static_this hx_exception expr.epos in - let e_wrap = fcall e_hxexception "wrap" [expr] base_exception_t expr.epos in - make_throw e_wrap expr.epos - in - let unwrap_expr local_to_unwrap = field (mk_cast local_to_unwrap hx_exception_t local_to_unwrap.epos) "obj" t_dynamic local_to_unwrap.epos in - let rethrow_expr exc = { exc with eexpr = TThrow exc } in - let catch_map v e = - let exc = make_static_this exc_cl e.epos in - let e_setstack = fcall exc "setException" [make_local v e.epos] com.basic.tvoid e.epos in - Type.concat e_setstack e; - in - let std_cl = find_class com ([],"Std") in - let gen_typecheck e t pos = - let std = make_static_this std_cl pos in - let e_type = make_typeexpr (module_type_of_type t) pos in - fcall std "is" [e; e_type] com.basic.tbool pos - in - init com should_wrap wrap_throw unwrap_expr rethrow_expr base_exception_t hx_exception_t catch_map gen_typecheck diff --git a/src/generators/genas3.ml b/src/generators/genas3.ml deleted file mode 100644 index 10dbcd094c76034ba0a060ded124fdb5aae10fc2..0000000000000000000000000000000000000000 --- a/src/generators/genas3.ml +++ /dev/null @@ -1,1322 +0,0 @@ -(* - The Haxe Compiler - Copyright (C) 2005-2019 Haxe Foundation - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - *) - -open Type -open Common -open FlashProps - -type context_infos = { - com : Common.context; -} - -type context = { - inf : context_infos; - ch : out_channel; - buf : Buffer.t; - path : Globals.path; - mutable get_sets : (string * bool,string) Hashtbl.t; - mutable curclass : tclass; - mutable tabs : string; - mutable in_value : tvar option; - mutable in_static : bool; - mutable handle_break : bool; - mutable imports : (string,string list list) Hashtbl.t; - mutable gen_uid : int; - mutable local_types : t list; - mutable constructor_block : bool; - mutable block_inits : (unit -> unit) option; -} - -let follow = Abstract.follow_with_abstracts - -let is_var_field f = - match f with - | FStatic (_,f) | FInstance (_,_,f) -> - (match f.cf_kind with Var _ | Method MethDynamic -> true | _ -> false) - | _ -> - false - -let is_special_compare e1 e2 = - match e1.eexpr, e2.eexpr with - | TConst TNull, _ | _ , TConst TNull -> None - | _ -> - match follow e1.etype, follow e2.etype with - | TInst ({ cl_path = ["flash"],"NativeXml" } as c,_) , _ | _ , TInst ({ cl_path = ["flash"],"NativeXml" } as c,_) -> Some c - | _ -> None - -let is_fixed_override cf t = - let is_type_parameter c = match c.cl_kind with - | KTypeParameter _ -> true - | _ -> false - in - match follow cf.cf_type,follow t with - | TFun(_,r1),TFun(_,r2) -> - begin match follow r1,follow r2 with - | TInst(c1,_),TInst(c2,_) when c1 != c2 && not (is_type_parameter c1) && not (is_type_parameter c2) -> true - | _ -> false - end - | _ -> - false - -let protect name = - match name with - | "Error" | "Namespace" | "Object" -> "_" ^ name - | _ -> name - -let s_path ctx stat path p = - match path with - | ([],name) -> - (match name with - | "Int" -> "int" - | "Float" -> "Number" - | "Dynamic" -> "Object" - | "Bool" -> "Boolean" - | "Enum" -> "Class" - | "EnumValue" -> "enum" - | _ -> name) - | (["flash"],"FlashXml__") -> - "Xml" - | (["flash";"errors"],"Error") -> - "Error" - | (["flash"],"Vector") -> - "Vector" - | (["flash";"xml"],"XML") -> - "XML" - | (["flash";"xml"],"XMLList") -> - "XMLList" - | ["flash";"utils"],"QName" -> - "QName" - | ["flash";"utils"],"Namespace" -> - "Namespace" - | (["haxe"],"Int32") when not stat -> - "int" - | (pack,name) -> - let name = protect name in - let packs = (try Hashtbl.find ctx.imports name with Not_found -> []) in - if not (List.mem pack packs) then Hashtbl.replace ctx.imports name (pack :: packs); - Globals.s_type_path (pack,name) - -let reserved = - let h = Hashtbl.create 0 in - List.iter (fun l -> Hashtbl.add h l ()) - (* these ones are defined in order to prevent recursion in some Std functions *) - ["is";"as";"int";"uint";"const";"getTimer";"typeof";"parseInt";"parseFloat"; - (* AS3 keywords which are not Haxe ones *) - "finally";"with";"final";"internal";"native";"namespace";"include";"delete"; - (* some globals give some errors with Flex SDK as well *) - "print";"trace"; - (* we don't include get+set since they are not 'real' keywords, but they can't be used as method names *) - "function";"class";"var";"if";"else";"while";"do";"for";"break";"continue";"return";"extends";"implements"; - "import";"switch";"case";"default";"static";"public";"private";"try";"catch";"new";"this";"throw";"interface"; - "override";"package";"null";"true";"false";"void" - ]; - h - - (* "each", "label" : removed (actually allowed in locals and fields accesses) *) - -let s_ident n = - if Hashtbl.mem reserved n then "_" ^ n else n - -let valid_as3_ident s = - try - for i = 0 to String.length s - 1 do - match String.unsafe_get s i with - | 'a'..'z' | 'A'..'Z' | '$' | '_' -> () - | '0'..'9' when i > 0 -> () - | _ -> raise Exit - done; - true - with Exit -> - false - -let anon_field s = - let s = s_ident s in - if not (valid_as3_ident s) then "\"" ^ (StringHelper.s_escape s) ^ "\"" else s - -let rec create_dir acc = function - | [] -> () - | d :: l -> - let dir = String.concat "/" (List.rev (d :: acc)) in - if not (Sys.file_exists dir) then Unix.mkdir dir 0o755; - create_dir (d :: acc) l - -let init infos path = - let dir = infos.com.file :: fst path in - create_dir [] dir; - let ch = open_out (String.concat "/" dir ^ "/" ^ snd path ^ ".as") in - let imports = Hashtbl.create 0 in - Hashtbl.add imports (snd path) [fst path]; - { - inf = infos; - tabs = ""; - ch = ch; - path = path; - buf = Buffer.create (1 lsl 14); - in_value = None; - in_static = false; - handle_break = false; - imports = imports; - curclass = null_class; - gen_uid = 0; - local_types = []; - get_sets = Hashtbl.create 0; - constructor_block = false; - block_inits = None; - } - -let close ctx = - begin match ctx.inf.com.main_class with - | Some tp when tp = ctx.curclass.cl_path -> - output_string ctx.ch "// Compile __main__.as instead\n"; - | _ -> - () - end; - output_string ctx.ch (Printf.sprintf "package %s {\n" (String.concat "." (fst ctx.path))); - Hashtbl.iter (fun name paths -> - List.iter (fun pack -> - let path = pack, name in - if path <> ctx.path then output_string ctx.ch ("\timport " ^ Globals.s_type_path path ^ ";\n"); - ) paths - ) ctx.imports; - output_string ctx.ch (Buffer.contents ctx.buf); - close_out ctx.ch - -let gen_local ctx l = - ctx.gen_uid <- ctx.gen_uid + 1; - if ctx.gen_uid = 1 then l else l ^ string_of_int ctx.gen_uid - -let spr ctx s = Buffer.add_string ctx.buf s -let print ctx = Printf.kprintf (fun s -> Buffer.add_string ctx.buf s) - -let unsupported p = abort "This expression cannot be generated to AS3" p - -let newline ctx = - let rec loop p = - match Buffer.nth ctx.buf p with - | '}' | '{' | ':' | ';' -> print ctx "\n%s" ctx.tabs - | '\n' | '\t' -> loop (p - 1) - | _ -> print ctx ";\n%s" ctx.tabs - in - loop (Buffer.length ctx.buf - 1) - -let block_newline ctx = match Buffer.nth ctx.buf (Buffer.length ctx.buf - 1) with - | '}' -> print ctx ";\n%s" ctx.tabs - | _ -> newline ctx - -let rec concat ctx s f = function - | [] -> () - | [x] -> f x - | x :: l -> - f x; - spr ctx s; - concat ctx s f l - -let open_block ctx = - let oldt = ctx.tabs in - ctx.tabs <- "\t" ^ ctx.tabs; - (fun() -> ctx.tabs <- oldt) - -let parent e = - match e.eexpr with - | TParenthesis _ -> e - | _ -> mk (TParenthesis e) e.etype e.epos - -let default_value tstr = - match tstr with - | "int" | "uint" -> "0" - | "Number" -> "NaN" - | "Boolean" -> "false" - | _ -> "null" - -let rec type_str ctx t p = - match t with - | TEnum _ | TInst _ when List.memq t ctx.local_types -> - "*" - | TAbstract ({a_path = [],"Null"},[t]) -> - (match follow t with - | TAbstract ({ a_path = [],"UInt" },_) - | TAbstract ({ a_path = [],"Int" },_) - | TAbstract ({ a_path = [],"Float" },_) - | TAbstract ({ a_path = [],"Bool" },_) -> "*" - | _ -> type_str ctx t p) - | TAbstract (a,pl) when not (Meta.has Meta.CoreType a.a_meta) -> - type_str ctx (Abstract.get_underlying_type a pl) p - | TAbstract (a,_) -> - (match a.a_path with - | [], "Void" -> "void" - | [], "UInt" -> "uint" - | [], "Int" -> "int" - | [], "Float" -> "Number" - | [], "Bool" -> "Boolean" - | ["flash"], "AnyType" -> "*" - | _ -> s_path ctx true a.a_path p) - | TEnum (e,_) -> - if e.e_extern then "Object" else s_path ctx true e.e_path p - | TInst ({ cl_path = ["flash"],"Vector" },[pt]) -> - (match pt with - | TInst({cl_kind = KTypeParameter _},_) -> "*" - | _ -> "Vector.<" ^ type_str ctx pt p ^ ">") - | TInst (c,_) -> - (match c.cl_kind with - | KNormal | KGeneric | KGenericInstance _ | KAbstractImpl _ -> s_path ctx false c.cl_path p - | KTypeParameter _ | KExpr _ | KMacroType | KGenericBuild _ -> "*") - | TFun _ -> - "Function" - | TMono r -> - (match !r with None -> "*" | Some t -> type_str ctx t p) - | TAnon _ | TDynamic _ -> - "*" - | TType (t,args) -> - (match t.t_path with - | [], "UInt" -> "uint" - | _ -> type_str ctx (apply_params t.t_params args t.t_type) p) - | TLazy f -> - type_str ctx (lazy_type f) p - -let rec iter_switch_break in_switch e = - match e.eexpr with - | TFunction _ | TWhile _ | TFor _ -> () - | TSwitch _ when not in_switch -> iter_switch_break true e - | TBreak when in_switch -> raise Exit - | _ -> iter (iter_switch_break in_switch) e - -let handle_break ctx e = - let old_handle = ctx.handle_break in - try - iter_switch_break false e; - ctx.handle_break <- false; - (fun() -> ctx.handle_break <- old_handle) - with - Exit -> - spr ctx "try {"; - let b = open_block ctx in - newline ctx; - ctx.handle_break <- true; - (fun() -> - b(); - ctx.handle_break <- old_handle; - newline ctx; - spr ctx "} catch( e : * ) { if( e != \"__break__\" ) throw e; }"; - ) - -let this ctx = if ctx.in_value <> None then "$this" else "this" - -let generate_resources infos = - if Hashtbl.length infos.com.resources <> 0 then begin - let dir = (infos.com.file :: ["__res"]) in - create_dir [] dir; - let add_resource name data = - let name = Bytes.unsafe_to_string (Base64.str_encode name) in - let ch = open_out_bin (String.concat "/" (dir @ [name])) in - output_string ch data; - close_out ch - in - Hashtbl.iter (fun name data -> add_resource name data) infos.com.resources; - let ctx = init infos ([],"__resources__") in - spr ctx "\timport flash.utils.Dictionary;\n"; - spr ctx "\tpublic class __resources__ {\n"; - spr ctx "\t\tpublic static var list:Dictionary;\n"; - let inits = ref [] in - let k = ref 0 in - Hashtbl.iter (fun name _ -> - let varname = ("v" ^ (string_of_int !k)) in - k := !k + 1; - print ctx "\t\t[Embed(source = \"__res/%s\", mimeType = \"application/octet-stream\")]\n" (Bytes.unsafe_to_string (Base64.str_encode name)); - print ctx "\t\tpublic static var %s:Class;\n" varname; - inits := ("list[\"" ^ StringHelper.s_escape name ^ "\"] = " ^ varname ^ ";") :: !inits; - ) infos.com.resources; - spr ctx "\t\tstatic public function __init__():void {\n"; - spr ctx "\t\t\tlist = new Dictionary();\n"; - List.iter (fun init -> - print ctx "\t\t\t%s\n" init - ) !inits; - spr ctx "\t\t}\n"; - spr ctx "\t}\n"; - spr ctx "}"; - close ctx; - end - -let gen_constant ctx p = function - | TInt i -> print ctx "%ld" i - | TFloat s -> spr ctx s - | TString s -> print ctx "\"%s\"" (StringHelper.s_escape s) - | TBool b -> spr ctx (if b then "true" else "false") - | TNull -> spr ctx "null" - | TThis -> spr ctx (this ctx) - | TSuper -> spr ctx "super" - -let rec gen_function_header ctx name f params p = - let old = ctx.in_value in - let old_t = ctx.local_types in - let old_bi = ctx.block_inits in - ctx.in_value <- None; - ctx.local_types <- List.map snd params @ ctx.local_types; - let init () = - List.iter (fun (v,o) -> match o with - | Some c when is_nullable v.v_type && c.eexpr <> TConst TNull -> - newline ctx; - print ctx "if(%s==null) %s=" v.v_name v.v_name; - gen_expr ctx c; - | _ -> () - ) f.tf_args; - ctx.block_inits <- None; - in - ctx.block_inits <- Some init; - print ctx "function%s(" (match name with None -> "" | Some (n,meta) -> - let rec loop = function - | [] -> n - | (Meta.Getter,[Ast.EConst (Ast.Ident i),_],_) :: _ -> "get " ^ i - | (Meta.Setter,[Ast.EConst (Ast.Ident i),_],_) :: _ -> "set " ^ i - | _ :: l -> loop l - in - " " ^ loop meta - ); - concat ctx "," (fun (v,c) -> - match v.v_name with - | "__arguments__" -> - print ctx "...__arguments__" - | _ -> - let tstr = type_str ctx v.v_type p in - print ctx "%s : %s" (s_ident v.v_name) tstr; - match c with - | None -> - if ctx.constructor_block then print ctx " = %s" (default_value tstr); - | Some ({eexpr = TConst _ } as e) -> - spr ctx " = "; - gen_expr ctx e - | _ -> - spr ctx " = null" - ) f.tf_args; - print ctx ") : %s " (type_str ctx f.tf_type p); - (fun () -> - ctx.in_value <- old; - ctx.local_types <- old_t; - ctx.block_inits <- old_bi; - ) - -and gen_call ctx e el r = - match e.eexpr , el with - | TCall (x,_) , el -> - spr ctx "("; - gen_value ctx e; - spr ctx ")"; - spr ctx "("; - concat ctx "," (gen_value ctx) el; - spr ctx ")"; - | TIdent "__is__" , [e1;e2] -> - gen_value ctx e1; - spr ctx " is "; - gen_value ctx e2; - | TIdent "__in__" , [e1;e2] -> - spr ctx "("; - gen_value ctx e1; - spr ctx " in "; - gen_value ctx e2; - spr ctx ")" - | TIdent "__as__", [e1;e2] -> - gen_value ctx e1; - spr ctx " as "; - gen_value ctx e2; - | TIdent "__int__", [e] -> - spr ctx "int("; - gen_value ctx e; - spr ctx ")"; - | TIdent "__float__", [e] -> - spr ctx "Number("; - gen_value ctx e; - spr ctx ")"; - | TIdent "__typeof__", [e] -> - spr ctx "typeof "; - gen_value ctx e; - | TIdent "__keys__", [e] -> - let ret = (match ctx.in_value with None -> assert false | Some r -> r) in - print ctx "%s = new Array()" ret.v_name; - newline ctx; - let tmp = gen_local ctx "$k" in - print ctx "for(var %s : String in " tmp; - gen_value ctx e; - print ctx ") %s.push(%s)" ret.v_name tmp; - | TIdent "__hkeys__", [e] -> - let ret = (match ctx.in_value with None -> assert false | Some r -> r) in - print ctx "%s = new Array()" ret.v_name; - newline ctx; - let tmp = gen_local ctx "$k" in - print ctx "for(var %s : String in " tmp; - gen_value ctx e; - print ctx ") %s.push(%s.substr(1))" ret.v_name tmp; - | TIdent "__foreach__", [e] -> - let ret = (match ctx.in_value with None -> assert false | Some r -> r) in - print ctx "%s = new Array()" ret.v_name; - newline ctx; - let tmp = gen_local ctx "$k" in - print ctx "for each(var %s : * in " tmp; - gen_value ctx e; - print ctx ") %s.push(%s)" ret.v_name tmp; - | TIdent "__new__", e :: args -> - spr ctx "new "; - gen_value ctx e; - spr ctx "("; - concat ctx "," (gen_value ctx) args; - spr ctx ")"; - | TIdent "__delete__", [e;f] -> - spr ctx "delete("; - gen_value ctx e; - spr ctx "["; - gen_value ctx f; - spr ctx "]"; - spr ctx ")"; - | TIdent "__unprotect__", [e] -> - gen_value ctx e - | TIdent "__vector__", [] -> - let t = match r with TAbstract ({a_path = [],"Class"}, [vt]) -> vt | _ -> assert false in - spr ctx (type_str ctx t e.epos); - | TIdent "__vector__", [e] -> - spr ctx (type_str ctx r e.epos); - spr ctx "("; - gen_value ctx e; - spr ctx ")" - | TField (_, FStatic( { cl_path = (["flash"],"Lib") }, { cf_name = "as" })), [e1;e2] -> - gen_value ctx e1; - spr ctx " as "; - gen_value ctx e2 - | TField (_, FStatic ({ cl_path = (["flash"],"Vector") }, cf)), args -> - (match cf.cf_name, args with - | "ofArray", [e] | "convert", [e] -> - (match follow r with - | TInst ({ cl_path = (["flash"],"Vector") },[t]) -> - print ctx "Vector.<%s>(" (type_str ctx t e.epos); - gen_value ctx e; - print ctx ")"; - | _ -> assert false) - | _ -> assert false) - | TField(e1, (FAnon {cf_name = s} | FDynamic s)),[ef] when s = "map" || s = "filter" -> - spr ctx (s_path ctx true (["flash";],"Boot") e.epos); - gen_field_access ctx t_dynamic (s ^ "Dynamic"); - spr ctx "("; - concat ctx "," (gen_value ctx) [e1;ef]; - spr ctx ")" - | TField (ee,f), args when is_var_field f -> - spr ctx "("; - gen_value ctx e; - spr ctx ")"; - spr ctx "("; - concat ctx "," (gen_value ctx) el; - spr ctx ")" - | TField (e1,FInstance(_,_,cf)),el when is_fixed_override cf e.etype -> - let s = type_str ctx r e.epos in - spr ctx "(("; - gen_value ctx e; - spr ctx "("; - concat ctx "," (gen_value ctx) el; - spr ctx ")"; - print ctx ") as %s)" s - | TField (e1, f), el -> - begin - let default () = gen_call_default ctx e el in - let mk_prop_acccess prop_cl prop_tl prop_cf = mk (TField (e1, FInstance (prop_cl, prop_tl, prop_cf))) prop_cf.cf_type e.epos in - let mk_static_acccess cl prop_cf = mk (TField (e1, FStatic (cl, prop_cf))) prop_cf.cf_type e.epos in - let gen_assign lhs rhs = gen_expr ctx (mk (TBinop (OpAssign, lhs, rhs)) rhs.etype e.epos) in - match f, el with - | FInstance (cl, tl, cf), [] -> - (match is_extern_instance_accessor ~isget:true cl tl cf with - | Some (prop_cl, prop_tl, prop_cf) -> - let efield = mk_prop_acccess prop_cl prop_tl prop_cf in - gen_expr ctx efield - | None -> - default ()) - - | FInstance (cl, tl, cf), [evalue] -> - (match is_extern_instance_accessor ~isget:false cl tl cf with - | Some (prop_cl, prop_tl, prop_cf) -> - let efield = mk_prop_acccess prop_cl prop_tl prop_cf in - gen_assign efield evalue - | None -> - default ()) - - | FStatic (cl, cf), [] -> - (match is_extern_static_accessor ~isget:true cl cf with - | Some prop_cf -> - let efield = mk_static_acccess cl prop_cf in - gen_expr ctx efield - | None -> - default ()) - - | FStatic (cl, cf), [evalue] -> - (match is_extern_static_accessor ~isget:false cl cf with - | Some prop_cf -> - let efield = mk_static_acccess cl prop_cf in - gen_assign efield evalue - | None -> - default ()) - | _ -> - default () - end - | _ -> - gen_call_default ctx e el - -and gen_call_default ctx e el = - gen_value ctx e; - spr ctx "("; - concat ctx "," (gen_value ctx) el; - spr ctx ")" - -and gen_value_op ctx e = - match e.eexpr with - | TBinop (op,_,_) when op = Ast.OpAnd || op = Ast.OpOr || op = Ast.OpXor -> - spr ctx "("; - gen_value ctx e; - spr ctx ")"; - | _ -> - gen_value ctx e - -and gen_field_access ctx t s = - let field c = - match fst c.cl_path, snd c.cl_path, s with - | [], "Math", "NaN" - | [], "Math", "NEGATIVE_INFINITY" - | [], "Math", "POSITIVE_INFINITY" - | [], "Math", "isFinite" - | [], "Math", "isNaN" - | [], "Date", "now" - | [], "Date", "fromTime" - | [], "Date", "fromString" - -> - print ctx "[\"%s\"]" s - | [], "String", "charCodeAt" -> - spr ctx "[\"charCodeAtHX\"]" - | [], "Array", "map" -> - spr ctx "[\"mapHX\"]" - | [], "Array", "filter" -> - spr ctx "[\"filterHX\"]" - | [], "Date", "toString" -> - print ctx "[\"toStringHX\"]" - | [], "String", "cca" -> - print ctx ".charCodeAt" - | ["flash";"xml"], "XML", "namespace" -> - print ctx ".namespace" - | _ -> - print ctx ".%s" (s_ident s) - in - match follow t with - | TInst (c,_) -> field c - | TAnon a -> - (match !(a.a_status) with - | Statics c -> field c - | _ -> print ctx ".%s" (s_ident s)) - | _ -> - print ctx ".%s" (s_ident s) - -and gen_expr ctx e = - match e.eexpr with - | TConst c -> - gen_constant ctx e.epos c - | TLocal v -> - spr ctx (s_ident v.v_name) - | TArray ({ eexpr = TIdent "__global__" },{ eexpr = TConst (TString s) }) -> - let path = Ast.parse_path s in - spr ctx (s_path ctx false path e.epos) - | TArray (e1,e2) -> - gen_value ctx e1; - spr ctx "["; - gen_value ctx e2; - spr ctx "]"; - | TBinop (Ast.OpEq,e1,e2) when (match is_special_compare e1 e2 with Some c -> true | None -> false) -> - let c = match is_special_compare e1 e2 with Some c -> c | None -> assert false in - gen_expr ctx (mk (TCall (mk (TField (mk (TTypeExpr (TClassDecl c)) t_dynamic e.epos,FDynamic "compare")) t_dynamic e.epos,[e1;e2])) ctx.inf.com.basic.tbool e.epos); - (* what is this used for? *) -(* | TBinop (op,{ eexpr = TField (e1,s) },e2) -> - gen_value_op ctx e1; - gen_field_access ctx e1.etype s; - print ctx " %s " (Ast.s_binop op); - gen_value_op ctx e2; *) - (* assignments to variable or dynamic methods fields on interfaces are generated as class["field"] = value *) - | TBinop (op,{eexpr = TField (ei, FInstance({cl_interface = true},_,{cf_kind = (Method MethDynamic | Var _); cf_name = s}))},e2) -> - gen_value ctx ei; - print ctx "[\"%s\"]" s; - print ctx " %s " (Ast.s_binop op); - gen_value_op ctx e2; - | TBinop (op,e1,e2) -> - gen_value_op ctx e1; - print ctx " %s " (Ast.s_binop op); - gen_value_op ctx e2; - (* variable fields and dynamic methods on interfaces are generated as (class["field"] as class) *) - | TField (ei, FInstance({cl_interface = true},_,{cf_kind = (Method MethDynamic | Var _); cf_name = s})) -> - spr ctx "("; - gen_value ctx ei; - print ctx "[\"%s\"]" s; - print ctx " as %s)" (type_str ctx e.etype e.epos); - | TField({eexpr = TArrayDecl _} as e1,s) -> - spr ctx "("; - gen_expr ctx e1; - spr ctx ")"; - gen_field_access ctx e1.etype (field_name s) - | TEnumIndex e -> - gen_value ctx e; - print ctx ".index"; - | TEnumParameter (e,_,i) -> - gen_value ctx e; - print ctx ".params[%i]" i; - | TField (e,s) -> - gen_value ctx e; - gen_field_access ctx e.etype (field_name s) - | TTypeExpr t -> - spr ctx (s_path ctx true (t_path t) e.epos) - | TParenthesis e -> - spr ctx "("; - gen_value ctx e; - spr ctx ")"; - | TMeta (_,e) -> - gen_expr ctx e - | TReturn eo -> - if ctx.in_value <> None then unsupported e.epos; - (match eo with - | None -> - spr ctx "return" - | Some e when (match follow e.etype with TEnum({ e_path = [],"Void" },[]) | TAbstract ({ a_path = [],"Void" },[]) -> true | _ -> false) -> - print ctx "{"; - let bend = open_block ctx in - newline ctx; - gen_value ctx e; - newline ctx; - spr ctx "return"; - bend(); - newline ctx; - print ctx "}"; - | Some e -> - spr ctx "return "; - gen_value ctx e); - | TBreak -> - if ctx.in_value <> None then unsupported e.epos; - if ctx.handle_break then spr ctx "throw \"__break__\"" else spr ctx "break" - | TContinue -> - if ctx.in_value <> None then unsupported e.epos; - spr ctx "continue" - | TBlock el -> - print ctx "{"; - let bend = open_block ctx in - let cb = (if not ctx.constructor_block then - (fun () -> ()) - else if not (Texpr.constructor_side_effects e) then begin - ctx.constructor_block <- false; - (fun () -> ()) - end else begin - ctx.constructor_block <- false; - print ctx " if( !%s.skip_constructor ) {" (s_path ctx true (["flash"],"Boot") e.epos); - (fun() -> print ctx "}") - end) in - (match ctx.block_inits with None -> () | Some i -> i()); - List.iter (fun e -> gen_block_element ctx e) el; - bend(); - newline ctx; - cb(); - print ctx "}"; - | TFunction f -> - let h = gen_function_header ctx None f [] e.epos in - let old = ctx.in_static in - ctx.in_static <- true; - gen_expr ctx f.tf_expr; - ctx.in_static <- old; - h(); - | TCall (v,el) -> - gen_call ctx v el e.etype - | TArrayDecl el -> - spr ctx "["; - concat ctx "," (gen_value ctx) el; - spr ctx "]" - | TThrow e -> - spr ctx "throw "; - gen_value ctx e; - | TVar (v,eo) -> - spr ctx "var "; - print ctx "%s : %s" (s_ident v.v_name) (type_str ctx v.v_type e.epos); - begin match eo with - | None -> () - | Some e -> - spr ctx " = "; - gen_value ctx e - end - | TNew (c,params,el) -> - (match c.cl_path, params with - | (["flash"],"Vector"), [pt] -> print ctx "new Vector.<%s>(" (type_str ctx pt e.epos) - | _ -> print ctx "new %s(" (s_path ctx true c.cl_path e.epos)); - concat ctx "," (gen_value ctx) el; - spr ctx ")" - | TIf (cond,e,eelse) -> - spr ctx "if"; - gen_value ctx (parent cond); - spr ctx " "; - gen_expr ctx e; - (match eelse with - | None -> () - | Some e -> - newline ctx; - spr ctx "else "; - gen_expr ctx e); - | TUnop (op,Ast.Prefix,e) -> - spr ctx (Ast.s_unop op); - gen_value ctx e - | TUnop (op,Ast.Postfix,e) -> - gen_value ctx e; - spr ctx (Ast.s_unop op) - | TWhile (cond,e,Ast.NormalWhile) -> - let handle_break = handle_break ctx e in - spr ctx "while"; - gen_value ctx (parent cond); - spr ctx " "; - gen_expr ctx e; - handle_break(); - | TWhile (cond,e,Ast.DoWhile) -> - let handle_break = handle_break ctx e in - spr ctx "do "; - gen_expr ctx e; - spr ctx " while"; - gen_value ctx (parent cond); - handle_break(); - | TObjectDecl fields -> - spr ctx "{ "; - concat ctx ", " (fun ((f,_,_),e) -> print ctx "%s : " (anon_field f); gen_value ctx e) fields; - spr ctx "}" - | TFor (v,it,e) -> - let handle_break = handle_break ctx e in - let tmp = gen_local ctx "$it" in - print ctx "{ var %s : * = " tmp; - gen_value ctx it; - newline ctx; - print ctx "while( %s.hasNext() ) { var %s : %s = %s.next()" tmp (s_ident v.v_name) (type_str ctx v.v_type e.epos) tmp; - newline ctx; - gen_expr ctx e; - newline ctx; - spr ctx "}}"; - handle_break(); - | TTry (e,catchs) -> - spr ctx "try "; - gen_expr ctx e; - List.iter (fun (v,e) -> - newline ctx; - print ctx "catch( %s : %s )" (s_ident v.v_name) (type_str ctx v.v_type e.epos); - gen_expr ctx e; - ) catchs; - | TSwitch (e,cases,def) -> - spr ctx "switch"; - gen_value ctx (parent e); - spr ctx " {"; - newline ctx; - List.iter (fun (el,e2) -> - List.iter (fun e -> - spr ctx "case "; - gen_value ctx e; - spr ctx ":"; - ) el; - gen_block ctx e2; - print ctx "break"; - newline ctx; - ) cases; - (match def with - | None -> () - | Some e -> - spr ctx "default:"; - gen_block ctx e; - print ctx "break"; - newline ctx; - ); - spr ctx "}" - | TCast (e1,None) -> - let s = type_str ctx e.etype e.epos in - if s = "*" then - gen_expr ctx e1 - else begin - spr ctx "(("; - gen_value ctx e1; - print ctx ") as %s)" s - end - | TCast (e1,Some t) -> - gen_expr ctx (Codegen.default_cast ctx.inf.com e1 t e.etype e.epos) - | TIdent s -> - spr ctx s - -and gen_block_element ctx e = match e.eexpr with - | TObjectDecl fl -> - List.iter (fun (_,e) -> gen_block_element ctx e) fl - | _ -> - block_newline ctx; - gen_expr ctx e - -and gen_block ctx e = - newline ctx; - match e.eexpr with - | TBlock [] -> () - | _ -> - gen_expr ctx e; - newline ctx - -and gen_value ctx e = - let assign e = - mk (TBinop (Ast.OpAssign, - mk (TLocal (match ctx.in_value with None -> assert false | Some r -> r)) t_dynamic e.epos, - e - )) e.etype e.epos - in - let block e = - mk (TBlock [e]) e.etype e.epos - in - let value block = - let old = ctx.in_value in - let t = type_str ctx e.etype e.epos in - let r = alloc_var VGenerated (gen_local ctx "$r") e.etype e.epos in - ctx.in_value <- Some r; - if ctx.in_static then - print ctx "function() : %s " t - else - print ctx "(function($this:%s) : %s " (snd ctx.path) t; - let b = if block then begin - spr ctx "{"; - let b = open_block ctx in - newline ctx; - print ctx "var %s : %s" r.v_name t; - newline ctx; - b - end else - (fun() -> ()) - in - (fun() -> - if block then begin - newline ctx; - print ctx "return %s" r.v_name; - b(); - newline ctx; - spr ctx "}"; - end; - ctx.in_value <- old; - if ctx.in_static then - print ctx "()" - else - print ctx "(%s))" (this ctx) - ) - in - match e.eexpr with - | TCall ({ eexpr = TIdent "__keys__" },_) | TCall ({ eexpr = TIdent "__hkeys__" },_) -> - let v = value true in - gen_expr ctx e; - v() - | TConst _ - | TLocal _ - | TArray _ - | TBinop _ - | TField _ - | TEnumParameter _ - | TEnumIndex _ - | TTypeExpr _ - | TParenthesis _ - | TObjectDecl _ - | TArrayDecl _ - | TCall _ - | TNew _ - | TUnop _ - | TFunction _ - | TIdent _ -> - gen_expr ctx e - | TMeta (_,e1) -> - gen_value ctx e1 - | TCast (e1,None) -> - let s = type_str ctx e.etype e1.epos in - begin match s with - | "*" -> - gen_value ctx e1 - | "Function" | "Array" | "String" -> - spr ctx "(("; - gen_value ctx e1; - print ctx ") as %s)" s; - | _ -> - print ctx "%s(" s; - gen_value ctx e1; - spr ctx ")"; - end - | TCast (e1,Some t) -> - gen_value ctx (Codegen.default_cast ctx.inf.com e1 t e.etype e.epos) - | TReturn _ - | TBreak - | TContinue -> - unsupported e.epos - | TVar _ - | TFor _ - | TWhile _ - | TThrow _ -> - (* value is discarded anyway *) - let v = value true in - gen_expr ctx e; - v() - | TBlock [] -> - spr ctx "null" - | TBlock [e] -> - gen_value ctx e - | TBlock el -> - let v = value true in - let rec loop = function - | [] -> - spr ctx "return null"; - | [e] -> - gen_expr ctx (assign e); - | e :: l -> - gen_expr ctx e; - newline ctx; - loop l - in - loop el; - v(); - | TIf (cond,e,eo) -> - spr ctx "("; - gen_value ctx cond; - spr ctx "?"; - gen_value ctx e; - spr ctx ":"; - (match eo with - | None -> spr ctx "null" - | Some e -> gen_value ctx e); - spr ctx ")" - | TSwitch (cond,cases,def) -> - let v = value true in - gen_expr ctx (mk (TSwitch (cond, - List.map (fun (e1,e2) -> (e1,assign e2)) cases, - match def with None -> None | Some e -> Some (assign e) - )) e.etype e.epos); - v() - | TTry (b,catchs) -> - let v = value true in - gen_expr ctx (mk (TTry (block (assign b), - List.map (fun (v,e) -> v, block (assign e)) catchs - )) e.etype e.epos); - v() - -let generate_field ctx static f = - newline ctx; - ctx.in_static <- static; - ctx.gen_uid <- 0; - List.iter (fun(m,pl,_) -> - match m,pl with - | Meta.Meta, [Ast.ECall ((Ast.EConst (Ast.Ident n),_),args),_] -> - let mk_arg (a,p) = - match a with - | Ast.EConst (Ast.String(s,_)) -> (None, s) - | Ast.EBinop (Ast.OpAssign,(Ast.EConst (Ast.Ident n),_),(Ast.EConst (Ast.String(s,_)),_)) -> (Some n, s) - | _ -> abort "Invalid meta definition" p - in - print ctx "[%s" n; - (match args with - | [] -> () - | _ -> - print ctx "("; - concat ctx "," (fun a -> - match mk_arg a with - | None, s -> gen_constant ctx (snd a) (TString s) - | Some s, e -> print ctx "%s=" s; gen_constant ctx (snd a) (TString e) - ) args; - print ctx ")"); - print ctx "]"; - | _ -> () - ) f.cf_meta; - let cfl_overridden = TClass.get_overridden_fields ctx.curclass f in - let overrides_public = List.exists (fun cf -> Meta.has Meta.Public cf.cf_meta) cfl_overridden in - let public = (has_class_field_flag f CfPublic) || Hashtbl.mem ctx.get_sets (f.cf_name,static) || (f.cf_name = "main" && static) - || f.cf_name = "resolve" || Meta.has Meta.Public f.cf_meta - (* consider all abstract methods public to avoid issues with inlined private access *) - || (match ctx.curclass.cl_kind with KAbstractImpl _ -> true | _ -> false) - || overrides_public - in - let rights = (if static then "static " else "") ^ (if public then "public" else "protected") in - let p = ctx.curclass.cl_pos in - match f.cf_expr, f.cf_kind with - | Some { eexpr = TFunction fd }, Method (MethNormal | MethInline) -> - print ctx "%s%s " rights (if static || not (has_class_field_flag f CfFinal) then "" else " final "); - let rec loop c = - match c.cl_super with - | None -> () - | Some (c,_) -> - if PMap.mem f.cf_name c.cl_fields then - spr ctx "override " - else - loop c - in - if not static then loop ctx.curclass; - let h = gen_function_header ctx (Some (s_ident f.cf_name, f.cf_meta)) fd f.cf_params p in - gen_expr ctx fd.tf_expr; - h(); - newline ctx - | _ -> - let is_getset = (match f.cf_kind with Var { v_read = AccCall } | Var { v_write = AccCall } -> true | _ -> false) in - if ctx.curclass.cl_interface then - match follow f.cf_type with - | TFun (args,r) when (match f.cf_kind with Method MethDynamic | Var _ -> false | _ -> true) -> - let rec loop = function - | [] -> f.cf_name - | (Meta.Getter,[Ast.EConst (Ast.String(name,_)),_],_) :: _ -> "get " ^ name - | (Meta.Setter,[Ast.EConst (Ast.String(name,_)),_],_) :: _ -> "set " ^ name - | _ :: l -> loop l - in - print ctx "function %s(" (loop f.cf_meta); - concat ctx "," (fun (arg,o,t) -> - let tstr = type_str ctx t p in - print ctx "%s : %s" arg tstr; - if o then print ctx " = %s" (default_value tstr); - ) args; - print ctx ") : %s " (type_str ctx r p); - | _ -> () - else - let gen_init () = match f.cf_expr with - | None -> () - | Some e -> - if not static || (match e.eexpr with | TConst _ | TFunction _ | TTypeExpr _ -> true | _ -> false) then begin - print ctx " = "; - gen_value ctx e - end else - Codegen.ExtClass.add_static_init ctx.curclass f e e.epos - in - if is_getset then begin - let t = type_str ctx f.cf_type p in - let id = s_ident f.cf_name in - let v = (match f.cf_kind with Var v -> v | _ -> assert false) in - (match v.v_read with - | AccNormal | AccNo | AccNever -> - print ctx "%s function get %s() : %s { return $%s; }" rights id t id; - newline ctx - | AccCall -> - print ctx "%s function get %s() : %s { return %s(); }" rights id t ("get_" ^ f.cf_name); - newline ctx - | _ -> ()); - (match v.v_write with - | AccNormal | AccNo | AccNever -> - print ctx "%s function set %s( __v : %s ) : void { $%s = __v; }" rights id t id; - newline ctx - | AccCall -> - print ctx "%s function set %s( __v : %s ) : void { %s(__v); }" rights id t ("set_" ^ f.cf_name); - newline ctx - | _ -> ()); - print ctx "%sprotected var $%s : %s" (if static then "static " else "") (s_ident f.cf_name) (type_str ctx f.cf_type p); - gen_init() - end else begin - print ctx "%s var %s : %s" rights (s_ident f.cf_name) (type_str ctx f.cf_type p); - gen_init() - end - -let rec define_getset ctx stat c = - let def f name = - Hashtbl.add ctx.get_sets (name,stat) f.cf_name - in - let field f = - match f.cf_kind with - | Method _ -> () - | Var v -> - (match v.v_read with AccCall -> def f ("get_" ^ f.cf_name) | _ -> ()); - (match v.v_write with AccCall -> def f ("set_" ^ f.cf_name) | _ -> ()) - in - List.iter field (if stat then c.cl_ordered_statics else c.cl_ordered_fields); - match c.cl_super with - | Some (c,_) when not stat -> define_getset ctx stat c - | _ -> () - -let generate_class ctx c = - ctx.curclass <- c; - define_getset ctx true c; - define_getset ctx false c; - ctx.local_types <- List.map snd c.cl_params; - let pack = open_block ctx in - print ctx "\tpublic %s%s%s %s " (if c.cl_final then " final " else "") "" (if c.cl_interface then "interface" else "class") (snd c.cl_path); - (match c.cl_super with - | None -> () - | Some (csup,_) -> print ctx "extends %s " (s_path ctx true csup.cl_path c.cl_pos)); - (match c.cl_implements with - | [] -> () - | l -> - spr ctx (if c.cl_interface then "extends " else "implements "); - concat ctx ", " (fun (i,_) -> print ctx "%s" (s_path ctx true i.cl_path c.cl_pos)) l); - spr ctx "{"; - let cl = open_block ctx in - (match c.cl_constructor with - | None -> () - | Some f -> - let f = { f with - cf_name = snd c.cl_path; - cf_flags = set_flag f.cf_flags (int_of_class_field_flag CfPublic); - cf_kind = Method MethNormal; - } in - ctx.constructor_block <- true; - generate_field ctx false f; - ); - List.iter (generate_field ctx false) c.cl_ordered_fields; - List.iter (generate_field ctx true) c.cl_ordered_statics; - let has_init = match c.cl_init with - | None -> false - | Some e -> - newline ctx; - spr ctx "static static_init function init() : void"; - gen_expr ctx (mk_block e); - true; - in - cl(); - newline ctx; - print ctx "}"; - pack(); - newline ctx; - print ctx "}"; - if has_init then begin - newline ctx; - spr ctx "namespace static_init"; - newline ctx; - print ctx "%s.static_init::init()" (s_path ctx true ctx.curclass.cl_path Globals.null_pos); - end; - newline ctx; - if c.cl_interface && Meta.has (Meta.Custom ":hasMetadata") c.cl_meta then begin - (* we have to reference the metadata class in order for it to be compiled *) - let path = fst c.cl_path,snd c.cl_path ^ "_HxMeta" in - spr ctx (Globals.s_type_path path); - newline ctx - end - -let generate_main ctx inits = - ctx.curclass <- { null_class with cl_path = [],"__main__" }; - let pack = open_block ctx in - print ctx "\timport flash.Lib"; - newline ctx; - print ctx "public class __main__ extends %s {" (s_path ctx true (["flash"],"Boot") Globals.null_pos); - let cl = open_block ctx in - newline ctx; - spr ctx "public function __main__() {"; - let fl = open_block ctx in - newline ctx; - spr ctx "super()"; - newline ctx; - spr ctx "flash.Lib.current = this"; - List.iter (fun e -> newline ctx; gen_expr ctx e) inits; - fl(); - newline ctx; - print ctx "}"; - cl(); - newline ctx; - print ctx "}"; - pack(); - newline ctx; - print ctx "}"; - newline ctx - -let generate_enum ctx e = - ctx.local_types <- List.map snd e.e_params; - let pack = open_block ctx in - let ename = snd e.e_path in - print ctx "\tpublic final class %s extends enum {" ename; - let cl = open_block ctx in - newline ctx; - print ctx "public static const __isenum : Boolean = true"; - newline ctx; - print ctx "public function %s( t : String, index : int, p : Array = null ) : void { this.tag = t; this.index = index; this.params = p; }" ename; - PMap.iter (fun _ c -> - newline ctx; - match c.ef_type with - | TFun (args,_) -> - print ctx "public static function %s(" c.ef_name; - concat ctx ", " (fun (a,o,t) -> - print ctx "%s : %s" (s_ident a) (type_str ctx t c.ef_pos); - if o then spr ctx " = null"; - ) args; - print ctx ") : %s {" ename; - print ctx " return new %s(\"%s\",%d,[" ename c.ef_name c.ef_index; - concat ctx "," (fun (a,_,_) -> spr ctx (s_ident a)) args; - print ctx "]); }"; - | _ -> - print ctx "public static var %s : %s = new %s(\"%s\",%d)" c.ef_name ename ename c.ef_name c.ef_index; - ) e.e_constrs; - newline ctx; - (match Texpr.build_metadata ctx.inf.com.basic (TEnumDecl e) with - | None -> () - | Some e -> - print ctx "public static var __meta__ : * = "; - gen_expr ctx e; - newline ctx); - print ctx "public static var __constructs__ : Array = [%s];" (String.concat "," (List.map (fun s -> "\"" ^ StringHelper.s_escape s ^ "\"") e.e_names)); - cl(); - newline ctx; - print ctx "}"; - pack(); - newline ctx; - print ctx "}"; - newline ctx - -let generate_base_enum ctx = - let pack = open_block ctx in - spr ctx "\timport flash.Boot"; - newline ctx; - spr ctx "public class enum {"; - let cl = open_block ctx in - newline ctx; - spr ctx "public var tag : String"; - newline ctx; - spr ctx "public var index : int"; - newline ctx; - spr ctx "public var params : Array"; - newline ctx; - spr ctx "public function toString() : String { return flash.Boot.enum_to_string(this); }"; - cl(); - newline ctx; - print ctx "}"; - pack(); - newline ctx; - print ctx "}"; - newline ctx - -let generate com = - com.warning "-as3 target is deprecated. Use -swf instead. See https://github.com/HaxeFoundation/haxe/issues/8295" Globals.null_pos; - let infos = { - com = com; - } in - generate_resources infos; - let ctx = init infos ([],"enum") in - generate_base_enum ctx; - close ctx; - let inits = ref [] in - List.iter (fun t -> - match t with - | TClassDecl c -> - let c = (match c.cl_path with - | ["flash"],"FlashXml__" -> { c with cl_path = [],"Xml" } - | (pack,name) -> { c with cl_path = (pack,protect name) } - ) in - if c.cl_extern then - (match c.cl_init with - | None -> () - | Some e -> inits := e :: !inits) - else - let ctx = init infos c.cl_path in - generate_class ctx c; - close ctx - | TEnumDecl e -> - let pack,name = e.e_path in - let e = { e with e_path = (pack,protect name) } in - if e.e_extern then - () - else - let ctx = init infos e.e_path in - generate_enum ctx e; - close ctx - | TTypeDecl _ | TAbstractDecl _ -> - () - ) com.types; - (match com.main with - | None -> () - | Some e -> inits := e :: !inits); - let ctx = init infos ([],"__main__") in - generate_main ctx (List.rev !inits); - close ctx diff --git a/src/generators/gencpp.ml b/src/generators/gencpp.ml index b6fa1aee87cfc6b5fe04dde6fa91cf430f5643ae..54c33ad9128b65ff52730f391944b4db2a86a843 100644 --- a/src/generators/gencpp.ml +++ b/src/generators/gencpp.ml @@ -50,7 +50,7 @@ let join_class_path path separator = result;; let class_text path = - join_class_path path "::" + "::" ^ (join_class_path path "::") ;; (* The internal classes are implemented by the core hxcpp system, so the cpp @@ -633,7 +633,7 @@ let rec is_objc_type t = | TInst(cl,_) -> cl.cl_extern && Meta.has Meta.Objc cl.cl_meta | TType(td,_) -> (Meta.has Meta.Objc td.t_meta) | TAbstract (a,_) -> (Meta.has Meta.Objc a.a_meta) - | TMono r -> (match !r with | Some t -> is_objc_type t | _ -> false) + | TMono r -> (match r.tm_type with | Some t -> is_objc_type t | _ -> false) | TLazy f -> is_objc_type (lazy_type f) | _ -> false ;; @@ -718,7 +718,7 @@ let rec class_string klass suffix params remap = | _ when is_dynamic_type_param klass.cl_kind -> "Dynamic" | ([],"#Int") -> "/* # */int" | (["cpp"],"UInt8") -> "unsigned char" - | ([],"Class") -> "hx::Class" + | ([],"Class") -> "::hx::Class" | ([],"EnumValue") -> "Dynamic" | ([],"Null") -> (match params with | [t] -> @@ -729,7 +729,7 @@ let rec class_string klass suffix params remap = | TAbstract ({ a_path = ["cpp"],"UInt8" },_) -> "Dynamic" | t when type_has_meta_key t Meta.NotNull -> "Dynamic" | _ -> "/*NULL*/" ^ (type_string t) ) - | _ -> assert false); + | _ -> die "" __LOC__); (* Objective-C class *) | path when is_objc_type (TInst(klass,[])) -> let str = join_class_path_remap klass.cl_path "::" in @@ -753,7 +753,7 @@ and type_string_suff suffix haxe_type remap = let type_string = type_string_remap remap in let join_class_path_remap = if remap then join_class_path_remap else join_class_path in (match haxe_type with - | TMono r -> (match !r with None -> "Dynamic" ^ suffix | Some t -> type_string_suff suffix t remap) + | TMono r -> (match r.tm_type with None -> "Dynamic" ^ suffix | Some t -> type_string_suff suffix t remap) | TAbstract ({ a_path = ([],"Void") },[]) -> "Void" | TAbstract ({ a_path = ([],"Bool") },[]) -> "bool" | TAbstract ({ a_path = ([],"Float") },[]) -> "Float" @@ -775,24 +775,24 @@ and type_string_suff suffix haxe_type remap = (match params with | [t] when (type_string (follow t) ) = "Dynamic" -> "Dynamic" | [t] -> "Array< " ^ (type_string (follow t) ) ^ " >" - | _ -> assert false) + | _ -> die "" __LOC__) | ["cpp"] , "FastIterator" -> (match params with | [t] -> "::cpp::FastIterator< " ^ (type_string (follow t) ) ^ " >" - | _ -> assert false) + | _ -> die "" __LOC__) | ["cpp"] , "Pointer" | ["cpp"] , "ConstPointer" -> (match params with | [t] -> "::cpp::Pointer< " ^ (type_string (follow t) ) ^ " >" - | _ -> assert false) + | _ -> die "" __LOC__) | ["cpp"] , "RawPointer" -> (match params with | [t] -> " " ^ (type_string (follow t) ) ^ " *" - | _ -> assert false) + | _ -> die "" __LOC__) | ["cpp"] , "RawConstPointer" -> (match params with | [t] -> "const " ^ (type_string (follow t) ) ^ " *" - | _ -> assert false) + | _ -> die "" __LOC__) | ["cpp"] , "Function" -> "::cpp::Function< " ^ (cpp_function_signature_params params ) ^ " >" | _ -> type_string_suff suffix (apply_params type_def.t_params params type_def.t_type) remap @@ -847,16 +847,16 @@ and cpp_function_signature_params params = match params with | [t; abi] -> (match follow abi with | TInst (klass,_) -> cpp_function_signature t (get_meta_string klass.cl_meta Meta.Abi) | _ -> print_endline (type_string abi); - assert false ) + die "" __LOC__ ) | _ -> print_endline ("Params:" ^ (String.concat "," (List.map type_string params) )); - assert false; + die "" __LOC__; and gen_interface_arg_type_name name opt typ = let type_str = (type_string typ) in (* type_str may have already converted Null to Dynamic because of NotNull tag ... *) (if (opt && (cant_be_null typ) && type_str<>"Dynamic" ) then - "hx::Null< " ^ type_str ^ " > " + "::hx::Null< " ^ type_str ^ " > " else type_str ) ^ " " ^ (keyword_remap name) @@ -1621,13 +1621,13 @@ and tcpp_to_string_suffix suffix tcpp = match tcpp with if suffix="_obj" then name else - "hx::Native< " ^ name ^ "* >"; + "::hx::Native< " ^ name ^ "* >"; | TCppInst klass -> (cpp_class_path_of klass) ^ suffix | TCppInterface klass when suffix="_obj" -> (cpp_class_path_of klass) ^ suffix | TCppInterface _ -> "::Dynamic" - | TCppClass -> "hx::Class" ^ suffix; + | TCppClass -> "::hx::Class" ^ suffix; | TCppGlobal -> "::Dynamic"; | TCppNull -> " ::Dynamic"; | TCppCode _ -> "Code" @@ -1638,14 +1638,14 @@ and tcpp_objc_block_struct argTypes retType = let suffix = (string_of_int (List.length argTypes)) in if (ret="void") then begin if (List.length argTypes) = 0 then - "hx::TObjcBlockVoidVoid" + "::hx::TObjcBlockVoidVoid" else - "hx::TObjcBlockVoidArgs" ^ suffix ^ "< " ^ args ^ " >" + "::hx::TObjcBlockVoidArgs" ^ suffix ^ "< " ^ args ^ " >" end else begin if (List.length argTypes) = 0 then - "hx::TObjcBlockRetVoid< " ^ ret ^ " >" + "::hx::TObjcBlockRetVoid< " ^ ret ^ " >" else - "hx::TObjcBlockRetArgs" ^ suffix ^ "< " ^ ret ^ "," ^ args ^ " >" + "::hx::TObjcBlockRetArgs" ^ suffix ^ "< " ^ ret ^ "," ^ args ^ " >" end and tcpp_to_string tcpp = @@ -1734,7 +1734,7 @@ let rec cpp_type_of stack ctx haxe_type = else begin let stack = haxe_type :: stack in (match haxe_type with - | TMono r -> (match !r with None -> TCppDynamic | Some t -> cpp_type_of stack ctx t) + | TMono r -> (match r.tm_type with None -> TCppDynamic | Some t -> cpp_type_of stack ctx t) | TEnum (enum,params) -> TCppEnum(enum) @@ -1825,7 +1825,7 @@ let rec cpp_type_of stack ctx haxe_type = TCppProtocol(klass) (* TODO - get the line number here *) | _ -> print_endline "cpp.objc.Protocol must refer to an interface"; - assert false; + die "" __LOC__; ) | (["cpp"],"Reference"), [param] -> TCppReference(cpp_type_of stack ctx param) @@ -1888,7 +1888,7 @@ let rec cpp_type_of stack ctx haxe_type = and cpp_function_type_of stack ctx function_type abi = let abi = (match follow abi with | TInst (klass1,_) -> get_meta_string klass1.cl_meta Meta.Abi - | _ -> assert false ) + | _ -> die "" __LOC__ ) in cpp_function_type_of_string stack ctx function_type abi and cpp_function_type_of_string stack ctx function_type abi_string = @@ -1974,7 +1974,7 @@ let rec cpp_object_name = function | TCppScalarArray(value) -> "::Array_obj< " ^ (tcpp_to_string value) ^ " >" | TCppObjC klass -> (cpp_class_path_of klass) ^ "_obj" | TCppInst klass -> (cpp_class_path_of klass) ^ "_obj" - | TCppClass -> "hx::Class_obj"; + | TCppClass -> "::hx::Class_obj"; | TCppDynamic -> "Dynamic" | TCppVoid -> "void" | TCppVoidStar -> "void *" @@ -2093,7 +2093,7 @@ let ctx_arg_type_name ctx name default_val arg_type prefix = let type_str = (ctx_type_string ctx arg_type) in match default_val with | Some {eexpr = TConst TNull} -> (type_str,remap_name) - | Some constant when (ctx_cant_be_null ctx arg_type) -> ("hx::Null< " ^ type_str ^ " > ",prefix ^ remap_name) + | Some constant when (ctx_cant_be_null ctx arg_type) -> ("::hx::Null< " ^ type_str ^ " > ",prefix ^ remap_name) | Some constant -> (type_str,prefix ^ remap_name) | _ -> (type_str,remap_name);; @@ -2126,7 +2126,7 @@ let rec ctx_tfun_arg_list ctx include_names arg_list = let type_str = (ctx_type_string ctx arg_type) in (* type_str may have already converted Null to Dynamic because of NotNull tag ... *) if o && (ctx_cant_be_null ctx arg_type) && type_str<>"Dynamic" then - "hx::Null< " ^ type_str ^ " > " + "::hx::Null< " ^ type_str ^ " > " else type_str in @@ -2283,7 +2283,7 @@ let cpp_template_param path native = if (native) then path else match path with - | "::Array" -> "hx::ArrayBase" + | "::Array" -> "::hx::ArrayBase" | "::Int" -> "int" | "::Bool" -> "bool" | x -> x @@ -2677,17 +2677,17 @@ let retype_expression ctx request_type function_args function_type expression_tr let retypedArgs = List.map (retype obj.cpptype) args in CppCall( FuncInstance(obj, InstPtr, member), retypedArgs), return_type - | CppFunction( FuncStatic(obj, false, member), _ ) when member.cf_name = "hx::AddressOf" -> + | CppFunction( FuncStatic(obj, false, member), _ ) when member.cf_name = "::hx::AddressOf" -> let arg = retype TCppUnchanged (List.hd args) in let rawType = match arg.cpptype with | TCppReference(x) -> x | x -> x in CppAddressOf(arg), TCppRawPointer("", rawType) - | CppFunction( FuncStatic(obj, false, member), _ ) when member.cf_name = "hx::StarOf" -> + | CppFunction( FuncStatic(obj, false, member), _ ) when member.cf_name = "::hx::StarOf" -> let arg = retype TCppUnchanged (List.hd args) in let rawType = match arg.cpptype with | TCppReference(x) -> x | x -> x in CppAddressOf(arg), TCppStar(rawType,false) - | CppFunction( FuncStatic(obj, false, member), _ ) when member.cf_name = "hx::Dereference" -> + | CppFunction( FuncStatic(obj, false, member), _ ) when member.cf_name = "::hx::Dereference" -> let arg = retype TCppUnchanged (List.hd args) in CppDereference(arg), arg.cpptype @@ -3092,6 +3092,7 @@ let retype_expression ctx request_type function_args function_type expression_tr else (match return_type with | TCppObjC(k) -> CppCastObjC(baseCpp,k), return_type | TCppPointer(_,_) + | TCppRawPointer(_,_) | TCppStar(_) | TCppInst(_) -> CppCast(baseCpp,return_type), return_type | TCppString -> CppCastScalar(baseCpp,"::String"), return_type @@ -3316,7 +3317,7 @@ let cpp_gen_default_values ctx args prefix = ctx.ctx_output ( if not_null then ".Default(" ^ (default_value_string ctx.ctx_common const) ^ ");\n" else - ";\n" ^ spacer ^ "\tif (hx::IsNull(" ^ pname ^ ")) " ^ name ^ " = " ^ (default_value_string ctx.ctx_common const) ^ ";\n" + ";\n" ^ spacer ^ "\tif (::hx::IsNull(" ^ pname ^ ")) " ^ name ^ " = " ^ (default_value_string ctx.ctx_common const) ^ ";\n" ); | _ -> () ) args; @@ -3440,11 +3441,11 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ | CppNull -> out "null()" | CppNil -> out "nil" - | CppThis ThisReal -> out "hx::ObjectPtr(this)" + | CppThis ThisReal -> out "::hx::ObjectPtr(this)" | CppThis _ -> out "__this" | CppSuper thiscall -> - out ("hx::ObjectPtr(" ^ (if thiscall=ThisReal then "this" else "__this.mPtr") ^ ")") + out ("::hx::ObjectPtr(" ^ (if thiscall=ThisReal then "this" else "__this.mPtr") ^ ")") | CppBreak -> out "break" | CppContinue -> out "continue" @@ -3471,7 +3472,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ out ".StaticCast< ::hx::EnumBase >()"; out "->_hx_getIndex()" - | CppNullAccess -> out ("hx::Throw(" ^ strq "Null access" ^ ")") + | CppNullAccess -> out ("::hx::Throw(" ^ strq "Null access" ^ ")") | CppFunction(func,_) -> (match func with | FuncThis(field,_) -> @@ -3480,7 +3481,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ gen expr; out ((if expr.cpptype=TCppString || inst=InstStruct then "." else "->") ^ (cpp_member_name_of field) ^ "_dyn()"); | FuncInterface(expr,_,field) -> gen expr; - out ("->__Field(" ^ strq field.cf_name ^ ", hx::paccDynamic)") + out ("->__Field(" ^ strq field.cf_name ^ ", ::hx::paccDynamic)") | FuncStatic(clazz,_,field) -> let rename = get_meta_string field.cf_meta Meta.Native in if rename<>"" then @@ -3493,7 +3494,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ if isGlobal then out " ::"; out name; | FuncInternal(expr,name,_) -> - gen expr; out ("->__Field(" ^ (strq name) ^ ",hx::paccDynamic)") + gen expr; out ("->__Field(" ^ (strq name) ^ ",::hx::paccDynamic)") | FuncSuper _ | FuncSuperConstruct _ -> abort "Can't create super closure" expr.cpppos | FuncNew _ -> abort "Can't create new closure" expr.cpppos | FuncEnumConstruct _ -> abort "Enum constructor outside of CppCall" expr.cpppos @@ -3517,7 +3518,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ let names = ExtString.String.nsplit field.cf_name ":" in let field_name, arg_names = match names with | name :: args -> name, args - | _ -> assert false (* per nsplit specs, this should never happen *) + | _ -> die "" __LOC__ (* per nsplit specs, this should never happen *) in out (" " ^ field_name); (try match arg_list, arg_names with @@ -3607,7 +3608,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ | TCppObjC klass -> (cpp_class_path_of klass) ^ "_obj::__new" | TCppNativePointer klass -> "new " ^ (cpp_class_path_of klass); | TCppInst klass -> (cpp_class_path_of klass) ^ "_obj::__new" - | TCppClass -> "hx::Class_obj::__new"; + | TCppClass -> "::hx::Class_obj::__new"; | TCppFunction _ -> tcpp_to_string newType | _ -> abort ("Unknown 'new' target " ^ (tcpp_to_string newType)) expr.cpppos in @@ -3637,7 +3638,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ let signature = ctx_function_signature ctx false member.cf_type "" in let name = cpp_member_name_of member in (*let void_cast = has_meta_key field.cf_meta Meta.Void in*) - out ("::cpp::Function< " ^ signature ^">(hx::AnyCast("); + out ("::cpp::Function< " ^ signature ^">(::hx::AnyCast("); out ("&::" ^(join_class_path_remap klass.cl_path "::")^ "_obj::" ^ name ); out " ))" @@ -3647,7 +3648,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ | CppDynamicField(obj,name) -> gen obj; - out ("->__Field(" ^ (strq name) ^ ",hx::paccDynamic)"); + out ("->__Field(" ^ (strq name) ^ ",::hx::paccDynamic)"); | CppArray(arrayLoc) -> (match arrayLoc with | ArrayTyped(arrayObj,index,_) -> @@ -3719,7 +3720,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ gen arrayObj; out "->__set("; gen index; out ","; gen rvalue; out ")" ) | CppDynamicRef(expr,name) -> - gen expr; out ("->__SetField(" ^ (strq name) ^ ","); gen rvalue; out ",hx::paccDynamic)" + gen expr; out ("->__SetField(" ^ (strq name) ^ ","); gen rvalue; out ",::hx::paccDynamic)" | CppExternRef(name, isGlobal) -> if isGlobal then out " ::"; out (name ^ " = "); ); out close; @@ -3735,7 +3736,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ out "("; gen_lvalue lvalue; out ","; gen rvalue; out ")" | CppPosition(name,line,clazz,func) -> - out ("hx::SourceInfo(" ^ strq name ^ "," ^ string_of_int(Int32.to_int line) ^ "," ^ strq clazz ^ "," ^ strq func ^ ")") + out ("::hx::SourceInfo(" ^ strq name ^ "," ^ string_of_int(Int32.to_int line) ^ "," ^ strq clazz ^ "," ^ strq func ^ ")") | CppClassOf (path,native) -> let path = "::" ^ (join_class_path_remap (path) "::" ) in @@ -3746,9 +3747,9 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ if (native) then out "null()" else if (path="::Array") then - out "hx::ArrayBase::__mClass" + out "::hx::ArrayBase::__mClass" else - out ("hx::ClassOf< " ^ path ^ " >()") + out ("::hx::ClassOf< " ^ path ^ " >()") | CppVar(loc) -> gen_val_loc loc false; @@ -3774,14 +3775,14 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ let lengthStr = string_of_int length in if (expr.cpptype!=TCppVoid) then out " ::Dynamic("; if (isStruct) && length>0 && length<=5 then begin - out ("hx::AnonStruct" ^ lengthStr ^"_obj< " ^ + out ("::hx::AnonStruct" ^ lengthStr ^"_obj< " ^ (String.concat "," (List.map (fun (_,value) -> tcpp_to_string value.cpptype) values) ) ^ " >::Create(" ); let sep = ref "" in List.iter (fun (name,value) -> out (!sep ^ (strq name) ^ "," ); sep:=","; gen value ) values; out ")"; end else begin - out ("hx::Anon_obj::Create(" ^ lengthStr ^")"); + out ("::hx::Anon_obj::Create(" ^ lengthStr ^")"); let sorted = List.sort (fun (_,_,h0) (_,_,h1) -> Int32.compare h0 h1 ) (List.map (fun (name,value) -> name,value,(gen_hash32 0 name ) ) values) in writer#push_indent; @@ -3806,7 +3807,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ | CppFloat f -> out_top ( f ^ "," ) | CppString s -> out_top ( (strq s) ^ "," ) | CppBool b -> out_top (if b then "1," else "0,") - | _ -> assert false + | _ -> die "" __LOC__ ) exprList; out_top ("\n};\n"); out ("::Array_obj< " ^ typeName ^ " >::fromData( " ^ id ^ "," ^ list_num exprList ^ ")"); @@ -3827,17 +3828,17 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ | CppBinop( Ast.OpUShr, left, right) -> - out "hx::UShr("; gen left; out ","; gen right; out ")"; + out "::hx::UShr("; gen left; out ","; gen right; out ")"; | CppBinop( Ast.OpMod, left, right) -> if is_constant_zero right then begin - out "hx::Mod("; gen left; out ",(double)( "; gen right; out " ))"; + out "::hx::Mod("; gen left; out ",(double)( "; gen right; out " ))"; end else begin - out "hx::Mod("; gen left; out ","; gen right; out ")"; + out "::hx::Mod("; gen left; out ","; gen right; out ")"; end | CppBinop( Ast.OpDiv, left, right) when is_constant_zero right -> - out "hx::DivByZero("; gen left; out ")"; + out "::hx::DivByZero("; gen left; out ")"; | CppBinop(op, left, right) -> let op = string_of_op op expr.cpppos in @@ -3847,13 +3848,13 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ gen right; out ")"; | CppCompare(opName, left, right, _) -> - out ("hx::" ^ opName ^ "( "); + out ("::hx::" ^ opName ^ "( "); gen left; out (","); gen right; out (" )"); | CppNullCompare(op, left) -> - out ("hx::" ^ op ^ "( "); gen left; out (" )"); + out ("::hx::" ^ op ^ "( "); gen left; out (" )"); | CppThrow(value) -> out "HX_STACK_DO_THROW("; gen value; out ")"; @@ -3983,7 +3984,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ (match cpp_type_of ctx v.v_type with | TCppInterface(klass) -> let hash = (cpp_class_hash klass) in - output_i (!else_str ^ "if (hx::TIsInterface< (int)" ^ hash ^ " >(_hx_e.mPtr))") + output_i (!else_str ^ "if (::hx::TIsInterface< (int)" ^ hash ^ " >(_hx_e.mPtr))") | TCppString -> output_i (!else_str ^ "if (_hx_e.IsClass< ::String >() && _hx_e->toString()!=null() )"); | _ -> @@ -4016,7 +4017,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ | CppTCast(expr,cppType) -> (match cppType with | TCppInterface(i) -> - out " hx::interface_check("; + out " ::hx::interface_check("; gen expr; out ("," ^ (cpp_class_hash i) ^")") | _ -> begin @@ -4024,7 +4025,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ if toType="Dynamic" then (out " ::Dynamic("; gen expr; out ")") else - (out ("hx::TCast< " ^ toType ^ " >::cast("); gen expr; out ")") + (out ("::hx::TCast< " ^ toType ^ " >::cast("); gen expr; out ")") end ) @@ -4036,17 +4037,17 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ gen expr; out (close ^ ".StaticCast< " ^ tcpp_to_string toType ^" >()") | CppCast(expr,toType) -> - (match expr.cppexpr, expr.cpptype with - | CppCall( FuncInternal _, _), _ -> + (match expr.cppexpr, expr.cpptype, toType with + | CppCall( FuncInternal _, _), _, _ -> gen expr; out (".StaticCast< " ^ tcpp_to_string toType ^" >()") - | _, TCppObjC(_) - | _, TCppObjCBlock(_) -> + | _, TCppObjC(_), _ + | _, TCppObjCBlock(_), _ -> out ("( ("^ tcpp_to_string toType ^")((id) ( "); gen expr; out (") ))") - | _,_ -> - (match toType with - | TCppObjectPtr -> out ("hx::DynamicPtr("); gen expr; out (")") - | t -> out ("( ("^ tcpp_to_string t ^")("); gen expr; out (") )") - ) + | _,_,TCppObjectPtr -> out ("::hx::DynamicPtr("); gen expr; out (")") + | _,TCppPointer(_,_), TCppStar(_,_) + | _,TCppPointer(_,_), TCppRawPointer(_,_) + -> out ("( ("^ tcpp_to_string toType ^")( ("); gen expr; out (").get_raw()) )") + | _ -> out ("( ("^ tcpp_to_string toType ^")("); gen expr; out (") )") ) | CppCastScalar(expr,scalar) -> @@ -4085,7 +4086,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ gen_val_loc varLoc true | CppArrayRef arrayLoc -> (match arrayLoc with | ArrayObject(arrayObj, index, _) -> - out "hx::IndexRef("; gen arrayObj; out ".mPtr,"; gen index; out ")"; + out "::hx::IndexRef("; gen arrayObj; out ".mPtr,"; gen index; out ")"; | ArrayTyped(arrayObj, index, _) -> gen arrayObj; out "["; gen index; out "]"; | ArrayPointer(arrayObj, index) -> @@ -4094,9 +4095,9 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ gen arrayObj; out "["; gen index; out "]"; | ArrayVirtual(arrayObj, index) | ArrayDynamic(arrayObj, index) -> - out "hx::IndexRef("; gen arrayObj; out ".mPtr,"; gen index; out ")"; + out "::hx::IndexRef("; gen arrayObj; out ".mPtr,"; gen index; out ")"; | ArrayImplements(_,arrayObj,index) -> - out "hx::__ArrayImplRef("; gen arrayObj; out ","; gen index; out ")"; + out "::hx::__ArrayImplRef("; gen arrayObj; out ","; gen index; out ")"; ) | CppExternRef(name,isGlobal) -> if isGlobal then out " ::"; out name | CppDynamicRef(expr,name) -> @@ -4104,7 +4105,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ | TCppVariant -> "getObject()" | _ -> ".mPtr" in - out "hx::FieldRef(("; gen expr ; out (")" ^ objPtr ^ "," ^ strq name ^ ")") + out "::hx::FieldRef(("; gen expr ; out (")" ^ objPtr ^ "," ^ strq name ^ ")") and gen_val_loc loc lvalue = match loc with @@ -4129,17 +4130,17 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ gen obj; out ("->" ^ (cpp_member_name_of member) ^ "_get()" ) and string_of_op_eq op pos = match op with - | OpAdd -> "hx::AddEq" - | OpMult -> "hx::MultEq" - | OpDiv -> "hx::DivEq" - | OpSub -> "hx::SubEq" - | OpAnd -> "hx::AndEq" - | OpOr -> "hx::OrEq" - | OpXor -> "hx::XorEq" - | OpShl -> "hx::ShlEq" - | OpShr -> "hx::ShrEq" - | OpUShr -> "hx::UShrEq" - | OpMod -> "hx::ModEq" + | OpAdd -> "::hx::AddEq" + | OpMult -> "::hx::MultEq" + | OpDiv -> "::hx::DivEq" + | OpSub -> "::hx::SubEq" + | OpAnd -> "::hx::AndEq" + | OpOr -> "::hx::OrEq" + | OpXor -> "::hx::XorEq" + | OpShl -> "::hx::ShlEq" + | OpShr -> "::hx::ShrEq" + | OpUShr -> "::hx::UShrEq" + | OpMod -> "::hx::ModEq" | _ -> abort "Bad assign op" pos and string_of_op op pos = match op with | OpAdd -> "+" @@ -4175,7 +4176,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_ writer#add_big_closures; let argsCount = list_num closure.close_args in output_i ("HX_BEGIN_LOCAL_FUNC_S" ^ size ^ "("); - out (if closure.close_this != None then "hx::LocalThisFunc," else "hx::LocalFunc,"); + out (if closure.close_this != None then "::hx::LocalThisFunc," else "::hx::LocalFunc,"); out ("_hx_Closure_" ^ (string_of_int closure.close_id) ); Hashtbl.iter (fun name var -> out ("," ^ (cpp_macro_var_type_of ctx var) ^ "," ^ (keyword_remap name)); @@ -4440,7 +4441,7 @@ let gen_field ctx class_def class_name ptr_name dot_name is_static is_interface output ("static ::Dynamic " ^ wrapName ^ "( " ); let sep = ref " " in if not is_static then begin - output "hx::Object *obj"; + output "::hx::Object *obj"; sep := ","; end; ExtList.List.iteri (fun i _ -> output (!sep ^ "const Dynamic &a" ^ (string_of_int i)) ; sep:=",") tcpp_args; @@ -4478,9 +4479,9 @@ let gen_field ctx class_def class_name ptr_name dot_name is_static is_interface let nName = string_of_int (List.length tcpp_args) in output ("::Dynamic " ^ class_name ^ "::" ^ remap_name ^ "_dyn() {\n\treturn "); if is_static then - output ("hx::CreateStaticFunction" ^ nName ^ "(\"" ^ remap_name ^ "\"," ^ wrapName ^ ");") + output ("::hx::CreateStaticFunction" ^ nName ^ "(\"" ^ remap_name ^ "\"," ^ wrapName ^ ");") else - output ("hx::CreateMemberFunction" ^ nName ^ "(\"" ^ remap_name ^ "\",this," ^ wrapName ^ ");"); + output ("::hx::CreateMemberFunction" ^ nName ^ "(\"" ^ remap_name ^ "\",this," ^ wrapName ^ ");"); output "}\n"; end else begin if (is_static) then output "STATIC_"; @@ -4580,7 +4581,7 @@ let gen_member_def ctx class_def is_static is_interface field = output (if (not is_static) then ")=0;\n" else ");\n"); if (reflective class_def field) then begin if (Common.defined ctx.ctx_common Define.DynamicInterfaceClosures) then - output (" inline ::Dynamic " ^ remap_name ^ "_dyn() { return __Field( " ^ (strq ctx.ctx_common field.cf_name) ^ ", hx::paccDynamic); }\n" ) + output (" inline ::Dynamic " ^ remap_name ^ "_dyn() { return __Field( " ^ (strq ctx.ctx_common field.cf_name) ^ ", ::hx::paccDynamic); }\n" ) else output (" virtual ::Dynamic " ^ remap_name ^ "_dyn()=0;\n" ); end @@ -4589,8 +4590,8 @@ let gen_member_def ctx class_def is_static is_interface field = let returnType = ctx_type_string ctx return_type in let returnStr = if returnType = "void" then "" else "return " in let commaArgList = if argList="" then argList else "," ^ argList in - let cast = "hx::interface_cast< ::" ^ join_class_path_remap class_def.cl_path "::" ^ "_obj *>" in - output (" " ^ returnType ^ " (hx::Object :: *_hx_" ^ remap_name ^ ")(" ^ argList ^ "); \n"); + let cast = "::hx::interface_cast< ::" ^ join_class_path_remap class_def.cl_path "::" ^ "_obj *>" in + output (" " ^ returnType ^ " (::hx::Object :: *_hx_" ^ remap_name ^ ")(" ^ argList ^ "); \n"); output (" static inline " ^ returnType ^ " " ^ remap_name ^ "( ::Dynamic _hx_" ^ commaArgList ^ ") {\n"); output (" " ^ returnStr ^ "(_hx_.mPtr->*( " ^ cast ^ "(_hx_.mPtr->_hx_getInterface(" ^ (cpp_class_hash class_def) ^ ")))->_hx_" ^ remap_name ^ ")(" ^ cpp_arg_names args ^ ");\n }\n" ); end @@ -4609,7 +4610,7 @@ let gen_member_def ctx class_def is_static is_interface field = if ( doDynamic ) then begin output ("::Dynamic " ^ remap_name ^ ";\n"); if (not is_static) && (is_gc_element ctx TCppDynamic) then - output ("\t\tinline ::Dynamic _hx_set_" ^ remap_name ^ "(hx::StackContext *_hx_ctx,::Dynamic _hx_v) { HX_OBJ_WB(this,_hx_v.mPtr) return " ^ remap_name ^ "=_hx_v; }\n"); + output ("\t\tinline ::Dynamic _hx_set_" ^ remap_name ^ "(::hx::StackContext *_hx_ctx,::Dynamic _hx_v) { HX_OBJ_WB(this,_hx_v.mPtr) return " ^ remap_name ^ "=_hx_v; }\n"); output (if is_static then "\t\tstatic " else "\t\t"); output ("inline ::Dynamic &" ^ remap_name ^ "_dyn() " ^ "{return " ^ remap_name^ "; }\n") end @@ -4648,7 +4649,7 @@ let gen_member_def ctx class_def is_static is_interface field = output (tcppStr ^ " " ^ remap_name ^ ";\n" ); if not is_static && (is_gc_element ctx tcpp) then begin let getPtr = match tcpp with | TCppString -> ".raw_ref()" | _ -> ".mPtr" in - output ("\t\tinline " ^ tcppStr ^ " _hx_set_" ^ remap_name ^ "(hx::StackContext *_hx_ctx," ^ tcppStr ^ " _hx_v) { HX_OBJ_WB(this,_hx_v" ^ getPtr ^ ") return " ^ remap_name ^ "=_hx_v; }\n"); + output ("\t\tinline " ^ tcppStr ^ " _hx_set_" ^ remap_name ^ "(::hx::StackContext *_hx_ctx," ^ tcppStr ^ " _hx_v) { HX_OBJ_WB(this,_hx_v" ^ getPtr ^ ") return " ^ remap_name ^ "=_hx_v; }\n"); end; (* Add a "dyn" function for variable to unify variable/function access *) @@ -4732,7 +4733,7 @@ let find_referenced_types_flags ctx obj field_name super_deps constructor_deps h if not (List.exists (fun t2 -> Type.fast_eq in_type t2) !visited) then begin visited := in_type :: !visited; begin match follow in_type with - | TMono r -> (match !r with None -> () | Some t -> visit_type t) + | TMono r -> (match r.tm_type with None -> () | Some t -> visit_type t) | TEnum (enum,params) -> add_type enum.e_path (* If a class has a template parameter, then we treat it as dynamic - except for the Array, Class, FastIterator or Pointer classes, for which we do a fully typed object *) @@ -4883,7 +4884,7 @@ let generate_main_footer2 output_main = output_main " }\n\n"; output_main "void __hxcpp_lib_main() {\n"; output_main " HX_TOP_OF_STACK\n"; - output_main " hx::Boot();\n"; + output_main " ::hx::Boot();\n"; output_main " __boot_all();\n"; output_main " __hxcpp_main();\n"; output_main " }\n" @@ -4896,7 +4897,7 @@ let generate_main ctx super_deps class_def = let main_expression = (match class_def.cl_ordered_statics with | [{ cf_expr = Some expression }] -> expression; - | _ -> assert false ) in + | _ -> die "" __LOC__ ) in ignore(find_referenced_types ctx (TClassDecl class_def) super_deps (Hashtbl.create 0) false false false); let depend_referenced = find_referenced_types ctx (TClassDecl class_def) super_deps (Hashtbl.create 0) false true false in let generate_startup filename is_main = @@ -4963,9 +4964,9 @@ let generate_boot ctx boot_enums boot_classes nonboot_classes init_classes = output_boot "\nvoid __files__boot();\n"; output_boot "\nvoid __boot_all()\n{\n"; output_boot "__files__boot();\n"; - output_boot "hx::RegisterResources( hx::GetResources() );\n"; + output_boot "::hx::RegisterResources( ::hx::GetResources() );\n"; if newScriptable then - output_boot ("hx::ScriptableRegisterNameSlots(scriptableInterfaceFuncs," ^ (string_of_int !(ctx.ctx_interface_slot_count) ) ^ ");\n"); + output_boot ("::hx::ScriptableRegisterNameSlots(scriptableInterfaceFuncs," ^ (string_of_int !(ctx.ctx_interface_slot_count) ) ^ ");\n"); List.iter ( fun class_path -> output_boot ("::" ^ ( join_class_path_remap class_path "::" ) ^ "_obj::__register();\n") ) @@ -5029,7 +5030,7 @@ let generate_files common_ctx file_info = output_files " 0 };\n"; output_files "} // namespace hx\n"; - output_files "void __files__boot() { __hxcpp_set_debugger_info(hx::__hxcpp_all_classes, hx::__hxcpp_all_files_fullpath); }\n"; + output_files "void __files__boot() { __hxcpp_set_debugger_info(::hx::__hxcpp_all_classes, ::hx::__hxcpp_all_files_fullpath); }\n"; files_file#close;; @@ -5098,7 +5099,7 @@ let generate_enum_files baseCtx enum_def super_deps meta = output_cpp (remap_class_name ^ " " ^ class_name ^ "::" ^ name ^ "(" ^ (ctx_tfun_arg_list ctx true args) ^")\n"); - output_cpp ("{\n\treturn hx::CreateEnum< " ^ class_name ^ " >(" ^ (strq name) ^ "," ^ + output_cpp ("{\n\treturn ::hx::CreateEnum< " ^ class_name ^ " >(" ^ (strq name) ^ "," ^ (string_of_int constructor.ef_index) ^ "," ^ (string_of_int (List.length args)) ^ ")" ); ExtList.List.iteri (fun i (arg,_,_) -> output_cpp ("->_hx_init(" ^ (string_of_int i) ^ "," ^ (keyword_remap arg) ^ ")")) args; output_cpp ";\n}\n\n" @@ -5111,7 +5112,7 @@ let generate_enum_files baseCtx enum_def super_deps meta = (match constructor.ef_type with | TFun(args,_) -> List.length args | _ -> 0 ) in - output_cpp ("bool " ^ class_name ^ "::__GetStatic(const ::String &inName, ::Dynamic &outValue, hx::PropertyAccess inCallProp)\n{\n"); + output_cpp ("bool " ^ class_name ^ "::__GetStatic(const ::String &inName, ::Dynamic &outValue, ::hx::PropertyAccess inCallProp)\n{\n"); PMap.iter (fun _ constructor -> let name = constructor.ef_name in let dyn = if constructor_arg_count constructor > 0 then "_dyn()" else "" in @@ -5150,7 +5151,7 @@ let generate_enum_files baseCtx enum_def super_deps meta = output_cpp ("}\n\n"); (* Dynamic "Get" Field function - string version *) - output_cpp ("hx::Val " ^ class_name ^ "::__Field(const ::String &inName,hx::PropertyAccess inCallProp)\n{\n"); + output_cpp ("::hx::Val " ^ class_name ^ "::__Field(const ::String &inName,::hx::PropertyAccess inCallProp)\n{\n"); let dump_constructor_test _ constr = output_cpp ("\tif (inName==" ^ (strq constr.ef_name) ^ ") return " ^ (keyword_remap constr.ef_name) ); @@ -5173,14 +5174,14 @@ let generate_enum_files baseCtx enum_def super_deps meta = (* ENUM - Mark static as used by GC - they are const now, so no marking*) (* ENUM - Visit static as used by GC - none *) - output_cpp ("hx::Class " ^ class_name ^ "::__mClass;\n\n"); + output_cpp ("::hx::Class " ^ class_name ^ "::__mClass;\n\n"); output_cpp ("Dynamic __Create_" ^ class_name ^ "() { return new " ^ class_name ^ "; }\n\n"); output_cpp ("void " ^ class_name ^ "::__register()\n{\n"); let text_name = strq (join_class_path class_path ".") in - output_cpp ("\nhx::Static(__mClass) = hx::_hx_RegisterClass(" ^ text_name ^ - ", hx::TCanCast< " ^ class_name ^ " >," ^ class_name ^ "_sStaticFields,0,\n"); + output_cpp ("\n::hx::Static(__mClass) = ::hx::_hx_RegisterClass(" ^ text_name ^ + ", ::hx::TCanCast< " ^ class_name ^ " >," ^ class_name ^ "_sStaticFields,0,\n"); output_cpp ("\t&__Create_" ^ class_name ^ ", &__Create,\n"); output_cpp ("\t&super::__SGetClass(), &Create" ^ class_name ^ ", 0\n"); output_cpp("#ifdef HXCPP_VISIT_ALLOCS\n , 0\n#endif\n"); @@ -5200,7 +5201,7 @@ let generate_enum_files baseCtx enum_def super_deps meta = match constructor.ef_type with | TFun (_,_) -> () | _ -> - output_cpp ( (keyword_remap name) ^ " = hx::CreateConstEnum< " ^ class_name ^ " >(" ^ (strq name) ^ "," ^ + output_cpp ( (keyword_remap name) ^ " = ::hx::CreateConstEnum< " ^ class_name ^ " >(" ^ (strq name) ^ "," ^ (string_of_int constructor.ef_index) ^ ");\n" ) ) enum_def.e_constrs; output_cpp ("}\n\n"); @@ -5213,7 +5214,7 @@ let generate_enum_files baseCtx enum_def super_deps meta = cpp_file#close; let h_file = new_header_file common_ctx common_ctx.file class_path in - let super = "hx::EnumBase_obj" in + let super = "::hx::EnumBase_obj" in let output_h = (h_file#write) in let def_string = join_class_path class_path "_" in @@ -5236,7 +5237,7 @@ let generate_enum_files baseCtx enum_def super_deps meta = output_h ("\t\tHX_DO_ENUM_RTTI;\n"); output_h ("\t\tstatic void __boot();\n"); output_h ("\t\tstatic void __register();\n"); - output_h ("\t\tstatic bool __GetStatic(const ::String &inName, Dynamic &outValue, hx::PropertyAccess inCallProp);\n"); + output_h ("\t\tstatic bool __GetStatic(const ::String &inName, Dynamic &outValue, ::hx::PropertyAccess inCallProp);\n"); output_h ("\t\t::String GetEnumName( ) const { return " ^ (strq (join_class_path class_path ".")) ^ "; }\n" ); output_h ("\t\t::String __ToString() const { return " ^ (strq (just_class_name ^ ".") )^ " + _hx_tag; }\n\n"); @@ -5382,7 +5383,7 @@ let has_boot_field class_def = let cpp_tfun_signature ctx include_names args return_type = let argList = ctx_tfun_arg_list ctx include_names args in let returnType = ctx_type_string ctx return_type in - ("( " ^ returnType ^ " (hx::Object::*)(" ^ argList ^ "))") + ("( " ^ returnType ^ " (::hx::Object::*)(" ^ argList ^ "))") ;; exception FieldFound of tclass_field;; @@ -5569,7 +5570,7 @@ let generate_protocol_delegate ctx class_def output = (argString) ^ "' != '" ^ (String.concat "," argNames) ^ "'" ) field.cf_pos end); output (" {\n"); - output ("\thx::NativeAttach _hx_attach;\n"); + output ("\t::hx::NativeAttach _hx_attach;\n"); output ( (if retStr="void" then "\t" else "\treturn ") ^ full_class_name ^ "::" ^ (keyword_remap field.cf_name) ^ "(haxeObj"); List.iter (fun (name,_,_) -> output ("," ^ name)) args; output (");\n}\n\n"); @@ -5598,7 +5599,7 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta let smart_class_name = (snd class_path) in let class_name_text = join_class_path class_path "." in let gcName = const_char_star class_name_text in - let ptr_name = "hx::ObjectPtr< " ^ class_name ^ " >" in + let ptr_name = "::hx::ObjectPtr< " ^ class_name ^ " >" in let debug = if (has_meta_key class_def.cl_meta Meta.NoDebug) || ( Common.defined baseCtx.ctx_common Define.NoDebug) then 0 else 1 in let scriptable = inScriptable && not class_def.cl_private in @@ -5698,9 +5699,9 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta out ("}\n\n"); if can_quick_alloc then begin - out (staticHead ^ ptr_name ^ " " ^ classScope ^ "__alloc(hx::Ctx *_hx_ctx" ^ + out (staticHead ^ ptr_name ^ " " ^ classScope ^ "__alloc(::hx::Ctx *_hx_ctx" ^ (if constructor_type_args="" then "" else "," ^constructor_type_args) ^") {\n"); - out ("\t" ^ class_name ^ " *__this = (" ^ class_name ^ "*)(hx::Ctx::alloc(_hx_ctx, sizeof(" ^ class_name ^ "), " ^ isContainer ^", " ^ gcName ^ "));\n"); + out ("\t" ^ class_name ^ " *__this = (" ^ class_name ^ "*)(::hx::Ctx::alloc(_hx_ctx, sizeof(" ^ class_name ^ "), " ^ isContainer ^", " ^ gcName ^ "));\n"); out ("\t*(void **)__this = " ^ class_name ^ "::_hx_vtable;\n"); let rec dump_dynamic class_def = if has_dynamic_member_functions class_def then @@ -5795,7 +5796,7 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta output_cpp ("Dynamic " ^ class_name ^ "::__CreateEmpty() { return new " ^ class_name ^ "; }\n\n"); output_cpp ("void *" ^ class_name ^ "::_hx_vtable = 0;\n\n"); - output_cpp ("Dynamic " ^ class_name ^ "::__Create(hx::DynamicArray inArgs)\n"); + output_cpp ("Dynamic " ^ class_name ^ "::__Create(::hx::DynamicArray inArgs)\n"); output_cpp ("{\n\t" ^ ptr_name ^ " _hx_result = new " ^ class_name ^ "();\n"); output_cpp ("\t_hx_result->__construct(" ^ (array_arg_list constructor_var_list) ^ ");\n"); output_cpp ("\treturn _hx_result;\n}\n\n"); @@ -5922,7 +5923,7 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta output_cpp "\n"; if (List.length dynamic_functions > 0) then begin - output_cpp ("void " ^ class_name ^ "::__alloc_dynamic_functions(hx::Ctx *_hx_ctx," ^ class_name ^ " *_hx_obj) {\n"); + output_cpp ("void " ^ class_name ^ "::__alloc_dynamic_functions(::hx::Ctx *_hx_ctx," ^ class_name ^ " *_hx_obj) {\n"); List.iter (fun name -> output_cpp ("\tif (!_hx_obj->" ^ name ^".mPtr) _hx_obj->" ^ name ^ " = new __default_" ^ name ^ "(_hx_obj);\n") ) dynamic_functions; @@ -6015,9 +6016,9 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta (has_meta_key field.cf_meta Meta.NativeProperty) || (Common.defined common_ctx Define.ForceNativeProperty) ) then - "inCallProp != hx::paccNever" + "inCallProp != ::hx::paccNever" else - "inCallProp == hx::paccAlways" + "inCallProp == ::hx::paccAlways" in let toCommon t f value = @@ -6028,13 +6029,13 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta | _ -> value ) ^ " )" in - let toVal f value = toCommon "hx::Val" f value in + let toVal f value = toCommon "::hx::Val" f value in let toDynamic f value = toCommon "" f value in if (has_get_member_field class_def) then begin (* Dynamic "Get" Field function - string version *) - output_cpp ("hx::Val " ^ class_name ^ "::__Field(const ::String &inName,hx::PropertyAccess inCallProp)\n{\n"); + output_cpp ("::hx::Val " ^ class_name ^ "::__Field(const ::String &inName,::hx::PropertyAccess inCallProp)\n{\n"); let get_field_dat = List.map (fun f -> (f.cf_name, String.length f.cf_name, (match f.cf_kind with @@ -6051,7 +6052,7 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta end; if (has_get_static_field class_def) then begin - output_cpp ("bool " ^ class_name ^ "::__GetStatic(const ::String &inName, Dynamic &outValue, hx::PropertyAccess inCallProp)\n{\n"); + output_cpp ("bool " ^ class_name ^ "::__GetStatic(const ::String &inName, Dynamic &outValue, ::hx::PropertyAccess inCallProp)\n{\n"); let get_field_dat = List.map (fun f -> (f.cf_name, String.length f.cf_name, (match f.cf_kind with @@ -6079,7 +6080,7 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta (* Dynamic "Set" Field function *) if (has_set_member_field class_def) then begin - output_cpp ("hx::Val " ^ class_name ^ "::__SetField(const ::String &inName,const hx::Val &inValue,hx::PropertyAccess inCallProp)\n{\n"); + output_cpp ("::hx::Val " ^ class_name ^ "::__SetField(const ::String &inName,const ::hx::Val &inValue,::hx::PropertyAccess inCallProp)\n{\n"); let set_field_dat = List.map (fun f -> let default_action = if is_gc_element ctx (cpp_type_of ctx f.cf_type) then @@ -6105,7 +6106,7 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta if (has_set_static_field class_def) then begin - output_cpp ("bool " ^ class_name ^ "::__SetStatic(const ::String &inName,Dynamic &ioValue,hx::PropertyAccess inCallProp)\n{\n"); + output_cpp ("bool " ^ class_name ^ "::__SetStatic(const ::String &inName,Dynamic &ioValue,::hx::PropertyAccess inCallProp)\n{\n"); let set_field_dat = List.map (fun f -> let default_action = @@ -6142,12 +6143,12 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta end; let storage field = match (cpp_type_of ctx field.cf_type) with - | TCppScalar("bool") -> "hx::fsBool" - | TCppScalar("int") -> "hx::fsInt" - | TCppScalar("Float") -> "hx::fsFloat" - | TCppString -> "hx::fsString" - | o when is_object_element ctx o -> "hx::fsObject" ^ " /* " ^ (tcpp_to_string o ) ^ " */ " - | u -> "hx::fsUnknown" ^ " /* " ^ (tcpp_to_string u) ^ " */ " + | TCppScalar("bool") -> "::hx::fsBool" + | TCppScalar("int") -> "::hx::fsInt" + | TCppScalar("Float") -> "::hx::fsFloat" + | TCppString -> "::hx::fsString" + | o when is_object_element ctx o -> "::hx::fsObject" ^ " /* " ^ (tcpp_to_string o ) ^ " */ " + | u -> "::hx::fsUnknown" ^ " /* " ^ (tcpp_to_string u) ^ " */ " in let dump_member_storage = (fun field -> output_cpp ("\t{" ^ (storage field) ^ ",(int)offsetof(" ^ class_name ^"," ^ (keyword_remap field.cf_name) ^")," ^ @@ -6164,19 +6165,19 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta let stored_fields = List.filter is_data_member implemented_instance_fields in if ( (List.length stored_fields) > 0) then begin - output_cpp ("static hx::StorageInfo " ^ class_name ^ "_sMemberStorageInfo[] = {\n"); + output_cpp ("static ::hx::StorageInfo " ^ class_name ^ "_sMemberStorageInfo[] = {\n"); List.iter dump_member_storage stored_fields; - output_cpp "\t{ hx::fsUnknown, 0, null()}\n};\n"; + output_cpp "\t{ ::hx::fsUnknown, 0, null()}\n};\n"; end else - output_cpp ("static hx::StorageInfo *" ^ class_name ^ "_sMemberStorageInfo = 0;\n"); + output_cpp ("static ::hx::StorageInfo *" ^ class_name ^ "_sMemberStorageInfo = 0;\n"); let stored_statics = List.filter is_data_member implemented_fields in if ( (List.length stored_statics) > 0) then begin - output_cpp ("static hx::StaticInfo " ^ class_name ^ "_sStaticStorageInfo[] = {\n"); + output_cpp ("static ::hx::StaticInfo " ^ class_name ^ "_sStaticStorageInfo[] = {\n"); List.iter dump_static_storage stored_statics; - output_cpp "\t{ hx::fsUnknown, 0, null()}\n};\n"; + output_cpp "\t{ ::hx::fsUnknown, 0, null()}\n};\n"; end else - output_cpp ("static hx::StaticInfo *" ^ class_name ^ "_sStaticStorageInfo = 0;\n"); + output_cpp ("static ::hx::StaticInfo *" ^ class_name ^ "_sStaticStorageInfo = 0;\n"); output_cpp "#endif\n\n"; end; (* cl_interface *) @@ -6218,7 +6219,7 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta | TFun (args,return_type) when not (is_data_member field) -> let isTemplated = not isStatic && not class_def.cl_interface in if isTemplated then output_cpp ("\ntemplate"); - output_cpp ("\nstatic void CPPIA_CALL " ^ scriptName ^ "(hx::CppiaCtx *ctx) {\n"); + output_cpp ("\nstatic void CPPIA_CALL " ^ scriptName ^ "(::hx::CppiaCtx *ctx) {\n"); let ret = match cpp_type_of ctx return_type with TCppScalar("bool") -> "b" | _ -> script_signature return_type false in if (ret<>"v") then output_cpp ("ctx->return" ^ (script_type return_type false) ^ "("); @@ -6270,8 +6271,8 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta output_cpp (" " ^ return_type ^ " " ^ name ^ "( " ^ args ^ " ) {\n"); if newInteface then begin - output_cpp ("\t\thx::CppiaCtx *__ctx = hx::CppiaCtx::getCurrent();\n" ); - output_cpp ("\t\thx::AutoStack __as(__ctx);\n" ); + output_cpp ("\t\t::hx::CppiaCtx *__ctx = ::hx::CppiaCtx::getCurrent();\n" ); + output_cpp ("\t\t::hx::AutoStack __as(__ctx);\n" ); output_cpp ("\t\t__ctx->pushObject(this);\n" ); List.iter (fun (name,opt, t ) -> output_cpp ("\t\t__ctx->push" ^ (script_type t opt) ^ "(" ^ (keyword_remap name) ^ ");\n" ); @@ -6281,8 +6282,8 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta output_cpp "\t}\n"; end else begin output_cpp ("\tif (" ^ vtable ^ ") {\n" ); - output_cpp ("\t\thx::CppiaCtx *__ctx = hx::CppiaCtx::getCurrent();\n" ); - output_cpp ("\t\thx::AutoStack __as(__ctx);\n" ); + output_cpp ("\t\t::hx::CppiaCtx *__ctx = ::hx::CppiaCtx::getCurrent();\n" ); + output_cpp ("\t\t::hx::AutoStack __as(__ctx);\n" ); output_cpp ("\t\t__ctx->pushObject(" ^ (if class_def.cl_interface then "mDelegate.mPtr" else "this" ) ^");\n" ); List.iter (fun (name,opt, t ) -> output_cpp ("\t\t__ctx->push" ^ (script_type t opt) ^ "(" ^ (keyword_remap name) ^ ");\n" ); @@ -6292,7 +6293,7 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta if (class_def.cl_interface) then begin - output_cpp (" " ^ delegate ^ "__Field(HX_CSTRING(\"" ^ field.cf_name ^ "\"), hx::paccNever)"); + output_cpp (" " ^ delegate ^ "__Field(HX_CSTRING(\"" ^ field.cf_name ^ "\"), ::hx::paccNever)"); if (List.length names <= 5) then output_cpp ("->__run(" ^ (String.concat "," names) ^ ");") else @@ -6303,7 +6304,7 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta output_cpp "return null();"; output_cpp "}\n"; if (class_def.cl_interface) && not dynamic_interface_closures then begin - output_cpp (" Dynamic " ^ name ^ "_dyn() { return mDelegate->__Field(HX_CSTRING(\"" ^ field.cf_name ^ "\"), hx::paccNever); }\n\n"); + output_cpp (" Dynamic " ^ name ^ "_dyn() { return mDelegate->__Field(HX_CSTRING(\"" ^ field.cf_name ^ "\"), ::hx::paccNever); }\n\n"); end end @@ -6317,7 +6318,7 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta let sctipt_name = class_name ^ "__scriptable" in if newInteface then begin - output_cpp ("class " ^ sctipt_name ^ " : public hx::Object {\n" ); + output_cpp ("class " ^ sctipt_name ^ " : public ::hx::Object {\n" ); output_cpp "public:\n"; end else begin output_cpp ("class " ^ sctipt_name ^ " : public " ^ class_name ^ " {\n" ); @@ -6358,19 +6359,19 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta output_cpp "#ifndef HXCPP_CPPIA_SUPER_ARG\n"; output_cpp "#define HXCPP_CPPIA_SUPER_ARG(x)\n"; output_cpp "#endif\n"; - output_cpp "static hx::ScriptNamedFunction __scriptableFunctions[] = {\n"; + output_cpp "static ::hx::ScriptNamedFunction __scriptableFunctions[] = {\n"; let dump_func f isStaticFlag = let s = try Hashtbl.find sigs f.cf_name with Not_found -> "v" in - output_cpp (" hx::ScriptNamedFunction(\"" ^ f.cf_name ^ "\",__s_" ^ f.cf_name ^ ",\"" ^ s ^ "\", " ^ isStaticFlag ^ " " ); + output_cpp (" ::hx::ScriptNamedFunction(\"" ^ f.cf_name ^ "\",__s_" ^ f.cf_name ^ ",\"" ^ s ^ "\", " ^ isStaticFlag ^ " " ); let superCall = if (isStaticFlag="true") || class_def.cl_interface then "0" else ("__s_" ^ f.cf_name ^ "") in output_cpp ("HXCPP_CPPIA_SUPER_ARG(" ^ superCall ^")" ); output_cpp (" ),\n" ) in List.iter (fun (f,_,_) -> dump_func f "false") new_sctipt_functions; List.iter (fun f -> dump_func f "true") static_functions; - output_cpp " hx::ScriptNamedFunction(0,0,0 HXCPP_CPPIA_SUPER_ARG(0) ) };\n"; + output_cpp " ::hx::ScriptNamedFunction(0,0,0 HXCPP_CPPIA_SUPER_ARG(0) ) };\n"; end else - output_cpp "static hx::ScriptNamedFunction *__scriptableFunctions = 0;\n"; + output_cpp "static ::hx::ScriptNamedFunction *__scriptableFunctions = 0;\n"; if newInteface then begin output_cpp ("\n\n" ^ class_name ^ " " ^ class_name ^ "_scriptable = {\n"); @@ -6389,14 +6390,14 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta (* Initialise static in boot function ... *) if (not class_def.cl_interface && not nativeGen) then begin (* Remap the specialised "extern" classes back to the generic names *) - output_cpp ("hx::Class " ^ class_name ^ "::__mClass;\n\n"); + output_cpp ("::hx::Class " ^ class_name ^ "::__mClass;\n\n"); if (scriptable) then begin (match class_def.cl_constructor with | Some field -> let signature = generate_script_function false field "__script_construct_func" "__construct" in - output_cpp ("hx::ScriptFunction " ^ class_name ^ "::__script_construct(__script_construct_func,\"" ^ signature ^ "\");\n"); + output_cpp ("::hx::ScriptFunction " ^ class_name ^ "::__script_construct(__script_construct_func,\"" ^ signature ^ "\");\n"); | _ -> - output_cpp ("hx::ScriptFunction " ^ class_name ^ "::__script_construct(0,0);\n"); + output_cpp ("::hx::ScriptFunction " ^ class_name ^ "::__script_construct(0,0);\n"); ); end; @@ -6413,25 +6414,25 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta output_cpp ("void " ^ class_name ^ "::__register()\n{\n"); output_cpp ("\t" ^ class_name ^ " _hx_dummy;\n"); output_cpp ("\t" ^ class_name ^ "::_hx_vtable = *(void **)&_hx_dummy;\n"); - output_cpp ("\thx::Static(__mClass) = new hx::Class_obj();\n"); + output_cpp ("\t::hx::Static(__mClass) = new ::hx::Class_obj();\n"); output_cpp ("\t__mClass->mName = " ^ (strq class_name_text) ^ ";\n"); output_cpp ("\t__mClass->mSuper = &super::__SGetClass();\n"); output_cpp ("\t__mClass->mConstructEmpty = &__CreateEmpty;\n"); output_cpp ("\t__mClass->mConstructArgs = &__Create;\n"); output_cpp ("\t__mClass->mGetStaticField = &" ^ ( - if (has_get_static_field class_def) then class_name ^ "::__GetStatic;\n" else "hx::Class_obj::GetNoStaticField;\n" )); + if (has_get_static_field class_def) then class_name ^ "::__GetStatic;\n" else "::hx::Class_obj::GetNoStaticField;\n" )); output_cpp ("\t__mClass->mSetStaticField = &" ^ ( - if (has_set_static_field class_def) then class_name ^ "::__SetStatic;\n" else "hx::Class_obj::SetNoStaticField;\n" )); + if (has_set_static_field class_def) then class_name ^ "::__SetStatic;\n" else "::hx::Class_obj::SetNoStaticField;\n" )); if hasMarkFunc then output_cpp ("\t__mClass->mMarkFunc = " ^ class_name ^ "_sMarkStatics;\n"); - output_cpp ("\t__mClass->mStatics = hx::Class_obj::dupFunctions(" ^ sStaticFields ^ ");\n"); - output_cpp ("\t__mClass->mMembers = hx::Class_obj::dupFunctions(" ^ sMemberFields ^ ");\n"); - output_cpp ("\t__mClass->mCanCast = hx::TCanCast< " ^ class_name ^ " >;\n"); + output_cpp ("\t__mClass->mStatics = ::hx::Class_obj::dupFunctions(" ^ sStaticFields ^ ");\n"); + output_cpp ("\t__mClass->mMembers = ::hx::Class_obj::dupFunctions(" ^ sMemberFields ^ ");\n"); + output_cpp ("\t__mClass->mCanCast = ::hx::TCanCast< " ^ class_name ^ " >;\n"); if hasMarkFunc then output_cpp ("#ifdef HXCPP_VISIT_ALLOCS\n\t__mClass->mVisitFunc = " ^ class_name ^ "_sVisitStatics;\n#endif\n"); output_cpp ("#ifdef HXCPP_SCRIPTABLE\n\t__mClass->mMemberStorageInfo = " ^ class_name ^ "_sMemberStorageInfo;\n#endif\n"); output_cpp ("#ifdef HXCPP_SCRIPTABLE\n\t__mClass->mStaticStorageInfo = " ^ class_name ^ "_sStaticStorageInfo;\n#endif\n"); - output_cpp ("\thx::_hx_RegisterClass(__mClass->mName, __mClass);\n"); + output_cpp ("\t::hx::_hx_RegisterClass(__mClass->mName, __mClass);\n"); if (scriptable) then output_cpp (" HX_SCRIPTABLE_REGISTER_CLASS(\""^class_name_text^"\"," ^ class_name ^ ");\n"); Hashtbl.iter (fun _ intf_def -> @@ -6439,20 +6440,20 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta ) native_implemented; output_cpp ("}\n\n"); end else if not nativeGen then begin - output_cpp ("hx::Class " ^ class_name ^ "::__mClass;\n\n"); + output_cpp ("::hx::Class " ^ class_name ^ "::__mClass;\n\n"); output_cpp ("void " ^ class_name ^ "::__register()\n{\n"); - output_cpp ("\thx::Static(__mClass) = new hx::Class_obj();\n"); + output_cpp ("\t::hx::Static(__mClass) = new ::hx::Class_obj();\n"); output_cpp ("\t__mClass->mName = " ^ (strq class_name_text) ^ ";\n"); output_cpp ("\t__mClass->mSuper = &super::__SGetClass();\n"); if hasMarkFunc then output_cpp ("\t__mClass->mMarkFunc = " ^ class_name ^ "_sMarkStatics;\n"); - output_cpp ("\t__mClass->mMembers = hx::Class_obj::dupFunctions(" ^ sMemberFields ^ ");\n"); - output_cpp ("\t__mClass->mCanCast = hx::TIsInterface< (int)" ^ (cpp_class_hash class_def) ^ " >;\n"); + output_cpp ("\t__mClass->mMembers = ::hx::Class_obj::dupFunctions(" ^ sMemberFields ^ ");\n"); + output_cpp ("\t__mClass->mCanCast = ::hx::TIsInterface< (int)" ^ (cpp_class_hash class_def) ^ " >;\n"); if hasMarkFunc then output_cpp ("#ifdef HXCPP_VISIT_ALLOCS\n\t__mClass->mVisitFunc = " ^ class_name ^ "_sVisitStatics;\n#endif\n"); - output_cpp ("\thx::_hx_RegisterClass(__mClass->mName, __mClass);\n"); + output_cpp ("\t::hx::_hx_RegisterClass(__mClass->mName, __mClass);\n"); if (scriptable) then output_cpp (" HX_SCRIPTABLE_REGISTER_INTERFACE(\""^class_name_text^"\"," ^ class_name ^ ");\n"); output_cpp ("}\n\n"); @@ -6504,10 +6505,10 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta | Some (klass,params) -> let name = (tcpp_to_string_suffix "_obj" (cpp_instance_type ctx klass params) ) in (if class_def.cl_interface && nativeGen then "virtual " else "" ) ^ name, name - | None when nativeGen && class_def.cl_interface -> "virtual hx::NativeInterface", "hx::NativeInterface" - | None when class_def.cl_interface -> "", "hx::Object" + | None when nativeGen && class_def.cl_interface -> "virtual ::hx::NativeInterface", "::hx::NativeInterface" + | None when class_def.cl_interface -> "", "::hx::Object" | None when nativeGen -> "", "" - | None -> "hx::Object", "hx::Object" + | None -> "::hx::Object", "::hx::Object" in let output_h = (h_file#write) in let def_string = join_class_path class_path "_" in @@ -6579,41 +6580,41 @@ let generate_class_files baseCtx super_deps constructor_deps class_def inScripta output_h ("\t\tenum { _hx_ClassId = " ^ classIdTxt ^ " };\n\n"); output_h ("\t\tvoid __construct(" ^ constructor_type_args ^ ");\n"); output_h ("\t\tinline void *operator new(size_t inSize, bool inContainer=" ^ isContainer ^",const char *inName=" ^ gcName ^ ")\n" ); - output_h ("\t\t\t{ return hx::Object::operator new(inSize,inContainer,inName); }\n" ); + output_h ("\t\t\t{ return ::hx::Object::operator new(inSize,inContainer,inName); }\n" ); output_h ("\t\tinline void *operator new(size_t inSize, int extra)\n" ); - output_h ("\t\t\t{ return hx::Object::operator new(inSize+extra," ^ isContainer ^ "," ^ gcName ^ "); }\n" ); + output_h ("\t\t\t{ return ::hx::Object::operator new(inSize+extra," ^ isContainer ^ "," ^ gcName ^ "); }\n" ); if inlineContructor then begin output_h "\n"; outputConstructor ctx (fun str -> output_h ("\t\t" ^ str) ) true end else begin output_h ("\t\tstatic " ^ptr_name^ " __new(" ^constructor_type_args ^");\n"); if can_quick_alloc then - output_h ("\t\tstatic " ^ptr_name^ " __alloc(hx::Ctx *_hx_ctx" ^ + output_h ("\t\tstatic " ^ptr_name^ " __alloc(::hx::Ctx *_hx_ctx" ^ (if constructor_type_args="" then "" else "," ^constructor_type_args) ^");\n"); end; output_h ("\t\tstatic void * _hx_vtable;\n"); output_h ("\t\tstatic Dynamic __CreateEmpty();\n"); - output_h ("\t\tstatic Dynamic __Create(hx::DynamicArray inArgs);\n"); + output_h ("\t\tstatic Dynamic __Create(::hx::DynamicArray inArgs);\n"); if (List.length dynamic_functions > 0) then - output_h ("\t\tstatic void __alloc_dynamic_functions(hx::Ctx *_hx_alloc," ^ class_name ^ " *_hx_obj);\n"); + output_h ("\t\tstatic void __alloc_dynamic_functions(::hx::Ctx *_hx_alloc," ^ class_name ^ " *_hx_obj);\n"); if (scriptable) then - output_h ("\t\tstatic hx::ScriptFunction __script_construct;\n"); + output_h ("\t\tstatic ::hx::ScriptFunction __script_construct;\n"); output_h ("\t\t//~" ^ class_name ^ "();\n\n"); output_h ("\t\tHX_DO_RTTI_ALL;\n"); if (has_get_member_field class_def) then - output_h ("\t\thx::Val __Field(const ::String &inString, hx::PropertyAccess inCallProp);\n"); + output_h ("\t\t::hx::Val __Field(const ::String &inString, ::hx::PropertyAccess inCallProp);\n"); if (has_get_static_field class_def) then - output_h ("\t\tstatic bool __GetStatic(const ::String &inString, Dynamic &outValue, hx::PropertyAccess inCallProp);\n"); + output_h ("\t\tstatic bool __GetStatic(const ::String &inString, Dynamic &outValue, ::hx::PropertyAccess inCallProp);\n"); if (has_set_member_field class_def) then - output_h ("\t\thx::Val __SetField(const ::String &inString,const hx::Val &inValue, hx::PropertyAccess inCallProp);\n"); + output_h ("\t\t::hx::Val __SetField(const ::String &inString,const ::hx::Val &inValue, ::hx::PropertyAccess inCallProp);\n"); if (has_set_static_field class_def) then - output_h ("\t\tstatic bool __SetStatic(const ::String &inString, Dynamic &ioValue, hx::PropertyAccess inCallProp);\n"); + output_h ("\t\tstatic bool __SetStatic(const ::String &inString, Dynamic &ioValue, ::hx::PropertyAccess inCallProp);\n"); if (has_get_fields class_def) then output_h ("\t\tvoid __GetFields(Array< ::String> &outFields);\n"); if (has_compare_field class_def) then - output_h ("\t\tint __Compare(const hx::Object *inRHS) const { " ^ - "return const_cast<" ^ class_name ^ " *>(this)->__compare(Dynamic((hx::Object *)inRHS)); }\n"); + output_h ("\t\tint __Compare(const ::hx::Object *inRHS) const { " ^ + "return const_cast<" ^ class_name ^ " *>(this)->__compare(Dynamic((::hx::Object *)inRHS)); }\n"); output_h ("\t\tstatic void __register();\n"); if (override_iteration) then begin @@ -6736,13 +6737,13 @@ let write_resources common_ctx = resource_file#write "}\n\n"; idx := 0; - resource_file#write "hx::Resource __Resources[] = "; + resource_file#write "::hx::Resource __Resources[] = "; resource_file#begin_block; Hashtbl.iter (fun name data -> let id = "__res_" ^ (string_of_int !idx) in resource_file#write_i ("{ " ^ (strq common_ctx name) ^ "," ^ (string_of_int (String.length data)) ^ "," ^ - "hx::" ^ id ^ " + 4 },\n"); + "::hx::" ^ id ^ " + 4 },\n"); incr idx; ) common_ctx.resources; @@ -7201,7 +7202,7 @@ let cppia_op_info = function | IaBinOp OpAssignOp OpGt | IaBinOp OpAssignOp OpLt | IaBinOp OpAssignOp OpAssignOp _ - | IaBinOp OpAssignOp OpArrow -> assert false + | IaBinOp OpAssignOp OpArrow -> die "" __LOC__ | IaTCast -> ("TCAST", 221) ;; @@ -7216,7 +7217,7 @@ class script_writer ctx filename asciiOut = val mutable indents = [] val mutable just_finished_block = false val mutable classCount = 0 - val mutable return_type = TMono(ref None) + val mutable return_type = TMono(Monomorph.create()) val buffer = Buffer.create 0 val identTable = Hashtbl.create 0 val fileTable = Hashtbl.create 0 @@ -7589,9 +7590,9 @@ class script_writer ctx filename asciiOut = | TField (obj,FInstance (_,_,field) ) when is_super obj -> this#write ( (this#op IaCallSuper) ^ (this#typeText obj.etype) ^ " " ^ (this#stringText field.cf_name) ^ argN ^ (this#commentOf field.cf_name) ^ "\n"); - (* Cppia does not have a "GetEnumIndex" op code - must use IaCallMember hx::EnumBase.__Index *) - | TField (obj,FInstance (_,_,field) ) when field.cf_name = "_hx_getIndex" && (script_type_string obj.etype)="hx::EnumBase" -> - this#write ( (this#op IaCallMember) ^ (this#typeTextString "hx::EnumBase") ^ " " ^ (this#stringText "__Index") ^ + (* Cppia does not have a "GetEnumIndex" op code - must use IaCallMember ::hx::EnumBase.__Index *) + | TField (obj,FInstance (_,_,field) ) when field.cf_name = "_hx_getIndex" && (script_type_string obj.etype)="::hx::EnumBase" -> + this#write ( (this#op IaCallMember) ^ (this#typeTextString "::hx::EnumBase") ^ " " ^ (this#stringText "__Index") ^ argN ^ (this#commentOf ("Enum index") ) ^ "\n"); this#gen_expression obj; | TField (obj,FInstance (_,_,field) ) when field.cf_name = "__Index" || (not (is_dynamic_in_cppia ctx obj) && is_real_function field) -> @@ -7738,12 +7739,12 @@ class script_writer ctx filename asciiOut = | TEnumParameter (expr,ef,i) -> let enum = match follow ef.ef_type with | TEnum(en,_) | TFun(_,TEnum(en,_)) -> en - | _ -> assert false + | _ -> die "" __LOC__ in this#write ( (this#op IaEnumI) ^ (this#typeText (TEnum(enum,[])) ) ^ (string_of_int i) ^ "\n"); this#gen_expression expr; | TEnumIndex expr -> - this#write ( (this#op IaCallMember) ^ (this#typeTextString "hx::EnumBase") ^ " " ^ (this#stringText "__Index") ^ "0" ^ (this#commentOf ("Enum index") ) ^ "\n"); + this#write ( (this#op IaCallMember) ^ (this#typeTextString "::hx::EnumBase") ^ " " ^ (this#stringText "__Index") ^ "0" ^ (this#commentOf ("Enum index") ) ^ "\n"); this#gen_expression expr; | TSwitch (condition,cases,optional_default) -> this#write ( (this#op IaSwitch) ^ (string_of_int (List.length cases)) ^ " " ^ @@ -7943,8 +7944,8 @@ class script_writer ctx filename asciiOut = this#write ( (this#op IaFEnum) ^ (this#enumText enum) ^ " " ^ (this#stringText field.ef_name) ^ (this#commentOf field.ef_name) ); | CppEnumIndex(obj) -> - (* Cppia does not have a "GetEnumIndex" op code - must use IaCallMember hx::EnumBase.__Index *) - this#write ( (this#op IaCallMember) ^ (this#typeTextString "hx::EnumBase") ^ " " ^ (this#stringText "__Index") ^ + (* Cppia does not have a "GetEnumIndex" op code - must use IaCallMember ::hx::EnumBase.__Index *) + this#write ( (this#op IaCallMember) ^ (this#typeTextString "::hx::EnumBase") ^ " " ^ (this#stringText "__Index") ^ "0" ^ (this#commentOf ("Enum index") ) ^ "\n"); gen_expression obj; diff --git a/src/generators/gencs.ml b/src/generators/gencs.ml index 3f7a21db97d2e23184ba8501bb5d68cfa40ff393..cc5633fd430fbb656227820c46ce4042d6b1ba5a 100644 --- a/src/generators/gencs.ml +++ b/src/generators/gencs.ml @@ -112,7 +112,7 @@ let rec is_null t = | TAbstract( { a_path = ([], "Null") }, _ ) -> true | TType( t, tl ) -> is_null (apply_params t.t_params tl t.t_type) | TMono r -> - (match !r with + (match r.tm_type with | Some t -> is_null t | _ -> false) | TLazy f -> @@ -134,7 +134,7 @@ let parse_explicit_iface = match split with | clname :: fn_name :: [] -> fn_name, (List.rev pack, clname) | pack_piece :: tl -> get_iface tl (pack_piece :: pack) - | _ -> assert false + | _ -> die "" __LOC__ in get_iface split [] in parse_explicit_iface @@ -228,27 +228,27 @@ struct let get_cl_from_t t = match follow t with | TInst(cl,_) -> cl - | _ -> assert false + | _ -> die "" __LOC__ let get_ab_from_t t = match follow t with | TAbstract(ab,_) -> ab - | _ -> assert false + | _ -> die "" __LOC__ let configure gen runtime_cl = let basic = gen.gcon.basic in - let uint = match get_type gen ([], "UInt") with | TTypeDecl t -> TType(t, []) | TAbstractDecl a -> TAbstract(a, []) | _ -> assert false in + let uint = match get_type gen ([], "UInt") with | TTypeDecl t -> TType(t, []) | TAbstractDecl a -> TAbstract(a, []) | _ -> die "" __LOC__ in let rec run e = match e.eexpr with (* Std.is() *) | TCall( - { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "is" })) }, + { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = ("is" | "isOfType") })) }, [ obj; { eexpr = TTypeExpr(TClassDecl { cl_path = [], "Dynamic" } | TAbstractDecl { a_path = [], "Dynamic" }) }] ) -> Type.map_expr run e | TCall( - { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "is"}) ) }, + { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = ("is" | "isOfType") }) ) }, [ obj; { eexpr = TTypeExpr(md) }] ) -> let md = change_md md in @@ -272,7 +272,7 @@ struct match obj.eexpr with | TLocal(v) -> f obj | _ -> - let var = mk_temp "is" obj.etype in + let var = mk_temp "isOfType" obj.etype in let added = { obj with eexpr = TVar(var, Some(obj)); etype = basic.tvoid } in let local = mk_local var obj.epos in { @@ -367,7 +367,7 @@ struct let local, added = mk_local ea1 in { e with eexpr = TBlock([ added; mk_ushr { e1 with eexpr = TArray(local, ea2) } ]); } | _ -> (* invalid left-side expression *) - assert false + die "" __LOC__ in ret @@ -398,7 +398,7 @@ struct let get_cl_from_t t = match follow t with | TInst(cl,_) -> cl - | _ -> assert false + | _ -> die "" __LOC__ let is_tparam t = match follow t with @@ -410,10 +410,10 @@ struct (* let tchar = match ( get_type gen (["cs"], "Char16") ) with | TTypeDecl t -> TType(t,[]) | TAbstractDecl a -> TAbstract(a,[]) - | _ -> assert false + | _ -> die "" __LOC__ in *) let string_ext = get_cl ( get_type gen (["haxe";"lang"], "StringExt")) in - let ti64 = match ( get_type gen (["cs"], "Int64") ) with | TTypeDecl t -> TType(t,[]) | TAbstractDecl a -> TAbstract(a,[]) | _ -> assert false in + let ti64 = match ( get_type gen (["cs"], "Int64") ) with | TTypeDecl t -> TType(t,[]) | TAbstractDecl a -> TAbstract(a,[]) | _ -> die "" __LOC__ in let boxed_ptr = if Common.defined gen.gcon Define.Unsafe then get_cl (get_type gen (["haxe";"lang"], "BoxedPointer")) @@ -581,7 +581,7 @@ let add_cast_handler gen = let get_narr_param t = match follow t with | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) -> param - | _ -> assert false + | _ -> die "" __LOC__ in let gtparam_cast_native_array e to_t = @@ -690,7 +690,7 @@ let reserved = let res = Hashtbl.create 120 in "remove"; "select"; "set"; "value"; "var"; "where"; "yield"; "await"]; res -let dynamic_anon = TAnon( { a_fields = PMap.empty; a_status = ref Closed } ) +let dynamic_anon = mk_anon (ref Closed) let rec get_class_modifiers meta cl_type cl_access cl_modifiers = match meta with @@ -740,7 +740,7 @@ let generate con = let native_arr_cl = get_cl ( get_type gen (["cs"], "NativeArray") ) in gen.gclasses.nativearray <- (fun t -> TInst(native_arr_cl,[t])); - gen.gclasses.nativearray_type <- (function TInst(_,[t]) -> t | _ -> assert false); + gen.gclasses.nativearray_type <- (function TInst(_,[t]) -> t | _ -> die "" __LOC__); gen.gclasses.nativearray_len <- (fun e p -> mk_field_access gen e "Length" p); let erase_generics = Common.defined gen.gcon Define.EraseGenerics in @@ -907,7 +907,7 @@ let generate con = let ifaces = Hashtbl.create 1 in - let ti64 = match ( get_type gen (["cs"], "Int64") ) with | TTypeDecl t -> TType(t,[]) | TAbstractDecl a -> TAbstract(a,[]) | _ -> assert false in + let ti64 = match ( get_type gen (["cs"], "Int64") ) with | TTypeDecl t -> TType(t,[]) | TAbstractDecl a -> TAbstract(a,[]) | _ -> die "" __LOC__ in let ttype = get_cl ( get_type gen (["System"], "Type") ) in @@ -1081,7 +1081,7 @@ let generate con = (if ret = "object" then "void" else ret) ^ "*" (* end of basic types *) | TInst ({ cl_kind = KTypeParameter _; cl_path=p }, []) -> snd p - | TMono r -> (match !r with | None -> "object" | Some t -> t_s (run_follow gen t)) + | TMono r -> (match r.tm_type with | None -> "object" | Some t -> t_s (run_follow gen t)) | TInst ({ cl_path = [], "String" }, []) -> "string" | TEnum (e, params) -> ("global::" ^ (module_s (TEnumDecl e))) | TInst (cl, _ :: _) when Meta.has Meta.Enum cl.cl_meta -> @@ -1096,7 +1096,7 @@ let generate con = | TAbstract(a,pl) when not (Meta.has Meta.CoreType a.a_meta) -> t_s (Abstract.get_underlying_type a pl) (* No Lazy type nor Function type made. That's because function types will be at this point be converted into other types *) - | _ -> if !strict_mode then begin trace ("[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]"); assert false end else "[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]" + | _ -> if !strict_mode then begin trace ("[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]"); die "" __LOC__ end else "[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]" and path_param_s md path params = match params with @@ -1295,7 +1295,7 @@ let generate con = write w "["; let args, value = match List.rev args with | v :: args -> List.rev args, v - | _ -> assert false + | _ -> die "" __LOC__ in let first = ref true in List.iter (fun f -> @@ -1454,7 +1454,7 @@ let generate con = expr_s w e; print w "label%s: {}" n | TBreak -> print w "goto label%s" n - | _ -> assert false) + | _ -> die "" __LOC__) | TMeta (_,e) -> expr_s w e | TArrayDecl el @@ -1761,12 +1761,12 @@ let generate con = write w "[ for not supported "; expr_s w content; write w " ]"; - if !strict_mode then assert false - | TObjectDecl _ -> write w "[ obj decl not supported ]"; if !strict_mode then assert false - | TFunction _ -> write w "[ func decl not supported ]"; if !strict_mode then assert false - | TEnumParameter _ -> write w "[ enum parameter not supported ]"; if !strict_mode then assert false - | TEnumIndex _ -> write w "[ enum index not supported ]"; if !strict_mode then assert false - | TIdent s -> write w "[ ident not supported ]"; if !strict_mode then assert false + if !strict_mode then die "" __LOC__ + | TObjectDecl _ -> write w "[ obj decl not supported ]"; if !strict_mode then die "" __LOC__ + | TFunction _ -> write w "[ func decl not supported ]"; if !strict_mode then die "" __LOC__ + | TEnumParameter _ -> write w "[ enum parameter not supported ]"; if !strict_mode then die "" __LOC__ + | TEnumIndex _ -> write w "[ enum index not supported ]"; if !strict_mode then die "" __LOC__ + | TIdent s -> write w "[ ident not supported ]"; if !strict_mode then die "" __LOC__ ) and do_call w e el = let params, el = extract_tparams [] el in @@ -1779,7 +1779,7 @@ let generate con = let md = match e.eexpr with | TField(ef, _) -> t_to_md (run_follow gen ef.etype) - | _ -> assert false + | _ -> die "" __LOC__ in write w "<"; ignore (List.fold_left (fun acc t -> @@ -1878,6 +1878,22 @@ let generate con = gen.gcon.error "Invalid expression inside @:meta metadata" p in + let gen_assembly_attributes w metadata = + List.iter (function + | Meta.AssemblyMeta, [EConst(String(s,_)), _], _ -> + write w "[assembly:"; + write w s; + write w "]"; + newline w + | Meta.AssemblyMeta, [meta], _ -> + write w "[assembly:"; + gen_spart w meta; + write w "]"; + newline w + | _ -> () + ) metadata + in + let gen_attributes w metadata = List.iter (function | Meta.Meta, [EConst(String(s,_)), _], _ -> @@ -1909,7 +1925,7 @@ let generate con = gen_attributes w tdef.t_meta; run (follow_once t) | TMono r -> - (match !r with + (match r.tm_type with | Some t -> run t | _ -> () (* avoid infinite loop / should be the same in this context *)) | TLazy f -> @@ -1935,7 +1951,7 @@ let generate con = let hxgen = is_hxgen (TClassDecl cl) in match cl_params with | (_ :: _) when not (erase_generics && is_hxgeneric (TClassDecl cl)) -> - let get_param_name t = match follow t with TInst(cl, _) -> snd cl.cl_path | _ -> assert false in + let get_param_name t = match follow t with TInst(cl, _) -> snd cl.cl_path | _ -> die "" __LOC__ in let combination_error c1 c2 = gen.gcon.error ("The " ^ (get_constraint c1) ^ " constraint cannot be combined with the " ^ (get_constraint c2) ^ " constraint.") cl.cl_pos in @@ -2057,7 +2073,7 @@ let generate con = | None -> true | Some ({ cf_kind = Method mkind } as m) -> (match mkind with | MethInline -> true | _ -> false) || (has_class_field_flag m CfFinal) - | _ -> assert false + | _ -> die "" __LOC__ in let is_virtual = not (is_interface || is_final || (has_class_field_flag prop CfFinal) || fn_is_final get || fn_is_final set) in @@ -2188,9 +2204,12 @@ let generate con = | Some e -> write w " = "; expr_s true w e; - | None -> () + write w ";" + | None when (Meta.has Meta.Property cf.cf_meta) -> + write w " { get; set; }"; + | None -> + write w ";" ); - write w ";" end (* TODO see how (get,set) variable handle when they are interfaces *) | Method _ when not (Type.is_physical_field cf) || (match cl.cl_kind, cf.cf_expr with | KAbstractImpl _, None -> true | _ -> false) -> List.iter (fun cf -> if cl.cl_interface || cf.cf_expr <> None then @@ -2248,8 +2267,8 @@ let generate con = let modifiers = modifiers @ modf in let visibility, is_virtual = if is_explicit_iface then "",false else if visibility = "private" then "private",false else visibility, is_virtual in let v_n = if is_static then "static" else if is_override && not is_interface then "override" else if is_virtual then "virtual" else "" in - let cf_type = if is_override && not is_overload && not (Meta.has Meta.Overload cf.cf_meta) then match field_access gen (TInst(cl, List.map snd cl.cl_params)) cf.cf_name with | FClassField(_,_,_,_,_,actual_t,_) -> actual_t | _ -> assert false else cf.cf_type in - let ret_type, args = match follow cf_type with | TFun (strbtl, t) -> (t, strbtl) | _ -> assert false in + let cf_type = if is_override && not is_overload && not (Meta.has Meta.Overload cf.cf_meta) then match field_access gen (TInst(cl, List.map snd cl.cl_params)) cf.cf_name with | FClassField(_,_,_,_,_,actual_t,_) -> actual_t | _ -> die "" __LOC__ else cf.cf_type in + let ret_type, args = match follow cf_type with | TFun (strbtl, t) -> (t, strbtl) | _ -> die "" __LOC__ in gen_nocompletion w cf.cf_meta; (* public static void funcName *) @@ -2276,7 +2295,7 @@ let generate con = match s.eexpr with | TFunction tf -> mk_block (tf.tf_expr) - | _ -> assert false (* FIXME *) + | _ -> die "" __LOC__ (* FIXME *) in let write_method_expr e = @@ -2293,7 +2312,7 @@ let generate con = line_reset_directive w; if unchecked then end_block w | _ -> - assert false + die "" __LOC__ in (if is_new then begin @@ -2328,7 +2347,7 @@ let generate con = t() ); write_method_expr { expr with eexpr = TBlock(rest) } - | _ -> assert false + | _ -> die "" __LOC__ end else write_method_expr expr ) @@ -2398,7 +2417,7 @@ let generate con = let idx_t, v_t = match follow get.cf_type with | TFun([_,_,arg_t],ret_t) -> t_s (run_follow gen arg_t), t_s (run_follow gen ret_t) - | _ -> gen.gcon.error "The __get function must be a function with one argument. " get.cf_pos; assert false + | _ -> gen.gcon.error "The __get function must be a function with one argument. " get.cf_pos; die "" __LOC__ in List.iter (fun (cl,args) -> match cl.cl_array_access with @@ -2519,12 +2538,28 @@ let generate con = end in - let gen_class w cl = + let gen_class w cl is_first_type = + if (is_first_type == false) then begin + if Meta.has Meta.AssemblyStrict cl.cl_meta then + gen.gcon.error "@:cs.assemblyStrict can only be used on the first class of a module" cl.cl_pos + else if Meta.has Meta.AssemblyMeta cl.cl_meta then + gen.gcon.error "@:cs.assemblyMeta can only be used on the first class of a module" cl.cl_pos; + end; + write w "#pragma warning disable 109, 114, 219, 429, 168, 162"; newline w; let should_close = match change_ns (TClassDecl cl) (fst (cl.cl_path)) with - | [] -> false + | [] -> + (* Should the assembly annotations be added to the class in this case? *) + + if Meta.has Meta.AssemblyStrict cl.cl_meta then + gen.gcon.error "@:cs.assemblyStrict cannot be used on top level modules" cl.cl_pos + else if Meta.has Meta.AssemblyMeta cl.cl_meta then + gen.gcon.error "@:cs.assemblyMeta cannot be used on top level modules" cl.cl_pos; + + false | ns -> + gen_assembly_attributes w cl.cl_meta; print w "namespace %s " (String.concat "." ns); begin_block w; true @@ -2538,7 +2573,7 @@ let generate con = else "object" :: (loop (pred i) acc) in - let tparams = loop (match m with [(EConst(Int s),_)] -> int_of_string s | _ -> assert false) [] in + let tparams = loop (match m with [(EConst(Int s),_)] -> int_of_string s | _ -> die "" __LOC__) [] in cl.cl_meta <- (Meta.Meta, [ EConst(String("global::haxe.lang.GenericInterface(typeof(global::" ^ module_s (TClassDecl cl) ^ "<" ^ String.concat ", " tparams ^ ">))",SDoubleQuotes) ), cl.cl_pos ], cl.cl_pos) :: cl.cl_meta @@ -2547,30 +2582,26 @@ let generate con = gen_attributes w cl.cl_meta; - let is_main = - match gen.gcon.main_class with - | Some ( (_,"Main") as path) when path = cl.cl_path && not cl.cl_interface -> - (* - for cases where the main class is called Main, there will be a problem with creating the entry point there. - In this special case, a special entry point class will be created - *) - write w "public class EntryPoint__Main "; - begin_block w; - write w "public static void Main() "; - begin_block w; - (if Hashtbl.mem gen.gtypes (["cs"], "Boot") then write w "global::cs.Boot.init();"; newline w); - (match gen.gcon.main with - | None -> - expr_s true w { eexpr = TTypeExpr(TClassDecl cl); etype = t_dynamic; epos = null_pos }; - write w ".main();" - | Some expr -> - expr_s false w (mk_block expr)); - end_block w; - end_block w; - newline w; - false - | Some path when path = cl.cl_path && not cl.cl_interface -> true - | _ -> false + let main_expr = + match gen.gentry_point with + | Some (_,({ cl_path = (_,"Main") } as cl_main),expr) when cl == cl_main && not cl.cl_interface -> + (* + for cases where the main class is called Main, there will be a problem with creating the entry point there. + In this special case, a special entry point class will be created + *) + write w "public class EntryPoint__Main "; + begin_block w; + write w "public static void Main() "; + begin_block w; + (if Hashtbl.mem gen.gtypes (["cs"], "Boot") then write w "global::cs.Boot.init();"; newline w); + expr_s false w expr; + write w ";"; + end_block w; + end_block w; + newline w; + None + | Some (_, cl_main,expr) when cl == cl_main && not cl.cl_interface -> Some expr + | _ -> None in let clt, access, modifiers = get_class_modifiers cl.cl_meta (if cl.cl_interface then "interface" else "class") "public" [] in @@ -2590,7 +2621,7 @@ let generate con = begin_block w; newline w; (* our constructor is expected to be a normal "new" function * - if !strict_mode && is_some cl.cl_constructor then assert false;*) + if !strict_mode && is_some cl.cl_constructor then die "" __LOC__;*) let rec loop meta = match meta with @@ -2601,17 +2632,14 @@ let generate con = in loop cl.cl_meta; - if is_main then begin + Option.may (fun expr -> write w "public static void Main()"; begin_block w; (if Hashtbl.mem gen.gtypes (["cs"], "Boot") then write w "global::cs.Boot.init();"; newline w); - (match gen.gcon.main with - | None -> - write w "main();"; - | Some expr -> - expr_s false w (mk_block expr)); + expr_s false w expr; + write w ";"; end_block w - end; + ) main_expr; (match cl.cl_init with | None -> () @@ -2728,7 +2756,7 @@ let generate con = | Some add, Some remove -> if custom && not cl.cl_interface then nonprops := add :: remove :: !nonprops - | _ -> assert false (* shouldn't happen because Filters.check_cs_events makes sure methods are present *) + | _ -> die "" __LOC__ (* shouldn't happen because Filters.check_cs_events makes sure methods are present *) ) events; let evts = List.map (fun(_,v) -> !v) events in @@ -2779,7 +2807,7 @@ let generate con = if should_close then end_block w in - let module_type_gen w md_tp = + let module_type_gen w md_tp is_first_type = let file_start = len w = 0 in let requires_root = no_root && file_start in if file_start then @@ -2789,7 +2817,24 @@ let generate con = | TClassDecl cl -> if not cl.cl_extern then begin (if requires_root then write w "using haxe.root;\n"; newline w;); - gen_class w cl; + + (if (Meta.has Meta.CsUsing cl.cl_meta) then + match (Meta.get Meta.CsUsing cl.cl_meta) with + | _,_,p when not !is_first_type -> + gen.gcon.error "@:cs.using can only be used on the first type of a module" p + | _,[],p -> + gen.gcon.error "One or several string constants expected" p + | _,e,_ -> + (List.iter (fun e -> + match e with + | (EConst(String(s,_))),_ -> write w (Printf.sprintf "using %s;\n" s) + | _,p -> gen.gcon.error "One or several string constants expected" p + ) e); + newline w + ); + + gen_class w cl !is_first_type; + is_first_type := false; newline w; newline w end; @@ -2798,6 +2843,7 @@ let generate con = if not e.e_extern && not (Meta.has Meta.Class e.e_meta) then begin (if requires_root then write w "using haxe.root;\n"; newline w;); gen_enum w e; + is_first_type := false; newline w; newline w end; @@ -2888,7 +2934,7 @@ let generate con = let e = { e with eexpr = TParenthesis(e) } in { (mk_field_access gen e "value" e.epos) with etype = t } | _ -> - trace (debug_type e.etype); gen.gcon.error "This expression is not a Nullable expression" e.epos; assert false + trace (debug_type e.etype); gen.gcon.error "This expression is not a Nullable expression" e.epos; die "" __LOC__ ) (fun v t has_value -> match has_value, real_type v.etype with @@ -2949,9 +2995,9 @@ let generate con = let object_iface = get_cl (get_type gen (["haxe";"lang"],"IHxObject")) in - let empty_en = match get_type gen (["haxe";"lang"], "EmptyObject") with TEnumDecl e -> e | _ -> assert false in + let empty_en = match get_type gen (["haxe";"lang"], "EmptyObject") with TEnumDecl e -> e | _ -> die "" __LOC__ in let empty_ctor_type = TEnum(empty_en, []) in - let empty_en_expr = mk (TTypeExpr (TEnumDecl empty_en)) (TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics empty_en) }) null_pos in + let empty_en_expr = mk (TTypeExpr (TEnumDecl empty_en)) (mk_anon (ref (EnumStatics empty_en))) null_pos in let empty_ctor_expr = mk (TField (empty_en_expr, FEnum(empty_en, PMap.find "EMPTY" empty_en.e_constrs))) empty_ctor_type null_pos in OverloadingConstructor.configure ~empty_ctor_type:empty_ctor_type ~empty_ctor_expr:empty_ctor_expr gen; @@ -2962,7 +3008,7 @@ let generate con = let get_specialized_postfix t = match t with | TAbstract({a_path = [],("Float" | "Int" as name)}, _) -> name | TAnon _ | TDynamic _ -> "Dynamic" - | _ -> print_endline (debug_type t); assert false + | _ -> print_endline (debug_type t); die "" __LOC__ in (fun t -> mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) ("insert" ^ get_specialized_postfix t) null_pos []), (fun t -> mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) ("remove" ^ get_specialized_postfix t) null_pos []) @@ -3109,7 +3155,7 @@ let generate con = | Some(Ast.OpAssignOp _), ([TDynamic _] | [TAnon _]) -> true | _ -> false) - | _ -> assert false + | _ -> die "" __LOC__ ) "__get" "__set"; let field_is_dynamic t field = @@ -3169,7 +3215,7 @@ let generate con = let string_cl = match gen.gcon.basic.tstring with | TInst(c,[]) -> c - | _ -> assert false + | _ -> die "" __LOC__ in let is_undefined e = match e.eexpr with @@ -3285,7 +3331,7 @@ let generate con = ) cases) | _ -> true ) - | _ -> assert false + | _ -> die "" __LOC__ ); ExpressionUnwrap.configure gen; @@ -3319,7 +3365,7 @@ let generate con = output_string f v; close_out f; - out_files := (Path.unique_full_path full_path) :: !out_files + out_files := (Path.UniqueKey.create full_path) :: !out_files ) gen.gcon.resources; end; (* add resources array *) @@ -3422,7 +3468,8 @@ let generate con = List.iter (fun md_def -> let source_dir = gen.gcon.file ^ "/src/" ^ (String.concat "/" (fst (path_of_md_def md_def))) in let w = SourceWriter.new_source_writer() in - let should_write = List.fold_left (fun should md -> module_type_gen w md || should) false md_def.m_types in + let is_first_type = ref true in + let should_write = List.fold_left (fun should md -> module_type_gen w md is_first_type || should) false md_def.m_types in if should_write then begin let path = path_of_md_def md_def in write_file gen w source_dir path "cs" out_files diff --git a/src/generators/genhl.ml b/src/generators/genhl.ml index dfc235b0bbcab8b5214669e4ae5137cb670713ca..29a70f8d270013a77a6456cfef125086cbe4bf37 100644 --- a/src/generators/genhl.ml +++ b/src/generators/genhl.ml @@ -104,6 +104,7 @@ type context = { mutable method_wrappers : ((ttype * ttype), int) PMap.t; mutable rec_cache : (Type.t * ttype option ref) list; mutable cached_tuples : (ttype list, ttype) PMap.t; + mutable tstring : ttype; macro_typedefs : (string, ttype) Hashtbl.t; array_impl : array_impl; base_class : tclass; @@ -139,12 +140,16 @@ let is_to_string t = | TFun([],r) -> (match follow r with TInst({ cl_path=[],"String" },[]) -> true | _ -> false) | _ -> false +let is_string = function + | HObj { pname = "String"} -> true + | _ -> false + let is_extern_field f = not (Type.is_physical_field f) || (match f.cf_kind with Method MethNormal -> List.exists (fun (m,_,_) -> m = Meta.HlNative) f.cf_meta | _ -> false) || has_class_field_flag f CfExtern let is_array_class name = match name with - | "hl.types.ArrayDyn" | "hl.types.ArrayBytes_Int" | "hl.types.ArrayBytes_Float" | "hl.types.ArrayObj" | "hl.types.ArrayBytes_Single" | "hl.types.ArrayBytes_hl_UI16" -> true + | "hl.types.ArrayDyn" | "hl.types.ArrayBytes_Int" | "hl.types.ArrayBytes_Float" | "hl.types.ArrayObj" | "hl.types.ArrayBytes_F32" | "hl.types.ArrayBytes_hl_UI16" -> true | _ -> false let is_array_type t = @@ -194,7 +199,7 @@ let type_size_bits = function | HUI16 -> 1 | HI32 | HF32 -> 2 | HI64 | HF64 -> 3 - | _ -> assert false + | _ -> die "" __LOC__ let new_lookup() = { @@ -288,7 +293,7 @@ let array_class ctx t = let member_fun c t = match follow t with | TFun (args, ret) -> TFun (("this",false,TInst(c,[])) :: args, ret) - | _ -> assert false + | _ -> die "" __LOC__ let rec unsigned t = match follow t with @@ -367,7 +372,7 @@ let get_rec_cache ctx t none_callback not_found_callback = let rec to_type ?tref ctx t = match t with | TMono r -> - (match !r with + (match r.tm_type with | None -> HDyn | Some t -> to_type ?tref ctx t) | TType (td,tl) -> @@ -392,7 +397,7 @@ let rec to_type ?tref ctx t = class_type ctx c (List.map snd c.cl_params) true | EnumStatics e -> enum_class ctx e - | _ -> assert false) + | _ -> die "" __LOC__) | TAnon a -> if PMap.is_empty a.a_fields then HDyn else (try @@ -472,7 +477,7 @@ and resolve_class ctx c pl statics = | ([],"Array"), [t] -> if statics then ctx.array_impl.abase else array_class ctx (to_type ctx t) | ([],"Array"), [] -> - assert false + die "" __LOC__ | _, _ when c.cl_extern -> not_supported() | _ -> @@ -584,9 +589,9 @@ and class_type ?(tref=None) ctx c pl statics = | Some r -> r := Some t); ctx.ct_depth <- ctx.ct_depth + 1; ctx.cached_types <- PMap.add key_path t ctx.cached_types; - if c.cl_path = ([],"Array") then assert false; + if c.cl_path = ([],"Array") then die "" __LOC__; if c == ctx.base_class then begin - if statics then assert false; + if statics then die "" __LOC__; p.pnfields <- 1; end; let tsup = (match c.cl_super with @@ -597,15 +602,15 @@ and class_type ?(tref=None) ctx c pl statics = | None -> 0, [||] | Some ((HObj psup | HStruct psup) as pt) -> if is_struct t <> is_struct pt then abort (if is_struct t then "Struct cannot extend a not struct class" else "Class cannot extend a struct") c.cl_pos; - if psup.pnfields < 0 then assert false; + if psup.pnfields < 0 then die "" __LOC__; p.psuper <- Some psup; psup.pnfields, psup.pvirtuals - | _ -> assert false + | _ -> die "" __LOC__ ) in let fa = DynArray.create() and pa = DynArray.create() and virtuals = DynArray.of_array virtuals in let add_field name get_t = let fid = DynArray.length fa + start_field in - let str = if name = "" then 0 else alloc_string ctx name in + let str = alloc_string ctx name in p.pindex <- PMap.add name (fid, HVoid) p.pindex; DynArray.add fa (name, str, HVoid); ctx.ct_delayed <- (fun() -> @@ -622,7 +627,7 @@ and class_type ?(tref=None) ctx c pl statics = let g = alloc_fid ctx c f in p.pfunctions <- PMap.add f.cf_name g p.pfunctions; let virt = if List.exists (fun ff -> ff.cf_name = f.cf_name) c.cl_overrides then - let vid = (try -(fst (get_index f.cf_name p))-1 with Not_found -> assert false) in + let vid = (try -(fst (get_index f.cf_name p))-1 with Not_found -> die "" __LOC__) in DynArray.set virtuals vid g; Some vid else if is_overridden ctx c f then begin @@ -636,7 +641,7 @@ and class_type ?(tref=None) ctx c pl statics = DynArray.add pa { fname = f.cf_name; fid = alloc_string ctx f.cf_name; fmethod = g; fvirtual = virt; }; None | Method MethDynamic when List.exists (fun ff -> ff.cf_name = f.cf_name) c.cl_overrides -> - Some (try fst (get_index f.cf_name p) with Not_found -> assert false) + Some (try fst (get_index f.cf_name p) with Not_found -> die "" __LOC__) | _ -> let fid = add_field f.cf_name (fun() -> to_type ctx f.cf_type) in Some fid @@ -665,7 +670,7 @@ and class_type ?(tref=None) ctx c pl statics = end else begin (match c.cl_constructor with | Some f when not (is_extern_field f) -> - p.pbindings <- ((try fst (get_index "__constructor__" p) with Not_found -> assert false),alloc_fid ctx c f) :: p.pbindings + p.pbindings <- ((try fst (get_index "__constructor__" p) with Not_found -> die "" __LOC__),alloc_fid ctx c f) :: p.pbindings | _ -> ()); end; p.pnfields <- DynArray.length fa + start_field; @@ -707,7 +712,7 @@ and enum_type ?(tref=None) ctx e = (f.ef_name, alloc_string ctx f.ef_name, args) ) e.e_names); let ct = enum_class ctx e in - et.eglobal <- Some (alloc_global ctx (match ct with HObj o -> o.pname | _ -> assert false) ct); + et.eglobal <- Some (alloc_global ctx (match ct with HObj o -> o.pname | _ -> die "" __LOC__) ct); t and enum_class ctx e = @@ -732,7 +737,7 @@ and enum_class ctx e = } in let t = HObj p in ctx.cached_types <- PMap.add key_path t ctx.cached_types; - p.psuper <- Some (match class_type ctx ctx.base_enum [] false with HObj o -> o | _ -> assert false); + p.psuper <- Some (match class_type ctx ctx.base_enum [] false with HObj o -> o | _ -> die "" __LOC__); t and alloc_fun_path ctx path name = @@ -740,7 +745,7 @@ and alloc_fun_path ctx path name = and alloc_fid ctx c f = match f.cf_kind with - | Var _ -> assert false + | Var _ -> die "" __LOC__ | _ -> alloc_fun_path ctx c.cl_path f.cf_name and alloc_eid ctx e f = @@ -760,7 +765,7 @@ and class_global ?(resolve=true) ctx c = alloc_global ctx ("$" ^ s_type_path c.cl_path) t, t let resolve_class_global ctx cpath = - lookup ctx.cglobals ("$" ^ cpath) (fun() -> assert false) + lookup ctx.cglobals ("$" ^ cpath) (fun() -> die "" __LOC__) let resolve_type ctx path = PMap.find path ctx.cached_types @@ -811,7 +816,7 @@ let hold ctx r = let a = PMap.find t ctx.m.mallocs in let rec loop l = match l with - | [] -> if List.mem r a.a_hold then [] else assert false + | [] -> if List.mem r a.a_hold then [] else die "" __LOC__ | n :: l when n = r -> l | n :: l -> n :: loop l in @@ -825,7 +830,7 @@ let free ctx r = let last = ref true in let rec loop l = match l with - | [] -> assert false + | [] -> die "" __LOC__ | n :: l when n = r -> if List.mem r l then last := false; l @@ -918,7 +923,7 @@ let read_mem ctx rdst bytes index t = | HI32 | HI64 | HF32 | HF64 -> op ctx (OGetMem (rdst,bytes,index)) | _ -> - assert false + die "" __LOC__ let write_mem ctx bytes index t r = match t with @@ -929,7 +934,7 @@ let write_mem ctx bytes index t r = | HI32 | HI64 | HF32 | HF64 -> op ctx (OSetMem (bytes,index,r)) | _ -> - assert false + die "" __LOC__ let common_type ctx e1 e2 for_eq p = let t1 = to_type ctx e1.etype in @@ -1027,10 +1032,10 @@ let type_value ctx t p = | TEnumDecl e -> let r = alloc_tmp ctx (enum_class ctx e) in let rt = rtype ctx r in - op ctx (OGetGlobal (r, alloc_global ctx (match rt with HObj o -> o.pname | _ -> assert false) rt)); + op ctx (OGetGlobal (r, alloc_global ctx (match rt with HObj o -> o.pname | _ -> die "" __LOC__) rt)); r | TTypeDecl _ -> - assert false + die "" __LOC__ let rec eval_to ctx e (t:ttype) = match e.eexpr, t with @@ -1054,52 +1059,57 @@ let rec eval_to ctx e (t:ttype) = let r = eval_expr ctx e in cast_to ctx r t e.epos -and cast_to ?(force=false) ctx (r:reg) (t:ttype) p = +and to_string ctx (r:reg) p = let rt = rtype ctx r in - if safe_cast rt t then r else - match rt, t with - | _, HVoid -> - alloc_tmp ctx HVoid - | HVirtual _, HVirtual _ -> - let tmp = alloc_tmp ctx HDyn in - op ctx (OMov (tmp,r)); - cast_to ctx tmp t p - | (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64), (HF32 | HF64) -> - let tmp = alloc_tmp ctx t in - op ctx (OToSFloat (tmp, r)); - tmp - | (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64), (HUI8 | HUI16 | HI32 | HI64) -> - let tmp = alloc_tmp ctx t in - op ctx (OToInt (tmp, r)); - tmp - | (HUI8 | HUI16 | HI32), HObj { pname = "String" } -> + if safe_cast rt ctx.tstring then r else + match rt with + | HUI8 | HUI16 | HI32 -> let len = alloc_tmp ctx HI32 in hold ctx len; let lref = alloc_tmp ctx (HRef HI32) in let bytes = alloc_tmp ctx HBytes in op ctx (ORef (lref,len)); op ctx (OCall2 (bytes,alloc_std ctx "itos" [HI32;HRef HI32] HBytes,cast_to ctx r HI32 p,lref)); - let out = alloc_tmp ctx t in + let out = alloc_tmp ctx ctx.tstring in op ctx (OCall2 (out,alloc_fun_path ctx ([],"String") "__alloc__",bytes,len)); free ctx len; out - | (HF32 | HF64), HObj { pname = "String" } -> + | HF32 | HF64 -> let len = alloc_tmp ctx HI32 in let lref = alloc_tmp ctx (HRef HI32) in let bytes = alloc_tmp ctx HBytes in op ctx (ORef (lref,len)); op ctx (OCall2 (bytes,alloc_std ctx "ftos" [HF64;HRef HI32] HBytes,cast_to ctx r HF64 p,lref)); - let out = alloc_tmp ctx t in + let out = alloc_tmp ctx ctx.tstring in op ctx (OCall2 (out,alloc_fun_path ctx ([],"String") "__alloc__",bytes,len)); out - | _, HObj { pname = "String" } -> + | _ -> let r = cast_to ctx r HDyn p in - let out = alloc_tmp ctx t in + let out = alloc_tmp ctx ctx.tstring in op ctx (OJNotNull (r,2)); op ctx (ONull out); op ctx (OJAlways 1); op ctx (OCall1 (out,alloc_fun_path ctx ([],"Std") "string",r)); out + +and cast_to ?(force=false) ctx (r:reg) (t:ttype) p = + let rt = rtype ctx r in + if safe_cast rt t then r else + match rt, t with + | _, HVoid -> + alloc_tmp ctx HVoid + | HVirtual _, HVirtual _ -> + let tmp = alloc_tmp ctx HDyn in + op ctx (OMov (tmp,r)); + cast_to ctx tmp t p + | (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64), (HF32 | HF64) -> + let tmp = alloc_tmp ctx t in + op ctx (OToSFloat (tmp, r)); + tmp + | (HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64), (HUI8 | HUI16 | HI32 | HI64) -> + let tmp = alloc_tmp ctx t in + op ctx (OToInt (tmp, r)); + tmp | HObj o, HVirtual _ -> let out = alloc_tmp ctx t in (try @@ -1316,7 +1326,7 @@ and get_access ctx e = (match a, follow ethis.etype with | FStatic (c,({ cf_kind = Var _ | Method MethDynamic } as f)), _ -> let g, t = class_global ctx c in - AStaticVar (g, t, (match t with HObj o -> (try fst (get_index f.cf_name o) with Not_found -> assert false) | _ -> assert false)) + AStaticVar (g, t, (match t with HObj o -> (try fst (get_index f.cf_name o) with Not_found -> die "" __LOC__) | _ -> die "" __LOC__)) | FStatic (c,({ cf_kind = Method _ } as f)), _ -> AStaticFun (alloc_fid ctx c f) | FClosure (Some (cdef,pl), f), TInst (c,_) @@ -1390,7 +1400,7 @@ and array_read ctx ra (at,vt) ridx p = | HF32 | HF64 -> op ctx (OFloat (r,alloc_float ctx 0.)); | _ -> - assert false); + die "" __LOC__); let jend = jump ctx (fun i -> OJAlways i) in j(); let hbytes = alloc_tmp ctx HBytes in @@ -1461,7 +1471,7 @@ and jump_expr ctx e jcond = | OpGte -> if jcond then gte r1 r2 else lt r1 r2 | OpLt -> if jcond then lt r1 r2 else gte r1 r2 | OpLte -> if jcond then gte r2 r1 else lt r2 r1 - | _ -> assert false + | _ -> die "" __LOC__ ) | TBinop (OpBoolAnd, e1, e2) -> let j = jump_expr ctx e1 false in @@ -1489,7 +1499,7 @@ and eval_args ctx el t p = ) in hold ctx r; r - ) el (match t with HFun (args,_) -> args | HDyn -> List.map (fun _ -> HDyn) el | _ -> assert false) in + ) el (match t with HFun (args,_) -> args | HDyn -> List.map (fun _ -> HDyn) el | _ -> die "" __LOC__) in List.iter (free ctx) rl; set_curpos ctx p; rl @@ -1506,7 +1516,7 @@ and make_const ctx c p = let fields, t = (match c with | CString s -> let str, len = to_utf8 s p in - [alloc_string ctx str; alloc_i32 ctx (Int32.of_int len)], to_type ctx ctx.com.basic.tstring + [alloc_string ctx str; alloc_i32 ctx (Int32.of_int len)], ctx.tstring ) in let g = lookup_alloc ctx.cglobals t in g, Array.of_list fields @@ -1515,7 +1525,7 @@ and make_const ctx c p = g and make_string ctx s p = - let r = alloc_tmp ctx (to_type ctx ctx.com.basic.tstring) in + let r = alloc_tmp ctx ctx.tstring in op ctx (OGetGlobal (r, make_const ctx (CString s) p)); r @@ -1622,14 +1632,14 @@ and eval_expr ctx e = (match follow s.etype with | TInst (csup,_) -> (match csup.cl_constructor with - | None -> assert false + | None -> die "" __LOC__ | Some f -> let r = alloc_tmp ctx HVoid in let el = eval_args ctx el (to_type ctx f.cf_type) e.epos in op ctx (OCallN (r, alloc_fid ctx csup f, 0 :: el)); r ) - | _ -> assert false); + | _ -> die "" __LOC__); | TCall ({ eexpr = TIdent s }, el) when s.[0] = '$' -> let invalid() = abort "Invalid native call" e.epos in (match s, el with @@ -1976,8 +1986,8 @@ and eval_expr ctx e = op ctx (OGetTID (r,eval_to ctx v HType)); r | "$resources", [] -> - let tdef = (try List.find (fun t -> (t_infos t).mt_path = (["haxe";"_Resource"],"ResourceContent")) ctx.com.types with Not_found -> assert false) in - let t = class_type ctx (match tdef with TClassDecl c -> c | _ -> assert false) [] false in + let tdef = (try List.find (fun t -> (t_infos t).mt_path = (["haxe";"_Resource"],"ResourceContent")) ctx.com.types with Not_found -> die "" __LOC__) in + let t = class_type ctx (match tdef with TClassDecl c -> c | _ -> die "" __LOC__) [] false in let arr = alloc_tmp ctx HArray in let rt = alloc_tmp ctx HType in op ctx (OType (rt,t)); @@ -1988,7 +1998,7 @@ and eval_expr ctx e = let rb = alloc_tmp ctx HBytes in let ridx = reg_int ctx 0 in hold ctx ridx; - let has_len = (match t with HObj p -> PMap.mem "dataLen" p.pindex | _ -> assert false) in + let has_len = (match t with HObj p -> PMap.mem "dataLen" p.pindex | _ -> die "" __LOC__) in list_iteri (fun i (k,v) -> op ctx (ONew ro); op ctx (OString (rb,alloc_string ctx k)); @@ -2045,6 +2055,8 @@ and eval_expr ctx e = get_enum_index ctx v | TCall ({ eexpr = TField (_,FStatic ({ cl_path = [],"Type" },{ cf_name = "enumIndex" })) },[v]) when (match follow v.etype with TEnum _ -> true | _ -> false) -> get_enum_index ctx v + | TCall ({ eexpr = TField (ef,FStatic ({ cl_path = [],"Reflect" } as c,{ cf_name = "makeVarArgs" })) } as e1,[v]) -> + eval_expr ctx {e with eexpr = TCall({e1 with eexpr = TField(ef,FStatic(c, PMap.find "_makeVarArgs" c.cl_statics))},[v])} | TCall ({ eexpr = TField (_,FStatic ({ cl_path = [],"Std" },{ cf_name = "instance" })) },[v;vt]) | TCall ({ eexpr = TField (_,FStatic ({ cl_path = [],"Std" },{ cf_name = "downcast" })) },[v;vt]) -> let r = eval_expr ctx v in @@ -2166,7 +2178,7 @@ and eval_expr ctx e = let _, sid, _ = vp.vfields.(fid) in op ctx (ODynGet (r,robj, sid)) | _ -> - assert false) + die "" __LOC__) | ADynamic (ethis, f) -> let robj = eval_null_check ctx ethis in op ctx (ODynGet (r,robj,f)) @@ -2176,7 +2188,7 @@ and eval_expr ctx e = let fid = alloc_fun_path ctx en.e_path name in if fid = cur_fid then begin let ef = PMap.find name en.e_constrs in - let eargs, et = (match follow ef.ef_type with TFun (args,ret) -> args, ret | _ -> assert false) in + let eargs, et = (match follow ef.ef_type with TFun (args,ret) -> args, ret | _ -> die "" __LOC__) in let ct = ctx.com.basic in let p = ef.ef_pos in let eargs = List.map (fun (n,o,t) -> Type.alloc_var VGenerated n t en.e_pos, if o then Some (mk (TConst TNull) t_dynamic null_pos) else None) eargs in @@ -2202,7 +2214,7 @@ and eval_expr ctx e = op ctx (ONew r); hold ctx r; List.iter (fun ((s,_,_),ev) -> - let fidx = (try PMap.find s vp.vindex with Not_found -> assert false) in + let fidx = (try PMap.find s vp.vindex with Not_found -> die "" __LOC__) in let _, _, ft = vp.vfields.(fidx) in let v = eval_to ctx ev ft in op ctx (OSetField (r,fidx,v)); @@ -2213,7 +2225,7 @@ and eval_expr ctx e = let r = alloc_tmp ctx HDynObj in op ctx (ONew r); hold ctx r; - let a = (match follow e.etype with TAnon a -> Some a | t -> if t == t_dynamic then None else assert false) in + let a = (match follow e.etype with TAnon a -> Some a | t -> if t == t_dynamic then None else die "" __LOC__) in List.iter (fun ((s,_,_),ev) -> let ft = (try (match a with None -> raise Not_found | Some a -> PMap.find s a.a_fields).cf_type with Not_found -> ev.etype) in let v = eval_to ctx ev (to_type ctx ft) in @@ -2232,7 +2244,7 @@ and eval_expr ctx e = op ctx (ONew r); hold ctx r; (match c.cl_constructor with - | None -> if c.cl_implements <> [] then assert false + | None -> if c.cl_implements <> [] then die "" __LOC__ | Some { cf_expr = None } -> abort (s_type_path c.cl_path ^ " does not have a constructor") e.epos | Some ({ cf_expr = Some cexpr } as constr) -> let rl = eval_args ctx el (to_type ctx cexpr.etype) e.epos in @@ -2285,7 +2297,7 @@ and eval_expr ctx e = | HUI8 | HUI16 | HI32 | HI64 | HF32 | HF64 -> op ctx (OAdd (r,a,b)) | HObj { pname = "String" } -> - op ctx (OCall2 (r,alloc_fun_path ctx ([],"String") "__add__",a,b)) + op ctx (OCall2 (r,alloc_fun_path ctx ([],"String") "__add__",to_string ctx a e1.epos,to_string ctx b e2.epos)) | HDyn -> op ctx (OCall2 (r,alloc_fun_path ctx ([],"Std") "__add__",a,b)) | t -> @@ -2298,11 +2310,11 @@ and eval_expr ctx e = | OpMult -> op ctx (OMul (r,a,b)) | OpMod -> op ctx (if unsigned e1.etype then OUMod (r,a,b) else OSMod (r,a,b)) | OpDiv -> op ctx (OSDiv (r,a,b)) (* don't use UDiv since both operands are float already *) - | _ -> assert false) + | _ -> die "" __LOC__) | HDyn -> - op ctx (OCall3 (r, alloc_std ctx "dyn_op" [HI32;HDyn;HDyn] HDyn, reg_int ctx (match bop with OpSub -> 1 | OpMult -> 2 | OpMod -> 3 | OpDiv -> 4 | _ -> assert false), a, b)) + op ctx (OCall3 (r, alloc_std ctx "dyn_op" [HI32;HDyn;HDyn] HDyn, reg_int ctx (match bop with OpSub -> 1 | OpMult -> 2 | OpMod -> 3 | OpDiv -> 4 | _ -> die "" __LOC__), a, b)) | _ -> - assert false) + die "" __LOC__) | OpShl | OpShr | OpUShr | OpAnd | OpOr | OpXor -> (match rtype ctx r with | HUI8 | HUI16 | HI32 | HI64 -> @@ -2315,13 +2327,13 @@ and eval_expr ctx e = | OpXor -> op ctx (OXor (r,a,b)) | _ -> ()) | HDyn -> - op ctx (OCall3 (r, alloc_std ctx "dyn_op" [HI32;HDyn;HDyn] HDyn, reg_int ctx (match bop with OpShl -> 5 | OpShr -> 6 | OpUShr -> 7 | OpAnd -> 8 | OpOr -> 9 | OpXor -> 10 | _ -> assert false), a, b)) + op ctx (OCall3 (r, alloc_std ctx "dyn_op" [HI32;HDyn;HDyn] HDyn, reg_int ctx (match bop with OpShl -> 5 | OpShr -> 6 | OpUShr -> 7 | OpAnd -> 8 | OpOr -> 9 | OpXor -> 10 | _ -> die "" __LOC__), a, b)) | _ -> - assert false) + die "" __LOC__) | OpAssignOp bop -> loop bop | _ -> - assert false + die "" __LOC__ in loop bop in @@ -2346,10 +2358,18 @@ and eval_expr ctx e = r | OpAdd | OpSub | OpMult | OpDiv | OpMod | OpShl | OpShr | OpUShr | OpAnd | OpOr | OpXor -> let t = (match to_type ctx e.etype with HNull t -> t | t -> t) in + let conv_string = bop = OpAdd && is_string t in + let eval e = + if conv_string then + let r = eval_expr ctx e in + to_string ctx r e.epos + else + eval_to ctx e t + in let r = alloc_tmp ctx t in - let a = eval_to ctx e1 t in + let a = eval e1 in hold ctx a; - let b = eval_to ctx e2 t in + let b = eval e2 in free ctx a; binop r a b; r @@ -2426,7 +2446,7 @@ and eval_expr ctx e = op ctx (OSetEnumField (ctx.m.mcaptreg,index,r)); r | AEnum _ | ANone | AInstanceFun _ | AInstanceProto _ | AStaticFun _ | AVirtualMethod _ -> - assert false) + die "" __LOC__) | OpBoolOr -> let r = alloc_tmp ctx HBool in let j = jump_expr ctx e1 true in @@ -2459,12 +2479,12 @@ and eval_expr ctx e = | acc -> gen_assign_op ctx acc e1 (fun r -> hold ctx r; - let b = eval_to ctx e2 (rtype ctx r) in + let b = if bop = OpAdd && is_string (rtype ctx r) then to_string ctx (eval_expr ctx e2) e2.epos else eval_to ctx e2 (rtype ctx r) in free ctx r; binop r r b; r)) | OpInterval | OpArrow | OpIn -> - assert false) + die "" __LOC__) | TUnop (Not,_,v) -> let tmp = alloc_tmp ctx HBool in let r = eval_to ctx v HBool in @@ -2526,7 +2546,7 @@ and eval_expr ctx e = op ctx (OSub (r2, r2, tmp)); op ctx (OSafeCast (r, r2)); | _ -> - assert false + die "" __LOC__ in (match get_access ctx v, fix with | ALocal (v,r), Prefix -> @@ -2637,7 +2657,7 @@ and eval_expr ctx e = cast_to ~force:true ctx rv t e.epos) | TArrayDecl el -> let r = alloc_tmp ctx (to_type ctx e.etype) in - let et = (match follow e.etype with TInst (_,[t]) -> to_type ctx t | _ -> assert false) in + let et = (match follow e.etype with TInst (_,[t]) -> to_type ctx t | _ -> die "" __LOC__) in let array_bytes bits t tname get_op = let b = alloc_tmp ctx HBytes in let size = reg_int ctx ((List.length el) lsl bits) in @@ -2694,7 +2714,7 @@ and eval_expr ctx e = | AArray (a,at,idx) -> array_read ctx a at idx e.epos | _ -> - assert false) + die "" __LOC__) | TMeta (_,e) -> eval_expr ctx e | TFor (v,it,loop) -> @@ -2810,7 +2830,7 @@ and eval_expr ctx e = | HEnum e -> let _,_,args = e.efields.(f.ef_index) in args.(index), Array.length e.efields = 1 - | _ -> assert false + | _ -> die "" __LOC__ ) in let er = eval_expr ctx ec in if is_single then op ctx (ONullCheck er); (* #7560 *) @@ -2857,7 +2877,7 @@ and eval_expr ctx e = | TInst (c,_) -> TClassDecl c | TAbstract (a,_) -> TAbstractDecl a | TEnum (e,_) -> TEnumDecl e - | _ -> assert false + | _ -> die "" __LOC__ ) in hold ctx rtrap; let r = type_value ctx ct ec.epos in @@ -3013,7 +3033,7 @@ and gen_assign_op ctx acc e1 f = op ctx (ODynSet (robj,fid,r)); r | ANone | ALocal _ | AStaticFun _ | AInstanceFun _ | AInstanceProto _ | AVirtualMethod _ | AEnum _ -> - assert false + die "" __LOC__ and build_capture_vars ctx f = let ignored_vars = ref PMap.empty in @@ -3069,8 +3089,8 @@ and gen_method_wrapper ctx rt t p = let fid = lookup_alloc ctx.cfids () in ctx.method_wrappers <- PMap.add (rt,t) fid ctx.method_wrappers; let old = ctx.m in - let targs, tret = (match t with HFun (args, ret) -> args, ret | _ -> assert false) in - let iargs, iret = (match rt with HFun (args, ret) -> args, ret | _ -> assert false) in + let targs, tret = (match t with HFun (args, ret) -> args, ret | _ -> die "" __LOC__) in + let iargs, iret = (match rt with HFun (args, ret) -> args, ret | _ -> die "" __LOC__) in ctx.m <- method_context fid HDyn null_capture false; let rfun = alloc_tmp ctx rt in let rargs = List.map (fun t -> @@ -3164,18 +3184,18 @@ and make_fun ?gen_content ctx name fidx f cthis cparent = (match c.eexpr with | TConst (TInt i) -> op ctx (OInt (t,alloc_i32 ctx i)) | TConst (TFloat s) -> op ctx (OInt (t,alloc_i32 ctx (Int32.of_float (float_of_string s)))) - | _ -> assert false) + | _ -> die "" __LOC__) | HF32 | HF64 -> (match c.eexpr with | TConst (TInt i) -> op ctx (OFloat (t,alloc_float ctx (Int32.to_float i))) | TConst (TFloat s) -> op ctx (OFloat (t,alloc_float ctx (float_of_string s))) - | _ -> assert false) + | _ -> die "" __LOC__) | HBool -> (match c.eexpr with | TConst (TBool b) -> op ctx (OBool (t,b)) - | _ -> assert false) + | _ -> die "" __LOC__) | _ -> - assert false); + die "" __LOC__); if capt = None then add_assign ctx v; let jend = jump ctx (fun n -> OJAlways n) in j(); @@ -3188,7 +3208,7 @@ and make_fun ?gen_content ctx name fidx f cthis cparent = | Some c -> let j = jump ctx (fun n -> OJNotNull (r,n)) in (match c.eexpr with - | TConst (TNull | TThis | TSuper) -> assert false + | TConst (TNull | TThis | TSuper) -> die "" __LOC__ | TConst (TInt i) when (match to_type ctx (Abstract.follow_with_abstracts v.v_type) with HUI8 | HUI16 | HI32 | HI64 | HDyn -> true | _ -> false) -> let tmp = alloc_tmp ctx HI32 in op ctx (OInt (tmp, alloc_i32 ctx i)); @@ -3291,7 +3311,7 @@ let generate_static ctx c f = | (Meta.HlNative,[(EConst(String(lib,_)),_)] ,_ ) :: _ -> add_native lib f.cf_name | (Meta.HlNative,[(EConst(Float(ver)),_)] ,_ ) :: _ -> - let cur_ver = (try Common.raw_defined_value ctx.com "hl-ver" with Not_found -> "") in + let cur_ver = (try Common.defined_value ctx.com Define.HlVer with Not_found -> "") in if cur_ver < ver then let gen_content() = op ctx (OThrow (make_string ctx ("Requires compiling with -D hl-ver=" ^ ver ^ ".0 or higher") null_pos)); @@ -3320,7 +3340,7 @@ let rec generate_member ctx c f = let o = (match class_type ctx c (List.map snd c.cl_params) false with | HObj o | HStruct o -> o - | _ -> assert false + | _ -> die "" __LOC__ ) in (* @@ -3330,7 +3350,7 @@ let rec generate_member ctx c f = match f.cf_kind with | Method MethDynamic -> let r = alloc_tmp ctx (to_type ctx f.cf_type) in - let fid = (try fst (get_index f.cf_name o) with Not_found -> assert false) in + let fid = (try fst (get_index f.cf_name o) with Not_found -> die "" __LOC__) in op ctx (OGetThis (r,fid)); op ctx (OJNotNull (r,2)); op ctx (OInstanceClosure (r,alloc_fid ctx c f,0)); @@ -3344,7 +3364,7 @@ let rec generate_member ctx c f = (* function __string() return this.toString().bytes *) let ethis = mk (TConst TThis) (TInst (c,List.map snd c.cl_params)) p in let tstr = mk (TCall (mk (TField (ethis,FInstance(c,List.map snd c.cl_params,f))) f.cf_type p,[])) ctx.com.basic.tstring p in - let cstr, cf_bytes = (try (match ctx.com.basic.tstring with TInst(c,_) -> c, PMap.find "bytes" c.cl_fields | _ -> assert false) with Not_found -> assert false) in + let cstr, cf_bytes = (try (match ctx.com.basic.tstring with TInst(c,_) -> c, PMap.find "bytes" c.cl_fields | _ -> die "" __LOC__) with Not_found -> die "" __LOC__) in let estr = mk (TReturn (Some (mk (TField (tstr,FInstance (cstr,[],cf_bytes))) cf_bytes.cf_type p))) ctx.com.basic.tvoid p in ignore(make_fun ctx (s_type_path c.cl_path,"__string") (alloc_fun_path ctx c.cl_path "__string") { tf_expr = estr; tf_args = []; tf_type = cf_bytes.cf_type; } (Some c) None) end @@ -3407,9 +3427,9 @@ let generate_static_init ctx types main = let index name = match ct with | HObj o -> - fst (try get_index name o with Not_found -> assert false) + fst (try get_index name o with Not_found -> die "" __LOC__) | _ -> - assert false + die "" __LOC__ in let rc = (match t with @@ -3505,9 +3525,9 @@ let generate_static_init ctx types main = let index name = match et with | HObj o -> - fst (try get_index name o with Not_found -> assert false) + fst (try get_index name o with Not_found -> die "" __LOC__) | _ -> - assert false + die "" __LOC__ in let avalues = alloc_tmp ctx HArray in @@ -3540,16 +3560,16 @@ let generate_static_init ctx types main = let index name = match t with | HObj o -> - fst (try get_index name o with Not_found -> assert false) + fst (try get_index name o with Not_found -> die "" __LOC__) | _ -> - assert false + die "" __LOC__ in let g = alloc_global ctx ("$" ^ name) t in let r = alloc_tmp ctx t in let rt = alloc_tmp ctx HType in op ctx (ONew r); - op ctx (OType (rt,(match name with "Int" -> HI32 | "Float" -> HF64 | "Dynamic" -> HDyn | "Bool" -> HBool | _ -> assert false))); + op ctx (OType (rt,(match name with "Int" -> HI32 | "Float" -> HF64 | "Dynamic" -> HDyn | "Bool" -> HBool | _ -> die "" __LOC__))); op ctx (OSetField (r,index "__type__",rt)); op ctx (OSetField (r,index (if is_bool then "__ename__" else "__name__"),make_string ctx name pos)); op ctx (OSetGlobal (g,r)); @@ -3605,7 +3625,7 @@ let write_index_gen b i = if i < 0x2000 then begin b ((i lsr 8) lor 0xA0); b (i land 0xFF); - end else if i >= 0x20000000 then assert false else begin + end else if i >= 0x20000000 then die "" __LOC__ else begin b ((i lsr 24) lor 0xE0); b ((i lsr 16) land 0xFF); b ((i lsr 8) land 0xFF); @@ -3616,7 +3636,7 @@ let write_index_gen b i = else if i < 0x2000 then begin b ((i lsr 8) lor 0x80); b (i land 0xFF); - end else if i >= 0x20000000 then assert false else begin + end else if i >= 0x20000000 then die "" __LOC__ else begin b ((i lsr 24) lor 0xC0); b ((i lsr 16) land 0xFF); b ((i lsr 8) land 0xFF); @@ -3630,7 +3650,7 @@ let write_code ch code debug = let write_index = write_index_gen byte in let rec write_type t = - write_index (try PMap.find t htypes with Not_found -> assert false) + write_index (try PMap.find t htypes with Not_found -> die "" __LOC__) in let write_op op = @@ -3667,7 +3687,7 @@ let write_code ch code debug = write_index r; write_index f; let n = List.length rl in - if n > 0xFF then assert false; + if n > 0xFF then die "" __LOC__; byte n; List.iter write_index rl | OType (r,t) -> @@ -3708,7 +3728,7 @@ let write_code ch code debug = write_index b; write_index c; | _ -> - assert false + die "" __LOC__ in IO.nwrite_string ch "HLB"; @@ -3773,7 +3793,7 @@ let write_code ch code debug = | HDyn -> byte 9 | HFun (args,ret) | HMethod (args,ret) -> let n = List.length args in - if n > 0xFF then assert false; + if n > 0xFF then die "" __LOC__; byte (match t with HFun _ -> 10 | _ -> 20); byte n; List.iter write_type args; @@ -3818,7 +3838,7 @@ let write_code ch code debug = write_index (Array.length e.efields); Array.iter (fun (_,nid,tl) -> write_index nid; - if Array.length tl > 0xFF then assert false; + if Array.length tl > 0xFF then die "" __LOC__; byte (Array.length tl); Array.iter write_type tl; ) e.efields @@ -3913,12 +3933,12 @@ let create_context com is_macro dump = let get_class name = match get_type name with | TClassDecl c -> c - | _ -> assert false + | _ -> die "" __LOC__ in let get_abstract name = match get_type name with | TAbstractDecl a -> a - | _ -> assert false + | _ -> die "" __LOC__ in let ctx = { com = com; @@ -3939,6 +3959,7 @@ let create_context com is_macro dump = cached_tuples = PMap.empty; cfids = new_lookup(); defined_funs = Hashtbl.create 0; + tstring = HVoid; array_impl = { aall = get_class "ArrayAccess"; abase = get_class "ArrayBase"; @@ -3946,7 +3967,7 @@ let create_context com is_macro dump = aobj = get_class "ArrayObj"; aui16 = get_class "ArrayBytes_hl_UI16"; ai32 = get_class "ArrayBytes_Int"; - af32 = get_class "ArrayBytes_Single"; + af32 = get_class "ArrayBytes_hl_F32"; af64 = get_class "ArrayBytes_Float"; }; base_class = get_class "Class"; @@ -3963,6 +3984,7 @@ let create_context com is_macro dump = ct_delayed = []; ct_depth = 0; } in + ctx.tstring <- to_type ctx ctx.com.basic.tstring; ignore(alloc_string ctx ""); ignore(class_type ctx ctx.base_class [] false); ctx @@ -3970,7 +3992,7 @@ let create_context com is_macro dump = let add_types ctx types = List.iter (fun t -> match t with - | TClassDecl ({ cl_path = ["hl";"types"], ("BytesIterator"|"ArrayBytes") } as c) -> + | TClassDecl ({ cl_path = ["hl";"types"], ("BytesIterator"|"BytesKeyValueIterator"|"ArrayBytes") } as c) -> c.cl_extern <- true | TClassDecl c -> let rec loop p f = diff --git a/src/generators/genhxold.ml b/src/generators/genhxold.ml index 9a32668200c186d6cbe8d4527ed9dfc86db3abdf..988badeec7e6109ec9819e08cb75d9644d46bf68 100644 --- a/src/generators/genhxold.ml +++ b/src/generators/genhxold.ml @@ -70,7 +70,7 @@ let generate_type com t = let rec notnull t = match t with | TMono r -> - (match !r with + (match r.tm_type with | None -> t | Some t -> notnull t) | TLazy f -> @@ -86,7 +86,7 @@ let generate_type com t = and stype t = match t with | TMono r -> - (match !r with + (match r.tm_type with | None -> "Unknown" | Some t -> stype t) | TInst ({ cl_kind = KTypeParameter _ } as c,tl) -> @@ -113,7 +113,7 @@ let generate_type com t = and ftype t = match t with | TMono r -> - (match !r with + (match r.tm_type with | None -> stype t | Some t -> ftype t) | TLazy f -> @@ -196,7 +196,7 @@ let generate_type com t = a,(if o then Some (loop f.cf_meta) else None ),t ) args, ret | _ -> - assert false + die "" __LOC__ ) in let tparams = (match f.cf_params with [] -> "" | l -> "<" ^ String.concat "," (List.map fst l) ^ ">") in p "function %s%s(%s) : %s" name tparams (String.concat ", " (List.map sparam params)) (stype ret); diff --git a/src/generators/genjava.ml b/src/generators/genjava.ml index 4989bb83510b66df372407d79596f14f1bd8eca6..ab28b5e4f90985043a803b5baa71aaa71a90d25b 100644 --- a/src/generators/genjava.ml +++ b/src/generators/genjava.ml @@ -181,7 +181,7 @@ let parse_explicit_iface = match split with | clname :: fn_name :: [] -> fn_name, (List.rev pack, clname) | pack_piece :: tl -> get_iface tl (pack_piece :: pack) - | _ -> assert false + | _ -> die "" __LOC__ in get_iface split [] in parse_explicit_iface @@ -218,7 +218,7 @@ struct let get_cl_from_t t = match follow t with | TInst(cl,_) -> cl - | _ -> assert false + | _ -> die "" __LOC__ let configure gen runtime_cl = let basic = gen.gcon.basic in @@ -254,7 +254,7 @@ struct (* Std.is() *) | TCall( - { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "is" })) }, + { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = ("is" | "isOfType") })) }, [ obj; { eexpr = TTypeExpr(md) } ] ) -> let mk_is is_basic obj md = @@ -482,7 +482,7 @@ struct let has_case = ref false in (* first we need to reorder all cases so all collisions are close to each other *) - let get_str e = match e.eexpr with | TConst(TString s) -> s | _ -> assert false in + let get_str e = match e.eexpr with | TConst(TString s) -> s | _ -> die "" __LOC__ in let has_conflict = ref false in let rec reorder_cases unordered ordered = @@ -514,7 +514,7 @@ struct match ret with | (el, e) :: ( (_,_) :: _ as tl ) -> loop tl ( (true, el, e) :: acc ) | (el, e) :: [] -> ( (false, el, e) :: acc ) - | _ -> assert false + | _ -> die "" __LOC__ in List.rev (loop ret []) else @@ -564,7 +564,7 @@ struct in Some conds, hashed_exprs - | _ -> assert false + | _ -> die "" __LOC__ ) (None,[]) el in let e = if has_default then Type.concat execute_def_set e else e in let e = if !has_conflict then Type.concat e { e with eexpr = TBreak; etype = basic.tvoid } else e in @@ -602,13 +602,13 @@ struct let get_cl_from_t t = match follow t with | TInst(cl,_) -> cl - | _ -> assert false + | _ -> die "" __LOC__ let configure gen runtime_cl = let cl_boolean = get_cl (get_type gen (["java";"lang"],"Boolean")) in let cl_number = get_cl (get_type gen (["java";"lang"],"Number")) in - (if java_hash "Testing string hashCode implementation from haXe" <> (Int32.of_int 545883604) then assert false); + (if java_hash "Testing string hashCode implementation from haXe" <> (Int32.of_int 545883604) then die "" __LOC__); let basic = gen.gcon.basic in let tbyte = mt_to_t_dyn ( get_type gen (["java"], "Int8") ) in let tshort = mt_to_t_dyn ( get_type gen (["java"], "Int16") ) in @@ -633,8 +633,8 @@ struct | "Long" -> cl, ti64 | _ -> - assert false) - | _ -> assert false + die "" __LOC__) + | _ -> die "" __LOC__ in let mk_valueof_call boxed_t expr = @@ -691,7 +691,7 @@ struct "numToLong" | TInst({ cl_path = (["java";"lang"],"Short") },[]) -> "numToShort" - | _ -> gen.gcon.error ("Invalid boxed type " ^ (debug_type boxed_t)) expr.epos; assert false + | _ -> gen.gcon.error ("Invalid boxed type " ^ (debug_type boxed_t)) expr.epos; die "" __LOC__ in { eexpr = TCall( @@ -905,11 +905,13 @@ let rec handle_throws gen cf = Type.iter iter e with | Exit -> (* needs typed exception to be caught *) let throwable = get_cl (get_type gen (["java";"lang"],"Throwable")) in + let cast_cl = get_cl (get_type gen (["java";"lang"],"RuntimeException")) in let catch_var = alloc_var "typedException" (TInst(throwable,[])) in let rethrow = mk_local catch_var e.epos in - let hx_exception = get_cl (get_type gen (["haxe";"lang"], "HaxeException")) in - let wrap_static = mk_static_field_access (hx_exception) "wrap" (TFun([("obj",false,t_dynamic)], t_dynamic)) rethrow.epos in - let wrapped = { rethrow with eexpr = TThrow { rethrow with eexpr = TCall(wrap_static, [rethrow]) }; } in + let hx_exception = get_cl (get_type gen (["haxe"], "Exception")) in + let wrap_static = mk_static_field_access (hx_exception) "thrown" (TFun([("obj",false,t_dynamic)], t_dynamic)) rethrow.epos in + let thrown_value = mk_cast (TInst(cast_cl,[])) { rethrow with eexpr = TCall(wrap_static, [rethrow]) } in + let wrapped = { rethrow with eexpr = TThrow thrown_value; } in let map_throws cl = let var = alloc_var "typedException" (TInst(cl,List.map (fun _ -> t_dynamic) cl.cl_params)) in var, { tf.tf_expr with eexpr = TThrow (mk_local var e.epos) } @@ -936,7 +938,7 @@ let reserved = let res = Hashtbl.create 120 in "void"; "volatile"; "while"; ]; res -let dynamic_anon = TAnon( { a_fields = PMap.empty; a_status = ref Closed } ) +let dynamic_anon = mk_anon (ref Closed) let rec get_class_modifiers meta cl_type cl_access cl_modifiers = match meta with @@ -958,6 +960,7 @@ let rec get_fun_modifiers meta access modifiers = | (Meta.Volatile,[],_) :: meta -> get_fun_modifiers meta access ("volatile" :: modifiers) | (Meta.Transient,[],_) :: meta -> get_fun_modifiers meta access ("transient" :: modifiers) | (Meta.Native,[],_) :: meta -> get_fun_modifiers meta access ("native" :: modifiers) + | (Meta.NativeJni,[],_) :: meta -> get_fun_modifiers meta access ("native" :: modifiers) | _ :: meta -> get_fun_modifiers meta access modifiers let generate con = @@ -991,7 +994,7 @@ let generate con = (try let native_arr_cl = get_cl ( get_type gen (["java"], "NativeArray") ) in gen.gclasses.nativearray <- (fun t -> TInst(native_arr_cl,[t])); - gen.gclasses.nativearray_type <- (function TInst(_,[t]) -> t | _ -> assert false); + gen.gclasses.nativearray_type <- (function TInst(_,[t]) -> t | _ -> die "" __LOC__); gen.gclasses.nativearray_len <- (fun e p -> mk_field_access gen e "length" p); let fn_cl = get_cl (get_type gen (["haxe";"lang"],"Function")) in @@ -1001,7 +1004,7 @@ let generate con = (*let string_ref = get_cl ( get_type gen (["haxe";"lang"], "StringRefl")) in*) - let ti64 = match ( get_type gen (["java"], "Int64") ) with | TAbstractDecl a -> TAbstract(a,[]) | _ -> assert false in + let ti64 = match ( get_type gen (["java"], "Int64") ) with | TAbstractDecl a -> TAbstract(a,[]) | _ -> die "" __LOC__ in let has_tdynamic params = List.exists (fun e -> match run_follow gen e with | TDynamic _ -> true | _ -> false) params @@ -1254,7 +1257,7 @@ let generate con = | TInst ({ cl_kind = KTypeParameter _; cl_path=p }, []) -> snd p | TAbstract ({ a_path = [], "Dynamic" },[]) -> path_s_import pos (["java";"lang"], "Object") [] - | TMono r -> (match !r with | None -> "java.lang.Object" | Some t -> t_s stack pos (run_follow gen t)) + | TMono r -> (match r.tm_type with | None -> "java.lang.Object" | Some t -> t_s stack pos (run_follow gen t)) | TInst ({ cl_path = [], "String" }, []) -> path_s_import pos (["java";"lang"], "String") [] | TAbstract ({ a_path = [], "Class" }, [p]) | TAbstract ({ a_path = [], "Enum" }, [p]) @@ -1278,7 +1281,7 @@ let generate con = | TDynamic _ -> path_s_import pos (["java";"lang"], "Object") [] (* No Lazy type nor Function type made. That's because function types will be at this point be converted into other types *) - | _ -> if !strict_mode then begin trace ("[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]"); assert false end else "[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]" + | _ -> if !strict_mode then begin trace ("[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]"); die "" __LOC__ end else "[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]" end and param_t_s stack pos t = match run_follow gen t with @@ -1526,7 +1529,7 @@ let generate con = newline w; expr_s w e; | TBreak -> print w "break label%s" n - | _ -> assert false) + | _ -> die "" __LOC__) | TMeta (_,e) -> expr_s w e | TCall ({ eexpr = TIdent "__array__" }, el) @@ -1610,7 +1613,7 @@ let generate con = | params -> let md = match e.eexpr with | TField(ef, _) -> t_to_md (run_follow gen ef.etype) - | _ -> assert false + | _ -> die "" __LOC__ in write w "<"; ignore (List.fold_left (fun acc t -> @@ -1801,11 +1804,11 @@ let generate con = write w "[ for not supported "; expr_s w content; write w " ]"; - if !strict_mode then assert false - | TObjectDecl _ -> write w "[ obj decl not supported ]"; if !strict_mode then assert false - | TFunction _ -> write w "[ func decl not supported ]"; if !strict_mode then assert false - | TEnumParameter _ -> write w "[ enum parameter not supported ]"; if !strict_mode then assert false - | TEnumIndex _ -> write w "[ enum index not supported ]"; if !strict_mode then assert false + if !strict_mode then die "" __LOC__ + | TObjectDecl _ -> write w "[ obj decl not supported ]"; if !strict_mode then die "" __LOC__ + | TFunction _ -> write w "[ func decl not supported ]"; if !strict_mode then die "" __LOC__ + | TEnumParameter _ -> write w "[ enum parameter not supported ]"; if !strict_mode then die "" __LOC__ + | TEnumIndex _ -> write w "[ enum index not supported ]"; if !strict_mode then die "" __LOC__ in expr_s w e in @@ -1877,7 +1880,7 @@ let generate con = gen_annotations w ~add_newline:false tdef.t_meta; run (follow_once t) | TMono r -> - (match !r with + (match r.tm_type with | Some t -> run t | _ -> () (* avoid infinite loop / should be the same in this context *)) | TLazy f -> @@ -1898,7 +1901,7 @@ let generate con = | [] -> ("","") | _ -> - let params = sprintf "<%s>" (String.concat ", " (List.map (fun (_, tcl) -> match follow tcl with | TInst(cl, _) -> snd cl.cl_path | _ -> assert false) cl_params)) in + let params = sprintf "<%s>" (String.concat ", " (List.map (fun (_, tcl) -> match follow tcl with | TInst(cl, _) -> snd cl.cl_path | _ -> die "" __LOC__) cl_params)) in let params_extends = List.fold_left (fun acc (name, t) -> match run_follow gen t with | TInst (cl, p) -> @@ -1906,7 +1909,7 @@ let generate con = | [] -> acc | _ -> acc) (* TODO | _ -> (sprintf " where %s : %s" name (String.concat ", " (List.map (fun (cl,p) -> path_param_s (TClassDecl cl) cl.cl_path p) cl.cl_implements))) :: acc ) *) - | _ -> trace (t_s null_pos t); assert false (* FIXME it seems that a cl_params will never be anything other than cl.cl_params. I'll take the risk and fail if not, just to see if that confirms *) + | _ -> trace (t_s null_pos t); die "" __LOC__ (* FIXME it seems that a cl_params will never be anything other than cl.cl_params. I'll take the risk and fail if not, just to see if that confirms *) ) [] cl_params in (params, String.concat " " params_extends) in @@ -1988,13 +1991,13 @@ let generate con = let visibility, modifiers = get_fun_modifiers cf.cf_meta visibility [] in let visibility, is_virtual = if is_explicit_iface then "",false else visibility, is_virtual in let v_n = if is_static then "static" else if is_override && not is_interface then "" else if not is_virtual then "final" else "" in - let cf_type = if is_override && not is_overload && not (Meta.has Meta.Overload cf.cf_meta) then match field_access gen (TInst(cl, List.map snd cl.cl_params)) cf.cf_name with | FClassField(_,_,_,_,_,actual_t,_) -> actual_t | _ -> assert false else cf.cf_type in + let cf_type = if is_override && not is_overload && not (Meta.has Meta.Overload cf.cf_meta) then match field_access gen (TInst(cl, List.map snd cl.cl_params)) cf.cf_name with | FClassField(_,_,_,_,_,actual_t,_) -> actual_t | _ -> die "" __LOC__ else cf.cf_type in let params = List.map snd cl.cl_params in let ret_type, args = match follow cf_type, follow cf.cf_type with | TFun (strbtl, t), TFun(rargs, _) -> (apply_params cl.cl_params params (real_type t), List.map2 (fun(_,_,t) (n,o,_) -> (n,o,apply_params cl.cl_params params (real_type t))) strbtl rargs) - | _ -> assert false + | _ -> die "" __LOC__ in (if is_override && not is_interface then write w "@Override "); @@ -2023,7 +2026,7 @@ let generate con = match s.eexpr with | TFunction tf -> mk_block (tf.tf_expr) - | _ -> assert false (* FIXME *) + | _ -> die "" __LOC__ (* FIXME *) in (if is_new then begin (*let rec get_super_call el = @@ -2131,7 +2134,7 @@ let generate con = (* public class Test : X, Y, Z where A : Y *) begin_block w; (* our constructor is expected to be a normal "new" function * - if !strict_mode && is_some cl.cl_constructor then assert false;*) + if !strict_mode && is_some cl.cl_constructor then die "" __LOC__;*) let rec loop cl = List.iter (fun cf -> add_scope cf.cf_name) cl.cl_ordered_fields; @@ -2151,29 +2154,25 @@ let generate con = in loop cl.cl_meta; - (match gen.gcon.main_class with - | Some path when path = cl.cl_path -> - write w "public static void main(String[] args)"; - begin_block w; - (try - let t = Hashtbl.find gen.gtypes ([], "Sys") in - match t with - | TClassDecl(cl) when PMap.mem "_args" cl.cl_statics -> - write w "Sys._args = args;"; newline w - | _ -> () - with | Not_found -> () - ); - write w "haxe.java.Init.init();"; - newline w; - (match gen.gcon.main with - | Some(expr) -> - expr_s w (mk_block expr) - | None -> - write w "main();"); - end_block w; - newline w - | _ -> () - ); + (match gen.gentry_point with + | Some (_,cl_main,expr) when cl == cl_main -> + write w "public static void main(String[] args)"; + begin_block w; + (try + let t = Hashtbl.find gen.gtypes ([], "Sys") in + match t with + | TClassDecl(cl) when PMap.mem "_args" cl.cl_statics -> + write w "Sys._args = args;"; newline w + | _ -> () + with Not_found -> + ()); + write w "haxe.java.Init.init();"; + newline w; + expr_s w expr; + write w ";"; + end_block w; + newline w + | _ -> ()); (match cl.cl_init with | None -> () @@ -2322,9 +2321,9 @@ let generate con = let object_iface = get_cl (get_type gen (["haxe";"lang"],"IHxObject")) in - let empty_en = match get_type gen (["haxe";"lang"], "EmptyObject") with TEnumDecl e -> e | _ -> assert false in + let empty_en = match get_type gen (["haxe";"lang"], "EmptyObject") with TEnumDecl e -> e | _ -> die "" __LOC__ in let empty_ctor_type = TEnum(empty_en, []) in - let empty_en_expr = mk (TTypeExpr (TEnumDecl empty_en)) (TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics empty_en) }) null_pos in + let empty_en_expr = mk (TTypeExpr (TEnumDecl empty_en)) (mk_anon (ref (EnumStatics empty_en))) null_pos in let empty_ctor_expr = mk (TField (empty_en_expr, FEnum(empty_en, PMap.find "EMPTY" empty_en.e_constrs))) empty_ctor_type null_pos in OverloadingConstructor.configure ~empty_ctor_type:empty_ctor_type ~empty_ctor_expr:empty_ctor_expr gen; @@ -2334,7 +2333,7 @@ let generate con = | TAbstract({a_path = [],"Float"}, _) -> "Float" | TInst({cl_path = [],"String"},_) -> "String" | TAnon _ | TDynamic _ -> "Dynamic" - | _ -> print_endline (debug_type t); assert false + | _ -> print_endline (debug_type t); die "" __LOC__ in let rcf_static_insert t = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) ("insert" ^ get_specialized_postfix t) null_pos [] in let rcf_static_remove t = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) ("remove" ^ get_specialized_postfix t) null_pos [] in @@ -2445,7 +2444,7 @@ let generate con = ( match run_follow gen (follow e1.etype) with | TInst({ cl_path = (["java"], "NativeArray") }, _) -> false | _ -> true ) - | _ -> assert false + | _ -> die "" __LOC__ ) "__get" "__set"; let field_is_dynamic is_dynamic t field = @@ -2596,7 +2595,7 @@ let generate con = ) cases) | _ -> true ) - | _ -> assert false + | _ -> die "" __LOC__ ); ExpressionUnwrap.configure gen; @@ -2615,7 +2614,7 @@ let generate con = JavaSpecificESynf.configure gen runtime_cl; (* add native String as a String superclass *) - let str_cl = match gen.gcon.basic.tstring with | TInst(cl,_) -> cl | _ -> assert false in + let str_cl = match gen.gcon.basic.tstring with | TInst(cl,_) -> cl | _ -> die "" __LOC__ in str_cl.cl_super <- Some (get_cl (get_type gen (["haxe";"lang"], "NativeString")), []); Path.mkdir_from_path (gen.gcon.file ^ "/src"); @@ -2634,7 +2633,7 @@ let generate con = output_string f v; close_out f; - out_files := (Path.unique_full_path full_path) :: !out_files + out_files := (Path.UniqueKey.create full_path) :: !out_files ) gen.gcon.resources; (try let c = get_cl (Hashtbl.find gen.gtypes (["haxe"], "Resource")) in diff --git a/src/generators/genjs.ml b/src/generators/genjs.ml index 08bcd1ea1bdf036057a5f72798985ec51170b972..dc7b3dde41500322091c29f2bf1403715cf3bb79 100644 --- a/src/generators/genjs.ml +++ b/src/generators/genjs.ml @@ -61,6 +61,7 @@ type ctx = { mutable type_accessor : module_type -> string; mutable separator : bool; mutable found_expose : bool; + mutable catch_vars : texpr list; } type object_store = { @@ -68,14 +69,15 @@ type object_store = { mutable os_fields : object_store list; } -let get_exposed ctx path meta = +let process_expose meta f_default f = try let (_, args, pos) = Meta.get Meta.Expose meta in - (match args with - | [ EConst (String(s,_)), _ ] -> [s] - | [] -> [path] - | _ -> abort "Invalid @:expose parameters" pos) - with Not_found -> [] + match args with + | [ EConst (String(s,_)), _ ] -> f s + | [] -> f (f_default ()) + | _ -> abort "Invalid @:expose parameters" pos + with Not_found -> + () let dot_path = s_type_path @@ -137,21 +139,17 @@ let ident s = if Hashtbl.mem kwds s then "$" ^ s else s let check_var_declaration v = if Hashtbl.mem kwds2 v.v_name then v.v_name <- "$" ^ v.v_name let anon_field s = if Hashtbl.mem kwds s || not (valid_js_ident s) then "'" ^ s ^ "'" else s -let static_field ctx c s = - match s with - | "length" | "name" when not c.cl_extern || Meta.has Meta.HxGen c.cl_meta-> - let with_dollar = ".$" ^ s in - if get_es_version ctx.com >= 6 then - try - let f = PMap.find s c.cl_statics in - match f.cf_kind with - | Method _ -> "." ^ s - | _ -> with_dollar - with Not_found -> - with_dollar - else - with_dollar - | s -> field s +let static_field ctx c f = + let s = f.cf_name in + match s with + | "length" | "name" when not c.cl_extern || Meta.has Meta.HxGen c.cl_meta -> + (match f.cf_kind with + | Method _ when ctx.es_version >= 6 -> + "." ^ s + | _ -> + ".$" ^ s) + | s -> + field s let has_feature ctx = Common.has_feature ctx.com let add_feature ctx = Common.add_feature ctx.com @@ -339,6 +337,10 @@ let rec needs_switch_break e = let this ctx = match ctx.in_value with None -> "this" | Some _ -> "$this" +let is_iterator_field_access fa = match field_name fa with + | "iterator" | "keyValueIterator" -> true + | _ -> false + let is_dynamic_iterator ctx e = let check x = let rec loop t = match follow t with @@ -352,10 +354,10 @@ let is_dynamic_iterator ctx e = loop (Abstract.get_underlying_type a tl) | _ -> false in - has_feature ctx "HxOverrides.iter" && loop x.etype + has_feature ctx "haxe.iterators.ArrayIterator.*" && loop x.etype in match e.eexpr with - | TField (x,f) when field_name f = "iterator" -> check x + | TField (x,f) when is_iterator_field_access f -> check x | _ -> false @@ -368,8 +370,18 @@ let gen_constant ctx p = function | TThis -> spr ctx (this ctx) | TSuper -> assert (ctx.es_version >= 6); spr ctx "super" -let print_deprecation_message com msg p = - com.warning msg p +let print_deprecation_message = DeprecationCheck.warn_deprecation + +let is_code_injection_function e = + match e.eexpr with + | TIdent "__js__" + | TField (_, FStatic ({ cl_path = ["js"],"Syntax" }, { cf_name = "code" | "plainCode" })) + -> true + | _ -> + false + +let var ctx = + if ctx.es_version >= 6 then "let" else "var" let rec gen_call ctx e el in_value = match e.eexpr , el with @@ -390,7 +402,7 @@ let rec gen_call ctx e el in_value = List.iter (fun p -> print ctx ","; gen_value ctx p) params; spr ctx ")"; ); - | TCall (x,_) , el when (match x.eexpr with TIdent "__js__" -> false | _ -> true) -> + | TCall (x,_) , el when not (is_code_injection_function x) -> spr ctx "("; gen_value ctx e; spr ctx ")"; @@ -399,11 +411,26 @@ let rec gen_call ctx e el in_value = spr ctx ")"; | TField (_, FStatic ({ cl_path = ["js"],"Syntax" }, { cf_name = meth })), args -> gen_syntax ctx meth args e.epos + | TField (_, FStatic ({ cl_path = ["js"],"Lib" }, { cf_name = "rethrow" })), [] -> + (match ctx.catch_vars with + | e :: _ -> + spr ctx "throw "; + gen_value ctx e + | _ -> + abort "js.Lib.rethrow can only be called inside a catch block" e.epos + ) + | TField (_, FStatic ({ cl_path = ["js"],"Lib" }, { cf_name = "getOriginalException" })), [] -> + (match ctx.catch_vars with + | e :: _ -> + gen_value ctx e + | _ -> + abort "js.Lib.getOriginalException can only be called inside a catch block" e.epos + ) | TIdent "__new__", args -> print_deprecation_message ctx.com "__new__ is deprecated, use js.Syntax.construct instead" e.epos; gen_syntax ctx "construct" args e.epos | TIdent "__js__", args -> - (* TODO: add deprecation warning when we figure out what to do with purity here *) + print_deprecation_message ctx.com "__js__ is deprecated, use js.Syntax.code instead" e.epos; gen_syntax ctx "code" args e.epos | TIdent "__instanceof__", args -> print_deprecation_message ctx.com "__instanceof__ is deprecated, use js.Syntax.instanceof instead" e.epos; @@ -438,7 +465,7 @@ let rec gen_call ctx e el in_value = spr ctx "]"; | TIdent "`trace", [e;infos] -> if has_feature ctx "haxe.Log.trace" then begin - let t = (try List.find (fun t -> t_path t = (["haxe"],"Log")) ctx.com.types with _ -> assert false) in + let t = (try List.find (fun t -> t_path t = (["haxe"],"Log")) ctx.com.types with _ -> die "" __LOC__) in spr ctx (ctx.type_accessor t); spr ctx ".trace("; gen_value ctx e; @@ -462,6 +489,11 @@ let rec gen_call ctx e el in_value = print ctx "$getIterator("; gen_value ctx x; print ctx ")"; + | TField (x,f), [] when field_name f = "keyValueIterator" && is_dynamic_iterator ctx e -> + add_feature ctx "use.$getKeyValueIterator"; + print ctx "$getKeyValueIterator("; + gen_value ctx x; + print ctx ")"; | _ -> gen_value ctx e; spr ctx "("; @@ -494,11 +526,19 @@ and gen_expr ctx e = spr ctx "["; gen_value ctx e2; spr ctx "]"; - | TBinop (op,{ eexpr = TField (x,f) },e2) when field_name f = "iterator" -> + | TBinop (op,{ eexpr = TField (x,f) },e2) when is_iterator_field_access f -> gen_value ctx x; - spr ctx (field "iterator"); + spr ctx (field (field_name f)); print ctx " %s " (Ast.s_binop op); gen_value ctx e2; + | TBinop ((OpEq | OpNotEq) as op,{ eexpr = TField (x,(FClosure _ as f)) },{ eexpr = TConst TNull }) -> + gen_value ctx x; + spr ctx (field (field_name f)); + print ctx " %s null" (Ast.s_binop op) + | TBinop ((OpEq | OpNotEq) as op,{ eexpr = TConst TNull },{ eexpr = TField (x,(FClosure _ as f)) }) -> + print ctx "null %s " (Ast.s_binop op); + gen_value ctx x; + spr ctx (field (field_name f)) | TBinop (op,e1,e2) -> gen_value ctx e1; print ctx " %s " (Ast.s_binop op); @@ -508,16 +548,21 @@ and gen_expr ctx e = print ctx "$iterator("; gen_value ctx x; print ctx ")"; + | TField (x,f) when field_name f = "keyValueIterator" && is_dynamic_iterator ctx e -> + add_feature ctx "use.$keyValueIterator"; + print ctx "$keyValueIterator("; + gen_value ctx x; + print ctx ")"; (* Don't generate `$iterator(value)` for exprs like `value.iterator--` *) - | TUnop (op,flag,({eexpr = TField (x,f)} as fe)) when field_name f = "iterator" && is_dynamic_iterator ctx fe -> + | TUnop (op,flag,({eexpr = TField (x,f)} as fe)) when is_iterator_field_access f && is_dynamic_iterator ctx fe -> (match flag with | Prefix -> spr ctx (Ast.s_unop op); gen_value ctx x; - spr ctx ".iterator" + print ctx ".%s" (field_name f) | Postfix -> gen_value ctx x; - spr ctx ".iterator"; + print ctx ".%s" (field_name f); spr ctx (Ast.s_unop op)) | TField (x,FClosure (Some ({cl_path=[],"Array"},_), {cf_name="push"})) -> (* see https://github.com/HaxeFoundation/haxe/issues/1997 *) @@ -548,7 +593,7 @@ and gen_expr ctx e = | TEnumParameter (x,f,i) -> gen_value ctx x; if not (Common.defined ctx.com Define.JsEnumsAsArrays) then - let fname = (match f.ef_type with TFun((args,_)) -> let fname,_,_ = List.nth args i in fname | _ -> assert false ) in + let fname = (match f.ef_type with TFun((args,_)) -> let fname,_,_ = List.nth args i in fname | _ -> die "" __LOC__ ) in print ctx ".%s" (ident fname) else print ctx "[%i]" (i + 2) @@ -564,8 +609,7 @@ and gen_expr ctx e = in let x = skip x in gen_value ctx x; - let name = field_name f in - spr ctx (match f with FStatic(c,_) -> static_field ctx c name | FEnum _ | FInstance _ | FAnon _ | FDynamic _ | FClosure _ -> field name) + spr ctx (match f with FStatic(c,f) -> static_field ctx c f | FEnum _ | FInstance _ | FAnon _ | FDynamic _ | FClosure _ -> field (field_name f)) | TTypeExpr t -> spr ctx (ctx.type_accessor t) | TParenthesis e -> @@ -579,7 +623,7 @@ and gen_expr ctx e = gen_expr ctx e | TBreak -> print ctx "break _hx_loop%s" n; - | _ -> assert false) + | _ -> die "" __LOC__) | TMeta (_,e) -> gen_expr ctx e | TReturn eo -> @@ -615,7 +659,7 @@ and gen_expr ctx e = spr ctx "throw "; gen_value ctx e; | TVar (v,eo) -> - spr ctx "var "; + spr ctx ((var ctx) ^ " "); check_var_declaration v; spr ctx (ident v.v_name); begin match eo with @@ -689,7 +733,7 @@ and gen_expr ctx e = let id = ctx.id_counter in ctx.id_counter <- ctx.id_counter + 1; let name = "$it" ^ string_of_int id in - print ctx "var %s = " name; + print ctx "%s %s = " (var ctx) name; gen_value ctx it; newline ctx; name @@ -697,7 +741,7 @@ and gen_expr ctx e = print ctx "while( %s.hasNext() ) {" it; let bend = open_block ctx in newline ctx; - print ctx "var %s = %s.next()" (ident v.v_name) it; + print ctx "%s %s = %s.next()" (var ctx) (ident v.v_name) it; gen_block_element ctx e; bend(); newline ctx; @@ -708,7 +752,9 @@ and gen_expr ctx e = gen_expr ctx etry; check_var_declaration v; print ctx " catch( %s ) " v.v_name; - gen_expr ctx ecatch + ctx.catch_vars <- (mk (TLocal v) v.v_type v.v_pos) :: ctx.catch_vars; + gen_expr ctx ecatch; + ctx.catch_vars <- List.tl ctx.catch_vars | TTry _ -> abort "Unhandled try/catch, please report" e.epos | TSwitch (e,cases,def) -> @@ -782,7 +828,7 @@ and gen_block_element ?(after=false) ctx e = else (match eelse with | [] -> () | [e] -> gen_block_element ~after ctx e - | _ -> assert false) + | _ -> die "" __LOC__) | TFunction _ -> gen_block_element ~after ctx (mk (TParenthesis e) e.etype e.epos) | TObjectDecl fl -> @@ -796,7 +842,7 @@ and gen_value ctx e = let clear_mapping = add_mapping ctx e in let assign e = mk (TBinop (Ast.OpAssign, - mk (TLocal (match ctx.in_value with None -> assert false | Some v -> v)) t_dynamic e.epos, + mk (TLocal (match ctx.in_value with None -> die "" __LOC__ | Some v -> v)) t_dynamic e.epos, e )) e.etype e.epos in @@ -958,15 +1004,12 @@ and gen_syntax ctx meth args pos = let code, code_pos = match code.eexpr with | TConst (TString s) -> s, code.epos - | _ -> abort "The `code` argument for js.Syntax must be a string constant" code.epos + | _ -> abort "The `code` argument for js.Syntax.code must be a string constant" code.epos in begin match args with - | [] -> - if code = "this" then - spr ctx (this ctx) - else - spr ctx (String.concat "\n" (ExtString.String.nsplit code "\r\n")) + | [] when code = "this" -> + spr ctx (this ctx) | _ -> let rec reveal_expr expr = match expr.eexpr with @@ -983,6 +1026,13 @@ and gen_syntax ctx meth args pos = in Codegen.interpolate_code ctx.com code args (spr ctx) (gen_value ctx) code_pos end + | "plainCode", [code] -> + let code = + match code.eexpr with + | TConst (TString s) -> s + | _ -> abort "The `code` argument for js.Syntax.plainCode must be a string constant" code.epos + in + spr ctx (String.concat "\n" (ExtString.String.nsplit code "\r\n")) | "field" , [eobj;efield] -> gen_value ctx eobj; (match Texpr.skip efield with @@ -1035,23 +1085,22 @@ let path_to_brackets path = let parts = ExtString.String.nsplit path "." in "[\"" ^ (String.concat "\"][\"" parts) ^ "\"]" -let gen_class_static_field ctx c f = +let gen_class_static_field ctx c cl_path f = match f.cf_expr with | None | Some { eexpr = TConst TNull } when not (has_feature ctx "Type.getClassFields") -> () | None when not (is_physical_field f) -> () | None -> - print ctx "%s%s = null" (s_path ctx c.cl_path) (static_field ctx c f.cf_name); + print ctx "%s%s = null" (s_path ctx cl_path) (static_field ctx c f); newline ctx | Some e -> match e.eexpr with | TFunction _ -> - let path = (s_path ctx c.cl_path) ^ (static_field ctx c f.cf_name) in - let dot_path = (dot_path c.cl_path) ^ (static_field ctx c f.cf_name) in + let path = (s_path ctx cl_path) ^ (static_field ctx c f) in ctx.id_counter <- 0; print ctx "%s = " path; - (match (get_exposed ctx dot_path f.cf_meta) with [s] -> print ctx "$hx_exports%s = " (path_to_brackets s) | _ -> ()); + process_expose f.cf_meta (fun () -> (dot_path cl_path) ^ "." ^ f.cf_name) (fun s -> print ctx "$hx_exports%s = " (path_to_brackets s)); gen_value ctx e; newline ctx; | _ -> @@ -1077,14 +1126,14 @@ let gen_class_field ctx c f = gen_value ctx e; ctx.separator <- false -let generate_class___name__ ctx c = +let generate_class___name__ ctx cl_path = if has_feature ctx "js.Boot.isClass" then begin - let p = s_path ctx c.cl_path in + let p = s_path ctx cl_path in print ctx "%s.__name__ = " p; - (match has_feature ctx "Type.getClassName", c.cl_path with + (match has_feature ctx "Type.getClassName", cl_path with | true, _ | _, ([], ("Array" | "String")) -> - print ctx "\"%s\"" (dot_path c.cl_path) + print ctx "\"%s\"" (dot_path cl_path) | _ -> print ctx "true" ); @@ -1098,33 +1147,57 @@ let generate_class___isInterface__ ctx c = newline ctx; end +let get_generated_class_path = function + (* we want to generate abstract implementations with the path of the abstract itself, unless there is @:native involved *) + | { cl_kind = KAbstractImpl a; cl_meta = m } when not (Meta.has Meta.Native m) -> + a.a_path + | { cl_path = p } -> + p + +let is_abstract_impl c = match c.cl_kind with KAbstractImpl _ -> true | _ -> false + let generate_class_es3 ctx c = - let p = s_path ctx c.cl_path in + let cl_path = get_generated_class_path c in + let is_abstract_impl = is_abstract_impl c in + if ctx.js_flatten then print ctx "var " else - generate_package_create ctx c.cl_path; - if ctx.js_modern || not ctx.has_resolveClass then + generate_package_create ctx cl_path; + + let p = s_path ctx cl_path in + let dotp = dot_path cl_path in + + let added_to_hxClasses = ctx.has_resolveClass && not is_abstract_impl in + + if ctx.js_modern || not added_to_hxClasses then print ctx "%s = " p else - print ctx "%s = $hxClasses[\"%s\"] = " p (dot_path c.cl_path); - (match (get_exposed ctx (dot_path c.cl_path) c.cl_meta) with [s] -> print ctx "$hx_exports%s = " (path_to_brackets s) | _ -> ()); - (match c.cl_kind with - | KAbstractImpl _ -> - (* abstract implementations only contain static members and don't need to have constructor functions *) - print ctx "{}"; ctx.separator <- true - | _ -> - (match c.cl_constructor with - | Some { cf_expr = Some e } -> gen_expr ctx e - | _ -> (print ctx "function() { }"); ctx.separator <- true) - ); + print ctx "%s = $hxClasses[\"%s\"] = " p dotp; + + process_expose c.cl_meta (fun () -> dotp) (fun s -> print ctx "$hx_exports%s = " (path_to_brackets s)); + + if is_abstract_impl then begin + (* abstract implementations only contain static members and don't need to have constructor functions *) + print ctx "{}"; + ctx.separator <- true + end else begin + match c.cl_constructor with + | Some { cf_expr = Some e } -> gen_expr ctx e + | _ -> (print ctx "function() { }"); ctx.separator <- true + end; + newline ctx; - if ctx.js_modern && ctx.has_resolveClass then begin - print ctx "$hxClasses[\"%s\"] = %s" (dot_path c.cl_path) p; + + if ctx.js_modern && added_to_hxClasses then begin + print ctx "$hxClasses[\"%s\"] = %s" dotp p; newline ctx; end; - generate_class___name__ ctx c; - generate_class___isInterface__ ctx c; + + if not is_abstract_impl then begin + generate_class___name__ ctx cl_path; + generate_class___isInterface__ ctx c; + end; if ctx.has_interface_check then (match c.cl_implements with @@ -1148,7 +1221,7 @@ let generate_class_es3 ctx c = newline ctx); end; - List.iter (gen_class_static_field ctx c) c.cl_ordered_statics; + List.iter (gen_class_static_field ctx c cl_path) c.cl_ordered_statics; let has_class = has_feature ctx "js.Boot.getClass" && (c.cl_super <> None || c.cl_ordered_fields <> [] || c.cl_constructor <> None) in let has_prototype = c.cl_super <> None || has_class || List.exists (can_gen_class_field ctx) c.cl_ordered_fields in @@ -1190,13 +1263,15 @@ let generate_class_es3 ctx c = flush ctx let generate_class_es6 ctx c = - let p = s_path ctx c.cl_path in + let cl_path = get_generated_class_path c in + let p = s_path ctx cl_path in + let dotp = dot_path cl_path in let cls_name = - if not ctx.js_flatten && (fst c.cl_path) <> [] then begin - generate_package_create ctx c.cl_path; + if not ctx.js_flatten && (fst cl_path) <> [] then begin + generate_package_create ctx cl_path; print ctx "%s = " p; - Path.flat_path c.cl_path + Path.flat_path cl_path end else p in @@ -1245,9 +1320,7 @@ let generate_class_es6 ctx c = gen_function ~keyword:("static " ^ (method_def_name cf)) ctx f pos; ctx.separator <- false; - (match get_exposed ctx ((dot_path c.cl_path) ^ (static_field ctx c cf.cf_name)) cf.cf_meta with - | [s] -> exposed_static_methods := (s,cf.cf_name) :: !exposed_static_methods; - | _ -> ()); + process_expose cf.cf_meta (fun () -> dotp ^ "." ^ cf.cf_name) (fun s -> exposed_static_methods := (s,cf.cf_name) :: !exposed_static_methods); false | _ -> true @@ -1264,22 +1337,27 @@ let generate_class_es6 ctx c = newline ctx ) !exposed_static_methods; - List.iter (gen_class_static_field ctx c) nonmethod_statics; + List.iter (gen_class_static_field ctx c cl_path) nonmethod_statics; + + let is_abstract_impl = is_abstract_impl c in - let expose = (match get_exposed ctx (dot_path c.cl_path) c.cl_meta with [s] -> "$hx_exports" ^ (path_to_brackets s) | _ -> "") in - if expose <> "" || ctx.has_resolveClass then begin - if ctx.has_resolveClass then begin - print ctx "$hxClasses[\"%s\"] = " (dot_path c.cl_path) + begin + let added = ref false in + if ctx.has_resolveClass && not is_abstract_impl then begin + added := true; + print ctx "$hxClasses[\"%s\"] = " dotp end; - if expose <> "" then begin - print ctx "%s = " expose + process_expose c.cl_meta (fun () -> dotp) (fun s -> added := true; print ctx "$hx_exports%s = " (path_to_brackets s)); + if !added then begin + spr ctx p; + newline ctx; end; - spr ctx p; - newline ctx; end; - generate_class___name__ ctx c; - generate_class___isInterface__ ctx c; + if not is_abstract_impl then begin + generate_class___name__ ctx cl_path; + generate_class___isInterface__ ctx c; + end; if ctx.has_interface_check then (match c.cl_implements with @@ -1380,7 +1458,7 @@ let generate_enum ctx e = (if as_objects then print ctx "$hxEnums[\"%s\"] = " dotp else if has_feature ctx "Type.resolveEnum" then - print ctx "$hxClasses[\"%s\"] = " (dot_path e.e_path)); + print ctx "$hxClasses[\"%s\"] = " dotp); spr ctx "{"; if has_feature ctx "js.Boot.isEnum" then print ctx " __ename__ : %s," (if has_feature ctx "Type.getEnumName" then "\"" ^ dotp ^ "\"" else "true"); print ctx " __constructs__ : [%s]" (String.concat "," (List.map (fun s -> Printf.sprintf "\"%s\"" s) e.e_names)); @@ -1459,9 +1537,9 @@ let generate_enum ctx e = flush ctx let generate_static ctx (c,f,e) = - let dot_path = (dot_path c.cl_path) ^ (static_field ctx c f.cf_name) in - (match (get_exposed ctx dot_path f.cf_meta) with [s] -> print ctx "$hx_exports%s = " (path_to_brackets s) | _ -> ()); - print ctx "%s%s = " (s_path ctx c.cl_path) (static_field ctx c f.cf_name); + let cl_path = get_generated_class_path c in + process_expose f.cf_meta (fun () -> (dot_path cl_path) ^ "." ^ f.cf_name) (fun s -> print ctx "$hx_exports%s = " (path_to_brackets s)); + print ctx "%s%s = " (s_path ctx cl_path) (static_field ctx c f); gen_value ctx e; newline ctx @@ -1497,7 +1575,7 @@ let generate_type ctx = function ctx.inits <- e :: ctx.inits); (* Special case, want to add Math.__name__ only when required, handle here since Math is extern *) let p = s_path ctx c.cl_path in - if p = "Math" then generate_class___name__ ctx c; + if p = "Math" then generate_class___name__ ctx c.cl_path; (* Another special case for Std because we do not want to generate it if it's empty. *) if p = "Std" && c.cl_ordered_statics = [] then () @@ -1505,7 +1583,7 @@ let generate_type ctx = function if (not c.cl_interface) || (need_to_generate_interface ctx c) then generate_class ctx c end else if Meta.has Meta.JsRequire c.cl_meta && is_directly_used ctx.com c.cl_meta then - generate_require ctx c.cl_path c.cl_meta + generate_require ctx (get_generated_class_path c) c.cl_meta else if not ctx.js_flatten && Meta.has Meta.InitPackage c.cl_meta then (match c.cl_path with | ([],_) -> () @@ -1553,18 +1631,25 @@ let alloc_ctx com es_version = in_value = None; in_loop = false; id_counter = 0; - type_accessor = (fun _ -> assert false); + type_accessor = (fun _ -> die "" __LOC__); separator = false; found_expose = false; + catch_vars = []; } in + ctx.type_accessor <- (fun t -> - let p = t_path t in match t with - | TClassDecl ({ cl_extern = true } as c) when not (Meta.has Meta.JsRequire c.cl_meta) - -> dot_path p - | TEnumDecl ({ e_extern = true } as e) when not (Meta.has Meta.JsRequire e.e_meta) - -> dot_path p - | _ -> s_path ctx p); + | TEnumDecl ({ e_extern = true } as e) when not (Meta.has Meta.JsRequire e.e_meta) -> + dot_path e.e_path + | TClassDecl c -> + let p = get_generated_class_path c in + if c.cl_extern && not (Meta.has Meta.JsRequire c.cl_meta) then + dot_path p + else + s_path ctx p + | _ -> + s_path ctx (t_path t) + ); ctx let gen_single_expr ctx e expr = @@ -1593,38 +1678,46 @@ let generate com = setup_kwds com; - let exposed = List.concat (List.map (fun t -> - match t with + let exposed = begin + let r = ref [] in + List.iter ( + function | TClassDecl c -> let path = dot_path c.cl_path in - let class_exposed = get_exposed ctx path c.cl_meta in - let static_exposed = List.map (fun f -> - get_exposed ctx (path ^ static_field ctx c f.cf_name) f.cf_meta - ) c.cl_ordered_statics in - List.concat (class_exposed :: static_exposed) - | _ -> [] - ) com.types) in + let add s = r := s :: !r in + process_expose c.cl_meta (fun () -> path) add; + List.iter (fun f -> + process_expose f.cf_meta (fun () -> path ^ "." ^ f.cf_name) add + ) c.cl_ordered_statics + | _ -> () + ) com.types; + !r + end in let anyExposed = exposed <> [] in - let exportMap = ref (PMap.create String.compare) in let exposedObject = { os_name = ""; os_fields = [] } in let toplevelExposed = ref [] in - List.iter (fun path -> ( - let parts = ExtString.String.nsplit path "." in - let rec loop p pre = match p with - | f :: g :: ls -> - let path = match pre with "" -> f | pre -> (pre ^ "." ^ f) in - if not (PMap.exists path !exportMap) then ( - let elts = { os_name = f; os_fields = [] } in - exportMap := PMap.add path elts !exportMap; - let cobject = match pre with "" -> exposedObject | pre -> PMap.find pre !exportMap in - cobject.os_fields <- elts :: cobject.os_fields - ); - loop (g :: ls) path; - | f :: [] when pre = "" -> - toplevelExposed := f :: !toplevelExposed; - | _ -> () - in loop parts ""; - )) exposed; + if anyExposed then begin + let exportMap = Hashtbl.create 0 in + List.iter (fun path -> + let parts = ExtString.String.nsplit path "." in + let rec loop p pre = + match p with + | f :: g :: ls -> + let path = match pre with "" -> f | pre -> (pre ^ "." ^ f) in + if not (Hashtbl.mem exportMap path) then ( + let elts = { os_name = f; os_fields = [] } in + Hashtbl.add exportMap path elts; + let cobject = match pre with "" -> exposedObject | pre -> Hashtbl.find exportMap pre in + cobject.os_fields <- elts :: cobject.os_fields + ); + loop (g :: ls) path; + | f :: [] when pre = "" -> + toplevelExposed := f :: !toplevelExposed; + | _ -> () + in + loop parts "" + ) exposed + end; let include_files = List.rev com.include_files in @@ -1763,11 +1856,22 @@ let generate com = List.iter (fun (_,_,e) -> chk_features e) ctx.statics; if has_feature ctx "use.$iterator" then begin add_feature ctx "use.$bind"; - print ctx "function $iterator(o) { if( o instanceof Array ) return function() { return HxOverrides.iter(o); }; return typeof(o.iterator) == 'function' ? $bind(o,o.iterator) : o.iterator; }"; + let array_iterator = s_path ctx (["haxe"; "iterators"], "ArrayIterator") in + print ctx "function $iterator(o) { if( o instanceof Array ) return function() { return new %s(o); }; return typeof(o.iterator) == 'function' ? $bind(o,o.iterator) : o.iterator; }" array_iterator; + newline ctx; + end; + if has_feature ctx "use.$keyValueIterator" then begin + add_feature ctx "use.$bind"; + print ctx "function $keyValueIterator(o) { if( o instanceof Array ) return function() { return HxOverrides.keyValueIter(o); }; return typeof(o.keyValueIterator) == 'function' ? $bind(o,o.keyValueIterator) : o.keyValueIterator; }"; newline ctx; end; if has_feature ctx "use.$getIterator" then begin - print ctx "function $getIterator(o) { if( o instanceof Array ) return HxOverrides.iter(o); else return o.iterator(); }"; + let array_iterator = s_path ctx (["haxe"; "iterators"], "ArrayIterator") in + print ctx "function $getIterator(o) { if( o instanceof Array ) return new %s(o); else return o.iterator(); }" array_iterator; + newline ctx; + end; + if has_feature ctx "use.$getKeyValueIterator" then begin + print ctx "function $getKeyValueIterator(o) { if( o instanceof Array ) return HxOverrides.keyValueIter(o); else return o.keyValueIterator(); }"; newline ctx; end; if has_feature ctx "use.$bind" then begin diff --git a/src/generators/genjvm.ml b/src/generators/genjvm.ml index 7dfa45b259aa7787cdba23389cf2786b2cd653e8..9550e75aff87799420b17ca73bdecd05e116e3da 100644 --- a/src/generators/genjvm.ml +++ b/src/generators/genjvm.ml @@ -30,109 +30,15 @@ open JvmAttribute open JvmSignature open JvmMethod open JvmBuilder +open Genshared (* Note: This module is the bridge between Haxe structures and JVM structures. No module in generators/jvm should reference any Haxe-specific type. *) (* hacks *) -let rec pow a b = match b with - | 0 -> Int32.one - | 1 -> a - | _ -> Int32.mul a (pow a (b - 1)) - -let java_hash s = - let h = ref Int32.zero in - let l = UTF8.length s in - let i31 = Int32.of_int 31 in - let i = ref 0 in - UTF8.iter (fun char -> - let char = Int32.of_int (UCharExt.uint_code char) in - h := Int32.add !h (Int32.mul char (pow i31 (l - (!i + 1)))); - incr i; - ) s; - !h - -let find_overload map_type c cf el = - let matches = ref [] in - let rec loop cfl = match cfl with - | cf :: cfl -> - begin match follow (monomorphs cf.cf_params (map_type cf.cf_type)) with - | TFun(tl'',_) as tf -> - let rec loop2 acc el tl = match el,tl with - | e :: el,(n,o,t) :: tl -> - begin try - Type.unify e.etype t; - loop2 ((e,o) :: acc) el tl - with _ -> - loop cfl - end - | [],[] -> - matches := ((List.rev acc),tf,(c,cf)) :: !matches; - loop cfl - | _ -> - loop cfl - in - loop2 [] el tl'' - | t -> - loop cfl - end; - | [] -> - List.rev !matches - in - loop (cf :: cf.cf_overloads) - -let filter_overloads candidates = - match Overloads.Resolution.reduce_compatible candidates with - | [_,_,(c,cf)] -> Some(c,cf) - | [] -> None - | ((_,_,(c,cf)) :: _) (* as resolved *) -> - (* let st = s_type (print_context()) in - print_endline (Printf.sprintf "Ambiguous overload for %s(%s)" name (String.concat ", " (List.map (fun e -> st e.etype) el))); - List.iter (fun (_,t,(c,cf)) -> - print_endline (Printf.sprintf "\tCandidate: %s.%s(%s)" (s_type_path c.cl_path) cf.cf_name (st t)); - ) resolved; *) - Some(c,cf) - -let find_overload_rec' is_ctor map_type c name el = - let candidates = ref [] in - let has_function t1 (_,t2,_) = - begin match follow t1,t2 with - | TFun(tl1,_),TFun(tl2,_) -> type_iseq (TFun(tl1,t_dynamic)) (TFun(tl2,t_dynamic)) - | _ -> false - end - in - let rec loop map_type c = - begin try - let cf = if is_ctor then - (match c.cl_constructor with Some cf -> cf | None -> raise Not_found) - else - PMap.find name c.cl_fields - in - begin match find_overload map_type c cf el with - | [] -> raise Not_found - | l -> - List.iter (fun ((_,t,_) as ca) -> - if not (List.exists (has_function t) !candidates) then candidates := ca :: !candidates - ) l - end; - if Meta.has Meta.Overload cf.cf_meta || cf.cf_overloads <> [] then raise Not_found - with Not_found -> - if c.cl_interface then - List.iter (fun (c,tl) -> loop (fun t -> apply_params c.cl_params (List.map map_type tl) t) c) c.cl_implements - else match c.cl_super with - | None -> () - | Some(c,tl) -> loop (fun t -> apply_params c.cl_params (List.map map_type tl) t) c - end; - in - loop map_type c; - filter_overloads (List.rev !candidates) - -let find_overload_rec is_ctor map_type c cf el = - if Meta.has Meta.Overload cf.cf_meta || cf.cf_overloads <> [] then - find_overload_rec' is_ctor map_type c cf.cf_name el - else - Some(c,cf) +let is_really_int t = + not (is_nullable t) && ExtType.is_int (follow t) let get_construction_mode c cf = if Meta.has Meta.HxGen cf.cf_meta then ConstructInitPlusNew @@ -142,26 +48,20 @@ let get_construction_mode c cf = exception HarderFailure of string -type field_generation_info = { - mutable has_this_before_super : bool; - (* This is an ordered list of fields that are targets of super() calls which is determined during - pre-processing. The generator can pop from this list assuming that it processes the expression - in the same order (which it should). *) - mutable super_call_fields : (tclass * tclass_field) list; -} - type generation_context = { com : Common.context; jar : Zip.out_file; + t_runtime_exception : Type.t; + entry_point : (tclass * texpr) option; t_exception : Type.t; t_throwable : Type.t; - anon_lut : ((string * jsignature) list,jpath) Hashtbl.t; - anon_path_lut : (path,jpath) Hashtbl.t; - field_infos : field_generation_info DynArray.t; - implicit_ctors : (path,(path * jsignature,tclass * tclass_field) PMap.t) Hashtbl.t; + mutable anon_identification : jsignature tanon_identification; + mutable preprocessor : jsignature preprocessor; default_export_config : export_config; + typed_functions : JvmFunctions.typed_functions; + closure_paths : (path * string * jsignature,path) Hashtbl.t; + mutable typedef_interfaces : jsignature typedef_interfaces; mutable current_field_info : field_generation_info option; - mutable anon_num : int; } type ret = @@ -169,11 +69,6 @@ type ret = | RVoid | RReturn -type method_type = - | MStatic - | MInstance - | MConstructor - type access_kind = | AKPost | AKPre @@ -181,18 +76,22 @@ type access_kind = type compare_kind = | CmpNormal of jcmp * jsignature - | CmpSpecial of (unit -> jbranchoffset ref) + | CmpSpecial of (jbranchoffset ref -> unit) type block_exit = | ExitExecute of (unit -> unit) | ExitLoop +let need_val = function + | RValue _ -> true + | _ -> false + open NativeSignatures -let rec jsignature_of_type stack t = +let rec jsignature_of_type gctx stack t = if List.exists (fast_eq t) stack then object_sig else - let jsignature_of_type = jsignature_of_type (t :: stack) in - let jtype_argument_of_type t = jtype_argument_of_type stack t in + let jsignature_of_type = jsignature_of_type gctx (t :: stack) in + let jtype_argument_of_type t = jtype_argument_of_type gctx stack t in match t with | TAbstract(a,tl) -> begin match a.a_path with @@ -206,15 +105,16 @@ let rec jsignature_of_type stack t = | ["java"],"Char16" -> TChar | [],"Single" -> TFloat | [],"Float" -> TDouble + | [],"Void" -> void_sig | [],"Null" -> begin match tl with | [t] -> get_boxed_type (jsignature_of_type t) - | _ -> assert false + | _ -> die "" __LOC__ end | (["haxe";"ds"],"Vector") | (["haxe";"extern"],"Rest") -> begin match tl with | [t] -> TArray(jsignature_of_type t,None) - | _ -> assert false + | _ -> die "" __LOC__ end | [],"Dynamic" -> object_sig @@ -230,7 +130,7 @@ let rec jsignature_of_type stack t = end | TDynamic _ -> object_sig | TMono r -> - begin match !r with + begin match r.tm_type with | Some t -> jsignature_of_type t | None -> object_sig end @@ -250,46 +150,33 @@ let rec jsignature_of_type stack t = let jsig = jsignature_of_type t in let jsig = if o then get_boxed_type jsig else jsig in jsig - ) tl) (if ExtType.is_void (follow tr) then None else Some (jsignature_of_type tr)) + ) tl) (return_of_type gctx stack tr) | TAnon an -> object_sig - | TType(td,tl) -> jsignature_of_type (apply_params td.t_params tl td.t_type) + | TType(td,tl) -> + begin match gctx.typedef_interfaces#get_interface_class td.t_path with + | Some c -> TObject(c.cl_path,[]) + | None -> jsignature_of_type (apply_params td.t_params tl td.t_type) + end | TLazy f -> jsignature_of_type (lazy_type f) -and jtype_argument_of_type stack t = - TType(WNone,jsignature_of_type stack t) +and jtype_argument_of_type gctx stack t = + let jsig = jsignature_of_type gctx stack t in + let jsig = get_boxed_type jsig in + TType(WNone,jsig) -let jsignature_of_type t = - jsignature_of_type [] t +and return_of_type gctx stack t = + if ExtType.is_void (follow t) then None else Some (jsignature_of_type gctx stack t) -module TAnonIdentifiaction = struct - let convert_fields fields = - let l = PMap.fold (fun cf acc -> cf :: acc) fields [] in - let l = List.sort (fun cf1 cf2 -> compare cf1.cf_name cf2.cf_name) l in - List.map (fun cf -> cf.cf_name,jsignature_of_type cf.cf_type) l +let jsignature_of_type gctx t = + jsignature_of_type gctx [] t - let identify gctx fields = - if PMap.is_empty fields then - haxe_dynamic_object_path,[] - else begin - let l = convert_fields fields in - try - Hashtbl.find gctx.anon_lut l,l - with Not_found -> - let id = gctx.anon_num in - gctx.anon_num <- gctx.anon_num + 1; - let path = (["haxe";"generated"],Printf.sprintf "Anon%i" id) in - Hashtbl.add gctx.anon_lut l path; - path,l - end +let return_of_type gctx t = + return_of_type gctx [] t - let identify_as gctx path fields = - if not (PMap.is_empty fields) && not (Hashtbl.mem gctx.anon_path_lut path) then begin - let fields = convert_fields fields in - Hashtbl.add gctx.anon_lut fields path; - Hashtbl.add gctx.anon_path_lut path path; - end - -end +let convert_fields gctx fields = + let l = PMap.foldi (fun s cf acc -> (s,cf) :: acc) fields [] in + let l = List.sort (fun (s1,_) (s2,_) -> compare s1 s2) l in + List.map (fun (s,cf) -> s,jsignature_of_type gctx cf.cf_type) l module AnnotationHandler = struct let generate_annotations builder meta = @@ -332,6 +219,10 @@ module AnnotationHandler = struct List.iter (fun (m,el,_) -> match m,el with | Meta.Meta,[e] -> let path,annotation = parse_expr e in + let path = match path with + | [],name -> ["haxe";"root"],name + | _ -> path + in builder#add_annotation path annotation; | _ -> () @@ -349,7 +240,7 @@ let convert_cmp_op = function | OpLte -> CmpLe | OpGt -> CmpGt | OpGte -> CmpGe - | _ -> assert false + | _ -> die "" __LOC__ let flip_cmp_op = function | CmpEq -> CmpNe @@ -402,129 +293,113 @@ let is_interface_var_access c cf = let type_unifies a b = try Type.unify a b; true with _ -> false -let get_field_info gctx ml = - let rec loop ml = match ml with - | (Meta.Custom ":jvm.fieldInfo",[(EConst (Int s),_)],_) :: _ -> - Some (DynArray.get gctx.field_infos (int_of_string s)) - | _ :: ml -> - loop ml - | [] -> - None - in - loop ml - let follow = Abstract.follow_with_abstracts -class haxe_exception gctx (t : Type.t) = object(self) - val native_exception = - if follow t == t_dynamic then - throwable_sig,false - else if type_unifies t gctx.t_exception then - jsignature_of_type t,true - else - haxe_exception_sig,false - - val mutable native_exception_path = None +class haxe_exception gctx (t : Type.t) = + let is_haxe_exception = Exceptions.is_haxe_exception t + and native_type = jsignature_of_type gctx t in +object(self) + val native_path = (match native_type with TObject(path,_) -> path | _ -> die "" __LOC__) method is_assignable_to (exc2 : haxe_exception) = - match self#is_native_exception,exc2#is_native_exception with - | true, true -> - (* Native exceptions are assignable if they unify *) + match self#is_haxe_exception,exc2#is_haxe_exception with + | true, true | false, false -> type_unifies t exc2#get_type - | false,false -> - (* Haxe exceptions are always assignable to each other *) - true + (* `haxe.Exception` is assignable to java.lang.RuntimeException/Exception/Throwable *) | false,true -> - (* Haxe exception is assignable to native only if caught type is java.lang.Exception/Throwable *) - let exc2_native_exception_type = exc2#get_native_exception_type in - exc2_native_exception_type = throwable_sig || exc2_native_exception_type = exception_sig + List.mem exc2#get_native_type [throwable_sig; exception_sig; runtime_exception_sig] | _ -> - (* Native to Haxe is never assignable *) false - method is_native_exception = snd native_exception - method get_native_exception_type = fst native_exception - - method get_native_exception_path = - match native_exception_path with - | None -> - let path = (match (fst native_exception) with TObject(path,_) -> path | _ -> assert false) in - native_exception_path <- Some path; - path - | Some path -> - path + method is_haxe_exception = is_haxe_exception + method get_native_type = native_type + method get_native_path = native_path method get_type = t end -class closure_context (jsig : jsignature) = object(self) - val lut = Hashtbl.create 0 - val sigs = DynArray.create() - - method add (var_id : int) (var_name : string) (var_sig : jsignature) = - DynArray.add sigs ((var_id,var_name),var_sig); - Hashtbl.add lut var_id (var_sig,var_name) - - method get (code : JvmCode.builder) (var_id : int) = - let var_sig,var_name = Hashtbl.find lut var_id in - if DynArray.length sigs > 1 then begin - (-1), - (fun () -> - code#aload jsig 0; - let offset = code#get_pool#add_field self#get_path var_name var_sig FKField in - code#getfield offset jsig var_sig - ), - (fun () -> - code#aload jsig 0; - let offset = code#get_pool#add_field self#get_path var_name var_sig FKField in - code#putfield offset jsig var_sig - ) - end else begin - (-1), - (fun () -> - code#aload jsig 0; - ), +let generate_equals_function (jc : JvmClass.builder) jsig_arg = + let jm_equals = jc#spawn_method "equals" (method_sig [jsig_arg] (Some TBool)) [MPublic] in + let code = jm_equals#get_code in + let _,load,_ = jm_equals#add_local "other" jsig_arg VarArgument in + jm_equals#finalize_arguments; + load(); + code#instanceof jc#get_this_path; + jm_equals#if_then + (code#if_ CmpNe) + (fun () -> + code#bconst false; + jm_equals#return; + ); + load(); + let _,load,save = jm_equals#add_local "other" jc#get_jsig VarWillInit in + jm_equals#cast jc#get_jsig; + save(); + jm_equals,load + +let create_field_closure gctx jc path_this jm name jsig = + let jsig_this = object_path_sig path_this in + let context = ["this",jsig_this] in + let wf = new JvmFunctions.typed_function gctx.typed_functions (FuncMember(path_this,name)) jc jm context in + let jc_closure = wf#get_class in + ignore(wf#generate_constructor true); + let args,ret = match jsig with + | TMethod(args,ret) -> + List.mapi (fun i jsig -> (Printf.sprintf "arg%i" i,jsig)) args,ret + | _ -> + die "" __LOC__ + in + let jm_invoke = wf#generate_invoke args ret in + let vars = List.map (fun (name,jsig) -> + jm_invoke#add_local name jsig VarArgument + ) args in + jm_invoke#finalize_arguments; + jm_invoke#load_this; + jm_invoke#getfield jc_closure#get_this_path "this" jsig_this; + List.iter (fun (_,load,_) -> + load(); + ) vars; + jm_invoke#invokevirtual path_this name (method_sig (List.map snd args) ret); + jm_invoke#return; + (* equals *) + begin + let jm_equals,load = generate_equals_function jc_closure object_sig in + let code = jm_equals#get_code in + jm_equals#load_this; + jm_equals#getfield jc_closure#get_this_path "this" jsig_this; + load(); + jm_equals#getfield jc_closure#get_this_path "this" jsig_this; + jm_equals#if_then + (code#if_acmp_eq jc_closure#get_jsig jc_closure#get_jsig) (fun () -> - code#aload jsig 0; - ) - end - - method get_constructor_sig = - method_sig (List.map snd (DynArray.to_list sigs)) None - - method get_jsig = jsig - method get_path = match jsig with TObject(path,_) -> path | _ -> assert false - - method get_args = DynArray.to_list sigs -end - -let create_context_class gctx jc jm name vl = match vl with - | [(vid,vname,vsig)] -> - let jsig = get_boxed_type vsig in - let ctx_class = new closure_context jsig in - ctx_class#add vid vname jsig; - ctx_class - | _ -> - let jc = jc#spawn_inner_class (Some jm) object_path None in - let path = jc#get_this_path in - let ctx_class = new closure_context (object_path_sig path) in - let jsigs = List.map (fun (_,_,vsig) -> vsig) vl in - let jm_ctor = jc#spawn_method "" (method_sig jsigs None) [MPublic] in - jm_ctor#load_this; - jm_ctor#call_super_ctor ConstructInit (method_sig [] None); - List.iter2 (fun (vid,vname,vtype) jsig -> - jm_ctor#add_argument_and_field vname jsig; - ctx_class#add vid vname jsig; - ) vl jsigs; - jm_ctor#get_code#return_void; - write_class gctx.jar path (jc#export_class gctx.default_export_config); - ctx_class + code#bconst false; + jm_equals#return; + ); + code#bconst true; + jm_equals#return; + end; + write_class gctx.jar jc_closure#get_this_path (jc_closure#export_class gctx.default_export_config); + jc_closure#get_this_path + +let create_field_closure gctx jc path_this jm name jsig f = + let jsig_this = object_path_sig path_this in + let closure_path = try + Hashtbl.find gctx.closure_paths (path_this,name,jsig) + with Not_found -> + let closure_path = create_field_closure gctx jc path_this jm name jsig in + Hashtbl.add gctx.closure_paths (path_this,name,jsig) closure_path; + closure_path + in + jm#construct ConstructInit closure_path (fun () -> + f(); + [jsig_this] + ) let rvalue_any = RValue None let rvalue_sig jsig = RValue (Some jsig) -let rvalue_type t = RValue (Some (jsignature_of_type t)) +let rvalue_type gctx t = RValue (Some (jsignature_of_type gctx t)) -class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return_type : Type.t) = object(self) +class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return_type : jsignature option) = object(self) val com = gctx.com val code = jm#get_code val pool : JvmConstantPool.constant_pool = jc#get_pool @@ -532,14 +407,14 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return val mutable local_lookup = Hashtbl.create 0; val mutable last_line = 0 - val mutable breaks = [] - val mutable continue = 0 + val mutable break = None + val mutable continue = None val mutable caught_exceptions = [] val mutable block_exits = [] val mutable env = None method vtype t = - jsignature_of_type t + jsignature_of_type gctx t method mknull t = com.basic.tnull (follow t) @@ -555,14 +430,24 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return slot,load,store method get_local_by_id (vid,vname) = - if vid = 0 then - (0,(fun () -> jm#load_this),(fun () -> assert false)) + if vid = 0 && env = None then + (0,(fun () -> jm#load_this),(fun () -> die "" __LOC__)) else try Hashtbl.find local_lookup vid with Not_found -> try begin match env with | Some env -> - env#get code vid + let name,jsig = List.assoc vid env in + (-1, + (fun () -> + jm#load_this; + jm#getfield jc#get_this_path name jsig + ), + (fun () -> + jm#load_this; + jm#putfield jc#get_this_path name jsig + ) + ) | None -> raise Not_found end @@ -572,8 +457,8 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return method get_local v = self#get_local_by_id (v.v_id,v.v_name) - method set_context (ctx : closure_context) = - env <- Some ctx + method set_env (env' : (int * (string * jsignature)) list) = + env <- Some env' (* casting *) @@ -587,69 +472,67 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return | RValue (Some jsig) -> jm#cast jsig | _ -> self#cast t + method make_static_closure_field (name : string) (jc_closure : JvmClass.builder) = + let jm_init = jc_closure#get_static_init_method in + let jf_closure = jc_closure#spawn_field name jc_closure#get_jsig [FdStatic;FdPublic] in + jm_init#construct ConstructInit jc_closure#get_this_path (fun () -> []); + jm_init#putstatic jc_closure#get_this_path jf_closure#get_name jf_closure#get_jsig; + method tfunction e tf = - let name = jc#get_next_closure_name in - let outside = match Texpr.collect_captured_vars e with - | [],false -> - None - | vl,accesses_this -> - let vl = List.map (fun v -> v.v_id,v.v_name,jsignature_of_type v.v_type) vl in - let vl = if accesses_this then (0,"this",jc#get_jsig) :: vl else vl in - let ctx_class = create_context_class gctx jc jm name vl in - Some ctx_class - in - let jsig = - let args = List.map (fun (v,cto) -> - if cto <> None then v.v_type <- self#mknull v.v_type; - self#vtype v.v_type + let outside,accesses_this = Texpr.collect_captured_vars e in + let env = List.map (fun v -> + v.v_id,(v.v_name,self#vtype v.v_type) + ) outside in + let env = if accesses_this then ((0,("this",jc#get_jsig)) :: env) else env in + let context = List.map snd env in + let wf = new JvmFunctions.typed_function gctx.typed_functions FuncLocal jc jm context in + let jc_closure = wf#get_class in + ignore(wf#generate_constructor (env <> [])); + let args,ret = + let args = List.map (fun (v,eo) -> + (* TODO: Can we do this differently? *) + if eo <> None then v.v_type <- self#mknull v.v_type; + v.v_name,self#vtype v.v_type ) tf.tf_args in - let args = match outside with - | None -> args - | Some ctx_class -> ctx_class#get_jsig :: args - in - method_sig args (if ExtType.is_void (follow tf.tf_type) then None else Some (self#vtype tf.tf_type)) + args,(return_of_type gctx tf.tf_type) in - begin - let jm = jc#spawn_method name jsig [MPublic;MStatic] in - let handler = new texpr_to_jvm gctx jc jm tf.tf_type in - begin match outside with - | None -> () - | Some ctx_class -> - handler#set_context ctx_class; - let name = match ctx_class#get_args with - | [(_,name),_] -> name - | _ -> "_hx_ctx" - in - ignore(handler#add_named_local name ctx_class#get_jsig) - end; - let inits = List.map (fun (v,cto) -> - let _,load,save = handler#add_local v VarArgument in - match cto with - | Some e when (match e.eexpr with TConst TNull -> false | _ -> true) -> - let f () = - load(); - let jsig = self#vtype v.v_type in - jm#if_then - (fun () -> jm#get_code#if_nonnull_ref jsig) - (fun () -> - handler#texpr (rvalue_sig jsig) e; - jm#cast jsig; - save(); - ) - in - Some f - | _ -> - None - ) tf.tf_args in - jm#finalize_arguments; - List.iter (function - | None -> () - | Some f -> f() - ) inits; - handler#texpr RReturn tf.tf_expr; + let jm_invoke = wf#generate_invoke args ret in + let handler = new texpr_to_jvm gctx jc_closure jm_invoke ret in + handler#set_env env; + let args = List.map (fun (v,eo) -> + handler#add_local v VarArgument,v,eo + ) tf.tf_args in + jm_invoke#finalize_arguments; + List.iter (fun ((_,load,save),v,eo) -> match eo with + | Some e when (match e.eexpr with TConst TNull -> false | _ -> true) -> + load(); + let jsig = self#vtype v.v_type in + jm_invoke#if_then + (jm_invoke#get_code#if_nonnull jsig) + (fun () -> + handler#texpr (rvalue_sig jsig) e; + jm_invoke#cast jsig; + save(); + ) + | _ -> + () + ) args; + handler#texpr RReturn tf.tf_expr; + begin match env with + | [] -> + let name = snd jc_closure#get_this_path in + self#make_static_closure_field name jc_closure; + jm#getstatic jc_closure#get_this_path name (object_path_sig jc_closure#get_this_path); + | _ -> + jm#construct ConstructInit jc_closure#get_this_path (fun () -> + (List.map (fun (id,(name,jsig)) -> + let _,load,_ = self#get_local_by_id (id,name) in + load(); + jsig + ) env); + ); end; - jm#read_closure true jc#get_this_path name jsig; - outside + write_class gctx.jar jc_closure#get_this_path (jc_closure#export_class gctx.default_export_config); (* access *) @@ -659,16 +542,72 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return method write_native_array vta vte = NativeArray.write code vta vte + method read_anon_field cast t cf = + let default () = + jm#string cf.cf_name; + jm#invokestatic haxe_jvm_path "readField" (method_sig [object_sig;string_sig] (Some object_sig)); + cast(); + in + match gctx.anon_identification#identify true t with + | Some pfm -> + let cf = PMap.find cf.cf_name pfm.pfm_fields in + let path = pfm.pfm_path in + code#dup; + code#instanceof path; + jm#if_then_else + (code#if_ CmpEq) + (fun () -> + jm#cast (object_path_sig path); + jm#getfield path cf.cf_name (self#vtype cf.cf_type); + cast(); + ) + (fun () -> default()); + | None -> + default(); + + method read_static_closure (path : path) (name : string) (args : (string * jsignature) list) (ret : jsignature option) = + let jsig = method_sig (List.map snd args) ret in + let closure_path = try + Hashtbl.find gctx.closure_paths (path,name,jsig) + with Not_found -> + let wf = new JvmFunctions.typed_function gctx.typed_functions (FuncStatic(path,name)) jc jm [] in + let jc_closure = wf#get_class in + ignore(wf#generate_constructor false); + let jm_invoke = wf#generate_invoke args ret in + let vars = List.map (fun (name,jsig) -> + jm_invoke#add_local name jsig VarArgument + ) args in + jm_invoke#finalize_arguments; + List.iter (fun (_,load,_) -> + load(); + ) vars; + jm_invoke#invokestatic path name (method_sig (List.map snd args) ret); + jm_invoke#return; + Hashtbl.add gctx.closure_paths (path,name,jsig) jc_closure#get_this_path; + (* Static init *) + self#make_static_closure_field name jc_closure; + write_class gctx.jar jc_closure#get_this_path (jc_closure#export_class gctx.default_export_config); + jc_closure#get_this_path; + in + jm#getstatic closure_path name (object_path_sig closure_path); + method read cast e1 fa = + let read_static_closure path cf = + let args,ret = match follow cf.cf_type with + | TFun(tl,tr) -> List.map (fun (n,_,t) -> n,self#vtype t) tl,(return_of_type gctx tr) + | _ -> die "" __LOC__ + in + self#read_static_closure path cf.cf_name args ret + in match fa with | FStatic({cl_path = (["java";"lang"],"Math")},({cf_name = "NaN" | "POSITIVE_INFINITY" | "NEGATIVE_INFINITY"} as cf)) -> jm#getstatic double_path cf.cf_name TDouble | FStatic({cl_path = (["java";"lang"],"Math")},({cf_name = "isNaN" | "isFinite"} as cf)) -> - jm#read_closure true double_path cf.cf_name (jsignature_of_type cf.cf_type); + read_static_closure double_path cf; | FStatic({cl_path = (["java";"lang"],"String")},({cf_name = "fromCharCode"} as cf)) -> - jm#read_closure true (["haxe";"jvm"],"StringExt") cf.cf_name (jsignature_of_type cf.cf_type); + read_static_closure (["haxe";"jvm"],"StringExt") cf | FStatic(c,({cf_kind = Method (MethNormal | MethInline)} as cf)) -> - jm#read_closure true c.cl_path cf.cf_name (jsignature_of_type cf.cf_type); + read_static_closure c.cl_path cf | FStatic(c,cf) -> jm#getstatic c.cl_path cf.cf_name (self#vtype cf.cf_type); cast(); @@ -688,56 +627,49 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return let offset = pool#add_field en.e_path ef.ef_name jsig FKField in code#getstatic offset jsig; cast(); - | FAnon ({cf_name = s} as cf) -> + | FAnon cf -> self#texpr rvalue_any e1; - let default () = - jm#string s; - jm#invokestatic haxe_jvm_path "readField" (method_sig [object_sig;string_sig] (Some object_sig)); - cast(); - in - begin match follow e1.etype with - | TAnon an -> - let path,_ = TAnonIdentifiaction.identify gctx an.a_fields in - code#dup; - code#instanceof path; - jm#if_then_else - (fun () -> code#if_ref CmpEq) - (fun () -> - jm#cast (object_path_sig path); - jm#getfield path s (self#vtype cf.cf_type); - cast(); - ) - (fun () -> default()); - | _ -> - default(); - end + self#read_anon_field cast e1.etype cf; | FDynamic s | FInstance(_,_,{cf_name = s}) | FEnum(_,{ef_name = s}) | FClosure(Some({cl_interface = true},_),{cf_name = s}) | FClosure(None,{cf_name = s}) -> self#texpr rvalue_any e1; jm#string s; jm#invokestatic haxe_jvm_path "readField" (method_sig [object_sig;string_sig] (Some object_sig)); cast(); | FClosure((Some(c,_)),cf) -> - let jsig = self#vtype cf.cf_type in - jm#read_closure false c.cl_path cf.cf_name jsig; - self#texpr rvalue_any e1; - jm#invokevirtual method_handle_path "bindTo" (method_sig [object_sig] (Some method_handle_sig)); + create_field_closure gctx jc c.cl_path jm cf.cf_name (self#vtype cf.cf_type) (fun () -> + self#texpr rvalue_any e1; + ) method read_write ret ak e (f : unit -> unit) = let apply dup = - if ret <> RVoid && ak = AKPost then dup(); + if need_val ret && ak = AKPost then dup(); f(); - if ret <> RVoid && ak <> AKPost then dup(); + if need_val ret && ak <> AKPost then dup(); + in + let default s t = + if ak <> AKNone then code#dup; + jm#string s; + if ak <> AKNone then begin + code#dup_x1; + jm#invokestatic haxe_jvm_path "readField" (method_sig [object_sig;string_sig] (Some object_sig)); + self#cast_expect ret t; + end; + apply (fun () -> code#dup_x2); + self#cast (self#mknull t); + jm#invokestatic haxe_jvm_path "writeField" (method_sig [object_sig;string_sig;object_sig] None) in match (Texpr.skip e).eexpr with | TLocal v -> let _,load,store = self#get_local v in if ak <> AKNone then load(); apply (fun () -> code#dup); + self#cast v.v_type; store(); | TField(_,FStatic(c,cf)) -> let jsig_cf = self#vtype cf.cf_type in if ak <> AKNone then jm#getstatic c.cl_path cf.cf_name jsig_cf; apply (fun () -> code#dup); + jm#cast jsig_cf; jm#putstatic c.cl_path cf.cf_name jsig_cf; | TField(e1,FInstance(c,tl,cf)) when not (is_interface_var_access c cf) -> self#texpr rvalue_any e1; @@ -749,22 +681,40 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return apply (fun () -> code#dup_x1); self#cast cf.cf_type; jm#putfield c.cl_path cf.cf_name jsig_cf - | TField(e1,(FDynamic s | FAnon {cf_name = s} | FInstance(_,_,{cf_name = s}))) -> + | TField(e1,FAnon cf) -> self#texpr rvalue_any e1; - if ak <> AKNone then code#dup; - jm#string s; - if ak <> AKNone then begin - code#dup_x1; - jm#invokestatic haxe_jvm_path "readField" (method_sig [object_sig;string_sig] (Some object_sig)); - self#cast_expect ret e.etype; - end; - apply (fun () -> code#dup_x2); - self#cast (self#mknull e.etype); - jm#invokestatic haxe_jvm_path "writeField" (method_sig [object_sig;string_sig;object_sig] None) + begin match gctx.anon_identification#identify true e1.etype with + | Some pfm -> + let cf = PMap.find cf.cf_name pfm.pfm_fields in + let path = pfm.pfm_path in + code#dup; + code#instanceof path; + let jsig_cf = self#vtype cf.cf_type in + jm#if_then_else + (code#if_ CmpEq) + (fun () -> + jm#cast (object_path_sig path); + if ak <> AKNone then begin + code#dup; + jm#getfield path cf.cf_name jsig_cf; + end; + apply (fun () -> code#dup_x1); + jm#cast jsig_cf; + jm#putfield path cf.cf_name jsig_cf; + ) + (fun () -> + default cf.cf_name cf.cf_type; + if need_val ret then jm#cast jsig_cf; + ); + | None -> + default cf.cf_name cf.cf_type; + end + | TField(e1,(FDynamic s | FInstance(_,_,{cf_name = s}))) -> + self#texpr rvalue_any e1; + default s e.etype; | TArray(e1,e2) -> begin match follow e1.etype with | TInst({cl_path = (["haxe";"root"],"Array")} as c,[t]) -> - let t = self#mknull t in self#texpr rvalue_any e1; if ak <> AKNone then code#dup; self#texpr rvalue_any e2; @@ -775,7 +725,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return self#cast_expect ret e.etype; end; apply (fun () -> code#dup_x2;); - self#cast t; + jm#expect_reference_type; jm#invokevirtual c.cl_path "__set" (method_sig [TInt;object_sig] None); | TInst({cl_path = (["java"],"NativeArray")},[t]) -> let vte = self#vtype t in @@ -806,39 +756,71 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return end | _ -> print_endline (s_expr_ast false "" (s_type (print_context())) e); - assert false + die "" __LOC__ (* branching *) method apply_cmp = function - | CmpNormal(op,_) -> (fun () -> code#if_ref op) + | CmpNormal(op,_) -> code#if_ op | CmpSpecial f -> f - method if_null t = - (fun () -> code#if_null_ref t) - - method if_not_null t = - (fun () -> code#if_nonnull_ref t) - - method condition e = match (Texpr.skip e).eexpr with + method condition (flip : bool) (e : texpr) (label_then : label) (label_else : label) = + let stack = jm#get_code#get_stack in + let (_,before) = stack#save in + let bool_and flip e1 e2 = + let label_then2 = jm#spawn_label "then2" in + self#condition flip e1 label_then2 label_else; + label_then2#here; + self#condition flip e2 label_then label_else; + in + let involves_float_compare e = + let rec loop e = match e.eexpr with + | TBinop((OpEq | OpNotEq | OpLt | OpGt | OpLte | OpGte),e1,e2) -> + if ExtType.is_float (follow e1.etype) || ExtType.is_float (follow e2.etype) then raise Exit; + loop e1; + loop e2; + | _ -> + Type.iter loop e + in + try + loop e; + false + with Exit -> + true + in + begin match (Texpr.skip e).eexpr with | TBinop((OpEq | OpNotEq | OpLt | OpGt | OpLte | OpGte) as op,e1,e2) -> let op = convert_cmp_op op in - self#binop_compare op e1 e2 + let op = if flip then flip_cmp_op op else op in + label_else#apply (self#apply_cmp (self#binop_compare op e1 e2)) + | TBinop(OpBoolAnd,e1,e2) when not flip -> + bool_and false e1 e2 + | TBinop(OpBoolOr,e1,e2) when flip -> + bool_and true e1 e2 + | TUnop(Not,_,e1) when not (involves_float_compare e1) -> + self#condition (not flip) e1 label_then label_else | _ -> - self#texpr rvalue_any e; + self#texpr (rvalue_sig TBool) e; + end; + let (_,after) = stack#save in + if after > before then begin jm#cast TBool; - CmpNormal(CmpEq,TBool) + label_else#if_ (if flip then CmpNe else CmpEq) + end method switch ret e1 cases def = - (* TODO: hack because something loses the exhaustiveness marker before we get here *) - let is_exhaustive = OptimizerTexpr.is_exhaustive e1 || (ExtType.is_bool (follow e1.etype) && List.length cases > 1) in + let need_val = match ret with + | RValue _ -> true + | RReturn -> return_type <> None + | _ -> false + in if cases = [] then self#texpr ret e1 else if List.for_all is_const_int_pattern cases then begin let cases = List.map (fun (el,e) -> let il = List.map (fun e -> match e.eexpr with | TConst (TInt i32) -> i32 - | _ -> assert false + | _ -> die "" __LOC__ ) el in (il,(fun () -> self#texpr ret e)) ) cases in @@ -848,14 +830,14 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return in self#texpr rvalue_any e1; jm#cast TInt; - ignore(jm#int_switch is_exhaustive cases def); + jm#int_switch need_val cases def end else if List.for_all is_const_string_pattern cases then begin let cases = List.map (fun (el,e) -> - let il = List.map (fun e -> match e.eexpr with - | TConst (TString s) -> java_hash s - | _ -> assert false + let sl = List.map (fun e -> match e.eexpr with + | TConst (TString s) -> s + | _ -> die "" __LOC__ ) el in - (il,(fun () -> self#texpr ret e)) + (sl,(fun () -> self#texpr ret e)) ) cases in let def = match def with | None -> None @@ -863,19 +845,9 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return in self#texpr rvalue_any e1; jm#cast string_sig; - let r = ref 0 in - (* all strings can be null and we're not supposed to cause NPEs here... *) - code#dup; - jm#if_then - (fun () -> jm#get_code#if_nonnull_ref string_sig) - (fun () -> - code#pop; - r := code#get_fp; - code#goto r - ); - jm#invokevirtual string_path "hashCode" (method_sig [] (Some TInt)); - let r_default = jm#int_switch is_exhaustive cases def in - r := r_default - !r; + let _,load,save = jm#add_local "_hx_tmp" string_sig VarWillInit in + save(); + jm#string_switch need_val load cases def; end else begin (* TODO: rewriting this is stupid *) let pop_scope = jm#push_scope in @@ -888,7 +860,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return let el = List.rev_map (fun (el,e) -> let f e' = mk (TBinop(OpEq,ev,e')) com.basic.tbool e'.epos in let e_cond = match el with - | [] -> assert false + | [] -> die "" __LOC__ | [e] -> f e | e :: el -> List.fold_left (fun eacc e -> @@ -898,7 +870,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return (e_cond,e) ) cases in (* If we rewrite an exhaustive switch that has no default value, treat the last case as the default case to satisfy control flow. *) - let cases,def = if is_exhaustive && def = None then (match List.rev cases with (_,e) :: cases -> List.rev cases,Some e | _ -> assert false) else cases,def in + let cases,def = if need_val && def = None then (match List.rev cases with (_,e) :: cases -> List.rev cases,Some e | _ -> die "" __LOC__) else cases,def in let e = List.fold_left (fun e_else (e_cond,e_then) -> Some (mk (TIf(e_cond,e_then,e_else)) e_then.etype e_then.epos)) def el in self#texpr ret (Option.get e); pop_scope() @@ -930,13 +902,13 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return else object_sig - method get_binop_type t1 t2 = self#get_binop_type_sig (jsignature_of_type t1) (jsignature_of_type t2) + method get_binop_type t1 t2 = self#get_binop_type_sig (jsignature_of_type gctx t1) (jsignature_of_type gctx t2) method do_compare op = match code#get_stack#get_stack_items 2 with | [TInt | TByte | TChar | TBool;TInt | TByte | TChar | TBool] -> let op = flip_cmp_op op in - CmpSpecial (fun () -> code#if_icmp_ref op) + CmpSpecial (code#if_icmp op) | [TObject((["java";"lang"],"String"),[]);TObject((["java";"lang"],"String"),[])] -> jm#invokestatic haxe_jvm_path "stringCompare" (method_sig [string_sig;string_sig] (Some TInt)); let op = flip_cmp_op op in @@ -947,7 +919,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return let op = flip_cmp_op op in CmpNormal(op,TBool) | [(TObject _ | TArray _ | TMethod _) as t1;(TObject _ | TArray _ | TMethod _) as t2] -> - CmpSpecial (fun () -> (if op = CmpEq then code#if_acmp_ne_ref else code#if_acmp_eq_ref) t1 t2) + CmpSpecial ((if op = CmpEq then code#if_acmp_ne else code#if_acmp_eq) t1 t2) | [TDouble;TDouble] -> let op = flip_cmp_op op in begin match op with @@ -972,15 +944,15 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return jerror (Printf.sprintf "Bad stack: %s" (String.concat ", " (List.map (generate_signature false) tl))); method binop_compare op e1 e2 = - let sig1 = jsignature_of_type e1.etype in - let sig2 = jsignature_of_type e2.etype in + let sig1 = jsignature_of_type gctx e1.etype in + let sig2 = jsignature_of_type gctx e2.etype in match (Texpr.skip e1),(Texpr.skip e2) with | {eexpr = TConst TNull},_ when not (is_unboxed sig2) -> self#texpr rvalue_any e2; - CmpSpecial ((if op = CmpEq then self#if_not_null else self#if_null) sig2) + CmpSpecial ((if op = CmpEq then jm#get_code#if_nonnull else jm#get_code#if_null) sig2) | _,{eexpr = TConst TNull} when not (is_unboxed sig1) -> self#texpr rvalue_any e1; - CmpSpecial ((if op = CmpEq then self#if_not_null else self#if_null) sig1) + CmpSpecial ((if op = CmpEq then jm#get_code#if_nonnull else jm#get_code#if_null) sig1) | {eexpr = TConst (TInt i32);etype = t2},e1 when Int32.to_int i32 = 0 && sig2 = TInt -> let op = match op with | CmpGt -> CmpGe @@ -1018,18 +990,18 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return self#texpr rvalue_any e1; jm#get_code#dup; jm#if_then_else - (self#if_not_null sig1) + (jm#get_code#if_nonnull sig1) (fun () -> jm#get_code#pop; self#texpr rvalue_any e2; - self#boolop (CmpSpecial (self#if_not_null sig2)) + self#boolop (CmpSpecial (jm#get_code#if_nonnull sig2)) ) (fun () -> jm#cast ~not_null:true cast_type; self#texpr rvalue_any e2; jm#get_code#dup; jm#if_then_else - (self#if_not_null sig2) + (jm#get_code#if_nonnull sig2) (fun () -> jm#get_code#pop; jm#get_code#pop; @@ -1046,7 +1018,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return self#texpr rvalue_any e1; jm#get_code#dup; jm#if_then_else - (self#if_not_null sig1) + (jm#get_code#if_nonnull sig1) (fun () -> jm#get_code#pop; jm#get_code#bconst (op = CmpNe) @@ -1078,7 +1050,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return in jm#get_code#dup; jm#if_then_else - (self#if_not_null sig2) + (jm#get_code#if_nonnull sig2) (fun () -> jm#get_code#pop; jm#get_code#pop; @@ -1104,7 +1076,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return | OpShl -> "opShl" | OpShr -> "opShr" | OpUShr -> "opUshr" - | _ -> assert false + | _ -> die "" __LOC__ in begin match cast_type with | TByte | TShort | TInt -> @@ -1222,7 +1194,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return in operand f1; jm#if_then_else - (fun () -> code#if_ref CmpEq) + (code#if_ CmpEq) (fun () -> operand f2) (fun () -> code#bconst false) | OpBoolOr -> @@ -1232,7 +1204,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return in operand f1; jm#if_then_else - (fun () -> code#if_ref CmpEq) + (code#if_ CmpEq) (fun () -> code#bconst true) (fun () -> operand f2) | _ -> @@ -1262,29 +1234,29 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return let slot,_,_ = self#get_local v in in_range true Int8Range slot - method binop ret op e1 e2 = match op with - | OpEq | OpNotEq | OpLt | OpGt | OpLte | OpGte -> + method binop ret op e1 e2 = match op,ret with + | (OpEq | OpNotEq | OpLt | OpGt | OpLte | OpGte),_ -> let op = convert_cmp_op op in self#boolop (self#binop_compare op e1 e2) - | OpAssign -> + | OpAssign,_ -> let f () = - self#texpr (rvalue_type e1.etype) e2; + self#texpr (rvalue_type gctx e1.etype) e2; self#cast e1.etype; in self#read_write ret AKNone e1 f - | OpAssignOp op -> - let jsig1 = jsignature_of_type e1.etype in + | OpAssignOp op,_ -> + let jsig1 = jsignature_of_type gctx e1.etype in begin match op,(Texpr.skip e1).eexpr,(Texpr.skip e2).eexpr with - | OpAdd,TLocal v,TConst (TInt i32) when ExtType.is_int v.v_type && in_range false Int8Range (Int32.to_int i32) && self#var_slot_is_in_int8_range v-> + | OpAdd,TLocal v,TConst (TInt i32) when is_really_int v.v_type && in_range false Int8Range (Int32.to_int i32) && self#var_slot_is_in_int8_range v-> let slot,load,_ = self#get_local v in let i = Int32.to_int i32 in code#iinc slot i; - if ret <> RVoid then load(); - | OpSub,TLocal v,TConst (TInt i32) when ExtType.is_int v.v_type && in_range false Int8Range (-Int32.to_int i32) && self#var_slot_is_in_int8_range v -> + if need_val ret then load(); + | OpSub,TLocal v,TConst (TInt i32) when is_really_int v.v_type && in_range false Int8Range (-Int32.to_int i32) && self#var_slot_is_in_int8_range v -> let slot,load,_ = self#get_local v in let i = -Int32.to_int i32 in code#iinc slot i; - if ret <> RVoid then load(); + if need_val ret then load(); | _ -> let f () = self#binop_basic ret op (self#get_binop_type e1.etype e2.etype) (fun () -> ()) (fun () -> self#texpr rvalue_any e2); @@ -1298,11 +1270,11 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return method unop ret op flag e = match op,(Texpr.skip e).eexpr with - | (Increment | Decrement),TLocal v when ExtType.is_int v.v_type && self#var_slot_is_in_int8_range v -> + | (Increment | Decrement),TLocal v when is_really_int v.v_type && self#var_slot_is_in_int8_range v -> let slot,load,_ = self#get_local v in - if flag = Postfix && ret <> RVoid then load(); + if flag = Postfix && need_val ret then load(); code#iinc slot (if op = Increment then 1 else -1); - if flag = Prefix && ret <> RVoid then load(); + if flag = Prefix && need_val ret then load(); | (Increment | Decrement),_ -> let is_null = is_null e.etype in let f () = @@ -1324,7 +1296,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return self#read_write ret (if flag = Prefix then AKPre else AKPost) e f; | Neg,_ -> self#texpr rvalue_any e; - let jsig = jsignature_of_type (follow e.etype) in + let jsig = jsignature_of_type gctx (follow e.etype) in jm#cast jsig; begin match jsig with | TLong -> code#lneg; @@ -1334,12 +1306,12 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return end; self#cast e.etype; | Not,_ -> - jm#if_then_else - (self#apply_cmp (self#condition e)) + jm#if_then_else_labeled + (self#condition false e) (fun () -> code#bconst false) (fun () -> code#bconst true) | NegBits,_ -> - let jsig = jsignature_of_type (follow e.etype) in + let jsig = jsignature_of_type gctx (follow e.etype) in self#texpr rvalue_any e; jm#cast jsig; begin match jsig with @@ -1357,7 +1329,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return (* calls *) method get_argument_signatures t el = - match jsignature_of_type t with + match jsignature_of_type gctx t with | TMethod(jsigs,r) -> jsigs,r | _ -> List.map (fun _ -> object_sig) el,(Some object_sig) @@ -1366,7 +1338,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return let varargs_type = match follow t with | TFun(tl,_) -> begin match List.rev tl with - | (_,_,(TAbstract({a_path = ["haxe";"extern"],"Rest"},[t]))) :: _ -> Some (jsignature_of_type t) + | (_,_,(TAbstract({a_path = ["haxe";"extern"],"Rest"},[t]))) :: _ -> Some (jsignature_of_type gctx t) | _ -> None end | _ -> @@ -1393,13 +1365,19 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return tl,tr method call ret tr e1 el = - let retype tr = match tr with None -> [] | Some t -> [t] in + let invoke t = + jm#cast haxe_function_sig; + let tl,tr = self#call_arguments t el in + let meth = gctx.typed_functions#register_signature tl tr in + jm#invokevirtual haxe_function_path meth.name (method_sig meth.dargs meth.dret); + tr + in let tro = match (Texpr.skip e1).eexpr with | TField(_,FStatic({cl_path = ["haxe";"jvm"],"Jvm"},({cf_name = "referenceEquals"} as cf))) -> let tl,tr = self#call_arguments cf.cf_type el in begin match tl with - | [t1;t2] -> self#boolop (CmpSpecial (fun () -> code#if_acmp_ne_ref t1 t2)) - | _ -> assert false + | [t1;t2] -> self#boolop (CmpSpecial (code#if_acmp_ne t1 t2)) + | _ -> die "" __LOC__ end; tr | TField(_,FStatic({cl_path = ["haxe";"jvm"],"Jvm"},({cf_name = "instanceof"}))) -> @@ -1407,7 +1385,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return | [e1;{eexpr = TTypeExpr mt;epos = pe}] -> self#texpr rvalue_any e1; self#expect_reference_type; - let path = match jsignature_of_type (type_of_module_type mt) with + let path = match jsignature_of_type gctx (type_of_module_type mt) with | TObject(path,_) -> path | _ -> Error.error "Class expected" pe in @@ -1415,41 +1393,6 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return Some TBool | _ -> Error.error "Type expression expected" e1.epos end; - | TField(_,FStatic({cl_path = ["haxe";"jvm"],"Jvm"},({cf_name = "invokedynamic"}))) -> - begin match el with - | e_bsm :: {eexpr = TConst (TString name)} :: {eexpr = TArrayDecl el_static_args} :: el -> - let t = tfun (List.map (fun e -> e.etype) el) tr in - let tl,tr = self#call_arguments t el in - let path,mname = match e_bsm.eexpr with - | TField(_,FStatic(c,cf)) -> c.cl_path,cf.cf_name - | _ -> Error.error "Reference to bootstrap method expected" e_bsm.epos - in - let rec loop consts jsigs static_args = match static_args with - | e :: static_args -> - let const,jsig = match e.eexpr with - | TConst (TString s) -> pool#add_const_string s,string_sig - | TConst (TInt i) -> pool#add (ConstInt i),TInt - | TConst (TFloat f) -> pool#add (ConstDouble (float_of_string f)),TDouble - | TField(_,FStatic(c,cf)) -> - let offset = pool#add_field c.cl_path cf.cf_name (self#vtype cf.cf_type) FKMethod in - pool#add (ConstMethodHandle(6, offset)),method_handle_sig - | _ -> Error.error "Invalid static argument" e.epos - in - loop (const :: consts) (jsig :: jsigs) static_args - | [] -> - List.rev consts,List.rev jsigs - in - let consts,jsigs = loop [] [] el_static_args in - let mtl = method_lookup_sig :: string_sig :: method_type_sig :: jsigs in - let index = jc#get_bootstrap_method path mname (method_sig mtl (Some call_site_sig)) consts in - let jsig_method = method_sig tl tr in - let offset_info = pool#add_name_and_type name jsig_method FKMethod in - let offset = pool#add (ConstInvokeDynamic(index,offset_info)) in - code#invokedynamic offset tl (retype tr); - tr - | _ -> - Error.error "Bad invokedynamic call" e1.epos - end | TField(_,FStatic({cl_path = (["java";"lang"],"Math")},{cf_name = ("isNaN" | "isFinite") as name})) -> begin match el with | [e1] -> @@ -1458,7 +1401,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return jm#invokestatic (["java";"lang"],"Double") name (method_sig [TDouble] (Some TBool)); Some TBool | _ -> - assert false + die "" __LOC__ end; | TField(_,FStatic({cl_path = (["java";"lang"],"Math")},{cf_name = ("floor" | "ceil" | "round") as name})) -> begin match el with @@ -1470,13 +1413,13 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return jm#cast TInt; Some TInt | _ -> - assert false + die "" __LOC__ end; | TField(_,FStatic({cl_path = (["java";"lang"],"Math")} as c,({cf_name = ("ffloor" | "fceil")} as cf))) -> let tl,tr = self#call_arguments cf.cf_type el in jm#invokestatic c.cl_path (String.sub cf.cf_name 1 (String.length cf.cf_name - 1)) (method_sig tl tr); tr - | TField(_,FStatic({cl_path = (["haxe";"_Int64"],"Int64_Impl_")},{cf_name = "make"})) -> + | TField(_,FStatic({cl_path = (["haxe"],"Int64$Int64_Impl_")},{cf_name = "make"})) -> begin match el with | [{eexpr = TConst (TInt i1)};{eexpr = TConst (TInt i2)}] -> let high = Int64.of_int32 i1 in @@ -1498,7 +1441,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return jm#get_code#lor_; Some TLong | _ -> - assert false + die "" __LOC__ end | TIdent "__array__" | TField(_,FStatic({cl_path = (["java"],"NativeArray")},{cf_name = "make"})) -> begin match follow tr with @@ -1515,12 +1458,33 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return | _ -> match filter_overloads (find_overload (fun t -> t) c cf el) with | None -> Error.error "Could not find overload" e1.epos - | Some(c,cf) -> + | Some(c,cf,_) -> c,cf in let tl,tr = self#call_arguments cf.cf_type el in jm#invokestatic c.cl_path cf.cf_name (method_sig tl tr); tr + | TField(e1,FInstance({cl_path=(["haxe";"root"],"StringBuf");cl_descendants=[]} as c,_,({cf_name="add"} as cf))) -> + self#texpr rvalue_any e1; + let jsig = match el with + | [ea1] -> + self#texpr rvalue_any ea1; + begin match code#get_stack#top with + | TBool | TChar | TDouble | TFloat | TInt | TLong | TObject((["java";"lang"],"String"),_) as jsig -> + jsig + | TByte | TShort -> + jm#cast TInt; + TInt + | _ -> + jm#cast object_sig; + object_sig + end; + | _ -> + ignore(self#call_arguments cf.cf_type el); + object_sig + in + jm#invokevirtual c.cl_path "add" (method_sig [jsig] None); + None | TField(e1,FInstance(c,tl,({cf_kind = Method (MethNormal | MethInline)} as cf))) -> let is_super = match e1.eexpr with | TConst TSuper -> @@ -1532,7 +1496,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return in begin match find_overload_rec false (apply_params c.cl_params tl) c cf el with | None -> Error.error "Could not find overload" e1.epos - | Some(c,cf) -> + | Some(c,cf,_) -> let tl,tr = self#call_arguments cf.cf_type el in (if is_super then jm#invokespecial else if c.cl_interface then jm#invokeinterface else jm#invokevirtual) c.cl_path cf.cf_name (self#vtype cf.cf_type); tr @@ -1542,6 +1506,29 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return let tr = self#vtype tr in jm#invokestatic en.e_path ef.ef_name (method_sig tl (Some tr)); Some tr + | TField(e11,FAnon cf) -> + begin match gctx.anon_identification#identify false e11.etype with + | Some {pfm_path=path_anon} -> + begin match gctx.typedef_interfaces#get_interface_class path_anon with + | Some c -> + let c,_,cf = raw_class_field (fun cf -> cf.cf_type) c [] cf.cf_name in + let path_inner = match c with + | Some(c,_) -> c.cl_path + | _ -> die "" __LOC__ + in + self#texpr rvalue_any e11; + let tl,tr = self#call_arguments cf.cf_type el in + jm#invokeinterface path_inner cf.cf_name (self#vtype cf.cf_type); + Option.may jm#cast tr; + tr + | None -> + self#texpr rvalue_any e1; + invoke e1.etype + end + | None -> + self#texpr rvalue_any e1; + invoke e1.etype + end | TConst TSuper -> let c,cf = match gctx.current_field_info with | Some ({super_call_fields = hd :: tl} as info) -> @@ -1610,42 +1597,20 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return if not term_try then jm#add_stack_frame; jm#close_jumps true ([term_try,r_try]); None - | _ -> assert false + | _ -> die "" __LOC__ end | _ -> - let rec has_unknown_args jsig = - is_dynamic_at_runtime jsig || match jsig with - | TMethod(jsigs,_) -> List.exists has_unknown_args jsigs - | _ -> false - in - if has_unknown_args (jsignature_of_type e1.etype) then begin - self#texpr rvalue_any e1; - jm#cast method_handle_sig; - self#new_native_array object_sig el; - jm#invokestatic haxe_jvm_path "call" (method_sig [method_handle_sig;array_sig object_sig] (Some object_sig)); - Some object_sig - end else begin - self#texpr rvalue_any e1; - jm#cast method_handle_sig; - let tl,tr = self#call_arguments e1.etype el in - jm#invokevirtual method_handle_path "invoke" (method_sig tl tr); - tr - end + self#texpr rvalue_any e1; + invoke e1.etype; in - match ret = RVoid,tro with - | true,Some _ -> code#pop - | true,None -> () - | false,Some _ -> self#cast tr; - | false,None -> assert false + match need_val ret,tro with + | false,Some _ -> code#pop + | false,None -> () + | true,Some _ -> self#cast tr; + | true,None -> die "" __LOC__ (* exceptions *) - method throw vt = - jm#expect_reference_type; - jm#invokestatic (["haxe";"jvm"],"Exception") "wrap" (method_sig [object_sig] (Some exception_sig)); - code#athrow; - jm#set_terminated true - method try_catch ret e1 catches = let restore = jm#start_branch in let fp_from = code#get_fp in @@ -1660,17 +1625,6 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return let term_try = jm#is_terminated in let r_try = jm#maybe_make_jump in let fp_to = code#get_fp in - let unwrap () = - code#dup; - code#instanceof haxe_exception_path; - jm#if_then_else - (fun () -> code#if_ref CmpEq) - (fun () -> - jm#cast haxe_exception_sig; - jm#getfield (["haxe";"jvm"],"Exception") "value" object_sig; - ) - (fun () -> jm#cast object_sig); - in let start_exception_block path jsig = restore(); let fp_target = code#get_fp in @@ -1683,8 +1637,6 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return }; code#get_stack#push jsig; jm#add_stack_frame; - jm#get_code#dup; - jm#invokestatic haxe_exception_path "setException" (method_sig [throwable_sig] None); in let run_catch_expr v e = let pop_scope = jm#push_scope in @@ -1695,64 +1647,15 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return jm#is_terminated in let add_catch (exc,v,e) = - start_exception_block exc#get_native_exception_path exc#get_native_exception_type; - if not exc#is_native_exception then begin - unwrap(); - self#cast v.v_type - end; + start_exception_block exc#get_native_path exc#get_native_type; let term = run_catch_expr v e in let r = jm#maybe_make_jump in term,r in - let commit_instanceof_checks excl = - start_exception_block throwable_path throwable_sig; - let pop_scope = jm#push_scope in - let _,load,save = jm#add_local "exc" throwable_sig VarWillInit in - code#dup; - save(); - unwrap(); - let restore = jm#start_branch in - let rl = ref [] in - let rec loop excl = match excl with - | [] -> - code#pop; - load(); - code#athrow; - jm#set_terminated true - | (_,v,e) :: excl -> - code#dup; - let path = match self#vtype (self#mknull v.v_type) with TObject(path,_) -> path | _ -> assert false in - if path = object_path then begin - code#pop; - restore(); - let term = run_catch_expr v e in - rl := (term,ref 0) :: !rl; - end else begin - code#instanceof path; - jm#if_then_else - (fun () -> code#if_ref CmpEq) - (fun () -> - restore(); - self#cast v.v_type; - let term = run_catch_expr v e in - rl := (term,ref 0) :: !rl; - ) - (fun () -> loop excl) - end - in - loop excl; - pop_scope(); - !rl - in let rec loop acc excl = match excl with | (exc,v,e) :: excl -> - if List.exists (fun (exc',_,_) -> exc'#is_assignable_to exc) excl || excl = [] && not exc#is_native_exception then begin - let res = commit_instanceof_checks ((exc,v,e) :: excl) in - acc @ res - end else begin - let res = add_catch (exc,v,e) in - loop (res :: acc) excl - end + let res = add_catch (exc,v,e) in + loop (res :: acc) excl | [] -> acc in @@ -1774,7 +1677,11 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return (* texpr *) method const ret t ct = match ct with - | Type.TInt i32 -> code#iconst i32 + | Type.TInt i32 -> + begin match ret with + | RValue (Some (TDouble | TObject((["java";"lang"],"Double"),_))) -> code#lconst (Int64.of_int32 i32) + | _ -> code#iconst i32 + end | TFloat f -> begin match ret with | RValue (Some (TFloat | TObject((["java";"lang"],"Float"),_))) -> code#fconst (float_of_string f) @@ -1792,37 +1699,6 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return method new_native_array jsig el = jm#new_native_array jsig (List.map (fun e -> fun () -> self#texpr (rvalue_sig jsig) e) el) - method basic_type_path name = - let offset = pool#add_field (["java";"lang"],name) "TYPE" java_class_sig FKField in - code#getstatic offset java_class_sig - - method type_expr = function - | TByte -> self#basic_type_path "Byte" - | TChar -> self#basic_type_path "Character" - | TDouble -> self#basic_type_path "Double" - | TFloat -> self#basic_type_path "Float" - | TInt -> self#basic_type_path "Integer" - | TLong -> self#basic_type_path "Long" - | TShort -> self#basic_type_path "Short" - | TBool -> self#basic_type_path "Boolean" - | TObject(path,_) -> - let offset = pool#add_path path in - let t = object_path_sig path in - code#ldc offset (TObject(java_class_path,[TType(WNone,t)])) - | TMethod _ -> - let offset = pool#add_path method_handle_path in - code#ldc offset (TObject(java_class_path,[TType(WNone,method_handle_sig)])) - | TTypeParameter _ -> - let offset = pool#add_path object_path in - code#ldc offset (TObject(java_class_path,[TType(WNone,object_sig)])) - | TArray _ as t -> - (* TODO: this seems hacky *) - let offset = pool#add_path ([],generate_signature false t) in - code#ldc offset (TObject(java_class_path,[TType(WNone,object_sig)])) - | jsig -> - print_endline (generate_signature false jsig); - assert false - method texpr ret e = try if not jm#is_terminated then self#texpr' ret e @@ -1833,22 +1709,24 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return code#set_line (Lexer.get_error_line e.epos); match e.eexpr with | TVar(v,Some e1) -> - self#texpr (rvalue_type v.v_type) e1; + self#texpr (rvalue_type gctx v.v_type) e1; self#cast v.v_type; let _,_,store = self#add_local v VarWillInit in store() | TVar(v,None) -> ignore(self#add_local v VarNeedDefault); - | TLocal _ | TConst _ | TTypeExpr _ when ret = RVoid -> + | TLocal _ | TConst _ | TTypeExpr _ when not (need_val ret) -> () | TLocal v -> let _,load,_ = self#get_local v in load() | TTypeExpr mt -> - self#type_expr (jsignature_of_type (type_of_module_type mt)) + let t = type_of_module_type mt in + if ExtType.is_void (follow t) then jm#get_basic_type_class "Void" + else jm#get_class (jsignature_of_type gctx t) | TUnop(op,flag,e1) -> begin match op with - | Not | Neg | NegBits when ret = RVoid -> self#texpr ret e1 + | Not | Neg | NegBits when not (need_val ret) -> self#texpr ret e1 | _ -> self#unop ret op flag e1 end | TBinop(OpAdd,e1,e2) when ExtType.is_string (follow e.etype) -> @@ -1881,7 +1759,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return | TBinop(op,e1,e2) -> begin match op with | OpAssign | OpAssignOp _ -> self#binop ret op e1 e2 - | _ when ret = RVoid -> + | _ when not (need_val ret) -> self#texpr ret e1; self#texpr ret e2; | _ -> @@ -1890,131 +1768,111 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return | TConst ct -> self#const ret e.etype ct | TIf(e1,e2,None) -> - jm#if_then - (self#apply_cmp (self#condition e1)) - (fun () -> self#texpr RVoid (mk_block e2)) + jm#if_then_labeled + (self#condition false e1) + (fun () -> self#texpr RVoid (mk_block e2)); | TIf(e1,e2,Some e3) -> - jm#if_then_else - (self#apply_cmp (self#condition e1)) + jm#if_then_else_labeled + (self#condition false e1) (fun () -> self#texpr ret (mk_block e2); - if ret <> RVoid then self#cast e.etype + if need_val ret then self#cast e.etype ) (fun () -> self#texpr ret (mk_block e3); - if ret <> RVoid then self#cast e.etype; + if need_val ret then self#cast e.etype; ) | TSwitch(e1,cases,def) -> self#switch ret e1 cases def | TWhile(e1,e2,flag) -> (* TODO: do-while *) - (* TODO: could optimize a bit *) block_exits <- ExitLoop :: block_exits; let is_true_loop = match (Texpr.skip e1).eexpr with TConst (TBool true) -> true | _ -> false in - jm#add_stack_frame; - let fp = code#get_fp in + let continue_label = jm#spawn_label "continue" in + let break_label = jm#spawn_label "break" in + let body_label = jm#spawn_label "body" in let old_continue = continue in - continue <- fp; - let old_breaks = breaks in - breaks <- []; + continue <- Some continue_label; + let old_break = break in + break <- Some break_label; + continue_label#here; let restore = jm#start_branch in - let jump_then = if not is_true_loop then self#apply_cmp (self#condition e1) () else ref 0 in + if not is_true_loop then self#condition false e1 body_label break_label; let pop_scope = jm#push_scope in + body_label#here; self#texpr RVoid e2; - if not jm#is_terminated then code#goto (ref (fp - code#get_fp)); + if not jm#is_terminated then continue_label#goto; pop_scope(); restore(); - if not is_true_loop || breaks <> [] then begin - jump_then := code#get_fp - !jump_then; - let fp' = code#get_fp in - List.iter (fun r -> r := fp' - !r) breaks; - jm#add_stack_frame - end else + if break_label#was_jumped_to || not is_true_loop then + break_label#here + else jm#set_terminated true; continue <- old_continue; - breaks <- old_breaks; + break <- old_break; block_exits <- List.tl block_exits; | TBreak -> self#emit_block_exits true; - let r = ref (code#get_fp) in - code#goto r; - breaks <- r :: breaks; - jm#set_terminated true; + begin match break with + | None -> + jerror "break outside loop" + | Some label -> + label#goto; + end; | TContinue -> self#emit_block_exits true; - code#goto (ref (continue - code#get_fp)); - jm#set_terminated true; + begin match continue with + | None -> + jerror "continue outside loop" + | Some label -> + label#goto; + end; | TTry(e1,catches) -> self#try_catch ret e1 catches | TField(e1,fa) -> - if ret = RVoid then self#texpr ret e1 + if not (need_val ret) then self#texpr ret e1 else self#read (fun () -> self#cast_expect ret e.etype) e1 fa; | TCall(e1,el) -> self#call ret e.etype e1 el | TNew({cl_path = (["java"],"NativeArray")},[t],[e1]) -> - self#texpr (match ret with RVoid -> RVoid | _ -> rvalue_any) e1; + self#texpr (if need_val ret then rvalue_any else RVoid) e1; (* Technically this could throw... but whatever *) - if ret <> RVoid then ignore(NativeArray.create jm#get_code jc#get_pool (jsignature_of_type t)) + if need_val ret then ignore(NativeArray.create jm#get_code jc#get_pool (jsignature_of_type gctx t)) | TNew(c,tl,el) -> begin match get_constructor (fun cf -> cf.cf_type) c with |_,cf -> begin match find_overload_rec true (apply_params c.cl_params tl) c cf el with | None -> Error.error "Could not find overload" e.epos - | Some (c',cf) -> + | Some (c',cf,_) -> let f () = let tl,_ = self#call_arguments cf.cf_type el in tl in - jm#construct ~no_value:(if ret = RVoid then true else false) (get_construction_mode c' cf) c.cl_path f + jm#construct ~no_value:(if not (need_val ret) then true else false) (get_construction_mode c' cf) c.cl_path f end end | TReturn None -> self#emit_block_exits false; - code#return_void; - jm#set_terminated true; + jm#return; | TReturn (Some e1) -> self#texpr rvalue_any e1; - self#cast return_type; - let vt = self#vtype return_type in + let jsig = Option.get return_type in + jm#cast jsig; self#emit_block_exits false; - code#return_value vt; - jm#set_terminated true; + jm#return; | TFunction tf -> - begin match self#tfunction e tf with - | None -> - () - | Some ctx_class -> - begin match ctx_class#get_args with - | [(arg,jsig)] -> - let _,load,_ = self#get_local_by_id arg in - load(); - self#expect_reference_type; - jm#invokevirtual method_handle_path "bindTo" (method_sig [object_sig] (Some method_handle_sig)); - | args -> - let f () = - let tl = List.map (fun (arg,jsig) -> - let _,load,_ = self#get_local_by_id arg in - load(); - jm#cast jsig; - jsig - ) args in - tl - in - jm#construct ConstructInit ctx_class#get_path f; - jm#invokevirtual method_handle_path "bindTo" (method_sig [object_sig] (Some method_handle_sig)); - end - end - | TArrayDecl el when ret = RVoid -> + self#tfunction e tf + | TArrayDecl el when not (need_val ret) -> List.iter (self#texpr ret) el | TArrayDecl el -> begin match follow e.etype with | TInst({cl_path = (["haxe";"root"],"Array")},[t]) -> - self#new_native_array (jsignature_of_type (self#mknull t)) el; + self#new_native_array (jsignature_of_type gctx (self#mknull t)) el; jm#invokestatic (["haxe";"root"],"Array") "ofNative" (method_sig [array_sig object_sig] (Some (object_path_sig (["haxe";"root"],"Array")))); self#cast e.etype | _ -> - assert false + die "" __LOC__ end - | TArray(e1,e2) when ret = RVoid -> + | TArray(e1,e2) when not (need_val ret) -> (* Array access never throws so this should be fine... *) self#texpr ret e1; self#texpr ret e2; @@ -2040,13 +1898,13 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return self#cast e.etype; end | TBlock [] -> - if ret = RReturn && not jm#is_terminated then code#return_void; + if ret = RReturn && not jm#is_terminated then jm#return; | TBlock el -> let rec loop el = match el with - | [] -> assert false + | [] -> die "" __LOC__ | [e1] -> - self#texpr (if ret = RReturn then RVoid else ret) e1; - if ret = RReturn && not jm#is_terminated then code#return_void; + self#texpr ret e1; + if ret = RReturn && not jm#is_terminated then jm#return; | e1 :: el -> self#texpr RVoid e1; loop el @@ -2056,13 +1914,13 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return pop_scope(); | TCast(e1,None) -> self#texpr ret e1; - if ret <> RVoid then self#cast e.etype + if need_val ret then self#cast e.etype | TCast(e1,Some mt) -> self#texpr rvalue_any e1; - let jsig = jsignature_of_type (type_of_module_type mt) in + let jsig = jsignature_of_type gctx (type_of_module_type mt) in if is_unboxed jsig || is_unboxed jm#get_code#get_stack#top then jm#cast jsig else code#checkcast (t_infos mt).mt_path; - if ret = RVoid then code#pop; + if not (need_val ret) then code#pop; | TParenthesis e1 | TMeta(_,e1) -> self#texpr ret e1 | TFor(v,e1,e2) -> @@ -2076,7 +1934,7 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return | TFun(tl,TEnum(en,_)) -> let n,_,t = List.nth tl i in en.e_path,n,self#vtype t - | _ -> assert false + | _ -> die "" __LOC__ in let cpath = ((fst path),Printf.sprintf "%s$%s" (snd path) ef.ef_name) in let jsig = (object_path_sig cpath) in @@ -2085,22 +1943,21 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return self#cast e.etype; | TThrow e1 -> self#texpr rvalue_any e1; - let exc = new haxe_exception gctx e1.etype in - if not (List.exists (fun exc' -> exc#is_assignable_to exc') caught_exceptions) then jm#add_thrown_exception exc#get_native_exception_path; - if not exc#is_native_exception then begin - let vt = self#vtype (self#mknull e1.etype) in - self#throw vt - end else begin - code#athrow; - jm#set_terminated true - end + if not (Exceptions.is_haxe_exception e1.etype) && not (type_unifies e1.etype gctx.t_runtime_exception) then begin + let exc = new haxe_exception gctx e1.etype in + if not (List.exists (fun exc' -> exc#is_assignable_to exc') caught_exceptions) then + jm#add_thrown_exception exc#get_native_path; + end; + code#athrow; + jm#set_terminated true | TObjectDecl fl -> - begin match follow e.etype with + let td = gctx.anon_identification#identify true e.etype in + begin match follow e.etype,td with (* The guard is here because in the case of quoted fields like `"a-b"`, the field is not part of the type. In this case we have to do full dynamic construction. *) - | TAnon an when List.for_all (fun ((name,_,_),_) -> PMap.mem name an.a_fields) fl -> - let path,fl' = TAnonIdentifiaction.identify gctx an.a_fields in - jm#construct ConstructInit path (fun () -> + | TAnon an,Some pfm when List.for_all (fun ((name,_,_),_) -> PMap.mem name an.a_fields) fl -> + let fl' = convert_fields gctx pfm.pfm_fields in + jm#construct ConstructInit pfm.pfm_path (fun () -> (* We have to respect declaration order, so let's temp var where necessary *) let rec loop fl fl' ok acc = match fl,fl' with | ((name,_,_),e) :: fl,(name',jsig) :: fl' -> @@ -2131,8 +1988,9 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return in let vars = loop fl fl' true [] in let vars = List.sort (fun (name1,_) (name2,_) -> compare name1 name2) vars in - List.iter (fun (_,load) -> + List.iter (fun (name,load) -> load(); + if List.mem_assoc name fl' then jm#cast (List.assoc name fl') ) vars; List.map snd fl'; ) @@ -2179,16 +2037,14 @@ let generate_dynamic_access gctx (jc : JvmClass.builder) fields is_anon = let jm = jc#spawn_method "_hx_getField" jsig [MPublic;MSynthetic] in let _,load,_ = jm#add_local "name" string_sig VarArgument in jm#finalize_arguments; - load(); - jm#invokevirtual string_path "hashCode" (method_sig [] (Some TInt)); let cases = List.map (fun (name,jsig,kind) -> - let hash = java_hash name in - [hash],(fun () -> - begin match kind with - | Method (MethNormal | MethInline) -> - jm#read_closure false jc#get_this_path name jsig; + [name],(fun () -> + begin match kind,jsig with + | Method (MethNormal | MethInline),TMethod(args,_) -> jm#load_this; - jm#invokevirtual method_handle_path "bindTo" (method_sig [object_sig] (Some method_handle_sig)); + jm#string name; + jm#new_native_array java_class_sig (List.map (fun jsig -> fun () -> jm#get_class jsig) args); + jm#invokestatic haxe_jvm_path "readFieldClosure" (method_sig [object_sig;string_sig;array_sig (java_class_sig)] (Some (object_sig))) | _ -> jm#load_this; jm#getfield jc#get_this_path name jsig; @@ -2203,7 +2059,7 @@ let generate_dynamic_access gctx (jc : JvmClass.builder) fields is_anon = load(); jm#invokespecial jc#get_super_path "_hx_getField" jsig; ) in - ignore(jm#int_switch false cases (Some def)); + jm#string_switch true load cases (Some def); jm#return end; let fields = List.filter (fun (_,_,kind) -> match kind with @@ -2240,14 +2096,14 @@ let generate_dynamic_access gctx (jc : JvmClass.builder) fields is_anon = jm#load_this; jm#getfield jc#get_this_path "_hx_deletedAField" boolean_sig; jm#if_then - (fun () -> jm#get_code#if_null_ref boolean_sig) + (jm#get_code#if_null boolean_sig) (fun () -> def(); ) end; ) ) fields in - ignore(jm#int_switch false cases (Some def)); + jm#int_switch false cases (Some def); jm#return end @@ -2271,11 +2127,11 @@ class tclass_to_jvm gctx c = object(self) end; if is_annotation then begin jc#add_access_flag 0x2000; - jc#add_interface (["java";"lang";"annotation"],"Annotation"); + jc#add_interface (["java";"lang";"annotation"],"Annotation") []; (* TODO: this should be done via Haxe metadata instead of hardcoding it here *) jc#add_annotation retention_path ["value",(AEnum(retention_policy_sig,"RUNTIME"))]; end; - if c.cl_path = (["haxe";"jvm"],"Enum") then jc#add_access_flag 0x4000; (* enum *) + if Meta.has Meta.JvmSynthetic c.cl_meta then jc#add_access_flag 0x1000 (* synthetic *) method private handle_relation_type_params = let map_type_params t = @@ -2295,26 +2151,26 @@ class tclass_to_jvm gctx c = object(self) let tr = loop tr in TFun(tl,tr) | _ -> - assert false + die "" __LOC__ in if !has_type_param then Some t else None in let make_bridge cf_impl t = - let jsig = jsignature_of_type t in + let jsig = jsignature_of_type gctx t in if not (jc#has_method cf_impl.cf_name jsig) then begin begin match follow t with | TFun(tl,tr) -> let jm = jc#spawn_method cf_impl.cf_name jsig [MPublic;MSynthetic;MBridge] in jm#load_this; - let jsig_impl = jsignature_of_type cf_impl.cf_type in - let jsigs,_ = match jsig_impl with TMethod(jsigs,jsig) -> jsigs,jsig | _ -> assert false in + let jsig_impl = jsignature_of_type gctx cf_impl.cf_type in + let jsigs,_ = match jsig_impl with TMethod(jsigs,jsig) -> jsigs,jsig | _ -> die "" __LOC__ in List.iter2 (fun (n,_,t) jsig -> - let _,load,_ = jm#add_local n (jsignature_of_type t) VarArgument in + let _,load,_ = jm#add_local n (jsignature_of_type gctx t) VarArgument in load(); jm#cast jsig; ) tl jsigs; jm#invokevirtual c.cl_path cf_impl.cf_name jsig_impl; - if not (ExtType.is_void (follow tr)) then jm#cast (jsignature_of_type tr); + if not (ExtType.is_void (follow tr)) then jm#cast (jsignature_of_type gctx tr); jm#return; | _ -> () @@ -2336,16 +2192,17 @@ class tclass_to_jvm gctx c = object(self) in let rec loop map_type c_int = List.iter (fun (c_int,tl) -> - let map_type t = apply_params c_int.cl_params tl (map_type t) in + (* Note: We have to apply parent params before child params (#9219). *) + let map_type t = map_type (apply_params c_int.cl_params tl t) in List.iter (fun cf -> match cf.cf_kind,raw_class_field (fun cf -> map_type cf.cf_type) c (List.map snd c.cl_params) cf.cf_name with | (Method (MethNormal | MethInline)),(Some(c',_),_,cf_impl) when c' == c -> let tl = match follow (map_type cf.cf_type) with | TFun(tl,_) -> tl - | _ -> assert false + | _ -> die "" __LOC__ in begin match find_overload_rec' false map_type c cf.cf_name (List.map (fun (_,_,t) -> Texpr.Builder.make_null t null_pos) tl) with - | Some(_,cf_impl) -> check true cf cf_impl + | Some(_,cf_impl,_) -> check true cf cf_impl | None -> () end; | _ -> @@ -2365,7 +2222,7 @@ class tclass_to_jvm gctx c = object(self) | _ -> () ) fields | _ -> - assert false + die "" __LOC__ end method private set_interfaces = @@ -2373,17 +2230,17 @@ class tclass_to_jvm gctx c = object(self) if is_annotation && c_int.cl_path = (["java";"lang";"annotation"],"Annotation") then () else begin - jc#add_interface c_int.cl_path + jc#add_interface c_int.cl_path (List.map (jtype_argument_of_type gctx []) tl) end ) c.cl_implements method private generate_empty_ctor = let jsig_empty = method_sig [haxe_empty_constructor_sig] None in - let jm_empty_ctor = jc#spawn_method "" jsig_empty [MPublic] in + let jm_empty_ctor = jc#spawn_method "" jsig_empty [MPublic;MSynthetic] in let _,load,_ = jm_empty_ctor#add_local "_" haxe_empty_constructor_sig VarArgument in jm_empty_ctor#load_this; if c.cl_constructor = None then begin - let handler = new texpr_to_jvm gctx jc jm_empty_ctor gctx.com.basic.tvoid in + let handler = new texpr_to_jvm gctx jc jm_empty_ctor None in DynArray.iter (fun e -> handler#texpr RVoid e; ) field_inits; @@ -2398,27 +2255,27 @@ class tclass_to_jvm gctx c = object(self) jm_empty_ctor#call_super_ctor ConstructInit jsig_empty end; if c.cl_constructor = None then begin - let handler = new texpr_to_jvm gctx jc jm_empty_ctor gctx.com.basic.tvoid in + let handler = new texpr_to_jvm gctx jc jm_empty_ctor None in DynArray.iter (fun e -> handler#texpr RVoid e; ) delayed_field_inits; end; - jm_empty_ctor#get_code#return_void; + jm_empty_ctor#return; method private generate_implicit_ctors = try - let sm = Hashtbl.find gctx.implicit_ctors c.cl_path in + let sm = gctx.preprocessor#get_implicit_ctor c.cl_path in PMap.iter (fun _ (c,cf) -> let cmode = get_construction_mode c cf in - let jm = jc#spawn_method (if cmode = ConstructInit then "" else "new") (jsignature_of_type cf.cf_type) [MPublic] in - let handler = new texpr_to_jvm gctx jc jm gctx.com.basic.tvoid in + let jm = jc#spawn_method (if cmode = ConstructInit then "" else "new") (jsignature_of_type gctx cf.cf_type) [MPublic] in + let handler = new texpr_to_jvm gctx jc jm None in jm#load_this; DynArray.iter (fun e -> handler#texpr RVoid e; ) field_inits; - let tl = match follow cf.cf_type with TFun(tl,_) -> tl | _ -> assert false in + let tl = match follow cf.cf_type with TFun(tl,_) -> tl | _ -> die "" __LOC__ in List.iter (fun (n,_,t) -> - let _,load,_ = jm#add_local n (jsignature_of_type t) VarArgument in + let _,load,_ = jm#add_local n (jsignature_of_type gctx t) VarArgument in load(); ) tl; jm#call_super_ctor cmode jm#get_jsig; @@ -2433,9 +2290,9 @@ class tclass_to_jvm gctx c = object(self) method generate_expr gctx jc jm e is_method scmode mtype = let e,args,tr = match e.eexpr with | TFunction tf when is_method -> - tf.tf_expr,tf.tf_args,tf.tf_type + tf.tf_expr,tf.tf_args,(return_of_type gctx tf.tf_type) | _ -> - e,[],t_dynamic + e,[],None in let handler = new texpr_to_jvm gctx jc jm tr in List.iter (fun (v,_) -> @@ -2466,12 +2323,14 @@ class tclass_to_jvm gctx c = object(self) handler#texpr RReturn e method generate_method gctx jc c mtype cf = - gctx.current_field_info <- get_field_info gctx cf.cf_meta; - let jsig = jsignature_of_type cf.cf_type in - let flags = [MPublic] in + gctx.current_field_info <- gctx.preprocessor#get_field_info cf.cf_meta; + let jsig = jsignature_of_type gctx cf.cf_type in + let flags = if Meta.has Meta.Private cf.cf_meta then [MPrivate] else if Meta.has Meta.Protected cf.cf_meta then [MProtected] else [MPublic] in let flags = if c.cl_interface then MAbstract :: flags else flags in let flags = if mtype = MStatic then MethodAccessFlags.MStatic :: flags else flags in let flags = if has_class_field_flag cf CfFinal then MFinal :: flags else flags in + let flags = if Meta.has Meta.JvmSynthetic cf.cf_meta then MSynthetic :: flags else flags in + let flags = if Meta.has Meta.NativeJni cf.cf_meta then MNative :: flags else flags in let name,scmode,flags = match mtype with | MConstructor -> let rec has_super_ctor c = match c.cl_super with @@ -2496,7 +2355,7 @@ class tclass_to_jvm gctx c = object(self) let stl = String.concat "" (List.map (fun (n,_) -> Printf.sprintf "%s:Ljava/lang/Object;" n ) cf.cf_params) in - let ssig = generate_method_signature true (jsignature_of_type cf.cf_type) in + let ssig = generate_method_signature true (jsignature_of_type gctx cf.cf_type) in let s = if cf.cf_params = [] then ssig else Printf.sprintf "<%s>%s" stl ssig in let offset = jc#get_pool#add_string s in jm#add_attribute (AttributeSignature offset); @@ -2504,9 +2363,10 @@ class tclass_to_jvm gctx c = object(self) AnnotationHandler.generate_annotations (jm :> JvmBuilder.base_builder) cf.cf_meta; method generate_field gctx (jc : JvmClass.builder) c mtype cf = - let jsig = jsignature_of_type cf.cf_type in - let flags = [FdPublic] in + let jsig = jsignature_of_type gctx cf.cf_type in + let flags = if Meta.has Meta.Private cf.cf_meta then [FdPrivate] else if Meta.has Meta.Protected cf.cf_meta then [FdProtected] else [FdPublic] in let flags = if mtype = MStatic then FdStatic :: flags else flags in + let flags = if Meta.has Meta.JvmSynthetic cf.cf_meta then FdSynthetic :: flags else flags in let jm = jc#spawn_field cf.cf_name jsig flags in let default e = let p = null_pos in @@ -2548,74 +2408,53 @@ class tclass_to_jvm gctx c = object(self) | _ -> default e; end; - let ssig = generate_signature true (jsignature_of_type cf.cf_type) in + let ssig = generate_signature true (jsignature_of_type gctx cf.cf_type) in let offset = jc#get_pool#add_string ssig in jm#add_attribute (AttributeSignature offset) - method generate_main = - let jsig = method_sig [array_sig string_sig] None in - let jm = jc#spawn_method "main" jsig [MPublic;MStatic] in - let _,load,_ = jm#add_local "args" (TArray(string_sig,None)) VarArgument in - if has_feature gctx.com "haxe.root.Sys.args" then begin - load(); - jm#putstatic (["haxe";"root"],"Sys") "_args" (TArray(string_sig,None)) - end; - jm#invokestatic (["haxe"; "java"], "Init") "init" (method_sig [] None); - jm#invokestatic jc#get_this_path "main" (method_sig [] None); - jm#return - - method private generate_fields = - let field mtype cf = match cf.cf_kind with - | Method (MethNormal | MethInline) -> - List.iter (fun cf -> - failsafe cf.cf_pos (fun () -> self#generate_method gctx jc c mtype cf); - if cf.cf_name = "main" then self#generate_main; - ) (cf :: List.filter (fun cf -> Meta.has Meta.Overload cf.cf_meta) cf.cf_overloads) - | _ -> - if not c.cl_interface && is_physical_field cf then failsafe cf.cf_pos (fun () -> self#generate_field gctx jc c mtype cf) - in - List.iter (field MStatic) c.cl_ordered_statics; - List.iter (field MInstance) c.cl_ordered_fields; - begin match c.cl_constructor,c.cl_super with - | Some cf,Some _ -> field MConstructor cf - | Some cf,None -> field MConstructor cf - | None,_ -> () - end; - begin match c.cl_init with - | None -> - () - | Some e -> - let cf = mk_field "" (tfun [] gctx.com.basic.tvoid) null_pos null_pos in - cf.cf_kind <- Method MethNormal; - let tf = { - tf_args = []; - tf_type = gctx.com.basic.tvoid; - tf_expr = mk_block e; - } in - let e = mk (TFunction tf) cf.cf_type null_pos in - cf.cf_expr <- Some e; - field MStatic cf - end + method generate_main e = + let jsig = method_sig [array_sig string_sig] None in + let jm = jc#spawn_method "main" jsig [MPublic;MStatic] in + let _,load,_ = jm#add_local "args" (TArray(string_sig,None)) VarArgument in + if has_feature gctx.com "haxe.root.Sys.args" then begin + load(); + jm#putstatic (["haxe";"root"],"Sys") "_args" (TArray(string_sig,None)) + end; + jm#invokestatic (["haxe"; "java"], "Init") "init" (method_sig [] None); + self#generate_expr gctx jc jm e true SCNone MStatic; + if not jm#is_terminated then jm#return + + method private generate_fields = + let field mtype cf = match cf.cf_kind with + | Method (MethNormal | MethInline) -> + List.iter (fun cf -> + failsafe cf.cf_pos (fun () -> self#generate_method gctx jc c mtype cf); + ) (cf :: List.filter (fun cf -> Meta.has Meta.Overload cf.cf_meta) cf.cf_overloads) + | _ -> + if not c.cl_interface && is_physical_field cf then failsafe cf.cf_pos (fun () -> self#generate_field gctx jc c mtype cf) + in + Option.may (fun (c2,e) -> if c2 == c then self#generate_main e) gctx.entry_point; + List.iter (field MStatic) c.cl_ordered_statics; + List.iter (field MInstance) c.cl_ordered_fields; + begin match c.cl_constructor,c.cl_super with + | Some cf,Some _ -> field MConstructor cf + | Some cf,None -> field MConstructor cf + | None,_ -> () + end; + begin match c.cl_init with + | None -> + () + | Some e -> + let jm = jc#get_static_init_method in + let handler = new texpr_to_jvm gctx jc jm None in + handler#texpr RReturn (mk_block e); + end method private generate_signature = - let stl = match c.cl_params with - | [] -> "" - | params -> - let stl = String.concat "" (List.map (fun (n,_) -> - Printf.sprintf "%s:Ljava/lang/Object;" n - ) c.cl_params) in - Printf.sprintf "<%s>" stl - in - let ssuper = match c.cl_super with - | Some(c,tl) -> generate_method_signature true (jsignature_of_type (TInst(c,tl))) - | None -> generate_method_signature true object_sig - in - let sinterfaces = String.concat "" (List.map (fun(c,tl) -> - generate_method_signature true (jsignature_of_type (TInst(c,tl))) - ) c.cl_implements) in - let s = Printf.sprintf "%s%s%s" stl ssuper sinterfaces in - let offset = jc#get_pool#add_string s in - jc#add_attribute (AttributeSignature offset) + jc#set_type_parameters (List.map fst c.cl_params); + match c.cl_super with + | Some(c,tl) -> jc#set_super_parameters (List.map (jtype_argument_of_type gctx []) tl) + | _ -> () method generate_annotations = AnnotationHandler.generate_annotations (jc :> JvmBuilder.base_builder) c.cl_meta; @@ -2623,6 +2462,7 @@ class tclass_to_jvm gctx c = object(self) method generate = self#set_access_flags; + jc#set_source_file c.cl_pos.pfile; self#generate_fields; self#set_interfaces; if not c.cl_interface then begin @@ -2631,10 +2471,9 @@ class tclass_to_jvm gctx c = object(self) self#handle_relation_type_params; end; self#generate_signature; - if not (Meta.has Meta.NativeGen c.cl_meta) then - generate_dynamic_access gctx jc (List.map (fun cf -> cf.cf_name,jsignature_of_type cf.cf_type,cf.cf_kind) c.cl_ordered_fields) false; + if not (Meta.has Meta.NativeGen c.cl_meta) && not c.cl_interface then + generate_dynamic_access gctx jc (List.map (fun cf -> cf.cf_name,jsignature_of_type gctx cf.cf_type,cf.cf_kind) c.cl_ordered_fields) false; self#generate_annotations; - jc#add_attribute (AttributeSourceFile (jc#get_pool#add_string c.cl_pos.pfile)); let jc = jc#export_class gctx.default_export_config in write_class gctx.jar c.cl_path jc end @@ -2643,17 +2482,60 @@ let generate_class gctx c = let conv = new tclass_to_jvm gctx c in conv#generate +let generate_enum_equals gctx (jc_ctor : JvmClass.builder) = + let jm_equals,load = generate_equals_function jc_ctor (haxe_enum_sig object_sig) in + let code = jm_equals#get_code in + let jm_equals_handler = new texpr_to_jvm gctx jc_ctor jm_equals (Some TBool) in + let is_maybe_enum jsig = match jsig with + | TObject _ | TTypeParameter _ -> true + | _ -> false + in + let compare jsig = + if is_maybe_enum jsig then begin + jm_equals#if_then_else + (jm_equals_handler#apply_cmp (jm_equals_handler#do_compare CmpNe)) + (fun () -> + jm_equals#invokestatic haxe_jvm_path "enumEq" (method_sig [object_sig;object_sig] (Some TBool)); + jm_equals#if_then + (code#if_ CmpNe) + (fun () -> + code#bconst false; + jm_equals#return; + ) + ) + (fun () -> + code#pop; + code#pop; + ) + end else + jm_equals#if_then + (jm_equals_handler#apply_cmp (jm_equals_handler#do_compare CmpNe)) + (fun () -> + code#bconst false; + jm_equals#return; + ); + in + load(); + jm_equals#invokevirtual java_enum_path "ordinal" (method_sig [] (Some TInt)); + jm_equals#load_this; + jm_equals#invokevirtual java_enum_path "ordinal" (method_sig [] (Some TInt)); + compare TInt; + let compare_field n jsig = + load(); + jm_equals#getfield jc_ctor#get_this_path n jsig; + if is_maybe_enum jsig then code#dup; + jm_equals#load_this; + jm_equals#getfield jc_ctor#get_this_path n jsig; + if is_maybe_enum jsig then code#dup_x1; + compare jsig; + in + jm_equals,compare_field + let generate_enum gctx en = let jc_enum = new JvmClass.builder en.e_path haxe_enum_path in jc_enum#add_access_flag 0x1; (* public *) jc_enum#add_access_flag 0x400; (* abstract *) - jc_enum#add_access_flag 0x4000; (* enum *) - begin - let jsig = haxe_enum_sig (object_path_sig en.e_path) in - let s = generate_signature true jsig in - let offset = jc_enum#get_pool#add_string s in - jc_enum#add_attribute (AttributeSignature offset) - end; + if Meta.has Meta.JvmSynthetic en.e_meta then jc_enum#add_access_flag 0x1000; (* synthetic *) let jsig_enum_ctor = method_sig [TInt;string_sig] None in (* Create base constructor *) begin @@ -2664,13 +2546,13 @@ let generate_enum gctx en = load1(); load2(); jm_ctor#call_super_ctor ConstructInit jsig_enum_ctor; - jm_ctor#get_code#return_void; + jm_ctor#return; end; let inits = DynArray.create () in let names = List.map (fun name -> let ef = PMap.find name en.e_constrs in let args = match follow ef.ef_type with - | TFun(tl,_) -> List.map (fun (n,_,t) -> n,jsignature_of_type t) tl + | TFun(tl,_) -> List.map (fun (n,_,t) -> n,jsignature_of_type gctx t) tl | _ -> [] in let jsigs = List.map snd args in @@ -2678,7 +2560,6 @@ let generate_enum gctx en = let jc_ctor = begin let jc_ctor = jc_enum#spawn_inner_class None jc_enum#get_this_path (Some ef.ef_name) in jc_ctor#add_access_flag 0x10; (* final *) - jc_ctor#add_access_flag 0x4000; (* enum *) let jsig_method = method_sig jsigs None in let jm_ctor = jc_ctor#spawn_method "" jsig_method [MPublic] in jm_ctor#load_this; @@ -2688,17 +2569,21 @@ let generate_enum gctx en = List.iter (fun (n,jsig) -> jm_ctor#add_argument_and_field n jsig ) args; - jm_ctor#get_code#return_void; + jm_ctor#return; jc_ctor#add_annotation (["haxe";"jvm";"annotation"],"EnumValueReflectionInformation") (["argumentNames",AArray (List.map (fun (name,_) -> AString name) args)]); if args <> [] then begin - let jm_params = jc_ctor#spawn_method "_hx_getParameters" (method_sig [] (Some (array_sig object_sig))) [MPublic] in + let jm_params = jc_ctor#spawn_method "_hx_getParameters" (method_sig [] (Some (array_sig object_sig))) [MPublic;MSynthetic] in + let jm_equals,compare_field = generate_enum_equals gctx jc_ctor in let fl = List.map (fun (n,jsig) -> + compare_field n jsig; (fun () -> jm_params#load_this; jm_params#getfield jc_ctor#get_this_path n jsig; jm_params#cast object_sig; ) ) args in + jm_equals#get_code#bconst true; + jm_equals#return; jm_params#new_native_array object_sig fl; jm_params#return end; @@ -2721,7 +2606,7 @@ let generate_enum gctx en = ) args; jsigs; ); - jm_static#get_code#return_value jc_enum#get_jsig; + jm_static#return; end; AString name ) en.e_names in @@ -2745,11 +2630,11 @@ let generate_enum gctx en = () | Some e -> ignore(jc_enum#spawn_field "__meta__" object_sig [FdStatic;FdPublic]); - let handler = new texpr_to_jvm gctx jc_enum jm_clinit (gctx.com.basic.tvoid) in + let handler = new texpr_to_jvm gctx jc_enum jm_clinit None in handler#texpr rvalue_any e; jm_clinit#putstatic jc_enum#get_this_path "__meta__" object_sig end; - jm_clinit#get_code#return_void; + jm_clinit#return; end; AnnotationHandler.generate_annotations (jc_enum :> JvmBuilder.base_builder) en.e_meta; jc_enum#add_annotation (["haxe";"jvm";"annotation"],"EnumReflectionInformation") (["constructorNames",AArray names]); @@ -2767,275 +2652,184 @@ let debug_path path = match path with | (["haxe";"lang"],_) -> false (* Old Haxe/Java stuff that's weird *) | _ -> true -let is_extern_abstract a = match a.a_impl with - | Some {cl_extern = true} -> true - | _ -> false - let generate_module_type ctx mt = failsafe (t_infos mt).mt_pos (fun () -> match mt with | TClassDecl c when not c.cl_extern && debug_path c.cl_path -> generate_class ctx c | TEnumDecl en when not en.e_extern -> generate_enum ctx en - | TAbstractDecl a when not (is_extern_abstract a) && Meta.has Meta.CoreType a.a_meta -> generate_abstract ctx a | _ -> () ) -module Preprocessor = struct - - let is_normal_anon an = match !(an.a_status) with - | Closed | Const | Opened -> true - | _ -> false - - let check_anon gctx e = match e.etype,follow e.etype with - | TType(td,_),TAnon an when is_normal_anon an -> - ignore(TAnonIdentifiaction.identify_as gctx td.t_path an.a_fields) - | _ -> - () - - let add_implicit_ctor gctx c c' cf = - let jsig = jsignature_of_type cf.cf_type in - try - let sm = Hashtbl.find gctx.implicit_ctors c.cl_path in - Hashtbl.replace gctx.implicit_ctors c.cl_path (PMap.add (c'.cl_path,jsig) (c',cf) sm); - with Not_found -> - Hashtbl.add gctx.implicit_ctors c.cl_path (PMap.add (c'.cl_path,jsig) (c',cf) PMap.empty) - - let make_native cf = - cf.cf_meta <- (Meta.NativeGen,[],null_pos) :: cf.cf_meta - - let make_haxe cf = - cf.cf_meta <- (Meta.HxGen,[],null_pos) :: cf.cf_meta - - let preprocess_constructor_expr gctx c cf e = - let used_this = ref false in - let this_before_super = ref false in - let super_call_fields = DynArray.create () in - let is_on_current_class cf = PMap.mem cf.cf_name c.cl_fields in - let find_super_ctor el = - let csup,map_type = match c.cl_super with - | Some(c,tl) -> c,apply_params c.cl_params tl - | _ -> assert false - in - match find_overload_rec' true map_type csup "new" el with - | Some(c,cf) -> - let rec loop csup = - if c != csup then begin - match csup.cl_super with - | Some(c',_) -> - add_implicit_ctor gctx csup c' cf; - loop c' - | None -> assert false - end - in - loop csup; - (c,cf) - | None -> Error.error "Could not find overload constructor" e.epos - in - let rec promote_this_before_super c cf = match get_field_info gctx cf.cf_meta with - | None -> jerror "Something went wrong" - | Some info -> - if not info.has_this_before_super then begin - make_haxe cf; - (* print_endline (Printf.sprintf "promoted this_before_super to %s.new : %s" (s_type_path c.cl_path) (s_type (print_context()) cf.cf_type)); *) - info.has_this_before_super <- true; - List.iter (fun (c,cf) -> promote_this_before_super c cf) info.super_call_fields - end - in - let rec loop e = - check_anon gctx e; - begin match e.eexpr with - | TBinop(OpAssign,{eexpr = TField({eexpr = TConst TThis},FInstance(_,_,cf))},e2) when is_on_current_class cf-> - (* Assigning this.field = value is fine if field is declared on our current class *) - loop e2; - | TConst TThis -> - used_this := true - | TCall({eexpr = TConst TSuper},el) -> - List.iter loop el; - if !used_this then begin - this_before_super := true; - make_haxe cf; - (* print_endline (Printf.sprintf "inferred this_before_super on %s.new : %s" (s_type_path c.cl_path) (s_type (print_context()) cf.cf_type)); *) - end; - let c,cf = find_super_ctor el in - if !this_before_super then promote_this_before_super c cf; - DynArray.add super_call_fields (c,cf); - | _ -> - Type.iter loop e - end; - in - loop e; - { - has_this_before_super = !this_before_super; - super_call_fields = DynArray.to_list super_call_fields; - } - - let preprocess_expr gctx e = - let rec loop e = - check_anon gctx e; - Type.iter loop e - in - loop e - - let check_overrides c = match c.cl_overrides with - | []-> +let generate_anons gctx = + Hashtbl.iter (fun path pfm -> + let fields = convert_fields gctx pfm.pfm_fields in + let jc = new JvmClass.builder path haxe_dynamic_object_path in + jc#add_access_flag 0x1; + begin + let jm_ctor = jc#spawn_method "" (method_sig (List.map snd fields) None) [MPublic] in + jm_ctor#load_this; + jm_ctor#get_code#aconst_null haxe_empty_constructor_sig; + jm_ctor#call_super_ctor ConstructInit (method_sig [haxe_empty_constructor_sig] None); + List.iter (fun (name,jsig) -> + jm_ctor#add_argument_and_field name jsig; + ) fields; + jm_ctor#return; + end; + begin + let string_map_path = (["haxe";"ds"],"StringMap") in + let string_map_sig = object_path_sig string_map_path in + let jm_fields = jc#spawn_method "_hx_getKnownFields" (method_sig [] (Some string_map_sig)) [MProtected;MSynthetic] in + let _,load,save = jm_fields#add_local "tmp" string_map_sig VarWillInit in + jm_fields#construct ConstructInit string_map_path (fun () -> []); + save(); + List.iter (fun (name,jsig) -> + load(); + let offset = jc#get_pool#add_const_string name in + jm_fields#get_code#sconst (string_sig) offset; + jm_fields#load_this; + jm_fields#getfield jc#get_this_path name jsig; + jm_fields#expect_reference_type; + jm_fields#invokevirtual string_map_path "set" (method_sig [string_sig;object_sig] None); + ) fields; + load(); + jm_fields#return + end; + generate_dynamic_access gctx jc (List.map (fun (name,jsig) -> name,jsig,Var {v_write = AccNormal;v_read = AccNormal}) fields) true; + begin match gctx.typedef_interfaces#get_interface_class path with + | None -> () - | fields -> - let csup,map_type = match c.cl_super with - | Some(c,tl) -> c,apply_params c.cl_params tl - | None -> assert false - in - let fix_covariant_return cf = - let tl = match follow cf.cf_type with - | TFun(tl,_) -> tl - | _ -> assert false - in - match find_overload_rec' false map_type csup cf.cf_name (List.map (fun (_,_,t) -> Texpr.Builder.make_null t null_pos) tl) with - | Some(_,cf') -> - let tr = match follow cf'.cf_type with - | TFun(_,tr) -> tr - | _ -> assert false - in - cf.cf_type <- TFun(tl,tr); - cf.cf_expr <- begin match cf.cf_expr with - | Some ({eexpr = TFunction tf} as e) -> - Some {e with eexpr = TFunction {tf with tf_type = tr}} - | e -> - e - end; - | None -> - () - (* TODO: this should never happen if we get the unification right *) - (* Error.error "Could not find overload" cf.cf_pos *) - in + | Some c -> + jc#add_interface c.cl_path []; List.iter (fun cf -> - fix_covariant_return cf; - List.iter fix_covariant_return cf.cf_overloads - ) fields + let jsig_cf = jsignature_of_type gctx cf.cf_type in + let jm = jc#spawn_method cf.cf_name jsig_cf [MPublic] in + let tl,tr = match follow cf.cf_type with + | TFun(tl,tr) -> tl,tr + | _ -> die "" __LOC__ + in + let locals = List.map (fun (n,_,t) -> + let jsig = jsignature_of_type gctx t in + jm#add_local n jsig VarArgument,jsig + ) tl in + jm#finalize_arguments; + jm#load_this; + jm#getfield path cf.cf_name jsig_cf; + List.iter (fun ((_,load,_),_) -> + load(); + ) locals; + let jret = return_of_type gctx tr in + let meth = gctx.typed_functions#register_signature (List.map snd locals) jret in + jm#invokevirtual haxe_function_path meth.name (method_sig meth.dargs meth.dret); + Option.may jm#cast jret; + jm#return + ) c.cl_ordered_fields + end; + write_class gctx.jar path (jc#export_class gctx.default_export_config) + ) gctx.anon_identification#get_anons - let rec get_constructor c = - match c.cl_constructor, c.cl_super with - | Some cf, _ -> c,cf - | None, None -> raise Not_found - | None, Some (csup,cparams) -> get_constructor csup - - let preprocess_class gctx c = - let field cf = match cf.cf_expr with - | None -> - () - | Some e -> - preprocess_expr gctx e - in - let has_dynamic_instance_method = ref false in - let has_field_init = ref false in - let field mtype cf = - List.iter field (cf :: cf.cf_overloads); - match mtype with - | MConstructor -> - () - | MInstance -> - begin match cf.cf_kind with - | Method MethDynamic -> has_dynamic_instance_method := true - | Var _ when cf.cf_expr <> None && not !has_field_init && c.cl_constructor = None && c.cl_super = None -> - has_field_init := true; - add_implicit_ctor gctx c c (mk_field "new" (tfun [] gctx.com.basic.tvoid) null_pos null_pos) - | _ -> () - end; - | MStatic -> - () - in - check_overrides c; - List.iter (field MStatic) c.cl_ordered_statics; - List.iter (field MInstance) c.cl_ordered_fields; - match c.cl_constructor with - | None -> - begin try - let csup,cf = get_constructor c in - List.iter (fun cf -> add_implicit_ctor gctx c csup cf) (cf :: cf.cf_overloads) - with Not_found -> - () - end; - | Some cf -> - let field cf = - if !has_dynamic_instance_method then make_haxe cf; - begin match cf.cf_expr with - | None -> - () - | Some e -> - let info = preprocess_constructor_expr gctx c cf e in - let index = DynArray.length gctx.field_infos in - DynArray.add gctx.field_infos info; - cf.cf_meta <- (Meta.Custom ":jvm.fieldInfo",[(EConst (Int (string_of_int index)),null_pos)],null_pos) :: cf.cf_meta; - if not (Meta.has Meta.HxGen cf.cf_meta) then begin - let rec loop next c = - if c.cl_extern then make_native cf - else match c.cl_constructor with - | Some cf' when Meta.has Meta.HxGen cf'.cf_meta -> make_haxe cf - | Some cf' when Meta.has Meta.NativeGen cf'.cf_meta -> make_native cf - | _ -> next c - in - let rec up c = match c.cl_super with - | None -> () - | Some(c,_) -> loop up c - in - let rec down c = List.iter (fun c -> loop down c) c.cl_descendants in - loop up c; - loop down c - end; - end - in - List.iter field (cf :: cf.cf_overloads) +let generate_typed_functions gctx = + let jc_function = gctx.typed_functions#generate in + write_class gctx.jar jc_function#get_this_path (jc_function#export_class gctx.default_export_config); + let jc_varargs = gctx.typed_functions#generate_var_args in + write_class gctx.jar jc_varargs#get_this_path (jc_varargs#export_class gctx.default_export_config); + let jc_closure_dispatch = gctx.typed_functions#generate_closure_dispatch in + write_class gctx.jar jc_closure_dispatch#get_this_path (jc_closure_dispatch#export_class gctx.default_export_config) +module Preprocessor = struct let make_root path = ["haxe";"root"],snd path + let check_path mt = + (* don't rewrite if there's an explicit @:native *) + if Meta.has Meta.Native mt.mt_meta then + () + else if mt.mt_private then begin + let m = mt.mt_module in + mt.mt_path <- (fst m.m_path,Printf.sprintf "%s$%s" (snd m.m_path) (snd mt.mt_path)) + end else if fst mt.mt_path = [] then + mt.mt_path <- make_root mt.mt_path + let preprocess gctx = + let rec has_runtime_meta = function + | (Meta.Custom s,_,_) :: _ when String.length s > 0 && s.[0] <> ':' -> + true + | _ :: l -> + has_runtime_meta l + | [] -> + false + in + (* go through com.modules so we can also pick up private typedefs *) + List.iter (fun m -> + List.iter (fun mt -> + match mt with + | TClassDecl ({cl_interface=true} as c) when has_runtime_meta c.cl_meta -> + () (* TODO: run-time interface metadata is a problem (issue #2042) *) + | TClassDecl _ | TEnumDecl _ -> + check_path (t_infos mt); + | TTypeDecl td -> + check_path (t_infos mt); + gctx.anon_identification#identify_typedef td + | _ -> + () + ) m.m_types + ) gctx.com.modules; + (* preprocess classes *) List.iter (fun mt -> match mt with | TClassDecl c -> - if fst c.cl_path = [] then c.cl_path <- make_root c.cl_path; - if debug_path c.cl_path && not c.cl_interface then preprocess_class gctx c - | TEnumDecl en -> - if fst en.e_path = [] then en.e_path <- make_root en.e_path; + if debug_path c.cl_path && not c.cl_interface then gctx.preprocessor#preprocess_class c | _ -> () + ) gctx.com.types; + (* find typedef-interface implementations *) + List.iter (fun mt -> match mt with + | TClassDecl c when debug_path c.cl_path && not c.cl_interface && not c.cl_extern -> + gctx.typedef_interfaces#process_class c; + | _ -> + () ) gctx.com.types end let file_name_and_extension file = match List.rev (ExtString.String.nsplit file "/") with | e1 :: _ -> e1 - | _ -> assert false + | _ -> die "" __LOC__ let generate com = mkdir_from_path com.file; - let jar_name,manifest_suffix = match com.main_class with - | Some path -> - let pack = match fst path with + let jar_name,manifest_suffix,entry_point = match get_entry_point com with + | Some (jarname,cl,expr) -> + let pack = match fst cl.cl_path with | [] -> ["haxe";"root"] | pack -> pack in - let name = snd path in - name,"\nMain-Class: " ^ (s_type_path (pack,name)) - | None -> "jar","" + jarname,"\nMain-Class: " ^ (s_type_path (pack,snd cl.cl_path)), Some (cl,expr) + | None -> "jar","",None in let jar_name = if com.debug then jar_name ^ "-Debug" else jar_name in let jar_dir = add_trailing_slash com.file in let jar_path = Printf.sprintf "%s%s.jar" jar_dir jar_name in + let anon_identification = new tanon_identification haxe_dynamic_object_path in let gctx = { com = com; jar = Zip.open_out jar_path; + t_runtime_exception = TInst(resolve_class com (["java";"lang"],"RuntimeException"),[]); + entry_point = entry_point; t_exception = TInst(resolve_class com (["java";"lang"],"Exception"),[]); t_throwable = TInst(resolve_class com (["java";"lang"],"Throwable"),[]); - anon_lut = Hashtbl.create 0; - anon_path_lut = Hashtbl.create 0; - anon_num = 0; - implicit_ctors = Hashtbl.create 0; - field_infos = DynArray.create(); + anon_identification = anon_identification; + preprocessor = Obj.magic (); + typedef_interfaces = Obj.magic (); + typed_functions = new JvmFunctions.typed_functions; + closure_paths = Hashtbl.create 0; current_field_info = None; default_export_config = { - export_debug = com.debug; + export_debug = true; } } in - Std.finally (Timer.timer ["generate";"java";"preprocess"]) Preprocessor.preprocess gctx; + gctx.anon_identification <- anon_identification; + gctx.preprocessor <- new preprocessor com.basic (jsignature_of_type gctx); + gctx.typedef_interfaces <- new typedef_interfaces anon_identification; + gctx.typedef_interfaces#add_interface_rewrite (["haxe";"root"],"Iterator") (["java";"util"],"Iterator") true; let class_paths = ExtList.List.filter_map (fun java_lib -> if java_lib#has_flag NativeLibraries.FlagIsStd then None else begin @@ -3063,40 +2857,15 @@ let generate com = let filename = Codegen.escape_res_name name true in Zip.add_entry v gctx.jar filename; ) com.resources; - List.iter (generate_module_type gctx) com.types; - Hashtbl.iter (fun fields path -> - let jc = new JvmClass.builder path haxe_dynamic_object_path in - jc#add_access_flag 0x1; - begin - let jm_ctor = jc#spawn_method "" (method_sig (List.map snd fields) None) [MPublic] in - jm_ctor#load_this; - jm_ctor#get_code#aconst_null haxe_empty_constructor_sig; - jm_ctor#call_super_ctor ConstructInit (method_sig [haxe_empty_constructor_sig] None); - List.iter (fun (name,jsig) -> - jm_ctor#add_argument_and_field name jsig; - ) fields; - jm_ctor#get_code#return_void; - end; - begin - let string_map_path = (["haxe";"ds"],"StringMap") in - let string_map_sig = object_path_sig string_map_path in - let jm_fields = jc#spawn_method "_hx_getKnownFields" (method_sig [] (Some string_map_sig)) [MProtected] in - let _,load,save = jm_fields#add_local "tmp" string_map_sig VarWillInit in - jm_fields#construct ConstructInit string_map_path (fun () -> []); - save(); - List.iter (fun (name,jsig) -> - load(); - let offset = jc#get_pool#add_const_string name in - jm_fields#get_code#sconst (string_sig) offset; - jm_fields#load_this; - jm_fields#getfield jc#get_this_path name jsig; - jm_fields#expect_reference_type; - jm_fields#invokevirtual string_map_path "set" (method_sig [string_sig;object_sig] None); - ) fields; - load(); - jm_fields#get_code#return_value string_map_sig - end; - generate_dynamic_access gctx jc (List.map (fun (name,jsig) -> name,jsig,Var {v_write = AccNormal;v_read = AccNormal}) fields) true; - write_class gctx.jar path (jc#export_class gctx.default_export_config) - ) gctx.anon_lut; + let generate_real_types () = + List.iter (generate_module_type gctx) com.types; + in + let generate_typed_interfaces () = + Hashtbl.iter (fun _ c -> generate_module_type gctx (TClassDecl c)) gctx.typedef_interfaces#get_interfaces; + in + Std.finally (Timer.timer ["generate";"java";"preprocess"]) Preprocessor.preprocess gctx; + Std.finally (Timer.timer ["generate";"java";"real types"]) generate_real_types (); + Std.finally (Timer.timer ["generate";"java";"typed interfaces"]) generate_typed_interfaces (); + Std.finally (Timer.timer ["generate";"java";"anons"]) generate_anons gctx; + Std.finally (Timer.timer ["generate";"java";"typed functions"]) generate_typed_functions gctx; Zip.close_out gctx.jar \ No newline at end of file diff --git a/src/generators/genlua.ml b/src/generators/genlua.ml index e15bddd7edad421e17f377b446fb1329325932ad..8e9fb8489c5b47a81af41ecc8a0ef19fc7577c14 100644 --- a/src/generators/genlua.ml +++ b/src/generators/genlua.ml @@ -146,9 +146,7 @@ let spr ctx s = let print ctx = ctx.separator <- false; - Printf.kprintf (fun s -> begin - Buffer.add_string ctx.buf s - end) + Printf.kprintf (fun s -> Buffer.add_string ctx.buf s) let newline ctx = print ctx "\n%s" ctx.tabs @@ -237,7 +235,7 @@ let mk_mr_box ctx e = match follow e.etype with | TInst (c,_) -> String.concat ", " (List.map (fun f -> "\"" ^ f.cf_name ^ "\"") c.cl_ordered_fields) - | _ -> assert false + | _ -> Globals.die "" __LOC__ in add_feature ctx "use._hx_box_mr"; add_feature ctx "use._hx_table"; @@ -251,7 +249,7 @@ let mk_mr_select com e ecall name = | TInst (c,_) -> index_of (fun f -> f.cf_name = name) c.cl_ordered_fields | _ -> - assert false + Globals.die "" __LOC__ in if i == 0 then mk_lua_code com "{0}" [ecall] e.etype e.epos @@ -320,7 +318,7 @@ let gen_constant ctx p = function | TBool b -> spr ctx (if b then "true" else "false") | TNull -> spr ctx "nil" | TThis -> spr ctx (this ctx) - | TSuper -> assert false + | TSuper -> Globals.die "" __LOC__ @@ -460,7 +458,7 @@ and gen_call ctx e el = print ctx "}, %i)" !count; | TIdent "`trace", [e;infos] -> if has_feature ctx "haxe.Log.trace" then begin - let t = (try List.find (fun t -> t_path t = (["haxe"],"Log")) ctx.com.types with _ -> assert false) in + let t = (try List.find (fun t -> t_path t = (["haxe"],"Log")) ctx.com.types with _ -> Globals.die "" __LOC__) in spr ctx (ctx.type_accessor t); spr ctx ".trace("; gen_value ctx e; @@ -691,7 +689,7 @@ and gen_expr ?(local=true) ctx e = begin | [(EConst(String(id,_)), _)] -> spr ctx (id ^ "_" ^ (ident v.v_name) ^ "_" ^ (field_name f)); | _ -> - assert false); + Globals.die "" __LOC__); | TField (x,f) -> gen_value ctx x; let name = field_name f in @@ -781,7 +779,7 @@ and gen_expr ?(local=true) ctx e = begin | TInst (c, _) -> List.map (fun f -> id ^ "_" ^name ^ "_" ^ f.cf_name) c.cl_ordered_fields | _ -> - assert false + Globals.die "" __LOC__ in spr ctx "local "; spr ctx (String.concat ", " names); @@ -917,8 +915,8 @@ and gen_expr ?(local=true) ctx e = begin | TWhile (cond,e,Ast.NormalWhile) -> gen_loop ctx "while" cond e | TWhile (cond,e,Ast.DoWhile) -> - println ctx "while true do "; gen_block_element ctx e; + newline ctx; gen_loop ctx "while" cond e | TObjectDecl [] -> spr ctx "_hx_e()"; @@ -940,7 +938,6 @@ and gen_expr ?(local=true) ctx e = begin println ctx "local _hx_status, _hx_result = pcall(function() "; let b = open_block ctx in gen_expr ctx e; - let vname = temp ctx in b(); println ctx "return _hx_pcall_default"; println ctx "end)"; @@ -953,58 +950,12 @@ and gen_expr ?(local=true) ctx e = begin println ctx " break"; println ctx "elseif not _hx_status then "; let bend = open_block ctx in - newline ctx; - print ctx "local %s = _hx_result" vname; - let last = ref false in - let else_block = ref false in - List.iter (fun (v,e) -> - if !last then () else - let t = (match follow v.v_type with - | TEnum (e,_) -> Some (TEnumDecl e) - | TInst (c,_) -> Some (TClassDecl c) - | TAbstract (a,_) -> Some (TAbstractDecl a) - | TFun _ - | TLazy _ - | TType _ - | TAnon _ -> - assert false - | TMono _ - | TDynamic _ -> - None - ) in - match t with - | None -> - last := true; - if !else_block then print ctx ""; - if vname <> v.v_name then begin - newline ctx; - print ctx "local %s = %s" v.v_name vname; - end; - gen_block_element ctx e; - if !else_block then begin - newline ctx; - print ctx " end "; - end - | Some t -> - if not !else_block then newline ctx; - print ctx "if( %s.__instanceof(%s," (ctx.type_accessor (TClassDecl { null_class with cl_path = ["lua"],"Boot" })) vname; - gen_value ctx (mk (TTypeExpr t) (mk_mono()) e.epos); - spr ctx ") ) then "; - let bend = open_block ctx in - if vname <> v.v_name then begin - newline ctx; - print ctx "local %s = %s" v.v_name vname; - end; - gen_block_element ctx e; - bend(); - newline ctx; - spr ctx "else"; - else_block := true - ) catchs; - if not !last then begin - println ctx " _G.error(%s)" vname; - spr ctx "end"; - end; + (match catchs with + | [v,e] -> + print ctx " local %s = _hx_result;" v.v_name; + gen_block_element ctx e; + | _ -> Globals.die "" __LOC__ + ); bend(); newline ctx; println ctx "elseif _hx_result ~= _hx_pcall_default then"; @@ -1105,7 +1056,7 @@ and gen_block_element ctx e = else (match eelse with | [] -> () | [e] -> gen_block_element ctx e - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | _ -> newline ctx; gen_expr ctx e; @@ -1151,7 +1102,7 @@ and gen_anon_value ctx e = and gen_value ctx e = let assign e = mk (TBinop (Ast.OpAssign, - mk (TLocal (match ctx.in_value with None -> assert false | Some v -> v)) t_dynamic e.epos, + mk (TLocal (match ctx.in_value with None -> Globals.die "" __LOC__ | Some v -> v)) t_dynamic e.epos, e )) e.etype e.epos in @@ -1674,7 +1625,7 @@ let generate_class ctx c = List.iter (gen_class_static_field ctx c) c.cl_ordered_statics; if (has_prototype ctx c) then begin - println ctx "%s.prototype = _hx_a();" p; + println ctx "%s.prototype = _hx_e();" p; let count = ref 0 in List.iter (fun f -> if can_gen_class_field ctx f then (gen_class_field ctx c f) ) c.cl_ordered_fields; if (has_class ctx c) then begin @@ -1862,7 +1813,7 @@ let alloc_ctx com = break_depth = 0; handle_continue = false; id_counter = 0; - type_accessor = (fun _ -> assert false); + type_accessor = (fun _ -> Globals.die "" __LOC__); separator = false; found_expose = false; lua_jit = Common.defined com Define.LuaJit; @@ -1965,13 +1916,16 @@ let generate com = print ctx "%s\n" file_content; in - (* table-to-array helper *) + (* base table-to-array helpers and metatables *) print_file (Common.find_file com "lua/_lua/_hx_tab_array.lua"); - (* lua workarounds for basic anonymous object functionality *) + (* base lua "toString" functionality for haxe objects*) + print_file (Common.find_file com "lua/_lua/_hx_tostring.lua"); + + (* base lua metatables for prototypes, inheritance, etc. *) print_file (Common.find_file com "lua/_lua/_hx_anon.lua"); - (* class reflection metadata *) + (* base runtime class stubs for haxe value types (Int, Float, etc) *) print_file (Common.find_file com "lua/_lua/_hx_classes.lua"); let include_files = List.rev com.include_files in @@ -2060,23 +2014,25 @@ let generate com = List.iter (transform_multireturn ctx) com.types; List.iter (generate_type ctx) com.types; - if has_feature ctx "use._bitop" || has_feature ctx "lua.Boot.clamp" then begin - print_file (Common.find_file com "lua/_lua/_hx_bit_clamp.lua"); + (* If bit ops are manually imported include the haxe wrapper for them *) + if has_feature ctx "use._bitop" then begin print_file (Common.find_file com "lua/_lua/_hx_bit.lua"); end; + (* integer clamping is always required, and will use bit ops if available *) + print_file (Common.find_file com "lua/_lua/_hx_bit_clamp.lua"); + (* Array is required, always patch it *) println ctx "_hx_array_mt.__index = Array.prototype"; newline ctx; let b = open_block ctx in - println ctx "local _hx_static_init = function()"; - (* Generate statics *) - List.iter (generate_static ctx) (List.rev ctx.statics); (* Localize init variables inside a do-block *) - (* Note: __init__ logic can modify static variables. *) + println ctx "local _hx_static_init = function()"; (* Generate static inits *) List.iter (gen_block_element ctx) (List.rev ctx.inits); + (* Generate statics *) + List.iter (generate_static ctx) (List.rev ctx.statics); b(); newline ctx; println ctx "end"; @@ -2125,9 +2081,25 @@ let generate com = List.iter (generate_enumMeta_fields ctx) com.types; - (match com.main with + match com.main with | None -> () - | Some e -> gen_expr ctx e; newline ctx); + | Some e -> + spr ctx "_G.xpcall("; + (match e.eexpr with + | TCall(e2,[]) -> + gen_value ctx e2; + | _-> + let fn = + { + tf_args = []; + tf_type = com.basic.tvoid; + tf_expr = mk (TBlock [e]) com.basic.tvoid e.epos; + } + in + gen_value ctx { e with eexpr = TFunction fn; etype = TFun ([],com.basic.tvoid) } + ); + spr ctx ", _hx_error)"; + newline ctx; if anyExposed then println ctx "return _hx_exports"; diff --git a/src/generators/genneko.ml b/src/generators/genneko.ml index 713e2cbf9b329572b0ff3f17767044406fc91c26..f78901ba8d1c9fed90b503478ebc5493b331b04f 100644 --- a/src/generators/genneko.ml +++ b/src/generators/genneko.ml @@ -177,7 +177,7 @@ let gen_constant ctx pe c = | TBool b -> (EConst (if b then True else False),p) | TNull -> null p | TThis -> this p - | TSuper -> assert false + | TSuper -> die "" __LOC__ let rec gen_binop ctx p op e1 e2 = (EBinop (Ast.s_binop op,gen_expr ctx e1,gen_expr ctx e2),p) @@ -193,7 +193,7 @@ and gen_unop ctx p op flag e = and gen_call ctx p e el = match e.eexpr , el with | TConst TSuper , _ -> - let c = (match follow e.etype with TInst (c,_) -> c | _ -> assert false) in + let c = (match follow e.etype with TInst (c,_) -> c | _ -> die "" __LOC__) in call p (builtin p "call") [ field p (gen_type_path p c.cl_path) "__construct__"; this p; @@ -204,7 +204,7 @@ and gen_call ctx p e el = (EObject [("name",gen_constant ctx e.epos (TString name));("data",gen_big_string ctx p data)],p) :: acc ) ctx.com.resources []) | TField ({ eexpr = TConst TSuper; etype = t },f) , _ -> - let c = (match follow t with TInst (c,_) -> c | _ -> assert false) in + let c = (match follow t with TInst (c,_) -> c | _ -> die "" __LOC__) in call p (builtin p "call") [ field p (gen_type_path p (fst c.cl_path,"@" ^ snd c.cl_path)) (field_name f); this p; @@ -245,7 +245,7 @@ and gen_expr ctx e = else call p (ident p ("@closure" ^ string_of_int n)) [tmp;ident p "@fun"] ] , p - | _ -> assert false) + | _ -> die "" __LOC__) | TEnumParameter (e,_,i) -> EArray (field p (gen_expr ctx e) "args",int p i),p | TEnumIndex e -> @@ -334,7 +334,7 @@ and gen_expr ctx e = | TEnum (e,_) -> Some e.e_path | TAbstract (a,_) -> Some a.a_path | TDynamic _ -> None - | _ -> assert false + | _ -> die "" __LOC__ ) in let cond = (match path with | None -> (EConst True,p) @@ -380,7 +380,7 @@ and gen_expr ctx e = e, List.map (fun (el,e2) -> match List.map (gen_expr ctx) el with - | [] -> assert false + | [] -> die "" __LOC__ | [e] -> e, gen_expr ctx e2 | _ -> raise Exit ) cases, @@ -392,7 +392,7 @@ and gen_expr ctx e = (EVars ["@tmp",Some e],p); List.fold_left (fun acc (el,e) -> let cond = (match el with - | [] -> assert false + | [] -> die "" __LOC__ | e :: l -> let eq e = (EBinop ("==",ident p "@tmp",gen_expr ctx e),p) in List.fold_left (fun acc e -> (EBinop ("||",acc,eq e),p)) (eq e) l @@ -736,7 +736,7 @@ let header() = let p = { psource = "
"; pline = 1 } in let fields l = let rec loop = function - | [] -> assert false + | [] -> die "" __LOC__ | [x] -> ident p x | x :: l -> field p (loop l) x in diff --git a/src/generators/genphp7.ml b/src/generators/genphp7.ml index 8cfec0b45512fb82d9e90628afc2b0cb833891b6..8edd26669524fa663922e2ad22aed31b3566f0c6 100644 --- a/src/generators/genphp7.ml +++ b/src/generators/genphp7.ml @@ -85,14 +85,6 @@ let hashtbl_keys tbl = Hashtbl.fold (fun key _ lst -> key :: lst) tbl [] *) let diff_lists list1 list2 = List.filter (fun x -> not (List.mem x list2)) list1 -(** - Type path for native PHP Exception class -*) -let native_exception_path = ([], "Throwable") -(** - Type path for Haxe exceptions wrapper -*) -let hxexception_type_path = (["php"; "_Boot"], "HxException") (** Type path of `php.Boot` *) @@ -178,20 +170,10 @@ end *) let is_keyword str = Hashtbl.mem php_keywords_tbl (String.lowercase str) -(** - Check if specified type is Void -*) -let is_void_type t = match follow t with TAbstract ({ a_path = void_type_path }, _) -> true | _ -> false - -(** - Check if specified type is Bool -*) -let is_bool_type t = match follow t with TAbstract ({ a_path = bool_type_path }, _) -> true | _ -> false - (** Check if specified type is php.NativeArray *) -let is_native_array_type t = match follow t with TAbstract ({ a_path = native_array_type_path }, _) -> true | _ -> false +let is_native_array_type t = match follow t with TAbstract ({ a_path = tp }, _) -> tp = native_array_type_path | _ -> false (** If `name` is not a reserved word in PHP then `name` is returned as-is. @@ -252,20 +234,7 @@ let error_message pos message = (stringify_pos pos) ^ ": " ^ message (** Terminates compiler process and prints user-friendly instructions about filing an issue in compiler repo. *) -let fail ?msg hxpos mlpos = - let msg = - error_message - hxpos - ( - (match msg with Some msg -> msg | _ -> "") - ^ " Unexpected expression. Please submit an issue with expression example and following information:" - ) - in - match mlpos with - | (file, line, _, _) -> - Printf.eprintf "%s\n" msg; - Printf.eprintf "%s:%d\n" file line; - assert false +let fail ?msg p = Globals.die (Option.default "" msg) ~p (** Check if `target` is a `Dynamic` type @@ -298,17 +267,12 @@ let is_int expr = match follow expr.etype with TAbstract ({ a_path = ([], "Int") (** Check if specified expression is of `Float` type *) -let is_float expr = match follow expr.etype with TAbstract ({ a_path = ([], "Float") }, _) -> true | _ -> false - -(** - Check if specified type is String -*) -let is_string_type t = match follow t with TInst ({ cl_path = ([], "String") }, _) -> true | _ -> false +let is_float expr = ExtType.is_float (follow expr.etype) (** Check if specified expression is of String type *) -let is_string expr = is_string_type expr.etype +let is_string expr = ExtType.is_string (follow expr.etype) (** Check if specified type is Array @@ -325,7 +289,7 @@ let is_function_type t = match follow t with TFun _ -> true | _ -> false *) let is_syntax_extern expr = match expr.eexpr with - | TField ({ eexpr = TTypeExpr (TClassDecl { cl_path = path }) }, _) when path = syntax_type_path -> true + | TField ({ eexpr = TTypeExpr (TClassDecl { cl_path = path }) }, _) -> path = syntax_type_path | _ -> false (** @@ -393,13 +357,24 @@ let needs_dereferencing for_assignment expr = | TArray (target_expr, _) -> is_create target_expr | _ -> false +(** + Check if the value of `expr` needs to be stored to a temporary variable to be + reused. +*) +let rec needs_temp_var expr = + match (reveal_expr_with_parenthesis expr).eexpr with + | TConst _ | TLocal _ -> false + | TField (target, FInstance _) | TField (target, FStatic _) -> needs_temp_var target + | TArray (target, index) -> needs_temp_var target || needs_temp_var index + | _ -> true + (** @return (arguments_list, return_type) *) let get_function_signature (field:tclass_field) : (string * bool * Type.t) list * Type.t = match follow field.cf_type with | TFun (args, return_type) -> (args, return_type) - | _ -> fail field.cf_pos __POS__ + | _ -> fail field.cf_pos __LOC__ (** Check if `target` is 100% guaranteed to be a scalar type in PHP. @@ -418,11 +393,18 @@ let is_sure_scalar (target:Type.t) = | _ -> false (** - Indicates if `expr` is guaranteed to be an access to a `var` field. + Indicates if `expr` has to be wrapped into parentheses to be called. *) -let is_sure_var_field_access expr = - match (reveal_expr expr).eexpr with - | TField (_, FStatic (_, { cf_kind = Var _ })) -> true +let rec needs_parenthesis_to_call expr = + match expr.eexpr with + | TParenthesis _ -> false + | TCast (e, None) + | TMeta (_, e) -> needs_parenthesis_to_call e + | TNew _ + | TObjectDecl _ + | TArrayDecl _ + | TField (_, FClosure (_,_)) + | TField (_, FStatic (_, { cf_kind = Var _ })) | TField (_, FInstance (_, _, { cf_kind = Var _ })) -> true (* | TField (_, FAnon { cf_kind = Var _ }) -> true *) (* Sometimes we get anon access to non-anonymous objects *) | _ -> false @@ -531,34 +513,6 @@ let get_full_type_name ?(escape=false) ?(omit_first_slash=false) (type_path:path else name -(** - Check if `target` is or implements native PHP `Throwable` interface -*) -let rec is_native_exception (target:Type.t) = - match follow target with - | TInst ({ cl_path = path }, _) when path = native_exception_path -> true - | TInst ({ cl_super = parent ; cl_implements = interfaces ; cl_path = path }, _) -> - let (parent, params) = - match parent with - | Some (parent, params) -> (Some parent, params) - | None -> (None, []) - in - let found = ref false in - List.iter - (fun (cls, params) -> - if not !found then - found := is_native_exception (TInst (cls, params)) - ) - interfaces; - if !found then - true - else - (match parent with - | Some parent -> is_native_exception (TInst (parent, params)) - | None -> false - ) - | _ -> false - (** @return Short type name. E.g. returns "Test" for (["example"], "Test") *) @@ -736,14 +690,14 @@ let need_boot_equal expr1 expr2 = *) let ensure_return_in_block block_expr = match block_expr.eexpr with - | TBlock [] -> fail block_expr.epos __POS__ + | TBlock [] -> fail block_expr.epos __LOC__ | TBlock exprs -> let reversed = List.rev exprs in let last_expr = List.hd reversed in let return_expr = { last_expr with eexpr = TReturn (Some last_expr) } in let reversed = return_expr::(List.tl reversed) in { block_expr with eexpr = TBlock (List.rev reversed) } - | _ -> fail block_expr.epos __POS__ + | _ -> fail block_expr.epos __LOC__ (** If `expr` is a block, then return list of expressions in that block. @@ -762,7 +716,7 @@ let unpack_block expr = let unpack_single_expr_block expr = match expr.eexpr with | TBlock [ e ] -> e - | TBlock _ -> fail expr.epos __POS__ + | TBlock _ -> fail expr.epos __LOC__ | _ -> expr (** @@ -799,7 +753,7 @@ let field_name field = *) let is_std_is expr = match expr.eexpr with - | TField (_, FStatic ({ cl_path = path }, { cf_name = "is" })) -> path = boot_type_path || path = std_type_path + | TField (_, FStatic ({ cl_path = path }, { cf_name = ("is" | "isOfType") })) -> path = boot_type_path || path = std_type_path | _ -> false (** @@ -1171,10 +1125,10 @@ class local_vars = *) method pop : string list * string list * string list = match used_locals with - | [] -> assert false + | [] -> die "" __LOC__ | used :: rest_used -> match declared_locals with - | [] -> assert false + | [] -> die "" __LOC__ | declared :: rest_declared -> let higher_vars = diff_lists (hashtbl_keys used) (hashtbl_keys declared) and declared_vars = hashtbl_keys declared in @@ -1204,14 +1158,14 @@ class local_vars = *) method declared (name:string) : unit = match declared_locals with - | [] -> assert false + | [] -> die "" __LOC__ | current :: _ -> Hashtbl.replace current name name (** Specify local var name used in current scope *) method used (name:string) : unit = match used_locals with - | [] -> assert false + | [] -> die "" __LOC__ | current :: _ -> Hashtbl.replace current name name (** Mark specified vars as captured by closures. @@ -1320,7 +1274,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = let alias_source = ref (List.rev module_path) in let get_alias_next_part () = match !alias_source with - | [] -> fail ~msg:("Failed to find already used type: " ^ get_full_type_name type_path) self#pos __POS__ + | [] -> fail ~msg:("Failed to find already used type: " ^ get_full_type_name type_path) self#pos __LOC__ | name :: rest -> alias_source := (match rest with | [] -> [name] @@ -1350,7 +1304,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = | Not_found -> Hashtbl.add use_table !alias_upper { ut_alias = !alias; ut_type_path = type_path; }; added := true - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ done; !alias end @@ -1373,13 +1327,13 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = | TFun _ -> self#use ~prefix:false ([], "Closure") | TAnon _ -> "object" | TDynamic _ -> "mixed" - | TLazy _ -> fail ~msg:"TLazy not implemented" self#pos __POS__ + | TLazy _ -> fail ~msg:"TLazy not implemented" self#pos __LOC__ | TMono mono -> - (match !mono with + (match mono.tm_type with | None -> "mixed" | Some t -> self#use_t t ) - | TType _ -> fail ~msg:"TType not implemented" self#pos __POS__ + | TType _ -> fail ~msg:"TType not implemented" self#pos __LOC__ | TAbstract (abstr, _) -> match abstr.a_path with | ([],"Int") -> "int" @@ -1516,7 +1470,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = access_expr ) } - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ (** Writes specified string to output buffer *) @@ -1625,15 +1579,12 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = self#write ")" | TObjectDecl fields -> self#write_expr_object_declaration fields | TArrayDecl exprs -> self#write_expr_array_decl exprs - | TCall (target, [arg1; arg2]) when is_std_is target && instanceof_compatible arg1 arg2 -> self#write_expr_syntax_instanceof [arg1; arg2] + | TCall (target, [arg1; arg2]) when is_std_is target -> self#write_expr_std_is target arg1 arg2 | TCall (_, [arg]) when is_native_struct_array_cast expr && is_object_declaration arg -> - (match (reveal_expr arg).eexpr with TObjectDecl fields -> self#write_assoc_array_decl fields | _ -> fail self#pos __POS__) - | TCall ({ eexpr = TIdent name}, args) when is_magic expr -> - ctx.pgc_common.warning ("untyped " ^ name ^ " is deprecated. Use php.Syntax instead.") self#pos; - self#write_expr_magic name args + (match (reveal_expr arg).eexpr with TObjectDecl fields -> self#write_assoc_array_decl fields | _ -> fail self#pos __LOC__) + | TCall ({ eexpr = TIdent name}, args) when is_magic expr -> self#write_expr_magic name args | TCall ({ eexpr = TField (expr, access) }, args) when is_string expr -> self#write_expr_call_string expr access args | TCall (expr, args) when is_syntax_extern expr -> self#write_expr_call_syntax_extern expr args - | TCall (target, args) when is_sure_var_field_access target -> self#write_expr_call (parenthesis target) args | TCall (target, args) -> self#write_expr_call target args | TNew (_, _, args) when is_string expr -> write_args self#write self#write_expr args | TNew (tcls, _, args) -> self#write_expr_new tcls args @@ -1643,7 +1594,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = | TFunction fn -> self#write_expr_function fn | TVar (var, expr) -> self#write_expr_var var expr | TBlock exprs -> self#write_expr_block expr - | TFor (var, iterator, body) -> fail self#pos __POS__ + | TFor (var, iterator, body) -> fail self#pos __LOC__ | TIf (condition, if_expr, else_expr) -> self#write_expr_if condition if_expr else_expr | TWhile (condition, expr, do_while) -> (match (reveal_expr_with_parenthesis condition).eexpr with @@ -1794,7 +1745,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = vars#captured used_vars; self#write " "; if List.length used_vars > 0 then begin - self#write " use ("; + self#write "use ("; write_args self#write (fun name -> self#write ("&$" ^ name)) used_vars; self#write ") " end; @@ -1867,12 +1818,16 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = and exprs = match expr.eexpr with TBlock exprs -> exprs | _ -> [expr] in let write_body () = let write_expr expr = - if not ctx.pgc_skip_line_directives && not (is_block expr) then + if not ctx.pgc_skip_line_directives && not (is_block expr) && expr.epos <> null_pos then if self#write_pos expr then self#write_indentation; - self#write_expr expr; match expr.eexpr with - | TBlock _ | TIf _ | TTry _ | TSwitch _ | TWhile (_, _, NormalWhile) -> self#write "\n" - | _ -> self#write ";\n" + | TBlock _ -> + self#write_as_block ~inline:true expr + | _ -> + self#write_expr expr; + match expr.eexpr with + | TBlock _ | TIf _ | TTry _ | TSwitch _ | TWhile (_, _, NormalWhile) -> self#write "\n" + | _ -> self#write ";\n" in let write_expr_with_indent expr = self#write_indentation; @@ -1933,73 +1888,21 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = *) method write_expr_throw expr = self#write "throw "; - if is_native_exception expr.etype then - self#write_expr expr - else if sure_extends_extern expr.etype || is_dynamic_type expr.etype then - begin - self#write "(is_object($__hx__throw = "; - self#write_expr expr; - self#write (") && $__hx__throw instanceof \\Throwable ? $__hx__throw : new " ^ (self#use hxexception_type_path) ^ "($__hx__throw))") - end - else - begin - self#write ("new " ^ (self#use hxexception_type_path) ^ "("); - self#write_expr expr; - self#write ")" - end + self#write_expr expr (** Writes try...catch to output buffer *) method write_expr_try_catch try_expr catches = - let catching_dynamic = ref false in - let haxe_exception = self#use hxexception_type_path - and first_catch = ref true in - let write_catch (var, expr) = - let dynamic = ref false in - (match follow var.v_type with - | TInst ({ cl_path = ([], "String") }, _) -> self#write "if (is_string($__hx__real_e)) {\n" - | TAbstract ({ a_path = ([], "Float") }, _) -> self#write "if (is_float($__hx__real_e)) {\n" - | TAbstract ({ a_path = ([], "Int") }, _) -> self#write "if (is_int($__hx__real_e)) {\n" - | TAbstract ({ a_path = ([], "Bool") }, _) -> self#write "if (is_bool($__hx__real_e)) {\n" - | TDynamic _ -> - dynamic := true; - catching_dynamic := true; - if not !first_catch then self#write "{\n" - | vtype -> self#write ("if ($__hx__real_e instanceof " ^ (self#use_t vtype) ^ ") {\n") - ); - if !dynamic && !first_catch then - begin - self#write ("$" ^ var.v_name ^ " = $__hx__real_e;\n"); - self#write_indentation; - self#write_as_block ~inline:true expr; - end - else - begin - self#indent_more; - self#write_statement ("$" ^ var.v_name ^ " = $__hx__real_e"); - self#write_indentation; - self#write_as_block ~inline:true expr; - self#indent_less; - self#write_with_indentation "}"; - end; - if not !dynamic then self#write " else "; - first_catch := false; - in self#write "try "; self#write_as_block try_expr; - self#write " catch (\\Throwable $__hx__caught_e) {\n"; - self#indent_more; - if has_feature ctx.pgc_common "haxe.CallStack.exceptionStack" then - self#write_statement ((self#use (["haxe"], "CallStack")) ^ "::saveExceptionTrace($__hx__caught_e)"); - self#write_statement ("$__hx__real_e = ($__hx__caught_e instanceof " ^ haxe_exception ^ " ? $__hx__caught_e->e : $__hx__caught_e)"); - self#write_indentation; - List.iter write_catch catches; - if not !catching_dynamic then - self#write " throw $__hx__caught_e;\n" - else - (match catches with [_] -> () | _ -> self#write "\n"); - self#indent_less; - self#write_with_indentation "}" + let rec traverse = function + | [] -> () + | (v,body) :: rest -> + self#write (" catch(" ^ (self#use_t v.v_type) ^ " $" ^ v.v_name ^ ") "); + self#write_as_block body; + traverse rest + in + traverse catches (** Writes TCast to output buffer *) @@ -2017,16 +1920,18 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = @see http://old.haxe.org/doc/advanced/magic#php-magic *) method write_expr_magic name args = + let msg = "untyped " ^ name ^ " is deprecated. Use php.Syntax instead." in + DeprecationCheck.warn_deprecation ctx.pgc_common msg self#pos; let error = ("Invalid arguments for " ^ name ^ " magic call") in match args with - | [] -> fail ~msg:error self#pos __POS__ + | [] -> fail ~msg:error self#pos __LOC__ | { eexpr = TConst (TString code) } as expr :: args -> (match name with | "__php__" -> (match expr.eexpr with | TConst (TString php) -> Codegen.interpolate_code ctx.pgc_common php args self#write self#write_expr self#pos - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ ) | "__call__" -> self#write (code ^ "("); @@ -2035,7 +1940,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = | "__physeq__" -> (match args with | [expr2] -> self#write_expr_binop OpEq expr expr2 - | _ -> fail ~msg:error self#pos __POS__ + | _ -> fail ~msg:error self#pos __LOC__ ) | "__var__" -> (match args with @@ -2045,20 +1950,20 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = self#write ("$" ^ code ^ "["); self#write_expr expr2; self#write "]" - | _ -> fail ~msg:error self#pos __POS__ + | _ -> fail ~msg:error self#pos __LOC__ ) - | _ -> fail ~msg:error self#pos __POS__ + | _ -> fail ~msg:error self#pos __LOC__ ) | [expr1; expr2] -> (match name with | "__physeq__" -> (match args with | [expr1; expr2] -> self#write_expr_binop OpEq expr1 expr2 - | _ -> fail ~msg:error self#pos __POS__ + | _ -> fail ~msg:error self#pos __LOC__ ) - | _ -> fail ~msg:error self#pos __POS__ + | _ -> fail ~msg:error self#pos __LOC__ ) - | _ -> fail ~msg:error self#pos __POS__ + | _ -> fail ~msg:error self#pos __LOC__ (** Writes TTypeExpr to output buffer *) @@ -2101,11 +2006,15 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = || is_php_class_const expr then self#write_expr expr - else begin - self#write "("; - self#write_expr expr; - self#write "??'null')" - end + else + match (reveal_expr expr).eexpr with + | TConst TNull -> self#write "'null'" + | TBinop _ | TUnop _ -> self#write_expr (parenthesis expr) + | TParenthesis { eexpr = (TBinop _ | TUnop _) } -> self#write_expr expr + | _ -> + self#write "("; + self#write_expr expr; + self#write "??'null')" and write_binop ?writer ?right_writer str = let write_left = match writer with None -> self#write_expr | Some writer -> writer in let write_right = match right_writer with None -> write_left | Some writer -> writer @@ -2302,7 +2211,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = self#write ((self#use hxstring_type_path) ^ "::" ^ (field_name field) ^ "("); write_args self#write self#write_expr (expr :: args); self#write ")" - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ (** Writes FStatic field access for methods to output buffer *) @@ -2328,7 +2237,6 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = method write_static_method_closure expr field_name = let expr = reveal_expr expr in self#write ((self#use boot_type_path) ^ "::getStaticClosure("); - (* self#write ("new " ^ (self#use hxclosure_type_path) ^ "("); *) (match (reveal_expr expr).eexpr with | TTypeExpr (TClassDecl { cl_path = ([], "String") }) -> self#write ((self#use hxstring_type_path) ^ "::class") @@ -2353,7 +2261,6 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = self#write_expr expr; self#write ("->" ^ (field_name field)) else - (* let new_closure = "new " ^ (self#use hxclosure_type_path) in *) let new_closure = ((self#use boot_type_path) ^ "::getInstanceClosure") in match expr.eexpr with | TTypeExpr mtype -> @@ -2388,7 +2295,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = | TTypeExpr (TClassDecl tcls) -> self#write (self#use_t (TInst (tcls, []))) | _ -> - if is_string type_expr then + if is_string (reveal_expr type_expr) then self#write_expr type_expr else begin self#write "("; @@ -2401,7 +2308,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = method write_expr_call_syntax_extern expr args = let name = match expr.eexpr with | TField (_, FStatic (_, field)) -> field_name field - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ in match name with | "code" | "codeDeref" -> self#write_expr_syntax_code args @@ -2425,7 +2332,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = *) method write_expr_syntax_code args = match args with - | [] -> fail self#pos __POS__ + | [] -> fail self#pos __LOC__ | { eexpr = TConst (TString php) } :: args -> let args = List.map (fun arg -> @@ -2445,7 +2352,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = | [ args_expr ] -> self#write "@"; self#write_expr args_expr - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ (** Writes native array declaration (for `php.Syntax.arrayDecl()`) *) @@ -2461,6 +2368,19 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = | [] -> self#write_assoc_array_decl [] | { eexpr = TObjectDecl fields } :: [] -> self#write_assoc_array_decl fields | _ -> ctx.pgc_common.error "php.Syntax.assocDecl() accepts object declaration only." self#pos + (** + Writes `e` to be used as a field access. + If `e` is a constant string, writes the constant without quotes. + Otherwise writes `{e}` + *) + method write_syntax_field_expr field_expr = + match reveal_expr field_expr with + | { eexpr = TConst (TString method_name) } -> + self#write method_name + | _ -> + self#write "{"; + self#write_expr field_expr; + self#write "}" (** Writes a call to instance method (for `php.Syntax.call()`) *) @@ -2468,12 +2388,12 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = match args with | obj_expr :: method_expr :: args -> self#write_expr obj_expr; - self#write "->{"; - self#write_expr method_expr; - self#write "}("; + self#write "->"; + self#write_syntax_field_expr method_expr; + self#write "("; write_args self#write (fun e -> self#write_expr e) args; self#write ")" - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ (** Writes a call to a static method (for `php.Syntax.staticCall()`) *) @@ -2481,12 +2401,12 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = match args with | type_expr :: method_expr :: args -> self#write_type type_expr; - self#write "::{"; - self#write_expr method_expr; - self#write "}("; + self#write "::"; + self#write_syntax_field_expr method_expr; + self#write "("; write_args self#write (fun e -> self#write_expr e) args; self#write ")" - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ (** Writes field access for reading (for `php.Syntax.getField()`) *) @@ -2494,10 +2414,9 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = match args with | obj_expr :: field_expr :: [] -> self#write_expr obj_expr; - self#write "->{"; - self#write_expr field_expr; - self#write "}" - | _ -> fail self#pos __POS__ + self#write "->"; + self#write_syntax_field_expr field_expr; + | _ -> fail self#pos __LOC__ (** Writes field access for writing (for `php.Syntax.setField()`) *) @@ -2510,7 +2429,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = self#write "}"; self#write " = "; self#write_expr value_expr - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ (** Writes static field access for reading (for `php.Syntax.getStaticField()`) *) @@ -2521,7 +2440,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = self#write "::${"; self#write_expr field_expr; self#write "}" - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ (** Writes static field access for writing (for `php.Syntax.setField()`) *) @@ -2534,14 +2453,14 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = self#write "}"; self#write " = "; self#write_expr value_expr - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ (** Writes `new` expression with class name taken local variable (for `php.Syntax.construct()`) *) method write_expr_syntax_construct args = let (class_expr, args) = match args with | class_expr :: args -> (class_expr, args) - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ in self#write "new "; self#write_expr class_expr; @@ -2563,7 +2482,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = self#write " ?? "; self#write_expr right; self#write ")"; - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ (** Writes `instanceof` expression to output buffer (for `php.Syntax.instanceof()`) *) @@ -2581,7 +2500,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = if not (is_string type_expr) then self#write "->phpClassName" ); self#write ")" - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ (** Writes either a "Cls::class" expression (if class is passed directly) or a `$cls->phpClassName` expression (if class is passed as a variable) to output buffer (for `php.Syntax.nativeClassName()`) @@ -2597,7 +2516,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = self#write_expr cls_expr; self#write "->phpClassName" ); - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ (** Writes `foreach` expression to output buffer (for `php.Syntax.foreach()`) *) @@ -2616,19 +2535,20 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = self#write (" as $" ^ key.v_name ^ " => $" ^ value.v_name ^ ") "); self#write_as_block ~unset_locals:true { body with eexpr = TBlock body_exprs }; | _ -> - fail self#pos __POS__ + fail self#pos __LOC__ (** Writes TCall to output buffer *) method write_expr_call target_expr args = - let target_expr = reveal_expr target_expr - and no_call = ref false in - (match target_expr.eexpr with - | TConst TSuper -> + let no_call = ref false in + (match reveal_expr target_expr with + | { eexpr = TConst TSuper } -> no_call := not has_super_constructor; if not !no_call then self#write "parent::__construct" - | TField (expr, FClosure (_,_)) -> self#write_expr (parenthesis target_expr) - | _ -> self#write_expr target_expr + | e when needs_parenthesis_to_call e -> + self#write_expr (parenthesis e) + | e -> + self#write_expr e ); if not !no_call then begin @@ -2636,13 +2556,51 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = write_args self#write self#write_expr args; self#write ")" end + (** + Writes `Std.isOfType(value, type)` to output buffer + *) + method write_expr_std_is target_expr value_expr type_expr = + if instanceof_compatible value_expr type_expr then + self#write_expr_syntax_instanceof [value_expr; type_expr] + else + let no_optimisation() = + self#write_expr_call target_expr [value_expr; type_expr] + in + match (reveal_expr type_expr).eexpr with + | TTypeExpr mtype -> + let t = follow (type_of_module_type mtype) in + if ExtType.is_string t then + begin + self#write "is_string("; + self#write_expr value_expr; + self#write ")" + end + else if ExtType.is_bool t then + begin + self#write "is_bool("; + self#write_expr value_expr; + self#write ")" + end + else if ExtType.is_float t && not (needs_temp_var value_expr) then + begin + self#write "(is_float("; + self#write_expr value_expr; + self#write ") || is_int("; + self#write_expr value_expr; + self#write "))" + end + else + no_optimisation() + | _ -> + no_optimisation() + (** Writes a name of a function or a constant from global php namespace *) method write_expr_php_global target_expr = match target_expr.eexpr with | TField (_, FStatic (_, field)) -> self#write (field_name field) - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ (** Writes access to PHP class constant *) @@ -2650,7 +2608,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = match target_expr.eexpr with | TField (_, FStatic (ecls, field)) -> self#write ((self#use_t (TInst (ecls, []))) ^ "::" ^ (field_name field)) - | _ -> fail self#pos __POS__ + | _ -> fail self#pos __LOC__ (** Writes TNew to output buffer *) @@ -2691,7 +2649,7 @@ class code_writer (ctx:php_generator_context) hx_type_path php_name = in if is_ternary then match else_expr with - | None -> fail self#pos __POS__ + | None -> fail self#pos __LOC__ | Some expr -> self#write_expr_ternary condition if_expr expr self#pos else begin @@ -3195,7 +3153,7 @@ class enum_builder ctx (enm:tenum) = E.g. "class SomeClass extends Another implements IFace" *) method private write_declaration = - self#write_doc (DocClass enm.e_doc); + self#write_doc (DocClass (gen_doc_text_opt enm.e_doc)); writer#write ("class " ^ self#get_name ^ " extends " ^ (writer#use hxenum_type_path)) (** Writes type body to output buffer. @@ -3221,10 +3179,10 @@ class enum_builder ctx (enm:tenum) = match follow field.ef_type with | TFun (args, _) -> args | TEnum _ -> [] - | _ -> fail field.ef_pos __POS__ + | _ -> fail field.ef_pos __LOC__ in writer#indent 1; - self#write_doc (DocMethod (args, TEnum (enm, []), field.ef_doc)); + self#write_doc (DocMethod (args, TEnum (enm, []), (gen_doc_text_opt field.ef_doc))); writer#write_with_indentation ("static public function " ^ name ^ " ("); write_args writer#write (writer#write_arg true) args; writer#write ") {\n"; @@ -3292,7 +3250,7 @@ class enum_builder ctx (enm:tenum) = let count = match follow field.ef_type with | TFun (params, _) -> List.length params | TEnum _ -> 0 - | _ -> fail field.ef_pos __POS__ + | _ -> fail field.ef_pos __LOC__ in writer#write_line ("'" ^ name ^ "' => " ^ (string_of_int count) ^ ",") ) @@ -3415,7 +3373,7 @@ class class_builder ctx (cls:tclass) = E.g. "class SomeClass extends Another implements IFace" *) method private write_declaration = - self#write_doc (DocClass cls.cl_doc); + self#write_doc (DocClass (gen_doc_text_opt cls.cl_doc)); if self#is_final then writer#write "final "; writer#write (if cls.cl_interface then "interface " else "class "); writer#write self#get_name; @@ -3440,7 +3398,7 @@ class class_builder ctx (cls:tclass) = if probably_descendant == iface then false else - is_parent iface probably_descendant + extends probably_descendant iface ) cls.cl_implements ) @@ -3579,7 +3537,7 @@ class class_builder ctx (cls:tclass) = writer#write_with_indentation (field_access ^ " = "); (match field.cf_expr with | Some expr -> writer#write_expr expr - | None -> fail field.cf_pos __POS__ + | None -> fail field.cf_pos __LOC__ ); writer#write ";\n" in @@ -3648,7 +3606,7 @@ class class_builder ctx (cls:tclass) = *) method private write_var field is_static = writer#indent 1; - self#write_doc (DocVar (writer#use_t field.cf_type, field.cf_doc)); + self#write_doc (DocVar (writer#use_t field.cf_type, (gen_doc_text_opt field.cf_doc))); writer#write_indentation; if is_static then writer#write "static "; let visibility = get_visibility field.cf_meta in @@ -3670,12 +3628,12 @@ class class_builder ctx (cls:tclass) = *) method private write_const field = match field.cf_expr with - | None -> fail writer#pos __POS__ + | None -> fail writer#pos __LOC__ (* Do not generate a PHP constant of `inline var` field if expression is not compatible with PHP const *) | Some expr when not (is_constant expr) -> () | Some expr -> writer#indent 1; - self#write_doc (DocVar (writer#use_t field.cf_type, field.cf_doc)); + self#write_doc (DocVar (writer#use_t field.cf_type, (gen_doc_text_opt field.cf_doc))); writer#write_with_indentation ("const " ^ (field_name field) ^ " = "); writer#write_expr expr; writer#write ";\n" @@ -3688,7 +3646,7 @@ class class_builder ctx (cls:tclass) = writer#indent 1; let (args, return_type) = get_function_signature field in List.iter (fun (arg_name, _, _) -> writer#declared_local_var arg_name) args; - self#write_doc (DocMethod (args, return_type, field.cf_doc)); + self#write_doc (DocMethod (args, return_type, (gen_doc_text_opt field.cf_doc))); writer#write_indentation; if self#is_final_field field then writer#write "final "; writer#write ((get_visibility field.cf_meta) ^ " "); @@ -3703,7 +3661,7 @@ class class_builder ctx (cls:tclass) = let name = if field.cf_name = "new" then "__construct" else (field_name field) in self#write_method name fn is_static; writer#write "\n" - | _ -> fail field.cf_pos __POS__ + | _ -> fail field.cf_pos __LOC__ (** Writes dynamic method to output buffer. Only for non-static methods. Static methods are created as static vars in `__hx__init`. @@ -3714,7 +3672,7 @@ class class_builder ctx (cls:tclass) = writer#indent 1; let (args, return_type) = get_function_signature field in List.iter (fun (arg_name, _, _) -> writer#declared_local_var arg_name) args; - self#write_doc (DocMethod (args, return_type, field.cf_doc)); + self#write_doc (DocMethod (args, return_type, (gen_doc_text_opt field.cf_doc))); writer#write_with_indentation ((get_visibility field.cf_meta) ^ " function " ^ (field_name field)); (match field.cf_expr with | None -> (* interface *) @@ -3736,7 +3694,7 @@ class class_builder ctx (cls:tclass) = writer#write_line "}"; (* Don't forget to create a field for default value *) writer#write_statement ("protected $__hx__default__" ^ (field_name field)) - | _ -> fail field.cf_pos __POS__ + | _ -> fail field.cf_pos __LOC__ ); (** Since PHP function names are case-insensitive we must check for method names clashes. @@ -3852,7 +3810,7 @@ class generator (ctx:php_generator_context) = self#generate_entry_point; match polyfills_source_path, polyfills_dest_path with | Some src, Some dst -> copy_file src dst - | _ -> fail null_pos __POS__ + | _ -> fail null_pos __LOC__ (** Generates calls to static __init__ methods in Boot.php *) @@ -3861,7 +3819,7 @@ class generator (ctx:php_generator_context) = | [] -> () | _ -> match boot with - | None -> fail null_pos __POS__ + | None -> fail null_pos __LOC__ | Some (_, filename) -> let channel = open_out_gen [Open_creat; Open_text; Open_append] 0o644 filename in List.iter @@ -3890,7 +3848,7 @@ class generator (ctx:php_generator_context) = output_string channel " }\n"; output_string channel ");\n"; (match boot with - | None -> fail null_pos __POS__ + | None -> fail null_pos __LOC__ | Some (builder, filename) -> let boot_class = get_full_type_name (add_php_prefix ctx builder#get_type_path) in output_string channel (boot_class ^ "::__hx__init();\n") @@ -3939,7 +3897,7 @@ let get_boot com : tclass = | TClassDecl cls -> cls | _ -> raise Not_found with - | Not_found -> fail ~msg:"php.Boot not found" null_pos __POS__ + | Not_found -> fail ~msg:"php.Boot not found" null_pos __LOC__ (** Entry point to Genphp7 diff --git a/src/generators/genpy.ml b/src/generators/genpy.ml index ec2e41bf6191d90148c3fd09575e702b1d151d3a..f4aa49d7c41bc5bd81d72bc07026cde7064acd4b 100644 --- a/src/generators/genpy.ml +++ b/src/generators/genpy.ml @@ -38,7 +38,7 @@ module Utils = struct abort (Printf.sprintf "Could not find type %s\n" (s_type_path path)) null_pos let mk_static_field c cf p = - let ta = TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } in + let ta = mk_anon ~fields:c.cl_statics (ref (Statics c)) in let ethis = mk (TTypeExpr (TClassDecl c)) ta p in let t = monomorphs cf.cf_params cf.cf_type in mk (TField (ethis,(FStatic (c,cf)))) t p @@ -47,7 +47,7 @@ module Utils = struct let ef = mk_static_field c cf p in let tr = match follow ef.etype with | TFun(args,tr) -> tr - | _ -> assert false + | _ -> die "" __LOC__ in mk (TCall(ef,el)) tr p @@ -221,7 +221,7 @@ module Transformer = struct let op = match unop with | Increment -> OpAdd | Decrement -> OpSub - | _ -> assert false + | _ -> die "" __LOC__ in let one = mk (TConst(TInt(Int32.of_int(1)))) t p in @@ -299,7 +299,7 @@ module Transformer = struct let tf = { tf with tf_expr = { tf.tf_expr with eexpr = TBlock(List.rev el)}} in {e with eexpr = TFunction tf} | _ -> - assert false + die "" __LOC__ let rec transform_function tf ae is_value = let p = tf.tf_expr.epos in @@ -391,7 +391,7 @@ module Transformer = struct let mk_eq e = mk (TBinop(OpEq,e1,e)) !t_bool (punion e1.epos e.epos) in let cond = match val_reversed with | [] -> - assert false + die "" __LOC__ | [e] -> mk_eq e | e :: el -> @@ -420,7 +420,7 @@ module Transformer = struct edef | [],None -> (* I don't think that can happen? *) - assert false + die "" __LOC__ | [case],_ -> case_to_if case edef | case :: cases,_ -> @@ -463,10 +463,10 @@ module Transformer = struct in let cases = Hashtbl.fold (fun i el acc -> let eint = mk (TConst (TInt (Int32.of_int i))) !t_int e1.epos in - let fs = match List.fold_left (fun eacc ec -> Some (mk_if ec eacc)) edef !el with Some e -> e | None -> assert false in + let fs = match List.fold_left (fun eacc ec -> Some (mk_if ec eacc)) edef !el with Some e -> e | None -> die "" __LOC__ in ([eint],fs) :: acc ) length_map [] in - let c_string = match !t_string with TInst(c,_) -> c | _ -> assert false in + let c_string = match !t_string with TInst(c,_) -> c | _ -> die "" __LOC__ in let cf_length = PMap.find "length" c_string.cl_fields in let ef = mk (TField(e1,FInstance(c_string,[],cf_length))) !t_int e1.epos in let res_var = alloc_var (ae.a_next_id()) ef.etype ef.epos in @@ -552,7 +552,7 @@ module Transformer = struct transform_exprs_to_block block ae.a_expr.etype false ae.a_expr.epos ae.a_next_id | _ -> debug_expr e1_.a_expr; - assert false + die "" __LOC__ and var_to_treturn_expr ?(capture = false) n t p = let x = mk (TLocal (to_tvar ~capture:capture n t p)) t p in @@ -576,17 +576,17 @@ module Transformer = struct in let def = (let ex = match exprs with - | [] -> assert false + | [] -> die "" __LOC__ | [x] -> (let exs = convert_return_expr x in match exs with - | [] -> assert false + | [] -> die "" __LOC__ | [x] -> x | x -> match List.rev x with | x::xs -> mk (TBlock exs) x.etype base.a_expr.epos - | _ -> assert false) + | _ -> die "" __LOC__) | x -> match List.rev x with @@ -597,8 +597,8 @@ module Transformer = struct match List.rev block with | x::_ -> mk (TBlock block) x.etype base.a_expr.epos - | _ -> assert false) - | _ -> assert false + | _ -> die "" __LOC__) + | _ -> die "" __LOC__ in let f1 = { tf_args = []; tf_type = TFun([],ex.etype); tf_expr = ex} in let fexpr = mk (TFunction f1) ex.etype ex.epos in @@ -653,7 +653,7 @@ module Transformer = struct | e :: el -> List.rev ((mk (TReturn (Some e)) t_dynamic e.epos) :: el),e.etype | [] -> - assert false + die "" __LOC__ in let my_block = transform_exprs_to_block block tr false ae.a_expr.epos ae.a_next_id in let fn = mk (TFunction { @@ -861,7 +861,7 @@ module Transformer = struct let op = match unop with | Increment -> OpAdd | Decrement -> OpSub - | _ -> assert false in + | _ -> die "" __LOC__ in transform_op_assign_op ae e op one is_value is_postfix | (_, TUnop(op, Prefix, e)) -> let e1 = trans true [] e in @@ -954,7 +954,7 @@ module Transformer = struct let r = { a_expr with eexpr = TArrayDecl exprs } in lift_expr ae.a_next_id ~blocks:blocks r | (is_value, TCast(e1,Some mt)) -> - let e = Codegen.default_cast ~vtmp:(ae.a_next_id()) (match !como with Some com -> com | None -> assert false) e1 mt ae.a_expr.etype ae.a_expr.epos in + let e = Codegen.default_cast ~vtmp:(ae.a_next_id()) (match !como with Some com -> com | None -> die "" __LOC__) e1 mt ae.a_expr.etype ae.a_expr.epos in transform_expr ae.a_next_id ~is_value:is_value e | (is_value, TCast(e,None)) -> let e = trans is_value [] e in @@ -972,7 +972,7 @@ module Transformer = struct | ( _, TConst _ ) -> lift_expr ae.a_next_id a_expr | ( _, TTypeExpr _ ) -> lift_expr ae.a_next_id a_expr - | ( _, TUnop _ ) -> assert false + | ( _, TUnop _ ) -> die "" __LOC__ | ( true, TWhile(econd, ebody, DoWhile) ) -> let new_expr = trans false [] a_expr in let f = exprs_to_func (new_expr.a_blocks @ [new_expr.a_expr]) (ae.a_next_id()) ae in @@ -1054,7 +1054,7 @@ module Printer = struct KeywordHandler.handle_keywords s let print_unop = function - | Increment | Decrement -> assert false + | Increment | Decrement -> die "" __LOC__ | Not -> "not " | Neg -> "-"; | NegBits -> "~" @@ -1080,7 +1080,7 @@ module Printer = struct | OpShr -> ">>" | OpUShr -> ">>" | OpMod -> "%" - | OpInterval | OpArrow | OpIn | OpAssignOp _ -> assert false + | OpInterval | OpArrow | OpIn | OpAssignOp _ -> die "" __LOC__ let print_string s = Printf.sprintf "\"%s\"" (StringHelper.s_escape s) @@ -1247,10 +1247,10 @@ module Printer = struct | "string" -> Printf.sprintf "Std._hx_is(%s, str)" (print_expr pctx e1) | "boolean" -> Printf.sprintf "Std._hx_is(%s, bool)" (print_expr pctx e1) | "number" -> Printf.sprintf "Std._hx_is(%s, float)" (print_expr pctx e1) - | _ -> assert false + | _ -> die "" __LOC__ end | _ -> - assert false + die "" __LOC__ end | TBinop(OpEq,e1,({eexpr = TConst TNull} as e2)) -> Printf.sprintf "(%s is %s)" (print_expr pctx e1) (print_expr pctx e2) @@ -1260,7 +1260,7 @@ module Printer = struct let ops = match op with | OpEq -> "is", "==", "HxOverrides.eq" | OpNotEq -> "is not", "!=", "not HxOverrides.eq" - | _ -> assert false + | _ -> die "" __LOC__ in let third (_,_,x) = x in let fst (x,_,_) = x in @@ -1393,19 +1393,7 @@ module Printer = struct | TContinue -> "continue" | TThrow e1 -> - let rec is_native_exception t = - match Abstract.follow_with_abstracts t with - | TInst ({ cl_path = [],"BaseException" }, _) -> - true - | TInst ({ cl_super = Some csup }, _) -> - is_native_exception (TInst(fst csup, snd csup)) - | _ -> - false - in - if is_native_exception e1.etype then - Printf.sprintf "raise %s" (print_expr pctx e1) - else - Printf.sprintf "raise _HxException(%s)" (print_expr pctx e1) + Printf.sprintf "raise %s" (print_expr pctx e1) | TCast(e1,None) -> print_expr pctx e1 | TMeta((Meta.Custom ":ternaryIf",_,_),{eexpr = TIf(econd,eif,Some eelse)}) -> @@ -1415,7 +1403,7 @@ module Printer = struct | TIdent s -> s | TSwitch _ | TCast(_, Some _) | TFor _ | TUnop(_,Postfix,_) -> - assert false + die "" __LOC__ and print_if_else pctx econd eif eelse as_elif = let econd1 = match econd.eexpr with @@ -1448,7 +1436,7 @@ module Printer = struct in let call_override s = match s with - | "iterator" | "toUpperCase" | "toLowerCase" | "pop" | "shift" | "join" | "push" | "map" | "filter" -> true + | "iterator" | "keyValueIterator" | "toUpperCase" | "toLowerCase" | "pop" | "shift" | "join" | "push" | "map" | "filter" -> true | _ -> false in match fa with @@ -1484,70 +1472,17 @@ module Printer = struct do_default() and print_try pctx e1 catches = - let has_catch_all = List.exists (fun (v,_) -> match follow v.v_type with - | TDynamic _ -> true - | _ -> false - ) catches in - let has_only_catch_all = has_catch_all && begin match catches with - | [_] -> true - | _ -> false - end in - let print_catch pctx i (v,e) = - let is_empty_expr = begin match e.eexpr with - | TBlock [] -> true - | _ -> false - end in - let indent = pctx.pc_indent in - (* Don't generate assignment to catch variable when catch expression is an empty block *) - let assign = if is_empty_expr then "" else Printf.sprintf "%s = _hx_e1\n%s" v.v_name indent in - let handle_base_type bt = - let t = print_base_type bt in - let print_custom_check t_str = - Printf.sprintf "if %s:\n%s %s %s" t_str indent assign (print_expr {pctx with pc_indent = " " ^ pctx.pc_indent} e) - in - let print_type_check t_str = - print_custom_check ("isinstance(_hx_e1, " ^ t_str ^ ")") - in - let res = match t with - | "str" -> print_type_check "str" - | "Bool" -> print_type_check "bool" - | "Int" -> print_custom_check "(isinstance(_hx_e1, int) and not isinstance(_hx_e1, bool))" (* for historic reasons bool extends int *) - | "Float" -> print_type_check "float" - | t -> print_type_check t - in - if i > 0 then - indent ^ "el" ^ res - else - res - in - match follow v.v_type with - | TDynamic _ -> - begin if has_only_catch_all then - Printf.sprintf "%s%s" assign (print_expr pctx e) - else - (* Dynamic is always the last block *) - Printf.sprintf "%selse:\n %s%s %s" indent indent assign (print_expr {pctx with pc_indent = " " ^ pctx.pc_indent} e) - end - | TInst(c,_) -> - handle_base_type (t_infos (TClassDecl c)) - | TEnum(en,_) -> - handle_base_type (t_infos (TEnumDecl en)) - | TAbstract(a,_) -> - handle_base_type (t_infos (TAbstractDecl a)) - | _ -> - assert false + let print_catch pctx (v,e) = + let s_type = print_module_type (module_type_of_type v.v_type) + and s_expr = pctx.pc_indent ^ (print_expr pctx e) in + Printf.sprintf "except %s as %s:\n%s" s_type v.v_name s_expr; in let indent = pctx.pc_indent in let print_expr_indented e = print_expr {pctx with pc_indent = " " ^ pctx.pc_indent} e in let try_str = Printf.sprintf "try:\n%s %s\n%s" indent (print_expr_indented e1) indent in - let except = if has_feature pctx "has_throw" then - Printf.sprintf "except Exception as _hx_e:\n%s _hx_e1 = _hx_e.val if isinstance(_hx_e, _HxException) else _hx_e\n%s " indent indent - else - Printf.sprintf "except Exception as _hx_e:\n%s _hx_e1 = _hx_e\n%s " indent indent - in - let catch_str = String.concat (Printf.sprintf "\n") (ExtList.List.mapi (fun i catch -> print_catch {pctx with pc_indent = " " ^ pctx.pc_indent} i catch) catches) in - let except_end = if not has_catch_all then Printf.sprintf "\n%s else:\n%s raise _hx_e" indent indent else "" in - Printf.sprintf "%s%s%s%s" try_str except catch_str except_end + let catch_pctx = {pctx with pc_indent = " " ^ pctx.pc_indent} in + let catch_str = String.concat (Printf.sprintf "\n") (List.map (print_catch catch_pctx) catches) in + Printf.sprintf "%s%s" try_str catch_str and print_call2 pctx e1 el = let id = print_expr pctx e1 in @@ -1580,7 +1515,7 @@ module Printer = struct | {eexpr = TObjectDecl fields} :: el -> List.rev el,fields | _ -> - assert false + die "" __LOC__ in begin match res with | e1 :: [] -> @@ -1667,12 +1602,12 @@ module Printer = struct "print(str(" ^ (print_expr pctx e) ^ "))" | TField(e1,((FAnon {cf_name = (("split" | "join" | "push" | "map" | "filter") as s)}) | FDynamic (("split" | "join" | "push" | "map" | "filter") as s))), [x] -> Printf.sprintf "HxOverrides.%s(%s, %s)" s (print_expr pctx e1) (print_expr pctx x) - | TField(e1,((FAnon {cf_name = (("iterator" | "toUpperCase" | "toLowerCase" | "pop" | "shift") as s)}) | FDynamic (("iterator" | "toUpperCase" | "toLowerCase" | "pop" | "shift") as s))), [] -> + | TField(e1,((FAnon {cf_name = (("iterator" | "keyValueIterator" | "toUpperCase" | "toLowerCase" | "pop" | "shift") as s)}) | FDynamic (("iterator" | "keyValueIterator" | "toUpperCase" | "toLowerCase" | "pop" | "shift") as s))), [] -> Printf.sprintf "HxOverrides.%s(%s)" s (print_expr pctx e1) | TField(_, (FStatic({cl_path = ["python"; "_KwArgs"], "KwArgs_Impl_"},{ cf_name="fromT" }))), [e2] -> let t = match follow call_expr.etype with | TAbstract(_, [t]) -> t - | _ -> assert false + | _ -> die "" __LOC__ in let native_fields = get_native_fields t in if PMap.is_empty native_fields then @@ -1872,12 +1807,12 @@ module Generator = struct (* Generating functions *) let gen_py_metas ctx metas indent = - List.iter (fun (n,el,_) -> + List.iter (fun (n,el,p) -> match el with - | [EConst(String(s,_)),_] -> - print ctx "%s@%s\n" indent s - | _ -> - assert false + | [EConst(String(s,_)),_] -> + print ctx "%s@%s\n" indent s + | _ -> + abort "@:python metadata must have a string literal argument" p ) metas let gen_expr ctx e field indent = @@ -1901,7 +1836,7 @@ module Generator = struct let call_f = mk (TCall(f_name,[])) e_last.etype e_last.epos in Some new_block,call_f | _ -> - assert false + die "" __LOC__ end | _ -> None,expr2 @@ -1993,7 +1928,7 @@ module Generator = struct newline ctx; gen_func_expr ctx ef c "__init__" py_metas true " " false cf.cf_pos | _ -> - assert false + die "" __LOC__ end let gen_class_field ctx c p cf = @@ -2067,7 +2002,7 @@ module Generator = struct has_static_methods := true; let field = handle_keywords cf.cf_name in let py_metas = filter_py_metas cf.cf_meta in - let e = match cf.cf_expr with Some e -> e | _ -> assert false in + let e = match cf.cf_expr with Some e -> e | _ -> die "" __LOC__ in newline ctx; gen_func_expr ctx e c field py_metas false " " true cf.cf_pos; ) methods; @@ -2110,6 +2045,8 @@ module Generator = struct newline ctx; newline ctx; newline ctx; + let py_metas = filter_py_metas c.cl_meta in + gen_py_metas ctx py_metas ""; print ctx "class %s" p; (match p_super with Some p -> print ctx "(%s)" p | _ -> ()); spr ctx ":"; @@ -2276,7 +2213,7 @@ module Generator = struct newline ctx; print ctx " @staticmethod\n def %s(%s):\n" f param_str; print ctx " return %s(\"%s\", %i, (%s))" p ef.ef_name ef.ef_index args_str; - | _ -> assert false + | _ -> die "" __LOC__ ) param_constructors; List.iter (fun ef -> @@ -2434,6 +2371,10 @@ module Generator = struct spr ctx " self.__dict__ = fields\n"; spr ctx " def __repr__(self):\n"; spr ctx " return repr(self.__dict__)\n"; + spr ctx " def __contains__(self, item):\n"; + spr ctx " return item in self.__dict__\n"; + spr ctx " def __getitem__(self, item):\n"; + spr ctx " return self.__dict__[item]\n"; spr ctx " def __getattr__(self, name):\n"; spr ctx " if (self._hx_disable_getattr):\n"; spr ctx " raise AttributeError('field does not exist')\n"; diff --git a/src/generators/genshared.ml b/src/generators/genshared.ml new file mode 100644 index 0000000000000000000000000000000000000000..207e3491e515136128f5feaa88c7644d12e7c7f0 --- /dev/null +++ b/src/generators/genshared.ml @@ -0,0 +1,536 @@ +open Globals +open Ast +open TType +open TFunctions +open TUnification + +type method_type = + | MStatic + | MInstance + | MConstructor + +let is_extern_abstract a = match a.a_impl with + | Some {cl_extern = true} -> true + | _ -> match a.a_path with + | ([],("Void" | "Float" | "Int" | "Single" | "Bool" | "Null")) -> true + | _ -> false + +let unify_cf map_type c cf el = + let monos = List.map (fun _ -> mk_mono()) cf.cf_params in + match follow (apply_params cf.cf_params monos (map_type cf.cf_type)) with + | TFun(tl'',_) as tf -> + let rec loop2 acc el tl = match el,tl with + | e :: el,(_,o,t) :: tl -> + begin try + Type.unify e.etype t; + loop2 ((e,o) :: acc) el tl + with _ -> + match t,tl with + | TAbstract({a_path=["haxe";"extern"],"Rest"},[t]),[] -> + begin try + let el = List.map (fun e -> unify t e.etype; e,o) el in + Some ((List.rev acc) @ el,tf,(c,cf,monos)) + with _ -> + None + end + | _ -> + None + end + | [],[] -> + Some ((List.rev acc),tf,(c,cf,monos)) + | _ -> + None + in + loop2 [] el tl'' + | t -> + None + +let unify_cf_with_fallback map_type c cf el = + match unify_cf map_type c cf el with + | Some(_,_,r) -> r + | None -> (c,cf,List.map snd cf.cf_params) + +let find_overload map_type c cf el = + let matches = ref [] in + let rec loop cfl = match cfl with + | cf :: cfl -> + begin match unify_cf map_type c cf el with + | Some r -> matches := r :: !matches; + | None -> () + end; + loop cfl + | [] -> + List.rev !matches + in + loop (cf :: cf.cf_overloads) + +let filter_overloads candidates = + match Overloads.Resolution.reduce_compatible candidates with + | [_,_,(c,cf,tl)] -> Some(c,cf,tl) + | [] -> None + | ((_,_,(c,cf,tl)) :: _) (* as resolved *) -> + (* let st = s_type (print_context()) in + print_endline (Printf.sprintf "Ambiguous overload for %s(%s)" name (String.concat ", " (List.map (fun e -> st e.etype) el))); + List.iter (fun (_,t,(c,cf)) -> + print_endline (Printf.sprintf "\tCandidate: %s.%s(%s)" (s_type_path c.cl_path) cf.cf_name (st t)); + ) resolved; *) + Some(c,cf,tl) + +let find_overload_rec' is_ctor map_type c name el = + let candidates = ref [] in + let has_function t1 (_,t2,_) = + begin match follow t1,t2 with + | TFun(tl1,_),TFun(tl2,_) -> type_iseq (TFun(tl1,t_dynamic)) (TFun(tl2,t_dynamic)) + | _ -> false + end + in + let rec loop map_type c = + begin try + let cf = if is_ctor then + (match c.cl_constructor with Some cf -> cf | None -> raise Not_found) + else + PMap.find name c.cl_fields + in + begin match find_overload map_type c cf el with + | [] -> raise Not_found + | l -> + List.iter (fun ((_,t,_) as ca) -> + if not (List.exists (has_function t) !candidates) then candidates := ca :: !candidates + ) l + end; + if Meta.has Meta.Overload cf.cf_meta || cf.cf_overloads <> [] then raise Not_found + with Not_found -> + if c.cl_interface then + List.iter (fun (c,tl) -> loop (fun t -> apply_params c.cl_params (List.map map_type tl) t) c) c.cl_implements + else match c.cl_super with + | None -> () + | Some(c,tl) -> loop (fun t -> apply_params c.cl_params (List.map map_type tl) t) c + end; + in + loop map_type c; + filter_overloads (List.rev !candidates) + +let find_overload_rec is_ctor map_type c cf el = + if Meta.has Meta.Overload cf.cf_meta || cf.cf_overloads <> [] then + find_overload_rec' is_ctor map_type c cf.cf_name el + else match unify_cf map_type c cf el with + | Some (_,_,(c,cf,tl)) -> Some (c,cf,tl) + | None -> Some(c,cf,List.map snd cf.cf_params) + +type path_field_mapping = { + pfm_path : path; + pfm_params : type_params; + pfm_fields : (string,tclass_field) PMap.t; +} + +let pfm_of_typedef td = match follow td.t_type with + | TAnon an -> { + pfm_path = td.t_path; + pfm_params = td.t_params; + pfm_fields = an.a_fields; + } + | _ -> + die "" __LOC__ + +exception Typedef_result of path_field_mapping + +class ['a] tanon_identification (empty_path : string list * string) = + let is_normal_anon an = match !(an.a_status) with + | Closed | Const | Opened -> true + | _ -> false + in +object(self) + + val td_anons = Hashtbl.create 0 + val mutable num = 0 + + method get_anons = td_anons + + method unify (tc : Type.t) (pfm : path_field_mapping) = + let check () = + let monos = List.map (fun _ -> mk_mono()) pfm.pfm_params in + let map = apply_params pfm.pfm_params monos in + begin match follow tc with + | TInst(c,tl) -> + PMap.iter (fun _ cf -> + let cf' = PMap.find cf.cf_name c.cl_fields in + if not (unify_kind cf'.cf_kind cf.cf_kind) then raise (Unify_error [Unify_custom "kind mismatch"]); + Type.unify (apply_params c.cl_params tl (monomorphs cf'.cf_params cf'.cf_type)) (map (monomorphs cf.cf_params cf.cf_type)) + ) pfm.pfm_fields + | TAnon an1 -> + let fields = ref an1.a_fields in + PMap.iter (fun _ cf -> + let cf' = PMap.find cf.cf_name an1.a_fields in + if not (unify_kind cf'.cf_kind cf.cf_kind) then raise (Unify_error [Unify_custom "kind mismatch"]); + fields := PMap.remove cf.cf_name !fields; + Type.type_eq EqDoNotFollowNull cf'.cf_type (map (monomorphs cf.cf_params cf.cf_type)) + ) pfm.pfm_fields; + if not (PMap.is_empty !fields) then raise (Unify_error [Unify_custom "not enough fields"]) + | _ -> + raise (Unify_error [Unify_custom "bad type"]) + end; + (* Check if we applied Void to a return type parameter... (#3463) *) + List.iter (fun t -> match follow t with + | TMono r -> + Monomorph.bind r t_dynamic + | t -> + if Type.ExtType.is_void t then raise(Unify_error [Unify_custom "return mono"]) + ) monos + in + try + check() + with Not_found -> + raise (Unify_error []) + + method find_compatible (tc : Type.t) = + try + Hashtbl.iter (fun _ td -> + try + self#unify tc td; + raise (Typedef_result td) + with Unify_error _ -> + () + ) td_anons; + raise Not_found + with Typedef_result td -> + td + + method identify_typedef (td : tdef) = + let rec loop t = match t with + | TAnon an when is_normal_anon an && not (PMap.is_empty an.a_fields) -> + Hashtbl.replace td_anons td.t_path (pfm_of_typedef td); + | TMono {tm_type = Some t} -> + loop t + | TLazy f -> + loop (lazy_type f) + | t -> + () + in + loop td.t_type + + method identify (accept_anons : bool) (t : Type.t) = + match t with + | TType(td,tl) -> + begin try + Some (Hashtbl.find td_anons td.t_path) + with Not_found -> + self#identify accept_anons (apply_params td.t_params tl td.t_type) + end + | TMono {tm_type = Some t} -> + self#identify accept_anons t + | TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> + self#identify accept_anons (Abstract.get_underlying_type a tl) + | TAbstract({a_path=([],"Null")},[t]) -> + self#identify accept_anons t + | TLazy f -> + self#identify accept_anons (lazy_type f) + | TAnon an when accept_anons && not (PMap.is_empty an.a_fields) -> + PMap.iter (fun _ cf -> + Gencommon.replace_mono cf.cf_type + ) an.a_fields; + begin try + Some (self#find_compatible t) + with Not_found -> + let id = num in + num <- num + 1; + let path = (["haxe";"generated"],Printf.sprintf "Anon%i" id) in + let pfm = { + pfm_path = path; + pfm_params = []; + pfm_fields = an.a_fields; + } in + Hashtbl.replace td_anons path pfm; + Some pfm + end; + | _ -> + None +end + +type field_generation_info = { + mutable has_this_before_super : bool; + (* This is an ordered list of fields that are targets of super() calls which is determined during + pre-processing. The generator can pop from this list assuming that it processes the expression + in the same order (which it should). *) + mutable super_call_fields : (tclass * tclass_field) list; +} + +class ['a] preprocessor (basic : basic_types) (convert : Type.t -> 'a) = + let make_native cf = + cf.cf_meta <- (Meta.NativeGen,[],null_pos) :: cf.cf_meta + in + let make_haxe cf = + cf.cf_meta <- (Meta.HxGen,[],null_pos) :: cf.cf_meta + in + let rec get_constructor c = + match c.cl_constructor, c.cl_super with + | Some cf, _ -> c,cf + | None, None -> raise Not_found + | None, Some (csup,cparams) -> get_constructor csup + in + object(self) + + val implicit_ctors : (path,((path * 'a),(tclass * tclass_field)) PMap.t) Hashtbl.t = Hashtbl.create 0 + val field_infos : field_generation_info DynArray.t = DynArray.create() + + method get_implicit_ctor (path : path) = + Hashtbl.find implicit_ctors path + + method get_field_info (ml : metadata) = + let rec loop ml = match ml with + | (Meta.Custom ":jvm.fieldInfo",[(EConst (Int s),_)],_) :: _ -> + Some (DynArray.get field_infos (int_of_string s)) + | _ :: ml -> + loop ml + | [] -> + None + in + loop ml + + method add_implicit_ctor (c : tclass) (c' : tclass) (cf : tclass_field) = + let jsig = convert cf.cf_type in + try + let sm = Hashtbl.find implicit_ctors c.cl_path in + Hashtbl.replace implicit_ctors c.cl_path (PMap.add (c'.cl_path,jsig) (c',cf) sm); + with Not_found -> + Hashtbl.add implicit_ctors c.cl_path (PMap.add (c'.cl_path,jsig) (c',cf) PMap.empty) + + method preprocess_constructor_expr (c : tclass) (cf : tclass_field) (e : texpr) = + let used_this = ref false in + let this_before_super = ref false in + let super_call_fields = DynArray.create () in + let is_on_current_class cf = PMap.mem cf.cf_name c.cl_fields in + let find_super_ctor el = + let csup,map_type = match c.cl_super with + | Some(c,tl) -> c,apply_params c.cl_params tl + | _ -> die "" __LOC__ + in + match find_overload_rec' true map_type csup "new" el with + | Some(c,cf,_) -> + let rec loop csup = + if c != csup then begin + match csup.cl_super with + | Some(c',_) -> + self#add_implicit_ctor csup c' cf; + loop c' + | None -> die "" __LOC__ + end + in + loop csup; + (c,cf) + | None -> Error.error "Could not find overload constructor" e.epos + in + let find_super_ctor el = + let _,cf = find_super_ctor el in + (* This is a bit hacky: We always want the direct super class, not the one that actually holds + the ctor. It will be implicitly copied to it anyway. *) + match c.cl_super with + | None -> die "" __LOC__ + | Some(c,_) -> c,cf + in + let rec promote_this_before_super c cf = match self#get_field_info cf.cf_meta with + | None -> failwith "Something went wrong" + | Some info -> + if not info.has_this_before_super then begin + make_haxe cf; + (* print_endline (Printf.sprintf "promoted this_before_super to %s.new : %s" (s_type_path c.cl_path) (s_type (print_context()) cf.cf_type)); *) + info.has_this_before_super <- true; + List.iter (fun (c,cf) -> promote_this_before_super c cf) info.super_call_fields + end + in + let rec loop e = + begin match e.eexpr with + | TBinop(OpAssign,{eexpr = TField({eexpr = TConst TThis},FInstance(_,_,cf))},e2) when is_on_current_class cf-> + (* Assigning this.field = value is fine if field is declared on our current class *) + loop e2; + | TConst TThis -> + used_this := true + | TCall({eexpr = TConst TSuper},el) -> + List.iter loop el; + if !used_this then begin + this_before_super := true; + make_haxe cf; + (* print_endline (Printf.sprintf "inferred this_before_super on %s.new : %s" (s_type_path c.cl_path) (s_type (print_context()) cf.cf_type)); *) + end; + let c,cf = find_super_ctor el in + if !this_before_super then promote_this_before_super c cf; + DynArray.add super_call_fields (c,cf); + | _ -> + Type.iter loop e + end; + in + loop e; + { + has_this_before_super = !this_before_super; + super_call_fields = DynArray.to_list super_call_fields; + } + + method check_overrides c = match c.cl_overrides with + | [] -> + () + | fields -> + let csup,map_type = match c.cl_super with + | Some(c,tl) -> c,apply_params c.cl_params tl + | None -> die "" __LOC__ + in + let fix_covariant_return cf = + let tl = match follow cf.cf_type with + | TFun(tl,_) -> tl + | _ -> die "" __LOC__ + in + match find_overload_rec' false map_type csup cf.cf_name (List.map (fun (_,_,t) -> Texpr.Builder.make_null t null_pos) tl) with + | Some(_,cf',_) -> + let tr = match follow cf'.cf_type with + | TFun(_,tr) -> tr + | _ -> die "" __LOC__ + in + cf.cf_type <- TFun(tl,tr); + cf.cf_expr <- begin match cf.cf_expr with + | Some ({eexpr = TFunction tf} as e) -> + Some {e with eexpr = TFunction {tf with tf_type = tr}} + | e -> + e + end; + | None -> + () + (* TODO: this should never happen if we get the unification right *) + (* Error.error "Could not find overload" cf.cf_pos *) + in + List.iter (fun cf -> + fix_covariant_return cf; + List.iter fix_covariant_return cf.cf_overloads + ) fields + + method preprocess_class (c : tclass) = + let has_dynamic_instance_method = ref false in + let has_field_init = ref false in + let field mtype cf = + match mtype with + | MConstructor -> + () + | MInstance -> + begin match cf.cf_kind with + | Method MethDynamic -> has_dynamic_instance_method := true + | Var _ when cf.cf_expr <> None && not !has_field_init && c.cl_constructor = None && c.cl_super = None -> + has_field_init := true; + self#add_implicit_ctor c c (mk_field "new" (tfun [] basic.tvoid) null_pos null_pos) + | _ -> () + end; + | MStatic -> + () + in + self#check_overrides c; + List.iter (field MStatic) c.cl_ordered_statics; + List.iter (field MInstance) c.cl_ordered_fields; + match c.cl_constructor with + | None -> + begin try + let csup,cf = get_constructor c in + List.iter (fun cf -> self#add_implicit_ctor c csup cf) (cf :: cf.cf_overloads) + with Not_found -> + () + end; + | Some cf -> + let field cf = + if !has_dynamic_instance_method then make_haxe cf; + begin match cf.cf_expr with + | None -> + () + | Some e -> + let info = self#preprocess_constructor_expr c cf e in + let index = DynArray.length field_infos in + DynArray.add field_infos info; + cf.cf_meta <- (Meta.Custom ":jvm.fieldInfo",[(EConst (Int (string_of_int index)),null_pos)],null_pos) :: cf.cf_meta; + if not (Meta.has Meta.HxGen cf.cf_meta) then begin + let rec loop next c = + if c.cl_extern then make_native cf + else match c.cl_constructor with + | Some cf' when Meta.has Meta.HxGen cf'.cf_meta -> make_haxe cf + | Some cf' when Meta.has Meta.NativeGen cf'.cf_meta -> make_native cf + | _ -> next c + in + let rec up c = match c.cl_super with + | None -> () + | Some(c,_) -> loop up c + in + let rec down c = List.iter (fun c -> loop down c) c.cl_descendants in + loop up c; + loop down c + end; + end + in + List.iter field (cf :: cf.cf_overloads) +end + +class ['a] typedef_interfaces (anon_identification : 'a tanon_identification) = object(self) + + val lut = Hashtbl.create 0 + val interfaces = Hashtbl.create 0 + val interface_rewrites = Hashtbl.create 0 + + method add_interface_rewrite (path_from : path) (path_to : path) (is_extern : bool) = + Hashtbl.replace interface_rewrites path_from (path_to,is_extern) + + method get_interface_class (path : path) = + try Some (Hashtbl.find interfaces path) + with Not_found -> None + + method get_interfaces = interfaces + + method process_class (c : tclass) = + if not (Hashtbl.mem lut c.cl_path) then + self#do_process_class c + + method private implements (path_class : path) (path_interface : path) = + try + let l = Hashtbl.find lut path_class in + List.exists (fun c -> c.cl_path = path_interface) l + with Not_found -> + false + + method private implements_recursively (c : tclass) (path : path) = + self#implements c.cl_path path || match c.cl_super with + | Some (c,_) -> self#implements_recursively c path + | None -> false + + method private make_interface_class (pfm : path_field_mapping) = + let path_inner = (fst pfm.pfm_path,snd pfm.pfm_path ^ "$Interface") in + try + Hashtbl.find interfaces path_inner + with Not_found -> + let fields = PMap.foldi (fun name cf acc -> match cf.cf_kind with + | Method (MethNormal | MethInline) -> + PMap.add name cf acc + | _ -> + acc + ) pfm.pfm_fields PMap.empty in + if PMap.is_empty fields then raise (Unify_error [Unify_custom "no fields"]); + let path,is_extern = try Hashtbl.find interface_rewrites pfm.pfm_path with Not_found -> path_inner,false in + let c = mk_class null_module path null_pos null_pos in + c.cl_interface <- true; + c.cl_fields <- fields; + c.cl_ordered_fields <- PMap.fold (fun cf acc -> cf :: acc) fields []; + if is_extern then c.cl_extern <- true; + Hashtbl.replace interfaces pfm.pfm_path c; + c + + method private do_process_class (c : tclass) = + begin match c.cl_super with + | Some(c,_) -> self#process_class c + | None -> () + end; + let tc = TInst(c,List.map snd c.cl_params) in + let l = Hashtbl.fold (fun _ pfm acc -> + let path = pfm.pfm_path in + let path_inner = (fst path,snd path ^ "$Interface") in + try + if self#implements_recursively c path_inner then raise (Unify_error [Unify_custom "already implemented"]); + anon_identification#unify tc pfm; + let ci = self#make_interface_class pfm in + c.cl_implements <- (ci,[]) :: c.cl_implements; + (* print_endline (Printf.sprintf "%s IMPLEMENTS %s" (s_type_path c.cl_path) (s_type_path path_inner)); *) + (ci :: acc) + with Unify_error _ -> + acc + ) anon_identification#get_anons [] in + Hashtbl.add lut c.cl_path l +end \ No newline at end of file diff --git a/src/generators/genswf.ml b/src/generators/genswf.ml index cfd8f4b9c5ecbdce13a23aa8b22d45868ef49836..9383f13d7d033fc0e1e8689595d567e7f3637202 100644 --- a/src/generators/genswf.ml +++ b/src/generators/genswf.ml @@ -88,7 +88,7 @@ let build_dependencies t = | TLazy f -> add_type_rec l (lazy_type f) | TMono r -> - (match !r with + (match r.tm_type with | None -> () | Some t -> add_type_rec l t) | TType (tt,pl) -> diff --git a/src/generators/genswf9.ml b/src/generators/genswf9.ml index 3abdf001a64f33d07ca6939581d694b710f00246..c61a6a89f3c5904d287bd6ce66f169a46b109277 100644 --- a/src/generators/genswf9.ml +++ b/src/generators/genswf9.ml @@ -185,7 +185,7 @@ let type_path ctx path = let rec follow_basic t = match t with | TMono r -> - (match !r with + (match r.tm_type with | Some t -> follow_basic t | _ -> t) | TLazy f -> @@ -288,7 +288,7 @@ let classify ctx t = | TDynamic _ -> KDynamic | TLazy _ -> - assert false + die "" __LOC__ (* some field identifiers might cause issues with SWC *) let reserved i = @@ -317,7 +317,7 @@ let ns_access cf = Some (HMName (cf.cf_name, HNNamespace ns)) | [(EConst (String(ns,_)),_); (EConst (Ident "internal"),_)] -> Some (HMName (cf.cf_name, HNInternal (Some ns))) - | _ -> assert false + | _ -> die "" __LOC__ with Not_found -> None @@ -335,7 +335,8 @@ let property ctx fa t = (match p with | "length" -> ident p, Some KInt, false (* UInt in the spec *) | "map" | "filter" when Common.defined ctx.com Define.NoFlashOverride -> ident (p ^ "HX"), None, true - | "copy" | "insert" | "remove" | "iterator" | "toString" | "map" | "filter" | "resize" -> ident p , None, true + | "copy" | "insert" | "contains" | "remove" | "iterator" | "keyValueIterator" + | "toString" | "map" | "filter" | "resize" -> ident p , None, true | _ -> as3 p, None, false); | TInst ({ cl_path = ["flash"],"Vector" },_) -> (match p with @@ -446,7 +447,7 @@ let coerce ctx t = | KBool -> HToBool | KType t -> HCast t | KDynamic -> HAsAny - | KNone -> assert false + | KNone -> die "" __LOC__ ) let set_reg ctx r = @@ -476,7 +477,7 @@ let pop ctx n = loop (n - 1) end in - if n < 0 then assert false; + if n < 0 then die "" __LOC__; let old = ctx.infos.istack in loop n; ctx.infos.istack <- old @@ -541,7 +542,7 @@ let rec setvar ctx (acc : write access) kret = else set_reg ctx r; | VGlobal _ | VId _ | VCast _ | VArray | VScope _ | VSuper _ when kret <> None -> - let r = alloc_reg ctx (match kret with None -> assert false | Some k -> k) in + let r = alloc_reg ctx (match kret with None -> die "" __LOC__ | Some k -> k) in set_reg_dup ctx r; setvar ctx acc None; write ctx (HReg r.rid); @@ -597,7 +598,7 @@ let open_block ctx retval = let old_regs = DynArray.map (fun r -> r.rused) ctx.infos.iregs in let old_locals = ctx.locals in (fun() -> - if ctx.infos.istack <> old_stack + (if retval then 1 else 0) then assert false; + if ctx.infos.istack <> old_stack + (if retval then 1 else 0) then die "" __LOC__; let rcount = DynArray.length old_regs + 1 in DynArray.iter (fun r -> if r.rid < rcount then @@ -682,7 +683,7 @@ let gen_constant ctx c t p = | TThis -> write ctx HThis | TSuper -> - assert false + die "" __LOC__ let end_fun ctx args dparams tret = { @@ -701,7 +702,7 @@ let end_fun ctx args dparams tret = hlmt_function = None; } -let gen_expr_ref = ref (fun _ _ _ -> assert false) +let gen_expr_ref = ref (fun _ _ _ -> die "" __LOC__) let gen_expr ctx e retval = (!gen_expr_ref) ctx e retval let begin_fun ctx args tret el stat p = @@ -745,7 +746,7 @@ let begin_fun ctx args tret el stat p = | TConst (TFloat s) -> HVFloat (float_of_string s) | TConst (TBool b) -> HVBool b | TConst TNull -> abort ("In Flash9, null can't be used as basic type " ^ s_type (print_context()) t) p - | _ -> assert false) + | _ -> die "" __LOC__) | _, Some {eexpr = TConst TNull} -> HVNone | k, Some c -> write ctx (HReg r.rid); @@ -881,7 +882,7 @@ let begin_loop ctx = ctx.breaks <- []; ctx.continues <- []; (fun cont_pos -> - if ctx.infos.istack <> ctx.infos.iloop then assert false; + if ctx.infos.istack <> ctx.infos.iloop then die "" __LOC__; List.iter (fun j -> j()) ctx.breaks; List.iter (fun j -> j cont_pos) ctx.continues; ctx.infos.iloop <- old_loop; @@ -1048,7 +1049,7 @@ let rec gen_expr_content ctx retval e = gen_constant ctx c e.etype e.epos | TThrow e -> ctx.infos.icond <- true; - if has_feature ctx.com "haxe.CallStack.exceptionStack" then begin + if has_feature ctx.com "haxe.CallStack.exceptionStack" && not (Exceptions.is_haxe_exception e.etype) then begin getvar ctx (VGlobal (type_path ctx (["flash"],"Boot"))); let id = type_path ctx (["flash";"errors"],"Error") in write ctx (HFindPropStrict id); @@ -1159,7 +1160,7 @@ let rec gen_expr_content ctx retval e = gen_expr ctx false e; if flag = NormalWhile then jstart(); let continue_pos = ctx.infos.ipos in - let _ = jump_expr_gen ctx econd true (fun j -> loop j; (fun() -> ())) in + let _j = jump_expr_gen ctx econd true (fun j -> loop j; (fun() -> ())) in branch(); end_loop continue_pos; if retval then write ctx HNull @@ -1194,7 +1195,7 @@ let rec gen_expr_content ctx retval e = write ctx HScope); (* store the exception into local var, using a tmp register if needed *) define_local ctx v e.epos; - let r = (match snd (try PMap.find v.v_id ctx.locals with Not_found -> assert false) with + let r = (match snd (try PMap.find v.v_id ctx.locals with Not_found -> die "" __LOC__) with | LReg _ -> None | _ -> let r = alloc_reg ctx (classify ctx t) in @@ -1212,7 +1213,7 @@ let rec gen_expr_content ctx retval e = | _ -> Type.iter call_loop e in let has_call = (try call_loop e; false with Exit -> true) in - if has_call && has_feature ctx.com "haxe.CallStack.exceptionStack" then begin + if has_call && has_feature ctx.com "haxe.CallStack.exceptionStack" && not (Exceptions.is_haxe_exception v.v_type) then begin getvar ctx (gen_local_access ctx v e.epos Read); write ctx (HAsType (type_path ctx (["flash";"errors"],"Error"))); let j = jump ctx J3False in @@ -1317,7 +1318,7 @@ let rec gen_expr_content ctx retval e = (!prev)(); let rec loop = function | [] -> - assert false + die "" __LOC__ | [v] -> write ctx (HReg r.rid); gen_expr ctx true v; @@ -1371,7 +1372,7 @@ let rec gen_expr_content ctx retval e = (* manual cast *) let tid = (match gen_access ctx (mk (TTypeExpr t) t_dynamic e.epos) Read with | VGlobal id -> id - | _ -> assert false + | _ -> die "" __LOC__ ) in match classify ctx e.etype with | KType n when (match n with HMPath ([],"String") -> false | _ -> true) -> @@ -1405,7 +1406,7 @@ and gen_call ctx retval e el r = gen_expr ctx true e; gen_expr ctx true t; write ctx (HOp A3OIs) - | TField (_,FStatic ({ cl_path = [],"Std" },{ cf_name = "is" })),[e;{ eexpr = TTypeExpr (TClassDecl _) } as t] -> + | TField (_,FStatic ({ cl_path = [],"Std" },{ cf_name = ("is" | "isOfType") })),[e;{ eexpr = TTypeExpr (TClassDecl _) } as t] -> (* fast inlining of Std.is with known values *) gen_expr ctx true e; gen_expr ctx true t; @@ -1503,7 +1504,7 @@ and gen_call ctx retval e el r = | 2l -> A3OMemSet32 | 3l -> A3OMemSetFloat | 4l -> A3OMemSetDouble - | _ -> assert false + | _ -> die "" __LOC__ )) | TIdent "__vmem_get__", [{ eexpr = TConst (TInt code) };e] -> gen_expr ctx true e; @@ -1513,7 +1514,7 @@ and gen_call ctx retval e el r = | 2l -> A3OMemGet32 | 3l -> A3OMemGetFloat | 4l -> A3OMemGetDouble - | _ -> assert false + | _ -> die "" __LOC__ )) | TIdent "__vmem_sign__", [{ eexpr = TConst (TInt code) };e] -> gen_expr ctx true e; @@ -1521,10 +1522,10 @@ and gen_call ctx retval e el r = | 0l -> A3OSign1 | 1l -> A3OSign8 | 2l -> A3OSign16 - | _ -> assert false + | _ -> die "" __LOC__ )) | TIdent "__vector__", [] -> - let t = match r with TAbstract ({a_path = [],"Class"}, [vt]) -> vt | _ -> assert false in + let t = match r with TAbstract ({a_path = [],"Class"}, [vt]) -> vt | _ -> die "" __LOC__ in gen_type ctx (type_id ctx t) | TIdent "__vector__", [ep] -> gen_type ctx (type_id ctx r); @@ -1537,7 +1538,7 @@ and gen_call ctx retval e el r = write ctx (HFindPropStrict id); List.iter (gen_expr ctx true) el; write ctx (HCallProperty (id,List.length el)); - | _ -> assert false) + | _ -> die "" __LOC__) | TConst TSuper , _ -> write ctx HThis; List.iter (gen_expr ctx true) el; @@ -1698,7 +1699,7 @@ and gen_binop ctx retval op e1 e2 t p = | OpShr -> A3OShr | OpUShr -> A3OUShr | OpMod -> A3OMod - | _ -> assert false + | _ -> die "" __LOC__ ) in match iop with | Some iop -> @@ -1728,7 +1729,7 @@ and gen_binop ctx retval op e1 e2 t p = | None -> gen_op A3OEq | Some c -> - let f = FStatic (c,try PMap.find "compare" c.cl_statics with Not_found -> assert false) in + let f = FStatic (c,try PMap.find "compare" c.cl_statics with Not_found -> die "" __LOC__) in gen_expr ctx true (mk (TCall (mk (TField (mk (TTypeExpr (TClassDecl c)) t_dynamic p,f)) t_dynamic p,[e1;e2])) ctx.com.basic.tbool p); in match op with @@ -1781,7 +1782,7 @@ and gen_binop ctx retval op e1 e2 t p = | OpLte -> gen_op A3OLte | OpInterval | OpArrow | OpIn -> - assert false + die "" __LOC__ and gen_expr ctx retval e = let old = ctx.infos.istack in @@ -2397,7 +2398,7 @@ let realize_required_accessors ctx cl = end end; end - | _ -> assert false + | _ -> die "" __LOC__ ) interface_props; !fields @@ -2426,7 +2427,7 @@ let generate_class ctx c = check_constructor ctx c fdata; old(); m - | _ -> assert false + | _ -> die "" __LOC__ ) in let has_protected = ref None in let make_name f stat = @@ -2567,7 +2568,7 @@ let generate_class ctx c = match generate_field_kind ctx f c true with | None -> acc | Some k -> - let count = (match k with HFMethod _ -> st_meth_count | HFVar _ -> st_field_count | _ -> assert false) in + let count = (match k with HFMethod _ -> st_meth_count | HFVar _ -> st_field_count | _ -> die "" __LOC__) in incr count; { hlf_name = make_name f true; @@ -2783,7 +2784,7 @@ let generate_resource ctx name = let t = TClassDecl c in match generate_type ctx t with | Some (m,f) -> (t,m,f) - | None -> assert false + | None -> die "" __LOC__ let generate com boot_name = let ctx = { diff --git a/src/generators/hl2c.ml b/src/generators/hl2c.ml index 128b144467256ec2e91f8b8e3a6e0c27bc5f8276..29485cf6639c84c6e02ac0b4945d9fd7593e11ad 100644 --- a/src/generators/hl2c.ml +++ b/src/generators/hl2c.ml @@ -87,6 +87,8 @@ let keywords = "auto";"break";"case";"char";"const";"continue";"default";"do";"double";"else";"enum";"extern";"float";"for";"goto"; "if";"int";"long";"register";"return";"short";"signed";"sizeof";"static";"struct";"switch";"typedef";"union";"unsigned"; "void";"volatile";"while"; + (* Values *) + "NULL";"true";"false"; (* MS specific *) "__asm";"dllimport2";"__int8";"naked2";"__based1";"__except";"__int16";"__stdcall";"__cdecl";"__fastcall";"__int32"; "thread2";"__declspec";"__finally";"__int64";"__try";"dllexport2";"__inline";"__leave";"asm"; @@ -221,7 +223,7 @@ let hash ctx sid = h let type_name ctx t = - try PMap.find t ctx.htypes with Not_found -> assert false + try PMap.find t ctx.htypes with Not_found -> Globals.die "" __LOC__ let define ctx s = if not (Hashtbl.mem ctx.hdefines s) then begin @@ -239,7 +241,7 @@ let rec define_type ctx t = define_type ctx ret | HEnum _ | HObj _ | HStruct _ when not (PMap.exists t ctx.defined_types) -> ctx.defined_types <- PMap.add t () ctx.defined_types; - define ctx (sprintf "#include <%s.h>" (try PMap.find t ctx.type_module with Not_found -> assert false).m_name) + define ctx (sprintf "#include <%s.h>" (try PMap.find t ctx.type_module with Not_found -> Globals.die "" __LOC__).m_name) | HVirtual vp when not (PMap.exists t ctx.defined_types) -> ctx.defined_types <- PMap.add t () ctx.defined_types; Array.iter (fun (_,_,t) -> define_type ctx t) vp.vfields @@ -258,7 +260,7 @@ let enum_constr_type ctx e i = "venum" else let name = if e.eid = 0 then - let name = (try PMap.find (HEnum e) ctx.htypes with Not_found -> assert false) in + let name = (try PMap.find (HEnum e) ctx.htypes with Not_found -> Globals.die "" __LOC__) in "Enum" ^ name else String.concat "_" (ExtString.String.nsplit e.ename ".") @@ -546,7 +548,7 @@ let generate_function ctx f = if t = HVoid then "" else let assign = reg r ^ " = " in if tsame t rt then assign else - if not (safe_cast t rt) then assert false + if not (safe_cast t rt) then Globals.die "" __LOC__ else assign ^ "(" ^ ctype rt ^ ")" in @@ -591,7 +593,7 @@ let generate_function ctx f = in let mcall r fid = function - | [] -> assert false + | [] -> Globals.die "" __LOC__ | o :: args -> match rtype o with | HObj _ | HStruct _ -> @@ -618,7 +620,7 @@ let generate_function ctx f = unblock(); sline "}" | _ -> - assert false + Globals.die "" __LOC__ in let set_field obj fid v = @@ -631,7 +633,7 @@ let generate_function ctx f = let dset = sprintf "hl_dyn_set%s(%s->value,%ld/*%s*/%s,%s)" (dyn_prefix t) (reg obj) (hash ctx nid) name (type_value_opt (rtype v)) (reg v) in sexpr "if( hl_vfields(%s)[%d] ) *(%s*)(hl_vfields(%s)[%d]) = (%s)%s; else %s" (reg obj) fid (ctype t) (reg obj) fid (ctype t) (reg v) dset | _ -> - assert false + Globals.die "" __LOC__ in let get_field r obj fid = @@ -644,7 +646,7 @@ let generate_function ctx f = let dget = sprintf "(%s)hl_dyn_get%s(%s->value,%ld/*%s*/%s)" (ctype t) (dyn_prefix t) (reg obj) (hash ctx nid) name (type_value_opt t) in sexpr "%shl_vfields(%s)[%d] ? (*(%s*)(hl_vfields(%s)[%d])) : %s" (rassign r t) (reg obj) fid (ctype t) (reg obj) fid dget | _ -> - assert false + Globals.die "" __LOC__ in let fret = (match f.ftype with @@ -652,7 +654,7 @@ let generate_function ctx f = sline "%s %s(%s) {" (ctype t) (funname f.findex) (String.concat "," (List.map (fun t -> incr rid; var_type (reg !rid) t) args)); t | _ -> - assert false + Globals.die "" __LOC__ ) in block(); let var_map = Hashtbl.create 0 in @@ -768,7 +770,7 @@ let generate_function ctx f = else if op = CNeq then sexpr "if( %s != %s && (!%s || !%s || !%s->value || !%s->value || %s->value != %s->value) ) goto %s" (reg a) (reg b) (reg a) (reg b) (reg a) (reg b) (reg a) (reg b) (label d) else - assert false + Globals.die "" __LOC__ | HEnum _, HEnum _ | HDynObj, HDynObj | HAbstract _, HAbstract _ -> phys_compare() | HVirtual _, HObj _-> @@ -777,7 +779,7 @@ let generate_function ctx f = else if op = CNeq then sexpr "if( %s ? (%s == NULL || %s->value != (vdynamic*)%s) : (%s != NULL) ) goto %s" (reg a) (reg b) (reg a) (reg b) (reg b) (label d) else - assert false + Globals.die "" __LOC__ | HObj _, HVirtual _ -> compare_op op b a d | ta, tb -> @@ -826,7 +828,7 @@ let generate_function ctx f = | HF64 -> sexpr "%s = fmod(%s,%s)" (reg r) (reg a) (reg b) | _ -> - assert false) + Globals.die "" __LOC__) | OUMod (r,a,b) -> sexpr "%s = %s == 0 ? 0 : ((unsigned)%s) %% ((unsigned)%s)" (reg r) (reg b) (reg a) (reg b) | OShl (r,a,b) -> @@ -873,7 +875,7 @@ let generate_function ctx f = let sargs = String.concat "," (List.map2 rcast pl args) in sexpr "%s%s->hasValue ? %s((vdynamic*)%s->value%s) : %s(%s)" (rassign r ret) (reg cl) (rfun cl (HDyn :: args) ret) (reg cl) (if sargs = "" then "" else "," ^ sargs) (rfun cl args ret) sargs | _ -> - assert false) + Globals.die "" __LOC__) | OStaticClosure (r,fid) -> sexpr "%s = &cl$%d" (reg r) (!cl_id); incr cl_id @@ -958,7 +960,7 @@ let generate_function ctx f = | HObj o | HStruct o -> sexpr "%s = (%s)hl_alloc_obj(%s)" (reg r) (tname o.pname) (type_value (rtype r)) | HDynObj -> sexpr "%s = hl_alloc_dynobj()" (reg r) | HVirtual _ as t -> sexpr "%s = hl_alloc_virtual(%s)" (reg r) (type_value t) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | OField (r,obj,fid) -> get_field r obj fid | OSetField (obj,fid,v) -> @@ -1020,7 +1022,7 @@ let generate_function ctx f = let h = hash ctx sid in sexpr "hl_dyn_set%s((vdynamic*)%s,%ld/*%s*/%s,%s)" (dyn_prefix (rtype v)) (reg o) h code.strings.(sid) (type_value_opt (rtype v)) (reg v) | OMakeEnum (r,cid,rl) -> - let e, et = (match rtype r with HEnum e -> e, enum_constr_type ctx e cid | _ -> assert false) in + let e, et = (match rtype r with HEnum e -> e, enum_constr_type ctx e cid | _ -> Globals.die "" __LOC__) in let need_tmp = List.mem r rl in let tmp = if not need_tmp then reg r else begin sexpr "{ venum *tmp"; @@ -1037,10 +1039,10 @@ let generate_function ctx f = | OEnumIndex (r,v) -> sexpr "%s = HL__ENUM_INDEX__(%s)" (reg r) (reg v) | OEnumField (r,e,cid,pid) -> - let tname,(_,_,tl) = (match rtype e with HEnum e -> enum_constr_type ctx e cid, e.efields.(cid) | _ -> assert false) in + let tname,(_,_,tl) = (match rtype e with HEnum e -> enum_constr_type ctx e cid, e.efields.(cid) | _ -> Globals.die "" __LOC__) in sexpr "%s((%s*)%s)->p%d" (rassign r tl.(pid)) tname (reg e) pid | OSetEnumField (e,pid,r) -> - let tname, (_,_,tl) = (match rtype e with HEnum e -> enum_constr_type ctx e 0, e.efields.(0) | _ -> assert false) in + let tname, (_,_,tl) = (match rtype e with HEnum e -> enum_constr_type ctx e 0, e.efields.(0) | _ -> Globals.die "" __LOC__) in sexpr "((%s*)%s)->p%d = (%s)%s" tname (reg e) pid (ctype tl.(pid)) (reg r) | OSwitch (r,idx,eend) -> sline "switch(%s) {" (reg r); @@ -1072,7 +1074,7 @@ let generate_function ctx f = | HArray -> sexpr "%s = (%s)hl_aptr(%s,void*)" (reg r) (ctype (rtype r)) (reg d) | _ -> - assert false) + Globals.die "" __LOC__) | ORefOffset (r,r2,off) -> sexpr "%s = %s + %s" (reg r) (reg r2) (reg off) | ONop _ -> @@ -1190,7 +1192,7 @@ let make_function_table code = ft.fe_args <- args; ft.fe_ret <- t | _ -> - assert false + Globals.die "" __LOC__ ) code.natives; Array.iter (fun f -> let fname = String.concat "_" (ExtString.String.nsplit (fundecl_name f) ".") in @@ -1201,7 +1203,7 @@ let make_function_table code = ft.fe_args <- args; ft.fe_ret <- t; | _ -> - assert false); + Globals.die "" __LOC__); ft.fe_decl <- Some f; Array.iter (fun op -> match op with @@ -1242,7 +1244,7 @@ let make_modules ctx all_types = in let add m fid = let f = ctx.ftable.(fid) in - if f.fe_module <> None then assert false; + if f.fe_module <> None then Globals.die "" __LOC__; f.fe_module <- Some m; m.m_functions <- f :: m.m_functions; in @@ -1305,7 +1307,7 @@ let make_modules ctx all_types = ) !all_modules; let contexts = ref PMap.empty in Array.iter (fun f -> - if f.fe_module = None && ExtString.String.starts_with f.fe_name "fun$" then f.fe_name <- "wrap" ^ type_name ctx (match f.fe_decl with None -> assert false | Some f -> f.ftype); + if f.fe_module = None && ExtString.String.starts_with f.fe_name "fun$" then f.fe_name <- "wrap" ^ type_name ctx (match f.fe_decl with None -> Globals.die "" __LOC__ | Some f -> f.ftype); (* assign context to function module *) match f.fe_args with | (HEnum e) as t :: _ when e.ename = "" -> @@ -1478,14 +1480,14 @@ let write_c com file (code:code) gnames = | HBytes -> "(vbyte*)" ^ string ctx idx | _ -> - assert false + Globals.die "" __LOC__ in let fields = match t with | HObj o | HStruct o -> let fields = List.map2 field_value (List.map (fun (_,_,t) -> t) (Array.to_list o.pfields)) (Array.to_list fields) in if is_struct t then fields else type_value ctx t :: fields | _ -> - assert false + Globals.die "" __LOC__ in sexpr "static struct _%s %s = {%s}" (ctype t) name (String.concat "," fields); ) code.constants; diff --git a/src/generators/hlcode.ml b/src/generators/hlcode.ml index b9cc7a6b184c6c835678a60b57312ef48f7c6bd7..7f4f3121685c8a36060b399d11978fd6d723d136 100644 --- a/src/generators/hlcode.ml +++ b/src/generators/hlcode.ml @@ -416,7 +416,7 @@ let gather_types (code:code) = DynArray.to_array arr, !types let lookup_type types t = - try PMap.find t types with Not_found -> assert false + try PMap.find t types with Not_found -> Globals.die "" __LOC__ (* --------------------------------------------------------------------------------------------------------------------- *) (* DUMP *) diff --git a/src/generators/hlinterp.ml b/src/generators/hlinterp.ml index b17d2b8e9f7de57c8284414c542da3caab7be400..02b84d40a300d0d68e12e33505c9854a344daa66 100644 --- a/src/generators/hlinterp.ml +++ b/src/generators/hlinterp.ml @@ -134,7 +134,7 @@ let get_type = function | VVirtual v -> Some (HVirtual v.vtype) | VArray _ -> Some HArray | VClosure (f,None) -> Some (match f with FFun f -> f.ftype | FNativeFun (_,_,t) -> t) - | VClosure (f,Some _) -> Some (match f with FFun { ftype = HFun(_::args,ret) } | FNativeFun (_,_,HFun(_::args,ret)) -> HFun (args,ret) | _ -> assert false) + | VClosure (f,Some _) -> Some (match f with FFun { ftype = HFun(_::args,ret) } | FNativeFun (_,_,HFun(_::args,ret)) -> HFun (args,ret) | _ -> Globals.die "" __LOC__) | VVarArgs _ -> Some (HFun ([],HDyn)) | VEnum (e,_,_) -> Some (HEnum e) | _ -> None @@ -152,7 +152,7 @@ let rec is_compatible v t = | _, HVoid -> true | VNull, t -> is_nullable t | VObj o, HObj _ -> safe_cast (HObj o.oproto.pclass) t - | VClosure _, HFun _ -> safe_cast (match get_type v with None -> assert false | Some t -> t) t + | VClosure _, HFun _ -> safe_cast (match get_type v with None -> Globals.die "" __LOC__ | Some t -> t) t | VBytes _, HBytes -> true | VDyn (_,t1), HNull t2 -> tsame t1 t2 | v, HNull t -> is_compatible v t @@ -187,8 +187,8 @@ let rec get_proto ctx p = let fields = Array.append fields (Array.map (fun (_,_,t) -> t) p.pfields) in let bindings = List.fold_left (fun acc (fid,fidx) -> let f = get_function ctx fidx in - let ft = (match f with FFun f -> f.ftype | FNativeFun _ -> assert false) in - let need_closure = (match ft, fields.(fid) with HFun (args,_), HFun(args2,_) -> List.length args > List.length args2 | HFun _, HDyn -> false | _ -> assert false) in + let ft = (match f with FFun f -> f.ftype | FNativeFun _ -> Globals.die "" __LOC__) in + let need_closure = (match ft, fields.(fid) with HFun (args,_), HFun(args2,_) -> List.length args > List.length args2 | HFun _, HDyn -> false | _ -> Globals.die "" __LOC__) in let acc = List.filter (fun (fid2,_) -> fid2 <> fid) acc in (fid, (fun v -> VClosure (f,if need_closure then Some v else None))) :: acc ) bindings p.pbindings in @@ -222,7 +222,7 @@ let alloc_obj ctx t = o.dvirtuals <- [v]; VVirtual v | _ -> - assert false + Globals.die "" __LOC__ let float_to_string f = let s = string_of_float f in @@ -417,7 +417,7 @@ let rec to_virtual ctx v vp = if vd.vtype == vp then v else if vd.vvalue = VNull then - assert false + Globals.die "" __LOC__ else to_virtual ctx vd.vvalue vp | _ -> @@ -438,9 +438,9 @@ let rec dyn_cast ctx v t rt = default() else match t, rt with | (HUI8|HUI16|HI32), (HF32|HF64) -> - (match v with VInt i -> VFloat (Int32.to_float i) | _ -> assert false) + (match v with VInt i -> VFloat (Int32.to_float i) | _ -> Globals.die "" __LOC__) | (HF32|HF64), (HUI8|HUI16|HI32) -> - (match v with VFloat f -> VInt (Int32.of_float f) | _ -> assert false) + (match v with VFloat f -> VInt (Int32.of_float f) | _ -> Globals.die "" __LOC__) | (HUI8|HUI16|HI32|HF32|HF64), HNull ((HUI8|HUI16|HI32|HF32|HF64) as rt) -> let v = dyn_cast ctx v t rt in VDyn (v,rt) @@ -474,35 +474,35 @@ let rec dyn_cast ctx v t rt = convert ret rconv ),rt),None) | _ -> - assert false) + Globals.die "" __LOC__) | HDyn, HFun (targs,tret) when (match v with VVarArgs _ -> true | _ -> false) -> VClosure (FNativeFun ("~varargs",(fun args -> dyn_call ctx v (List.map2 (fun v t -> (v,t)) args targs) tret ),rt),None) | HDyn, _ -> (match get_type v with - | None -> assert false + | None -> Globals.die "" __LOC__ | Some t -> dyn_cast ctx (match v with VDyn (v,_) -> v | _ -> v) t rt) | HNull t, _ -> (match v with | VDyn (v,t) -> dyn_cast ctx v t rt - | _ -> assert false) - | HObj _, HObj b when safe_cast rt t && (match get_type v with Some t -> safe_cast t rt | None -> assert false) -> + | _ -> Globals.die "" __LOC__) + | HObj _, HObj b when safe_cast rt t && (match get_type v with Some t -> safe_cast t rt | None -> Globals.die "" __LOC__) -> (* downcast *) v | (HObj _ | HDynObj | HVirtual _), HVirtual vp -> to_virtual ctx v vp | HVirtual _, _ -> (match v with - | VVirtual v -> dyn_cast ctx v.vvalue (match get_type v.vvalue with None -> assert false | Some t -> t) rt - | _ -> assert false) + | VVirtual v -> dyn_cast ctx v.vvalue (match get_type v.vvalue with None -> Globals.die "" __LOC__ | Some t -> t) rt + | _ -> Globals.die "" __LOC__) | HObj p, _ -> (match get_method p "__cast" with | None -> invalid() | Some f -> if v = VNull then VNull else let ret = ctx.fcall (get_function ctx f) [v;VType rt] in - if ret <> VNull && (match get_type ret with None -> assert false | Some vt -> safe_cast vt rt) then ret else invalid()) + if ret <> VNull && (match get_type ret with None -> Globals.die "" __LOC__ | Some vt -> safe_cast vt rt) then ret else invalid()) | _ -> invalid() @@ -510,7 +510,7 @@ and dyn_call ctx v args tret = match v with | VClosure (f,a) -> let ft = (match f with FFun f -> f.ftype | FNativeFun (_,_,t) -> t) in - let fargs, fret = (match ft with HFun (a,t) -> a, t | _ -> assert false) in + let fargs, fret = (match ft with HFun (a,t) -> a, t | _ -> Globals.die "" __LOC__) in let full_args = args and full_fargs = (match a with None -> fargs | Some _ -> List.tl fargs) in let rec loop args fargs = match args, fargs with @@ -549,7 +549,7 @@ let rec dyn_compare ctx a at b bt = if oa == ob then 0 else (match get_method oa.oproto.pclass "__compare" with | None -> invalid_comparison - | Some f -> (match ctx.fcall (get_function ctx f) [a;b] with VInt i -> Int32.to_int i | _ -> assert false)); + | Some f -> (match ctx.fcall (get_function ctx f) [a;b] with VInt i -> Int32.to_int i | _ -> Globals.die "" __LOC__)); | VDyn (v,t), _ -> dyn_compare ctx v t b bt | _, VDyn (v,t) -> @@ -581,8 +581,8 @@ let rec dyn_get_field ctx obj field rt = try let fid = PMap.find field p.pfunctions in (match get_function ctx fid with - | FFun fd as f -> get_with (VClosure (f,Some obj)) (match fd.ftype with HFun (_::args,t) -> HFun(args,t) | _ -> assert false) - | FNativeFun _ -> assert false) + | FFun fd as f -> get_with (VClosure (f,Some obj)) (match fd.ftype with HFun (_::args,t) -> HFun(args,t) | _ -> Globals.die "" __LOC__) + | FNativeFun _ -> Globals.die "" __LOC__) with Not_found -> match p.psuper with | None -> default rt @@ -614,7 +614,7 @@ let rebuild_virtuals ctx d = let old = d.dvirtuals in d.dvirtuals <- []; List.iter (fun v -> - let v2 = (match to_virtual ctx (VDynObj d) v.vtype with VVirtual v -> v | _ -> assert false) in + let v2 = (match to_virtual ctx (VDynObj d) v.vtype with VVirtual v -> v | _ -> Globals.die "" __LOC__) in v.vindexes <- v2.vindexes; v.vtable <- d.dvalues; ) old; @@ -624,7 +624,7 @@ let rec dyn_set_field ctx obj field v vt = let v, vt = (match vt with | HDyn -> (match get_type v with - | None -> if v = VNull then VNull, HDyn else assert false + | None -> if v = VNull then VNull, HDyn else Globals.die "" __LOC__ | Some t -> (match v with VDyn (v,_) -> v | _ -> v), t) | t -> v, t ) in @@ -765,7 +765,7 @@ let interp ctx f args = | HFun (fargs,fret) -> if ctx.checked && List.length fargs <> List.length args then error (Printf.sprintf "Invalid args: (%s) should be (%s)" (String.concat "," (List.map (vstr_d ctx) args)) (String.concat "," (List.map tstr fargs))); fret - | _ -> assert false + | _ -> Globals.die "" __LOC__ ) in let fcall = ctx.fcall in let rtype i = Array.unsafe_get f.regs i in @@ -797,13 +797,13 @@ let interp ctx f args = | HUI8 | HUI16 | HI32 -> (match get a, get b with | VInt a, VInt b -> VInt (iop a b) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | HF32 | HF64 -> (match get a, get b with | VFloat a, VFloat b -> VFloat (fop a b) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | _ -> - assert false + Globals.die "" __LOC__ in let iop f a b = match rtype a with @@ -811,25 +811,25 @@ let interp ctx f args = | HUI8 | HUI16 | HI32 -> (match get a, get b with | VInt a, VInt b -> VInt (f a b) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | _ -> - assert false + Globals.die "" __LOC__ in let iunop iop r = match rtype r with | HUI8 | HUI16 | HI32 -> (match get r with | VInt a -> VInt (iop a) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | _ -> - assert false + Globals.die "" __LOC__ in let ucompare a b = match a, b with | VInt a, VInt b -> let d = Int32.sub (Int32.shift_right_logical a 16) (Int32.shift_right_logical b 16) in Int32.to_int (if d = 0l then Int32.sub (Int32.logand a 0xFFFFl) (Int32.logand b 0xFFFFl) else d) - | _ -> assert false + | _ -> Globals.die "" __LOC__ in let vcompare ra rb op = let a = get ra in @@ -865,8 +865,8 @@ let interp ctx f args = | OAnd (r,a,b) -> set r (iop Int32.logand a b) | OOr (r,a,b) -> set r (iop Int32.logor a b) | OXor (r,a,b) -> set r (iop Int32.logxor a b) - | ONeg (r,v) -> set r (match get v with VInt v -> VInt (Int32.neg v) | VFloat f -> VFloat (-. f) | _ -> assert false) - | ONot (r,v) -> set r (match get v with VBool b -> VBool (not b) | _ -> assert false) + | ONeg (r,v) -> set r (match get v with VInt v -> VInt (Int32.neg v) | VFloat f -> VFloat (-. f) | _ -> Globals.die "" __LOC__) + | ONot (r,v) -> set r (match get v with VBool b -> VBool (not b) | _ -> Globals.die "" __LOC__) | OIncr r -> set r (iunop (fun i -> Int32.add i 1l) r) | ODecr r -> set r (iunop (fun i -> Int32.sub i 1l) r) | OCall0 (r,f) -> set r (fcall (func f) []) @@ -897,9 +897,9 @@ let interp ctx f args = | OJNotEq (a,b,i) -> if not (vcompare a b (=)) then pos := !pos + i | OJAlways i -> pos := !pos + i | OToDyn (r,a) -> set r (make_dyn (get a) f.regs.(a)) - | OToSFloat (r,a) -> set r (match get a with VInt v -> VFloat (Int32.to_float v) | VFloat _ as v -> v | _ -> assert false) - | OToUFloat (r,a) -> set r (match get a with VInt v -> VFloat (ufloat v) | VFloat _ as v -> v | _ -> assert false) - | OToInt (r,a) -> set r (match get a with VFloat v -> VInt (Int32.of_float v) | VInt i when rtype r = HI64 -> VInt64 (Int64.of_int32 i) | VInt _ as v -> v | _ -> assert false) + | OToSFloat (r,a) -> set r (match get a with VInt v -> VFloat (Int32.to_float v) | VFloat _ as v -> v | _ -> Globals.die "" __LOC__) + | OToUFloat (r,a) -> set r (match get a with VInt v -> VFloat (ufloat v) | VFloat _ as v -> v | _ -> Globals.die "" __LOC__) + | OToInt (r,a) -> set r (match get a with VFloat v -> VInt (Int32.of_float v) | VInt i when rtype r = HI64 -> VInt64 (Int64.of_int32 i) | VInt _ as v -> v | _ -> Globals.die "" __LOC__) | OLabel _ -> () | ONew r -> set r (alloc_obj ctx (rtype r)) @@ -911,7 +911,7 @@ let interp ctx f args = | VFNone -> dyn_get_field ctx obj (let n,_,_ = v.vtype.vfields.(fid) in n) (rtype r) | VFIndex i -> v.vtable.(i)) | VNull -> null_access() - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | OSetField (o,fid,r) -> let rv = get r in let o = get o in @@ -927,16 +927,16 @@ let interp ctx f args = check_obj rv o fid; v.vtable.(i) <- rv) | VNull -> null_access() - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | OGetThis (r, fid) -> - set r (match get 0 with VObj v | VStruct v -> v.ofields.(fid) | _ -> assert false) + set r (match get 0 with VObj v | VStruct v -> v.ofields.(fid) | _ -> Globals.die "" __LOC__) | OSetThis (fid, r) -> (match get 0 with | (VObj v | VStruct v) as o -> let rv = get r in check_obj rv o fid; v.ofields.(fid) <- rv - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | OCallMethod (r,m,rl) -> (match get (List.hd rl) with | VObj v -> set r (fcall v.oproto.pmethods.(m) (List.map get rl)) @@ -948,17 +948,17 @@ let interp ctx f args = let m = PMap.find name o.oproto.pclass.pfunctions in set r (dyn_call ctx (VClosure (get_function ctx m,Some obj)) (List.map (fun r -> get r, rtype r) (List.tl rl)) (rtype r)) with Not_found -> - assert false) + Globals.die "" __LOC__) | VDynObj _ -> set r (dyn_call ctx v.vvalue (List.map (fun r -> get r, rtype r) (List.tl rl)) (rtype r)) | _ -> - assert false) + Globals.die "" __LOC__) | VNull -> null_access() - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | OCallThis (r,m,rl) -> (match get 0 with | VObj v as o -> set r (fcall v.oproto.pmethods.(m) (o :: List.map get rl)) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | OCallClosure (r,v,rl) -> if rtype v = HDyn then set r (dyn_call ctx (get v) (List.map (fun r -> get r, rtype r) rl) (rtype r)) @@ -977,9 +977,9 @@ let interp ctx f args = let m = (match get o with | VObj v as obj -> VClosure (v.oproto.pmethods.(m), Some obj) | VNull -> null_access() - | _ -> assert false + | _ -> Globals.die "" __LOC__ ) in - set r (if m = VNull then m else dyn_cast ctx m (match get_type m with None -> assert false | Some v -> v) (rtype r)) + set r (if m = VNull then m else dyn_cast ctx m (match get_type m with None -> Globals.die "" __LOC__ | Some v -> v) (rtype r)) | OThrow r -> throw ctx (get r) | ORethrow r -> @@ -988,14 +988,14 @@ let interp ctx f args = | OGetUI8 (r,b,p) -> (match get b, get p with | VBytes b, VInt p -> set r (VInt (Int32.of_int (int_of_char (String.get b (Int32.to_int p))))) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | OGetUI16 (r,b,p) -> (match get b, get p with | VBytes b, VInt p -> let a = int_of_char (String.get b (Int32.to_int p)) in let b = int_of_char (String.get b (Int32.to_int p + 1)) in set r (VInt (Int32.of_int (a lor (b lsl 8)))) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | OGetMem (r,b,p) -> (match get b, get p with | VBytes b, VInt p -> @@ -1005,23 +1005,23 @@ let interp ctx f args = | HI64 -> VInt64 (get_i64 b p) | HF32 -> VFloat (Int32.float_of_bits (get_i32 b p)) | HF64 -> VFloat (Int64.float_of_bits (get_i64 b p)) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | _ -> - assert false) + Globals.die "" __LOC__) | OGetArray (r,a,i) -> (match get a, get i with | VArray (a,_), VInt i -> set r a.(Int32.to_int i) - | _ -> assert false); + | _ -> Globals.die "" __LOC__); | OSetUI8 (r,p,v) -> (match get r, get p, get v with | VBytes b, VInt p, VInt v -> Bytes.set (Bytes.unsafe_of_string b) (Int32.to_int p) (char_of_int ((Int32.to_int v) land 0xFF)) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | OSetUI16 (r,p,v) -> (match get r, get p, get v with | VBytes b, VInt p, VInt v -> Bytes.set (Bytes.unsafe_of_string b) (Int32.to_int p) (char_of_int ((Int32.to_int v) land 0xFF)); Bytes.set (Bytes.unsafe_of_string b) (Int32.to_int p + 1) (char_of_int (((Int32.to_int v) lsr 8) land 0xFF)) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | OSetMem (r,p,v) -> (match get r, get p with | VBytes b, VInt p -> @@ -1031,9 +1031,9 @@ let interp ctx f args = | HI64, VInt64 v -> set_i64 b p v | HF32, VFloat f -> set_i32 b p (Int32.bits_of_float f) | HF64, VFloat f -> set_i64 b p (Int64.bits_of_float f) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | _ -> - assert false) + Globals.die "" __LOC__) | OSetArray (a,i,v) -> (match get a, get i with | VArray (a,t), VInt i -> @@ -1042,7 +1042,7 @@ let interp ctx f args = let idx = Int32.to_int i in if ctx.checked && (idx < 0 || idx >= Array.length a) then error (Printf.sprintf "Can't set array index %d with %s" idx (vstr_d ctx v)); a.(Int32.to_int i) <- v - | _ -> assert false); + | _ -> Globals.die "" __LOC__); | OSafeCast (r, v) -> set r (dyn_cast ctx (get v) (rtype v) (rtype r)) | OUnsafeCast (r,v) -> @@ -1050,13 +1050,13 @@ let interp ctx f args = | OArraySize (r,a) -> (match get a with | VArray (a,_) -> set r (VInt (Int32.of_int (Array.length a))); - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | OType (r,t) -> set r (VType t) | OGetType (r,v) -> let v = get v in - let v = (match v with VVirtual { vvalue = VNull } -> assert false | VVirtual v -> v.vvalue | _ -> v) in - set r (VType (if v = VNull then HVoid else match get_type v with None -> assert false | Some t -> t)); + let v = (match v with VVirtual { vvalue = VNull } -> Globals.die "" __LOC__ | VVirtual v -> v.vvalue | _ -> v) in + set r (VType (if v = VNull then HVoid else match get_type v with None -> Globals.die "" __LOC__ | Some t -> t)); | OGetTID (r,v) -> set r (match get v with | VType t -> @@ -1083,44 +1083,44 @@ let interp ctx f args = | HNull _ -> 19 | HMethod _ -> 20 | HStruct _ -> 21))) - | _ -> assert false); + | _ -> Globals.die "" __LOC__); | ORef (r,v) -> set r (VRef (RStack (v + spos),rtype v)) | OUnref (v,r) -> set v (match get r with | VRef (r,_) -> get_ref ctx r - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | OSetref (r,v) -> (match get r with | VRef (r,t) -> let v = get v in check v t (fun() -> "ref"); set_ref ctx r v - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | OToVirtual (r,rv) -> - set r (to_virtual ctx (get rv) (match rtype r with HVirtual vp -> vp | _ -> assert false)) + set r (to_virtual ctx (get rv) (match rtype r with HVirtual vp -> vp | _ -> Globals.die "" __LOC__)) | ODynGet (r,o,f) -> set r (dyn_get_field ctx (get o) ctx.code.strings.(f) (rtype r)) | ODynSet (o,fid,vr) -> dyn_set_field ctx (get o) ctx.code.strings.(fid) (get vr) (rtype vr) | OMakeEnum (r,e,pl) -> - set r (VEnum ((match rtype r with HEnum e -> e | _ -> assert false),e,Array.map get (Array.of_list pl))) + set r (VEnum ((match rtype r with HEnum e -> e | _ -> Globals.die "" __LOC__),e,Array.map get (Array.of_list pl))) | OEnumAlloc (r,f) -> (match rtype r with | HEnum e -> let _, _, fl = e.efields.(f) in let vl = Array.create (Array.length fl) VUndef in set r (VEnum (e, f, vl)) - | _ -> assert false + | _ -> Globals.die "" __LOC__ ) | OEnumIndex (r,v) -> (match get v with | VEnum (_,i,_) -> set r (VInt (Int32.of_int i)) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | OEnumField (r, v, _, i) -> (match get v with | VEnum (_,_,vl) -> set r vl.(i) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | OSetEnumField (v, i, r) -> (match get v, rtype v with | VEnum (_,id,vl), HEnum e -> @@ -1128,13 +1128,13 @@ let interp ctx f args = let _, _, fields = e.efields.(id) in check rv fields.(i) (fun() -> "enumfield"); vl.(i) <- rv - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | OSwitch (r, indexes, _) -> (match get r with | VInt i -> let i = Int32.to_int i in if i >= 0 && i < Array.length indexes then pos := !pos + indexes.(i) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | ONullCheck r -> if get r = VNull then throw_msg ctx "Null access" | OTrap (r,j) -> @@ -1147,11 +1147,11 @@ let interp ctx f args = | ORefData (r,d) -> (match get d with | VArray (a,t) -> set r (VRef (RArray (a,0),t)) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | ORefOffset (r,r2,off) -> (match get r2, get off with | VRef (RArray (a,pos),t), VInt i -> set r (VRef (RArray (a,pos + Int32.to_int i),t)) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | ONop _ -> () ); @@ -1252,15 +1252,15 @@ let load_native ctx lib name t = | "alloc_bytes" -> (function | [VInt i] -> VBytes (Bytes.unsafe_to_string (Bytes.create (int i))) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "alloc_array" -> (function | [VType t;VInt i] -> VArray (Array.create (int i) (default t),t) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "alloc_obj" -> (function | [VType t] -> alloc_obj ctx t - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "alloc_enum_dyn" -> (function | [VType (HEnum e); VInt idx; VArray (vl,vt); VInt len] -> @@ -1272,13 +1272,13 @@ let load_native ctx lib name t = else VEnum (e,idx,Array.mapi (fun i v -> dyn_cast ctx v vt args.(i)) (Array.sub vl 0 len)) | vl -> - assert false) + Globals.die "" __LOC__) | "array_blit" -> (function | [VArray (dst,_); VInt dp; VArray (src,_); VInt sp; VInt len] -> Array.blit src (int sp) dst (int dp) (int len); VUndef - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "bytes_blit" -> (function | [VBytes dst; VInt dp; VBytes src; VInt sp; VInt len] -> @@ -1286,7 +1286,7 @@ let load_native ctx lib name t = VUndef | [(VBytes _ | VNull); VInt _; (VBytes _ | VNull); VInt _; VInt len] -> if len = 0l then VUndef else error "bytes_blit to NULL bytes"; - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "bsort_i32" -> (function | [VBytes b; VInt pos; VInt len; VClosure (f,c)] -> @@ -1295,59 +1295,59 @@ let load_native ctx lib name t = Array.stable_sort (fun a b -> match ctx.fcall f (match c with None -> [VInt a;VInt b] | Some v -> [v;VInt a;VInt b]) with | VInt i -> int i - | _ -> assert false + | _ -> Globals.die "" __LOC__ ) a; Array.iteri (fun i v -> set_i32 b (pos + i * 4) v) a; VUndef; | _ -> - assert false) + Globals.die "" __LOC__) | "bsort_f64" -> (function | [VBytes b; VInt pos; VInt len; VClosure _] -> - assert false + Globals.die "" __LOC__ | _ -> - assert false) + Globals.die "" __LOC__) | "itos" -> (function | [VInt v; VRef (r,_)] -> let str = Int32.to_string v in set_ref r (to_int (String.length str)); VBytes (caml_to_hl str) - | _ -> assert false); + | _ -> Globals.die "" __LOC__); | "ftos" -> (function | [VFloat f; VRef (r,_)] -> let str = float_to_string f in set_ref r (to_int (String.length str)); VBytes (caml_to_hl str) - | _ -> assert false); + | _ -> Globals.die "" __LOC__); | "value_to_string" -> (function | [v; VRef (r,_)] -> let str = caml_to_hl (vstr ctx v HDyn) in set_ref r (to_int ((String.length str) lsr 1 - 1)); VBytes str - | _ -> assert false); - | "math_isnan" -> (function [VFloat f] -> VBool (classify_float f = FP_nan) | _ -> assert false) - | "math_isfinite" -> (function [VFloat f] -> VBool (match classify_float f with FP_infinite | FP_nan -> false | _ -> true) | _ -> assert false) - | "math_round" -> (function [VFloat f] -> VInt (Int32.of_float (floor (f +. 0.5))) | _ -> assert false) - | "math_floor" -> (function [VFloat f] -> VInt (Int32.of_float (floor f)) | _ -> assert false) - | "math_ceil" -> (function [VFloat f] -> VInt (Int32.of_float (ceil f)) | _ -> assert false) - | "math_ffloor" -> (function [VFloat f] -> VFloat (floor f) | _ -> assert false) - | "math_fceil" -> (function [VFloat f] -> VFloat (ceil f) | _ -> assert false) - | "math_fround" -> (function [VFloat f] -> VFloat (floor (f +. 0.5)) | _ -> assert false) - | "math_abs" -> (function [VFloat f] -> VFloat (abs_float f) | _ -> assert false) - | "math_sqrt" -> (function [VFloat f] -> VFloat (if f < 0. then nan else sqrt f) | _ -> assert false) - | "math_cos" -> (function [VFloat f] -> VFloat (cos f) | _ -> assert false) - | "math_sin" -> (function [VFloat f] -> VFloat (sin f) | _ -> assert false) - | "math_tan" -> (function [VFloat f] -> VFloat (tan f) | _ -> assert false) - | "math_acos" -> (function [VFloat f] -> VFloat (acos f) | _ -> assert false) - | "math_asin" -> (function [VFloat f] -> VFloat (asin f) | _ -> assert false) - | "math_atan" -> (function [VFloat f] -> VFloat (atan f) | _ -> assert false) - | "math_atan2" -> (function [VFloat a; VFloat b] -> VFloat (atan2 a b) | _ -> assert false) - | "math_log" -> (function [VFloat f] -> VFloat (Pervasives.log f) | _ -> assert false) - | "math_exp" -> (function [VFloat f] -> VFloat (exp f) | _ -> assert false) - | "math_pow" -> (function [VFloat a; VFloat b] -> VFloat (a ** b) | _ -> assert false) + | _ -> Globals.die "" __LOC__); + | "math_isnan" -> (function [VFloat f] -> VBool (classify_float f = FP_nan) | _ -> Globals.die "" __LOC__) + | "math_isfinite" -> (function [VFloat f] -> VBool (match classify_float f with FP_infinite | FP_nan -> false | _ -> true) | _ -> Globals.die "" __LOC__) + | "math_round" -> (function [VFloat f] -> VInt (Int32.of_float (floor (f +. 0.5))) | _ -> Globals.die "" __LOC__) + | "math_floor" -> (function [VFloat f] -> VInt (Int32.of_float (floor f)) | _ -> Globals.die "" __LOC__) + | "math_ceil" -> (function [VFloat f] -> VInt (Int32.of_float (ceil f)) | _ -> Globals.die "" __LOC__) + | "math_ffloor" -> (function [VFloat f] -> VFloat (floor f) | _ -> Globals.die "" __LOC__) + | "math_fceil" -> (function [VFloat f] -> VFloat (ceil f) | _ -> Globals.die "" __LOC__) + | "math_fround" -> (function [VFloat f] -> VFloat (floor (f +. 0.5)) | _ -> Globals.die "" __LOC__) + | "math_abs" -> (function [VFloat f] -> VFloat (abs_float f) | _ -> Globals.die "" __LOC__) + | "math_sqrt" -> (function [VFloat f] -> VFloat (if f < 0. then nan else sqrt f) | _ -> Globals.die "" __LOC__) + | "math_cos" -> (function [VFloat f] -> VFloat (cos f) | _ -> Globals.die "" __LOC__) + | "math_sin" -> (function [VFloat f] -> VFloat (sin f) | _ -> Globals.die "" __LOC__) + | "math_tan" -> (function [VFloat f] -> VFloat (tan f) | _ -> Globals.die "" __LOC__) + | "math_acos" -> (function [VFloat f] -> VFloat (acos f) | _ -> Globals.die "" __LOC__) + | "math_asin" -> (function [VFloat f] -> VFloat (asin f) | _ -> Globals.die "" __LOC__) + | "math_atan" -> (function [VFloat f] -> VFloat (atan f) | _ -> Globals.die "" __LOC__) + | "math_atan2" -> (function [VFloat a; VFloat b] -> VFloat (atan2 a b) | _ -> Globals.die "" __LOC__) + | "math_log" -> (function [VFloat f] -> VFloat (Pervasives.log f) | _ -> Globals.die "" __LOC__) + | "math_exp" -> (function [VFloat f] -> VFloat (exp f) | _ -> Globals.die "" __LOC__) + | "math_pow" -> (function [VFloat a; VFloat b] -> VFloat (a ** b) | _ -> Globals.die "" __LOC__) | "parse_int" -> (function | [VBytes str; VInt pos; VInt len] -> @@ -1355,15 +1355,15 @@ let load_native ctx lib name t = VDyn (VInt (Numeric.parse_int (hl_to_caml_sub str (int pos) (int len))),HI32) with _ -> VNull) - | l -> assert false) + | l -> Globals.die "" __LOC__) | "parse_float" -> (function | [VBytes str; VInt pos; VInt len] -> (try VFloat (Numeric.parse_float (hl_to_caml_sub str (int pos) (int len))) with _ -> VFloat nan) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "dyn_compare" -> (function | [a;b] -> to_int (dyn_compare ctx a HDyn b HDyn) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "fun_compare" -> let ocompare o1 o2 = match o1, o2 with @@ -1378,91 +1378,91 @@ let load_native ctx lib name t = | "array_type" -> (function | [VArray (_,t)] -> VType t - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "value_cast" -> (function | [v;VType t] -> if is_compatible v t then v else throw_msg ctx ("Cannot cast " ^ vstr_d ctx v ^ " to " ^ tstr t); - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hballoc" -> (function | [] -> VAbstract (AHashBytes (Hashtbl.create 0)) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hbset" -> (function | [VAbstract (AHashBytes h);VBytes b;v] -> Hashtbl.replace h (hl_to_caml b) v; VUndef - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hbget" -> (function | [VAbstract (AHashBytes h);VBytes b] -> (try Hashtbl.find h (hl_to_caml b) with Not_found -> VNull) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hbvalues" -> (function | [VAbstract (AHashBytes h)] -> let values = Hashtbl.fold (fun _ v acc -> v :: acc) h [] in VArray (Array.of_list values, HDyn) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hbkeys" -> (function | [VAbstract (AHashBytes h)] -> let keys = Hashtbl.fold (fun s _ acc -> VBytes (caml_to_hl s) :: acc) h [] in VArray (Array.of_list keys, HBytes) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hbexists" -> (function | [VAbstract (AHashBytes h);VBytes b] -> VBool (Hashtbl.mem h (hl_to_caml b)) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hbremove" -> (function | [VAbstract (AHashBytes h);VBytes b] -> let m = Hashtbl.mem h (hl_to_caml b) in if m then Hashtbl.remove h (hl_to_caml b); VBool m - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hialloc" -> (function | [] -> VAbstract (AHashInt (Hashtbl.create 0)) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hiset" -> (function | [VAbstract (AHashInt h);VInt i;v] -> Hashtbl.replace h i v; VUndef - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "higet" -> (function | [VAbstract (AHashInt h);VInt i] -> (try Hashtbl.find h i with Not_found -> VNull) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hivalues" -> (function | [VAbstract (AHashInt h)] -> let values = Hashtbl.fold (fun _ v acc -> v :: acc) h [] in VArray (Array.of_list values, HDyn) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hikeys" -> (function | [VAbstract (AHashInt h)] -> let keys = Hashtbl.fold (fun i _ acc -> VInt i :: acc) h [] in VArray (Array.of_list keys, HI32) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hiexists" -> (function | [VAbstract (AHashInt h);VInt i] -> VBool (Hashtbl.mem h i) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hiremove" -> (function | [VAbstract (AHashInt h);VInt i] -> let m = Hashtbl.mem h i in if m then Hashtbl.remove h i; VBool m - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hoalloc" -> (function | [] -> VAbstract (AHashObject (ref [])) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hoset" -> (function | [VAbstract (AHashObject l);o;v] -> @@ -1475,26 +1475,26 @@ let load_native ctx lib name t = in l := replace !l; VUndef - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hoget" -> (function | [VAbstract (AHashObject l);o] -> (try List.assq (no_virtual o) !l with Not_found -> VNull) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hovalues" -> (function | [VAbstract (AHashObject l)] -> VArray (Array.of_list (List.map snd !l), HDyn) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hokeys" -> (function | [VAbstract (AHashObject l)] -> VArray (Array.of_list (List.map fst !l), HDyn) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hoexists" -> (function | [VAbstract (AHashObject l);o] -> VBool (List.mem_assq (no_virtual o) !l) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "horemove" -> (function | [VAbstract (AHashObject rl);o] -> @@ -1506,23 +1506,23 @@ let load_native ctx lib name t = | p :: l -> loop (p :: acc) l in VBool (loop [] !rl) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "sys_print" -> (function | [VBytes str] -> print_string (hl_to_caml str); VUndef - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "sys_time" -> (function | [] -> VFloat (Unix.gettimeofday()) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "sys_exit" -> (function | [VInt code] -> raise (Sys_exit (Int32.to_int code)) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "sys_utf8_path" -> (function | [] -> VBool true - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "sys_string" -> let cached_sys_name = ref None in (function @@ -1543,27 +1543,27 @@ let load_native ctx lib name t = | "Win32" | "Cygwin" -> "Windows" | s -> s)) | _ -> - assert false) + Globals.die "" __LOC__) | "sys_is64" -> (function | [] -> VBool (Sys.word_size = 64) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "hash" -> (function | [VBytes str] -> VInt (hash ctx (hl_to_caml str)) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "type_safe_cast" -> (function | [VType a; VType b] -> VBool (safe_cast a b) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "type_super" -> (function | [VType t] -> VType (match t with HObj { psuper = Some o } -> HObj o | _ -> HVoid) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "type_args_count" -> (function | [VType t] -> to_int (match t with HFun (args,_) -> List.length args | _ -> 0) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "type_get_global" -> (function | [VType t] -> @@ -1571,7 +1571,7 @@ let load_native ctx lib name t = | HObj c -> (match c.pclassglobal with None -> VNull | Some g -> ctx.t_globals.(g)) | HEnum e -> (match e.eglobal with None -> VNull | Some g -> ctx.t_globals.(g)) | _ -> VNull) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "type_set_global" -> (function | [VType t; v] -> @@ -1579,15 +1579,15 @@ let load_native ctx lib name t = | HObj c -> (match c.pclassglobal with None -> false | Some g -> ctx.t_globals.(g) <- v; true) | HEnum e -> (match e.eglobal with None -> false | Some g -> ctx.t_globals.(g) <- v; true) | _ -> false) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "type_name" -> (function | [VType t] -> VBytes (caml_to_hl (match t with | HObj o -> o.pname | HEnum e -> e.ename - | _ -> assert false)) - | _ -> assert false) + | _ -> Globals.die "" __LOC__)) + | _ -> Globals.die "" __LOC__) | "obj_fields" -> let rec get_fields v isRec = match v with @@ -1606,20 +1606,20 @@ let load_native ctx lib name t = in (function | [v] -> get_fields v true - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "obj_copy" -> (function | [VDynObj d | VVirtual { vvalue = VDynObj d }] -> VDynObj { dfields = Hashtbl.copy d.dfields; dvalues = Array.copy d.dvalues; dtypes = Array.copy d.dtypes; dvirtuals = [] } | [_] -> VNull - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "enum_parameters" -> (function | [VEnum (e,idx,pl)] -> let _,_, ptypes = e.efields.(idx) in VArray (Array.mapi (fun i v -> make_dyn v ptypes.(i)) pl,HDyn) | _ -> - assert false) + Globals.die "" __LOC__) | "type_instance_fields" -> (function | [VType t] -> @@ -1638,19 +1638,19 @@ let load_native ctx lib name t = in VArray (fields o,HBytes) | _ -> VNull) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "type_enum_fields" -> (function | [VType t] -> (match t with | HEnum e -> VArray (Array.map (fun (f,_,_) -> VBytes (caml_to_hl f)) e.efields,HBytes) | _ -> VNull) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "type_enum_values" -> (function | [VType (HEnum e)] -> VArray (Array.mapi (fun i (_,_,args) -> if Array.length args <> 0 then VNull else VEnum (e,i,[||])) e.efields,HDyn) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "type_enum_eq" -> (function | [VEnum _; VNull] | [VNull; VEnum _] -> VBool false @@ -1669,29 +1669,29 @@ let load_native ctx lib name t = | t -> dyn_compare ctx vl1.(i) t vl2.(i) t = 0) && chk (i + 1) in chk 0 - | _ -> assert false + | _ -> Globals.die "" __LOC__ in VBool (if e1 != e2 then false else loop v1 v2 e1) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "obj_get_field" -> (function | [o;VInt hash] -> - let f = (try Hashtbl.find ctx.cached_hashes hash with Not_found -> assert false) in + let f = (try Hashtbl.find ctx.cached_hashes hash with Not_found -> Globals.die "" __LOC__) in (match o with | VObj _ | VDynObj _ | VVirtual _ -> dyn_get_field ctx o f HDyn | _ -> VNull) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "obj_set_field" -> (function | [o;VInt hash;v] -> - let f = (try Hashtbl.find ctx.cached_hashes hash with Not_found -> assert false) in + let f = (try Hashtbl.find ctx.cached_hashes hash with Not_found -> Globals.die "" __LOC__) in dyn_set_field ctx o f v HDyn; VUndef - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "obj_has_field" -> (function | [o;VInt hash] -> - let f = (try Hashtbl.find ctx.cached_hashes hash with Not_found -> assert false) in + let f = (try Hashtbl.find ctx.cached_hashes hash with Not_found -> Globals.die "" __LOC__) in let rec loop o = match o with | VDynObj d -> Hashtbl.mem d.dfields f @@ -1704,11 +1704,11 @@ let load_native ctx lib name t = | _ -> false in VBool (loop o) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "obj_delete_field" -> (function | [o;VInt hash] -> - let f = (try Hashtbl.find ctx.cached_hashes hash with Not_found -> assert false) in + let f = (try Hashtbl.find ctx.cached_hashes hash with Not_found -> Globals.die "" __LOC__) in let rec loop o = match o with | VDynObj d when Hashtbl.mem d.dfields f -> @@ -1733,11 +1733,11 @@ let load_native ctx lib name t = | _ -> false in VBool (loop o) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "get_virtual_value" -> (function | [VVirtual v] -> v.vvalue - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "ucs2length" -> (function | [VBytes s; VInt pos] -> @@ -1747,15 +1747,15 @@ let load_native ctx lib name t = if c = 0 then p lsr 1 else loop (p + 2) in to_int (loop 0) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "utf8_to_utf16" -> (function | [VBytes s; VInt pos; VRef (r,HI32)] -> let s = String.sub s (int pos) (String.length s - (int pos)) in - let u16 = caml_to_hl (try String.sub s 0 (String.index s '\000') with Not_found -> assert false) in + let u16 = caml_to_hl (try String.sub s 0 (String.index s '\000') with Not_found -> Globals.die "" __LOC__) in set_ref r (to_int (String.length u16 - 2)); VBytes u16 - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "utf16_to_utf8" -> (function | [VBytes s; VInt pos; VRef (r,HI32)] -> @@ -1763,7 +1763,7 @@ let load_native ctx lib name t = let u8 = hl_to_caml s in set_ref r (to_int (String.length u8)); VBytes (u8 ^ "\x00") - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "ucs2_upper" -> (function | [VBytes s; VInt pos; VInt len] -> @@ -1777,7 +1777,7 @@ let load_native ctx lib name t = ) (String.sub s (int pos) ((int len) lsl 1)); Common.utf16_add buf 0; VBytes (Buffer.contents buf) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "ucs2_lower" -> (function | [VBytes s; VInt pos; VInt len] -> @@ -1791,7 +1791,7 @@ let load_native ctx lib name t = ) (String.sub s (int pos) ((int len) lsl 1)); Common.utf16_add buf 0; VBytes (Buffer.contents buf) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "url_encode" -> (function | [VBytes s; VRef (r, HI32)] -> @@ -1802,7 +1802,7 @@ let load_native ctx lib name t = let str = Buffer.contents buf in set_ref r (to_int (String.length str lsr 1 - 1)); VBytes str - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "url_decode" -> (function | [VBytes s; VRef (r, HI32)] -> @@ -1840,47 +1840,47 @@ let load_native ctx lib name t = let str = Buffer.contents b in set_ref r (to_int (UTF8.length str)); VBytes (caml_to_hl str) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "call_method" -> (function | [f;VArray (args,HDyn)] -> dyn_call ctx f (List.map (fun v -> v,HDyn) (Array.to_list args)) HDyn - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "no_closure" -> (function | [VClosure (f,_)] -> VClosure (f,None) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "get_closure_value" -> (function | [VClosure (_,None)] -> VNull | [VClosure (_,Some v)] -> v - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "make_var_args" -> (function | [VClosure (f,arg)] -> VVarArgs (f,arg) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "bytes_find" -> (function | [VBytes src; VInt pos; VInt len; VBytes chk; VInt cpos; VInt clen; ] -> to_int (try int pos + ExtString.String.find (String.sub src (int pos) (int len)) (String.sub chk (int cpos) (int clen)) with ExtString.Invalid_string -> -1) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "bytes_compare" -> (function | [VBytes a; VInt apos; VBytes b; VInt bpos; VInt len] -> to_int (String.compare (String.sub a (int apos) (int len)) (String.sub b (int bpos) (int len))) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "string_compare" -> (function | [VBytes a; VBytes b; VInt len] -> to_int (String.compare (String.sub a 0 ((int len) * 2)) (String.sub b 0 ((int len)*2))) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "bytes_fill" -> (function | [VBytes a; VInt pos; VInt len; VInt v] -> Bytes.fill (Bytes.unsafe_of_string a) (int pos) (int len) (char_of_int ((int v) land 0xFF)); VUndef - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "exception_stack" -> (function | [] -> VArray (Array.map (fun e -> VBytes (caml_to_hl (stack_frame ctx e))) (Array.of_list (List.rev ctx.error_stack)),HBytes) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "date_new" -> (function | [VInt y; VInt mo; VInt d; VInt h; VInt m; VInt s] -> @@ -1895,19 +1895,19 @@ let load_native ctx lib name t = } in to_date t | _ -> - assert false) + Globals.die "" __LOC__) | "date_now" -> (function | [] -> to_date (Unix.localtime (Unix.time())) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "date_get_time" -> (function | [VInt v] -> VFloat (fst (Unix.mktime (date v)) *. 1000.) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "date_from_time" -> (function | [VFloat f] -> to_date (Unix.localtime (f /. 1000.)) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "date_get_inf" -> (function | [VInt d;year;month;day;hours;minutes;seconds;wday] -> @@ -1916,7 +1916,7 @@ let load_native ctx lib name t = match r with | VNull -> () | VRef (r,HI32) -> set_ref r (to_int v) - | _ -> assert false + | _ -> Globals.die "" __LOC__ in set year (d.tm_year + 1900); set month d.tm_mon; @@ -1926,7 +1926,7 @@ let load_native ctx lib name t = set seconds d.tm_sec; set wday d.tm_wday; VUndef - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "date_to_string" -> (function | [VInt d; VRef (r,HI32)] -> @@ -1934,19 +1934,19 @@ let load_native ctx lib name t = let str = Printf.sprintf "%.4d-%.2d-%.2d %.2d:%.2d:%.2d" (t.tm_year + 1900) (t.tm_mon + 1) t.tm_mday t.tm_hour t.tm_min t.tm_sec in set_ref r (to_int (String.length str)); VBytes (caml_to_hl str) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "rnd_init_system" -> (function | [] -> Random.self_init(); VAbstract ARandom - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "rnd_int" -> (function | [VAbstract ARandom] -> VInt (Int32.of_int (Random.bits())) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "rnd_float" -> (function | [VAbstract ARandom] -> VFloat (Random.float 1.) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "regexp_new_options" -> (function | [VBytes str; VBytes opt] -> @@ -1998,7 +1998,7 @@ let load_native ctx lib name t = } in VAbstract (AReg r) | _ -> - assert false); + Globals.die "" __LOC__); | "regexp_match" -> (function | [VAbstract (AReg r);VBytes str;VInt pos;VInt len] -> @@ -2021,7 +2021,7 @@ let load_native ctx lib name t = VBool true; with Not_found -> VBool false) - | _ -> assert false); + | _ -> Globals.die "" __LOC__); | "regexp_matched_pos" -> (function | [VAbstract (AReg r); VInt n; VRef (rr,HI32)] -> @@ -2034,12 +2034,12 @@ let load_native ctx lib name t = (match (try r.r_groups.(n) with _ -> failwith ("Invalid group " ^ string_of_int n)) with | None -> to_int (-1) | Some (pos,pend) -> to_int pos) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "make_macro_pos" -> (function | [VBytes file;VInt min;VInt max] -> VAbstract (APos { Globals.pfile = String.sub file 0 (String.length file - 1); pmin = Int32.to_int min; pmax = Int32.to_int max }) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) | "dyn_op" -> let op_names = [|"+";"-";"*";"%";"/";"<<";">>";">>>";"&";"|";"^"|] in (function @@ -2060,7 +2060,7 @@ let load_native ctx lib name t = let b = dyn_cast ctx b HDyn HF64 in match a, b with | VFloat a, VFloat b -> VDyn (VFloat (op a b),HF64) - | _ -> assert false + | _ -> Globals.die "" __LOC__ end else error(); in @@ -2070,7 +2070,7 @@ let load_native ctx lib name t = let b = dyn_cast ctx b HDyn HI32 in match a, b with | VInt a, VInt b -> VDyn (VInt (op a b),HI32) - | _ -> assert false + | _ -> Globals.die "" __LOC__ end else error(); in @@ -2086,8 +2086,8 @@ let load_native ctx lib name t = | 8 -> iop Int32.logand | 9 -> iop Int32.logor | 10 -> iop Int32.logxor - | _ -> assert false) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) + | _ -> Globals.die "" __LOC__) | _ -> unresolved()) | "macro" -> @@ -2124,8 +2124,8 @@ let create checked = constants = [||]; }; checked = checked; - fcall = (fun _ _ -> assert false); - on_error = (fun _ _ -> assert false); + fcall = (fun _ _ -> Globals.die "" __LOC__); + on_error = (fun _ _ -> Globals.die "" __LOC__); resolve_macro_api = (fun _ -> None); } in ctx.on_error <- (fun msg stack -> failwith (vstr ctx msg HDyn ^ "\n" ^ String.concat "\n" (List.map (stack_frame ctx) stack))); @@ -2145,7 +2145,7 @@ let add_code ctx code = ctx.t_globals <- globals; (* expand function table *) let nfunctions = Array.length code.functions + Array.length code.natives in - let functions = Array.create nfunctions (FNativeFun ("",(fun _ -> assert false),HDyn)) in + let functions = Array.create nfunctions (FNativeFun ("",(fun _ -> Globals.die "" __LOC__),HDyn)) in Array.blit ctx.t_functions 0 functions 0 (Array.length ctx.t_functions); let rec loop i = if i = Array.length code.natives then () else @@ -2169,17 +2169,17 @@ let add_code ctx code = match t with | HI32 -> VInt code.ints.(idx) | HBytes -> VBytes (cached_string ctx idx) - | _ -> assert false + | _ -> Globals.die "" __LOC__ in let v = (match t with | HObj o -> - if Array.length o.pfields <> Array.length fields then assert false; + if Array.length o.pfields <> Array.length fields then Globals.die "" __LOC__; let proto,_,_ = get_proto ctx o in VObj { oproto = proto; ofields = Array.mapi (fun i (_,_,t) -> get_const_val t fields.(i)) o.pfields; } - | _ -> assert false + | _ -> Globals.die "" __LOC__ ) in ctx.t_globals.(g) <- v; ) code.constants; @@ -2209,7 +2209,7 @@ let check code macros = end else failwith (Printf.sprintf "\n%s:%d: %s" file dline msg) in - let targs, tret = (match f.ftype with HFun (args,ret) -> args, ret | _ -> assert false) in + let targs, tret = (match f.ftype with HFun (args,ret) -> args, ret | _ -> Globals.die "" __LOC__) in let rtype i = try f.regs.(i) with _ -> HObj { null_proto with pname = "OUT_OF_BOUNDS:" ^ string_of_int i } in let check t1 t2 = if not (safe_cast t1 t2) then error (tstr t1 ^ " should be " ^ tstr t2) @@ -2241,7 +2241,7 @@ let check code macros = if List.length args <> List.length targs then error (tstr (HFun (List.map rtype args, rtype r)) ^ " should be " ^ tstr ftypes.(f)); List.iter2 reg args targs; check tret (rtype r) - | _ -> assert false + | _ -> Globals.die "" __LOC__ in let can_jump delta = if !pos + 1 + delta < 0 || !pos + 1 + delta >= Array.length f.code then error "Jump outside function bounds"; @@ -2336,7 +2336,7 @@ let check code macros = | t -> check t (HFun (rtype 0 :: List.map rtype rl, rtype r))); | OCallMethod (r, m, rl) -> (match rl with - | [] -> assert false + | [] -> Globals.die "" __LOC__ | obj :: rl2 -> let check_args targs tret rl = if List.length targs <> List.length rl then false else begin @@ -2419,7 +2419,7 @@ let check code macros = reg o t; reg r (HFun (tl,tret)); | _ -> - assert false) + Globals.die "" __LOC__) | _ -> is_obj o) | OInstanceClosure (r,f,arg) -> @@ -2428,7 +2428,7 @@ let check code macros = reg arg t; if not (is_nullable t) then error (reg_inf r ^ " should be nullable"); reg r (HFun (tl,tret)); - | _ -> assert false); + | _ -> Globals.die "" __LOC__); | OThrow r -> reg r HDyn | ORethrow r -> @@ -2786,7 +2786,7 @@ let make_spec (code:code) (f:fundecl) = try Hashtbl.find block_args b.bstart with Not_found -> - assert false + Globals.die "" __LOC__ and calc_spec b = let bprev = List.filter (fun b2 -> b2.bstart < b.bstart) b.bprev in @@ -2795,7 +2795,7 @@ let make_spec (code:code) (f:fundecl) = let args = Array.make (Array.length f.regs) SUndef in (match f.ftype with | HFun (tl,_) -> list_iteri (fun i _ -> args.(i) <- SArg i) tl - | _ -> assert false); + | _ -> Globals.die "" __LOC__); args | b2 :: l -> let args = Array.copy (get_args b2) in @@ -2827,7 +2827,7 @@ let make_spec (code:code) (f:fundecl) = let r = emit (SCall (c,vl)) in (match r with | SResult result -> List.iter (fun v -> match v with SRef r -> args.(r) <- SRefResult result | _ -> ()) vl - | _ -> assert false); + | _ -> Globals.die "" __LOC__); r in for i = b.bstart to b.bend do diff --git a/src/generators/hlopt.ml b/src/generators/hlopt.ml index 7e18cf384e49514db14503fca95dbf2241a6b3bb..cadb9087a65c3c367ce33ef27cd1035121d1f2cc 100644 --- a/src/generators/hlopt.ml +++ b/src/generators/hlopt.ml @@ -508,7 +508,7 @@ let remap_fun ctx f dump get_str old_code = let reg_remap = ctx.r_used_regs <> nregs in let assigns = ref f.assigns in let write str = match dump with None -> () | Some ch -> IO.nwrite ch (Bytes.unsafe_of_string (str ^ "\n")) in - let nargs = (match f.ftype with HFun (args,_) -> List.length args | _ -> assert false) in + let nargs = (match f.ftype with HFun (args,_) -> List.length args | _ -> Globals.die "" __LOC__) in let live_bits = ctx.r_live_bits in let reg_map = ctx.r_reg_map in @@ -550,7 +550,7 @@ let remap_fun ctx f dump get_str old_code = if bp.bstart > b.bstart then acc else try let wp = PMap.find reg bp.bwrite in - if wp > p then assert false; + if wp > p then Globals.die "" __LOC__; loop wp @ acc with Not_found -> gather bp @ acc @@ -682,7 +682,7 @@ let remap_fun ctx f dump get_str old_code = | OJAlways d -> OJAlways (pos d) | OSwitch (r,cases,send) -> OSwitch (r, Array.map pos cases, pos send) | OTrap (r,d) -> OTrap (r,pos d) - | _ -> assert false) + | _ -> Globals.die "" __LOC__) ) !jumps; let assigns = !assigns in @@ -726,7 +726,7 @@ let _optimize (f:fundecl) = let set_live r min max = let offset = r / bit_regs in let mask = 1 lsl (r - offset * bit_regs) in - if min < 0 || max >= Array.length f.code then assert false; + if min < 0 || max >= Array.length f.code then Globals.die "" __LOC__; for i=min to max do let p = i * stride + offset in Array.unsafe_set live_bits p ((Array.unsafe_get live_bits p) lor mask); @@ -764,7 +764,7 @@ let _optimize (f:fundecl) = | b2 :: l -> let s = get_state b2 in let s = (match b2.bnext with - | [] -> assert false + | [] -> Globals.die "" __LOC__ | [_] -> s (* reuse *) | _ :: l -> let s2 = empty_state() in @@ -964,7 +964,7 @@ let _optimize (f:fundecl) = let used_regs = ref 0 in let reg_map = read_counts in - let nargs = (match f.ftype with HFun (args,_) -> List.length args | _ -> assert false) in + let nargs = (match f.ftype with HFun (args,_) -> List.length args | _ -> Globals.die "" __LOC__) in for i=0 to nregs-1 do if read_counts.(i) > 0 || write_counts.(i) > 0 || i < nargs then begin reg_map.(i) <- !used_regs; @@ -997,7 +997,7 @@ let optimize dump get_str (f:fundecl) (hxf:Type.tfunc) = try let c = PMap.find hxf (!opt_cache) in c.c_last_used <- !used_mark; - if Array.length f.code <> Array.length c.c_code then assert false; + if Array.length f.code <> Array.length c.c_code then Globals.die "" __LOC__; let code = c.c_code in Array.iter (fun i -> let op = (match Array.unsafe_get code i, Array.unsafe_get f.code i with @@ -1018,7 +1018,7 @@ let optimize dump get_str (f:fundecl) (hxf:Type.tfunc) = | ODynGet (r,o,_), ODynGet (_,_,idx) -> ODynGet (r,o,idx) | ODynSet (o,_,v), ODynSet (_,idx,_) -> ODynSet (o,idx,v) | OType (r,_), OType (_,t) -> OType (r,t) - | _ -> assert false) in + | _ -> Globals.die "" __LOC__) in Array.unsafe_set code i op ) c.c_remap_indexes; remap_fun c.c_rctx { f with code = code } dump get_str old_code diff --git a/src/generators/jvm/jvmClass.ml b/src/generators/jvm/jvmClass.ml index f8acdb41abc1f955a01bb71cb0c649b3a8952437..17435cea22edd48608c158c64b1bf7c6e328f4cb 100644 --- a/src/generators/jvm/jvmClass.ml +++ b/src/generators/jvm/jvmClass.ml @@ -32,37 +32,31 @@ class builder path_this path_super = object(self) val jsig = TObject(path_this,[]) val mutable offset_this = 0 val mutable offset_super = 0 + val mutable type_parameters = [] + val mutable super_type_parameters = [] + val mutable interfaces = [] val mutable interface_offsets = [] val fields = DynArray.create () val methods = DynArray.create () val method_sigs = Hashtbl.create 0 val inner_classes = Hashtbl.create 0 - val mutable closure_count = 0 - val mutable bootstrap_methods = [] - val mutable num_bootstrap_methods = 0 val mutable spawned_methods = [] - val mutable field_init_method = None + val mutable static_init_method = None + val mutable source_file = None - method add_interface path = - interface_offsets <- (pool#add_path path) :: interface_offsets + method add_interface (path : jpath) (params : jtype_argument list) = + interface_offsets <- (pool#add_path path) :: interface_offsets; + interfaces <- (path,params) :: interfaces + + method set_type_parameters (sl : string list) = + type_parameters <- sl + + method set_super_parameters (params : jtype_argument list) = + super_type_parameters <- params method add_field (f : jvm_field) = DynArray.add fields f - method get_bootstrap_method path name jsig (consts : jvm_constant_pool_index list) = - try - fst (List.assoc (path,name,consts) bootstrap_methods) - with Not_found -> - let offset = pool#add_field path name jsig FKMethod in - let offset = pool#add (ConstMethodHandle(6, offset)) in - let bm = { - bm_method_ref = offset; - bm_arguments = Array.of_list consts; - } in - bootstrap_methods <- ((path,name,consts),(offset,bm)) :: bootstrap_methods; - num_bootstrap_methods <- num_bootstrap_methods + 1; - num_bootstrap_methods - 1 - method get_pool = pool method get_this_path = path_this @@ -71,10 +65,15 @@ class builder path_this path_super = object(self) method get_offset_this = offset_this method get_access_flags = access_flags - method get_next_closure_name = - let name = Printf.sprintf "hx_closure$%i" closure_count in - closure_count <- closure_count + 1; - name + method set_source_file (file : string) = + source_file <- Some file + + method get_static_init_method = match static_init_method with + | Some jm -> jm + | None -> + let jm = self#spawn_method "" (method_sig [] None) [MethodAccessFlags.MStatic] in + static_init_method <- Some jm; + jm method has_method (name : string) (jsig : jsignature) = Hashtbl.mem method_sigs (name,generate_method_signature false jsig) @@ -99,6 +98,12 @@ class builder path_this path_super = object(self) end; let offset = pool#add_path path in Hashtbl.add inner_classes offset jc; + begin match source_file with + | None -> + () + | Some file -> + jc#set_source_file file + end; jc method spawn_method (name : string) (jsig_method : jsignature) (flags : MethodAccessFlags.t list) = @@ -144,16 +149,38 @@ class builder path_this path_super = object(self) self#add_attribute (AttributeInnerClasses a) end - method private commit_bootstrap_methods = - match bootstrap_methods with - | [] -> - () - | _ -> - let l = List.fold_left (fun acc (_,(_,bm)) -> bm :: acc) [] bootstrap_methods in - self#add_attribute (AttributeBootstrapMethods (Array.of_list l)) + method private generate_signature = + let stl = match type_parameters with + | [] -> "" + | params -> + let stl = String.concat "" (List.map (fun n -> + Printf.sprintf "%s:Ljava/lang/Object;" n + ) params) in + Printf.sprintf "<%s>" stl + in + let ssuper = generate_method_signature true (TObject(path_super,super_type_parameters)) in + let sinterfaces = String.concat "" (List.map (fun (path,params) -> + generate_method_signature true (TObject(path,params)) + ) interfaces) in + let s = Printf.sprintf "%s%s%s" stl ssuper sinterfaces in + let offset = self#get_pool#add_string s in + self#add_attribute (AttributeSignature offset) method export_class (config : export_config) = assert (not was_exported); + begin match source_file with + | None -> + () + | Some file -> + self#add_attribute (AttributeSourceFile (self#get_pool#add_string file)); + end; + begin match static_init_method with + | None -> + () + | Some jm -> + if not jm#is_terminated then jm#return; + end; + self#generate_signature; was_exported <- true; List.iter (fun (jm,pop_scope) -> begin match pop_scope with @@ -164,7 +191,6 @@ class builder path_this path_super = object(self) self#add_field jm#export_field end; ) (List.rev spawned_methods); - self#commit_bootstrap_methods; self#commit_inner_classes; self#commit_annotations pool; let attributes = self#export_attributes pool in diff --git a/src/generators/jvm/jvmCode.ml b/src/generators/jvm/jvmCode.ml index 73c15a20575e590190fff5dd58ebff27a70607f8..d8f9fe06f867d708267ddd34399f87337201e450 100644 --- a/src/generators/jvm/jvmCode.ml +++ b/src/generators/jvm/jvmCode.ml @@ -25,6 +25,22 @@ open JvmSignature exception EmptyStack +let terminates = function + | OpDreturn + | OpFreturn + | OpIreturn + | OpLreturn + | OpAreturn + | OpGoto _ + | OpGoto_w _ + | OpJsr _ + | OpJsr_w _ + | OpAthrow + | OpReturn -> + true + | _ -> + false + class jvm_stack = object(self) val mutable stack = []; val mutable stack_size = 0; @@ -88,6 +104,10 @@ class builder pool = object(self) val ops = DynArray.create(); val stack_debug = DynArray.create() val mutable fp = 0 + val mutable terminated = false + + method is_terminated = terminated + method set_terminated b = terminated <- b method debug_stack = let l = DynArray.to_list stack_debug in @@ -127,13 +147,13 @@ class builder pool = object(self) stack#pop with EmptyStack -> self#stack_error opcode expect cur; - assert false + Globals.die "" __LOC__ in (* TODO: some unification or something? *) match js,js' with | (TObject _ | TTypeParameter _),(TObject _ | TTypeParameter _ | TArray _) -> () (* TODO ??? *) | TMethod _,TMethod _ -> () - | TMethod _,TObject((["java";"lang";"invoke"],"MethodHandle"),[]) -> () + | TMethod _,TObject(path,[]) when path = NativeSignatures.haxe_function_path -> () | TTypeParameter _,TMethod _ -> () | TObject _,TMethod _ -> () | TMethod _,TObject _ -> () @@ -148,11 +168,12 @@ class builder pool = object(self) ) expect; List.iter stack#push (List.rev return); DynArray.add stack_debug (opcode,cur,stack#get_stack,current_line); + if terminates opcode then terminated <- true method op_maybe_wide op opw i tl tr = match get_numeric_range_unsigned i with | Int8Range -> self#op op 2 tl tr | Int16Range -> self#op (OpWide opw) 4 tl tr - | Int32Range -> assert false + | Int32Range -> Globals.die "" __LOC__ (* variables *) @@ -232,7 +253,7 @@ class builder pool = object(self) | (Int8Range | Int16Range),(Int8Range | Int16Range) -> self#op (OpWide (OpWIinc(index,i))) 6 [] [] | _ -> - assert false + Globals.die "" __LOC__ (* conversions *) @@ -342,22 +363,16 @@ class builder pool = object(self) (* control flow *) method if_ cmp r = self#op (OpIf(cmp,r)) 3 [TBool] [] - method if_ref cmp = let r = ref fp in self#if_ cmp r; r method if_icmp cmp r = self#op (OpIf_icmp(cmp,r)) 3 [TInt;TInt] [] - method if_icmp_ref cmp = let r = ref fp in self#if_icmp cmp r; r method if_acmp_eq t1 t2 r = self#op (OpIf_acmpeq r) 3 [t1;t2] [] - method if_acmp_eq_ref t1 t2 = let r = ref fp in self#if_acmp_eq t1 t2 r; r method if_acmp_ne t1 t2 r = self#op (OpIf_acmpne r) 3 [t1;t2] [] - method if_acmp_ne_ref t1 t2 = let r = ref fp in self#if_acmp_ne t1 t2 r; r method if_null t r = self#op (OpIfnull r) 3 [t] [] - method if_null_ref t = let r = ref fp in self#if_null t r; r method if_nonnull t r = self#op (OpIfnonnull r) 3 [t] [] - method if_nonnull_ref t = let r = ref fp in self#if_nonnull t r; r method goto r = self#op (OpGoto r) 3 [] [] diff --git a/src/generators/jvm/jvmConstantPool.ml b/src/generators/jvm/jvmConstantPool.ml index 6438bddbd94b6b4d6bbd27fc91b1cd50fb9039ea..79a8ddd72c5e5206691115e009f8ee1d70ded15c 100644 --- a/src/generators/jvm/jvmConstantPool.ml +++ b/src/generators/jvm/jvmConstantPool.ml @@ -87,7 +87,7 @@ class constant_pool = object(self) method add_path path = let s = self#s_type_path path in let offset = self#add_type s in - if String.contains (snd path) '$' then begin + if String.contains (snd path) '$' && not (ExtString.String.starts_with s "[") then begin let name1,name2 = ExtString.String.split (snd path) "$" in Hashtbl.replace inner_classes ((fst path,name1),name2) offset; end; diff --git a/src/generators/jvm/jvmFunctions.ml b/src/generators/jvm/jvmFunctions.ml new file mode 100644 index 0000000000000000000000000000000000000000..5b2230d684bc2b9830eb54f447453c4848a0169f --- /dev/null +++ b/src/generators/jvm/jvmFunctions.ml @@ -0,0 +1,449 @@ +open JvmGlobals.MethodAccessFlags +open JvmSignature +open NativeSignatures + +type signature_classification = + | CByte + | CChar + | CDouble + | CFloat + | CInt + | CLong + | CShort + | CBool + | CObject + +type method_signature = { + arity : int; + name : string; + has_nonobject : bool; + sort_string : string; + cargs : signature_classification list; + cret : signature_classification option; + dargs : jsignature list; + dret : jsignature option; + mutable next : method_signature option; +} + +let string_of_classification = function + | CByte -> "Byte" + | CChar -> "Char" + | CDouble -> "Double" + | CFloat -> "Float" + | CInt -> "Int" + | CLong -> "Long" + | CShort -> "Short" + | CBool -> "Bool" + | CObject -> "Object" + +let classify = function + | TByte -> CByte + | TChar -> CChar + | TDouble -> CDouble + | TFloat -> CFloat + | TInt -> CInt + | TLong -> CLong + | TShort -> CShort + | TBool -> CBool + | TObject _ + | TObjectInner _ + | TArray _ + | TMethod _ + | TTypeParameter _ + | TUninitialized _ -> CObject + +let declassify = function + | CByte -> TByte + | CChar -> TChar + | CDouble -> TDouble + | CFloat -> TFloat + | CInt -> TInt + | CLong -> TLong + | CShort -> TShort + | CBool -> TBool + | CObject -> object_path_sig object_path + +class typed_functions = object(self) + val signatures = Hashtbl.create 0 + val mutable max_arity = 0 + + method register_signature (tl : jsignature list) (tr : jsignature option) = + let cl = List.map classify tl in + let cr = Option.map classify tr in + self#get_signature cl cr + + method objectify (meth : method_signature) = + let cl_objects = List.map (fun _ -> CObject) meth.cargs in + self#get_signature cl_objects meth.cret + + method private get_signature + (cl : signature_classification list) + (cr : signature_classification option) + = + try + Hashtbl.find signatures (cl,cr) + with Not_found -> + self#do_register_signature cl cr + + method private do_register_signature + (cl : signature_classification list) + (cr : signature_classification option) + = + let to_string (cl,cr) = + Printf.sprintf "[%s] %s" + (String.concat ", " (List.map string_of_classification cl)) + (Option.map_default string_of_classification "CVoid" cr) + in + let meth = { + arity = List.length cl; + name = "invoke"; + has_nonobject = List.exists (function CObject -> false | _ -> true) cl; + sort_string = to_string (cl,cr); + cargs = cl; + cret = cr; + dargs = List.map declassify cl; + dret = Option.map declassify cr; + next = None; + } in + if meth.arity > max_arity then max_arity <- meth.arity; + Hashtbl.add signatures (meth.cargs,meth.cret) meth; + (* If the method has something that's not java.lang.Object, the next method is one where all arguments are + of type java.lang.Object. *) + if meth.has_nonobject then begin + let meth_objects = self#objectify meth in + meth.next <- Some meth_objects; + (* Otherwise, if the method has a return type that's not java.lang.Object, the next method is one that returns + java.lang.Object. *) + end else begin match cr with + | Some CObject -> + () + | _ -> + meth.next <- Some (self#get_signature meth.cargs (Some CObject)) + end; + meth + + method make_forward_method + (jc : JvmClass.builder) + (jm : JvmMethod.builder) + (meth_from : method_signature) + (meth_to : method_signature) + = + let args = List.mapi (fun i jsig -> + jm#add_local (Printf.sprintf "arg%i" i) jsig VarArgument + ) meth_from.dargs in + jm#finalize_arguments; + jm#load_this; + let rec loop loads jsigs = match loads,jsigs with + | (_,load,_) :: loads,jsig :: jsigs -> + load(); + jm#cast jsig; + loop loads jsigs + | [],jsig :: jsigs -> + jm#load_default_value jsig; + loop [] jsigs + | [],[] -> + () + | _,[] -> + Globals.die "" __LOC__ + in + loop args meth_to.dargs; + jm#invokevirtual jc#get_this_path meth_to.name (method_sig meth_to.dargs meth_to.dret); + begin match meth_from.dret,meth_to.dret with + | None,None -> + () + | Some jsig,Some _ -> + jm#cast jsig; + | None,Some jsig -> + jm#get_code#pop + | Some jsig,None -> + jm#load_default_value jsig; + end; + jm#return; + + method generate_invoke_dynamic (jc : JvmClass.builder) = + let array_sig = TArray(object_sig,None) in + let jm = jc#spawn_method "invokeDynamic" (method_sig [array_sig] (Some object_sig)) [MPublic] in + let _,load,_ = jm#add_local "args" array_sig VarArgument in + jm#finalize_arguments; + load(); + jm#get_code#arraylength array_sig; + let cases = ExtList.List.init max_arity (fun i -> + [Int32.of_int i],(fun () -> + jm#load_this; + let args = ExtList.List.init i (fun index -> + load(); + jm#get_code#iconst (Int32.of_int index); + jm#get_code#aaload array_sig object_sig; + object_sig + ) in + jm#invokevirtual jc#get_this_path "invoke" (method_sig args (Some object_sig)); + jm#return; + ) + ) in + let def = (fun () -> + jm#string "Invalid call"; + jm#invokestatic (["haxe";"jvm"],"Exception") "wrap" (method_sig [object_sig] (Some exception_sig)); + jm#get_code#athrow; + jm#set_terminated true; + ) in + ignore(jm#int_switch true cases (Some def)); + + method generate_closure_dispatch = + let jc = new JvmClass.builder (["haxe";"jvm"],"ClosureDispatch") haxe_function_path in + jc#add_access_flag 1; (* public *) + let jm_ctor = jc#spawn_method "" (method_sig [] None) [MPublic] in + jm_ctor#finalize_arguments; + jm_ctor#load_this; + jm_ctor#call_super_ctor ConstructInit (method_sig [] None); + jm_ctor#return; + let rec loop args i = + let jsig = method_sig args (Some object_sig) in + let jm = jc#spawn_method "invoke" jsig [MPublic] in + let vars = ExtList.List.init i (fun i -> + jm#add_local (Printf.sprintf "arg%i" i) object_sig VarArgument + ) in + jm#load_this; + jm#new_native_array object_sig (List.map (fun (_,load,_) () -> load()) vars); + jm#invokevirtual haxe_function_path "invokeDynamic" (method_sig [array_sig object_sig] (Some object_sig)); + jm#return; + if i < max_arity then loop (object_sig :: args) (i + 1) + in + loop [] 0; + jc + + method generate_var_args = + let jc = new JvmClass.builder (["haxe";"jvm"],"VarArgs") haxe_function_path in + jc#add_access_flag 1; (* public *) + let jm_ctor = jc#spawn_method "" (method_sig [haxe_function_sig] None) [MPublic] in + jm_ctor#add_argument_and_field "func" haxe_function_sig; + jm_ctor#finalize_arguments; + jm_ctor#load_this; + jm_ctor#call_super_ctor ConstructInit (method_sig [] None); + jm_ctor#return; + let rec loop args i = + let jsig = method_sig args (Some object_sig) in + let jm = jc#spawn_method "invoke" jsig [MPublic;MBridge;MSynthetic] in + let vars = ExtList.List.init i (fun i -> + jm#add_local (Printf.sprintf "arg%i" i) object_sig VarArgument + ) in + jm#load_this; + jm#getfield jc#get_this_path "func" haxe_function_sig; + jm#new_native_array object_sig (List.map (fun (_,load,_) () -> load()) vars); + jm#invokestatic (["haxe";"root"],"Array") "ofNative" (method_sig [array_sig object_sig] (Some (object_path_sig (["haxe";"root"],"Array")))); + jm#invokevirtual haxe_function_path "invoke" (method_sig [object_sig] (Some object_sig)); + jm#return; + if i < max_arity then loop (object_sig :: args) (i + 1) + in + loop [] 0; + jc + + method generate = + let l = Hashtbl.fold (fun _ v acc -> v :: acc) signatures [] in + let l = List.sort (fun meth1 meth2 -> compare (meth1.arity,meth1.sort_string) (meth2.arity,meth2.sort_string)) l in + let jc = new JvmClass.builder haxe_function_path object_path in + jc#add_access_flag 1; (* public *) + List.iter (fun meth -> + let jm = jc#spawn_method meth.name (method_sig meth.dargs meth.dret) [MPublic;MBridge;MSynthetic] in + begin match meth.next with + | Some meth_next -> + self#make_forward_method jc jm meth meth_next; + | None when meth.arity < max_arity && not meth.has_nonobject -> + let meth_next = self#get_signature (CObject :: meth.cargs) meth.cret in + self#make_forward_method jc jm meth meth_next + | None -> + List.iteri (fun i jsig -> + ignore(jm#add_local (Printf.sprintf "arg%i" i) jsig VarArgument) + ) meth.dargs; + jm#finalize_arguments; + begin match meth.dret with + | Some jsig -> jm#load_default_value jsig + | None -> () + end; + jm#return; + end; + ) l; + let jm_ctor = jc#spawn_method "" (method_sig [] None) [MPublic] in + jm_ctor#load_this; + jm_ctor#call_super_ctor ConstructInit (method_sig [] None); + jm_ctor#return; + self#generate_invoke_dynamic jc; + jc +end + +type typed_function_kind = + | FuncLocal + | FuncMember of jpath * string + | FuncStatic of jpath * string + +module JavaFunctionalInterfaces = struct + type t = { + jargs: jsignature list; + jret : jsignature option; + jpath : jpath; + jname : string; + jparams : string list; + } + + let java_functional_interfaces = + let juf = ["java";"util";"function"] in + let tp name = TTypeParameter name in + [ + { + jargs = []; + jret = None; + jpath = ["java";"lang"],"Runnable"; + jname = "run"; + jparams = [] + }; + { + jargs = [tp "T"]; + jret = None; + jpath = juf,"Consumer"; + jname = "accept"; + jparams = ["T"] + }; + { + jargs = [tp "T";tp "U"]; + jret = None; + jpath = juf,"BiConsumer"; + jname = "accept"; + jparams = ["T";"U"] + } + ] + + let unify jfi args ret = + let rec loop params want have = match want,have with + | [],[] -> + Some (jfi,List.map (fun s -> TType(WNone,List.assoc s params)) jfi.jparams) + | want1 :: want,have1 :: have -> + begin match want1 with + | TTypeParameter n -> + let have1 = get_boxed_type have1 in + loop ((n,have1) :: params) want have + | _ -> + if have1 <> want1 then None + else loop params want have + end + | _ -> + None + in + match jfi.jret,ret with + | None,None -> + loop [] jfi.jargs args + | Some (TTypeParameter n),Some jsig -> + let jsig = get_boxed_type jsig in + loop [n,jsig] jfi.jargs args + | Some jsig1,Some jsig2 -> + if jsig1 <> jsig2 then None + else loop [] jfi.jargs args + | _ -> + None + + + let find_compatible args ret = + ExtList.List.filter_map (fun jfi -> + if jfi.jparams = [] then begin + if jfi.jargs = args && jfi.jret = ret then + Some (jfi,[]) + else None + end else + unify jfi args ret + ) java_functional_interfaces +end + +open JavaFunctionalInterfaces + +class typed_function + (functions : typed_functions) + (kind : typed_function_kind) + (host_class : JvmClass.builder) + (host_method : JvmMethod.builder) + (context : (string * jsignature) list) + += object(self) + + val jc_closure = + let patch_name name = match name with + | "" -> "new" + | "" -> "__init__" + | name -> name + in + let name = match kind with + | FuncLocal -> + Printf.sprintf "Closure_%s_%i" (patch_name host_method#get_name) host_method#get_next_closure_id + | FuncStatic(path,name) -> + Printf.sprintf "%s_%s" (snd path) (patch_name name) + | FuncMember(path,name) -> + Printf.sprintf "%s_%s" (snd path) (patch_name name) + in + let jc = host_class#spawn_inner_class None haxe_function_path (Some name) in + jc#add_access_flag 0x10; (* final *) + jc + + method get_class = jc_closure + + method generate_constructor (public : bool) = + let context_sigs = List.map snd context in + let jm_ctor = jc_closure#spawn_method "" (method_sig context_sigs None) (if public then [MPublic] else []) in + List.iter (fun (name,jsig) -> + jm_ctor#add_argument_and_field name jsig; + ) context; + jm_ctor#load_this; + jm_ctor#call_super_ctor ConstructInit (method_sig [] None); + jm_ctor#return; + jm_ctor + + method generate_invoke (args : (string * jsignature) list) (ret : jsignature option)= + let arg_sigs = List.map snd args in + let meth = functions#register_signature arg_sigs ret in + let jsig_invoke = method_sig arg_sigs ret in + let jm_invoke = jc_closure#spawn_method meth.name jsig_invoke [MPublic] in + let implemented_interfaces = Hashtbl.create 0 in + let add_interface path params = + if not (Hashtbl.mem implemented_interfaces path) then begin + jc_closure#add_interface path params; + Hashtbl.add implemented_interfaces path true; + end + in + let spawn_forward_function meth_from meth_to is_bridge = + let flags = [MPublic] in + let flags = if is_bridge then MBridge :: MSynthetic :: flags else flags in + let jm_invoke_next = jc_closure#spawn_method meth_from.name (method_sig meth_from.dargs meth_from.dret) flags in + functions#make_forward_method jc_closure jm_invoke_next meth_from meth_to; + in + let check_functional_interfaces meth = + try + let l = JavaFunctionalInterfaces.find_compatible meth.dargs meth.dret in + List.iter (fun (jfi,params) -> + add_interface jfi.jpath params; + spawn_forward_function {meth with name=jfi.jname} meth false; + ) l + with Not_found -> + () + in + let rec loop meth = + check_functional_interfaces meth; + begin match meth.next with + | Some meth_next -> + spawn_forward_function meth_next meth true; + loop meth_next; + | None -> + () + end; + in + let return_differs = match meth.dret,ret with + | None,None -> false + | Some jsig1,Some jsig2 -> not (equals_at_runtime jsig1 jsig2) + | _ -> true + in + let meth = if not (List.for_all2 equals_at_runtime meth.dargs arg_sigs) || return_differs then begin + let meth_prev = meth in + let meth = {meth with dargs = arg_sigs; dret = ret} in + meth.next <- Some meth_prev; + meth + end else + meth + in + loop meth; + jm_invoke +end \ No newline at end of file diff --git a/src/generators/jvm/jvmMethod.ml b/src/generators/jvm/jvmMethod.ml index 03d7b520c6ffab4e763217b230f7f8423d74bc22..3dbf90a19f2bcfcfb07e5c49083ba8ab22b21575 100644 --- a/src/generators/jvm/jvmMethod.ml +++ b/src/generators/jvm/jvmMethod.ml @@ -25,6 +25,46 @@ open JvmSignature open JvmSignature.NativeSignatures open JvmBuilder +let rec pow a b = match b with + | 0 -> Int32.one + | 1 -> a + | _ -> Int32.mul a (pow a (b - 1)) + +let java_hash s = + let h = ref Int32.zero in + let l = UTF8.length s in + let i31 = Int32.of_int 31 in + let i = ref 0 in + UTF8.iter (fun char -> + let char = Int32.of_int (UCharExt.uint_code char) in + h := Int32.add !h (Int32.mul char (pow i31 (l - (!i + 1)))); + incr i; + ) s; + !h + +module HashtblList = struct + type ('a,'b) t = { + values : ('a,'b) Hashtbl.t; + mutable keys : 'a list; + } + + let create () = { + values = Hashtbl.create 0; + keys = [] + } + + let add htl key value = + if not (Hashtbl.mem htl.values key) then begin + htl.keys <- key :: htl.keys + end; + Hashtbl.add htl.values key value + + let as_list htl = + List.map (fun key -> + (key,Hashtbl.find_all htl.values key) + ) htl.keys +end + (* High-level method builder. *) type var_init_state = @@ -36,6 +76,10 @@ type construction_kind = | ConstructInitPlusNew | ConstructInit +type label_state = + | LabelSet of jbranchoffset + | LabelNotSet of jbranchoffset ref list ref + module NativeArray = struct let read code ja je = match je with | TBool -> code#baload TBool ja @@ -78,12 +122,12 @@ module NativeArray = struct | TInt -> primitive 10 | TLong -> primitive 11 | TObject(path,_) -> reference path - | TMethod _ -> reference NativeSignatures.method_handle_path + | TMethod _ -> reference NativeSignatures.haxe_function_path | TTypeParameter _ -> reference NativeSignatures.object_path | TArray _ -> let offset = pool#add_type (generate_signature false je) in code#anewarray ja offset - | TObjectInner _ | TUninitialized _ -> assert false + | TObjectInner _ | TUninitialized _ -> die "" __LOC__ end; ja end @@ -98,9 +142,7 @@ class builder jc name jsig = object(self) val mutable exceptions = [] val mutable argument_locals = [] val mutable thrown_exceptions = Hashtbl.create 0 - - (* per-branch *) - val mutable terminated = false + val mutable closure_count = 0 (* per-frame *) val mutable locals = [] @@ -125,17 +167,15 @@ class builder jc name jsig = object(self) | None -> failwith ("Uninitialized local " ^ name); | Some fp -> fp in - let ld = { - ld_start_pc = fp; - ld_length = fp_end - fp; - ld_name_index = jc#get_pool#add_string name; - ld_descriptor_index = jc#get_pool#add_string (generate_signature false t); - ld_index = old_offset + i - 1; - } in + let t = match t with + | TUninitialized None -> TObject(jc#get_this_path,[]) + | _ -> t + in + let ld = (fp,fp_end - fp,name,t,old_offset + i - (signature_size t)) in debug_locals <- ld :: debug_locals; loop (i - (signature_size t)) l | [] -> - assert false + die "" __LOC__ end in loop delta locals; @@ -150,6 +190,11 @@ class builder jc name jsig = object(self) | _ -> JvmVerificationTypeInfo.of_signature jc#get_pool t ) locals + method get_next_closure_id = + let id = closure_count in + closure_count <- closure_count + 1; + id + (** Adds the current state of locals and stack as a stack frame. This has to be called on every branch target. **) method add_stack_frame = let locals = self#get_locals_for_stack_frame locals in @@ -181,28 +226,28 @@ class builder jc name jsig = object(self) | TMethod(tl,tr) -> let offset = code#get_pool#add_field path name jsigm FKMethod in code#invokevirtual offset (object_path_sig path) tl (match tr with None -> [] | Some tr -> [tr]) - | _ -> assert false + | _ -> die "" __LOC__ (** Emits an invokeinterface instruction to invoke method [name] on [path] with signature [jsigm]. **) method invokeinterface (path : jpath) (name : string) (jsigm : jsignature) = match jsigm with | TMethod(tl,tr) -> let offset = code#get_pool#add_field path name jsigm FKInterfaceMethod in code#invokeinterface offset (object_path_sig path) tl (match tr with None -> [] | Some tr -> [tr]) - | _ -> assert false + | _ -> die "" __LOC__ (** Emits an invokespecial instruction to invoke method [name] on [path] with signature [jsigm]. **) method invokespecial (path : jpath) (name : string) (jsigm : jsignature) = match jsigm with | TMethod(tl,tr) -> let offset = code#get_pool#add_field path name jsigm FKMethod in code#invokespecial offset (object_path_sig path) tl (match tr with None -> [] | Some tr -> [tr]) - | _ -> assert false + | _ -> die "" __LOC__ (** Emits an invokestatic instruction to invoke method [name] on [path] with signature [jsigm]. **) method invokestatic (path : jpath) (name : string) (jsigm : jsignature) = match jsigm with | TMethod(tl,tr) -> let offset = code#get_pool#add_field path name jsigm FKMethod in code#invokestatic offset tl (match tr with None -> [] | Some tr -> [tr]) - | _ -> assert false + | _ -> die "" __LOC__ (** Emits a getfield instruction to get the value of field [name] on object [path] with signature [jsigf]. **) method getfield (path : jpath) (name : string) (jsigf : jsignature) = @@ -224,6 +269,37 @@ class builder jc name jsig = object(self) let offset = code#get_pool#add_field path name jsigf FKField in code#putstatic offset jsigf + method get_basic_type_class (name : string) = + self#getstatic (["java";"lang"],name) "TYPE" java_class_sig + + method get_class (jsig : jsignature) = + match jsig with + | TByte -> self#get_basic_type_class "Byte" + | TChar -> self#get_basic_type_class "Character" + | TDouble -> self#get_basic_type_class "Double" + | TFloat -> self#get_basic_type_class "Float" + | TInt -> self#get_basic_type_class "Integer" + | TLong -> self#get_basic_type_class "Long" + | TShort -> self#get_basic_type_class "Short" + | TBool -> self#get_basic_type_class "Boolean" + | TObject(path,_) -> + let offset = code#get_pool#add_path path in + let t = object_path_sig path in + code#ldc offset (TObject(java_class_path,[TType(WNone,t)])) + | TTypeParameter _ -> + let offset = code#get_pool#add_path object_path in + code#ldc offset (TObject(java_class_path,[TType(WNone,object_sig)])) + | TArray _ as t -> + (* TODO: this seems hacky *) + let offset = code#get_pool#add_path ([],generate_signature false t) in + code#ldc offset (TObject(java_class_path,[TType(WNone,object_sig)])) + | TMethod _ -> + let offset = code#get_pool#add_path haxe_function_path in + code#ldc offset (TObject(java_class_path,[TType(WNone,object_sig)])) + | jsig -> + print_endline (generate_signature false jsig); + die "" __LOC__ + (** Loads `this` **) method load_this = code#aload self#get_this_sig 0 @@ -301,15 +377,6 @@ class builder jc name jsig = object(self) NativeArray.write code jasig jsig ) fl - (** Adds a closure to method [name] ob [path] with signature [jsig_method] to the constant pool. - - Also emits an instruction to load the closure. - **) - method read_closure is_static path name jsig_method = - let offset = code#get_pool#add_field path name jsig_method FKMethod in - let offset = code#get_pool#add (ConstMethodHandle((if is_static then 6 else 5), offset)) in - code#ldc offset jsig_method - (** Emits a return instruction. **) @@ -320,9 +387,9 @@ class builder jc name jsig = object(self) code#return_void | Some jsig -> code#return_value jsig - end + end; | _ -> - assert false + die "" __LOC__ (* casting *) @@ -376,73 +443,172 @@ class builder jc name jsig = object(self) | _ -> () end - method adapt_method jsig = - () - (* let offset = code#get_pool#add_string (generate_method_signature false jsig) in - let offset = code#get_pool#add (ConstMethodType offset) in - self#get_code#dup; - self#if_then - (fun () -> self#get_code#if_null_ref jsig) - (fun () -> - code#ldc offset method_type_sig; - self#invokevirtual method_handle_path "asType" (method_sig [method_type_sig] (Some method_handle_sig)) - ); - ignore(code#get_stack#pop); - code#get_stack#push jsig; *) - (** Casts the top of the stack to [jsig]. If [allow_to_string] is true, Jvm.toString is called. **) method cast ?(not_null=false) ?(allow_to_string=false) jsig = let jsig' = code#get_stack#top in + let is_number_sig except = function + | TObject((["java";"lang"],("Byte" | "Short" | "Integer" | "Long" | "Float" | "Double" as name)),_) when name <> except -> + true + | _ -> + false + in + let rec unboxed_to_byte () = match code#get_stack#top with + | TByte | TBool -> () + | TChar | TShort | TInt -> + code#i2b TByte + | TLong -> + code#l2i; + unboxed_to_byte (); + | TFloat -> + code#f2i; + unboxed_to_byte (); + | TDouble -> + code#d2i; + unboxed_to_byte (); + | jsig -> + failwith (s_signature_kind jsig); + in + let rec unboxed_to_short () = match code#get_stack#top with + | TShort -> () + | TBool | TByte | TChar | TInt -> + code#i2s; + | TLong -> + code#l2i; + unboxed_to_short (); + | TFloat -> + code#f2i; + unboxed_to_short (); + | TDouble -> + code#d2i; + unboxed_to_short (); + | _ -> + die "" __LOC__ + in + let rec unboxed_to_int () = match code#get_stack#top with + | TBool | TByte | TShort | TChar | TInt -> + ignore(code#get_stack#pop); + code#get_stack#push TInt; + | TLong -> + code#l2i; + | TFloat -> + code#f2i; + | TDouble -> + code#d2i; + | _ -> + die "" __LOC__ + in + let rec unboxed_to_long () = match code#get_stack#top with + | TBool | TByte | TShort | TChar | TInt -> + code#i2l; + | TLong -> + () + | TFloat -> + code#f2l; + | TDouble -> + code#d2l; + | _ -> + die "" __LOC__ + in + let rec unboxed_to_float () = match code#get_stack#top with + | TBool | TByte | TShort | TChar | TInt -> + code#i2f; + | TLong -> + code#l2f; + | TFloat -> + () + | TDouble -> + code#d2f; + | _ -> + die "" __LOC__ + in + let rec unboxed_to_double () = match code#get_stack#top with + | TBool | TByte | TShort | TChar | TInt -> + code#i2d; + | TLong -> + code#l2d; + | TFloat -> + code#f2d; + | TDouble -> + () + | _ -> + die "" __LOC__ + in + let get_conv = function + | "Byte" -> unboxed_to_byte + | "Short" -> unboxed_to_short + | "Integer" -> unboxed_to_int + | "Long" -> unboxed_to_long + | "Float" -> unboxed_to_float + | "Double" -> unboxed_to_double + | _ -> die "" __LOC__ + in + let number_to name = + let boxed_sig = TObject((["java";"lang"],name),[]) in + self#invokestatic (["haxe";"jvm"],"Jvm") ("numberTo" ^ name) (method_sig [number_sig] (Some boxed_sig)) + in + let dynamic_to name = + let boxed_sig = TObject((["java";"lang"],name),[]) in + self#invokestatic (["haxe";"jvm"],"Jvm") ("dynamicTo" ^ name) (method_sig [object_sig] (Some boxed_sig)) + in + let numeric_cast_boxed name jsig = + if is_unboxed jsig then begin + (get_conv name) (); + self#expect_reference_type + end else if is_number_sig name jsig then + number_to name + else if jsig = object_sig then + dynamic_to name + else + code#checkcast (["java";"lang"],name) + in + let numeric_cast_unboxed name jsig = + if is_unboxed jsig then + (get_conv name) () + else begin + let unboxed_sig = get_unboxed_type (TObject((["java";"lang"],name),[])) in + self#expect_basic_type unboxed_sig; + (get_conv name) () + end + in begin match jsig,jsig' with - | TObject((["java";"lang"],"Double"),_),TInt -> - code#i2d; - self#expect_reference_type; - | TObject((["java";"lang"],"Double"),_),TObject((["java";"lang"],"Integer"),_) -> - self#invokestatic (["haxe";"jvm"],"Jvm") "nullIntToNullFloat" (method_sig [integer_sig] (Some double_sig)) - | TObject((["java";"lang"],"Double"),_),TObject((["java";"lang"],"Object"),_) -> - self#invokestatic (["haxe";"jvm"],"Jvm") "dynamicToNullFloat" (method_sig [object_sig] (Some double_sig)) - (* from double *) - | TFloat,TDouble -> - code#d2f - | TInt,TDouble -> + | TObject((["java";"lang"],"Byte"),_),jsig' -> + numeric_cast_boxed "Byte" jsig' + | TByte,jsig' -> + numeric_cast_unboxed "Byte" jsig' + | TObject((["java";"lang"],"Short"),_),jsig' -> + numeric_cast_boxed "Short" jsig' + | TShort,jsig' -> + numeric_cast_unboxed "Short" jsig' + | TObject((["java";"lang"],"Integer"),_),jsig' -> + numeric_cast_boxed "Integer" jsig' + | TInt,jsig' -> + numeric_cast_unboxed "Integer" jsig' + | TObject((["java";"lang"],"Long"),_),jsig' -> + numeric_cast_boxed "Long" jsig' + | TLong,jsig' -> + numeric_cast_unboxed "Long" jsig' + | TObject((["java";"lang"],"Float"),_),jsig' -> + numeric_cast_boxed "Float" jsig' + | TFloat,jsig' -> + numeric_cast_unboxed "Float" jsig' + | TObject((["java";"lang"],"Double"),_),jsig' -> + numeric_cast_boxed "Double" jsig' + | TDouble,jsig' -> + numeric_cast_unboxed "Double" jsig' + | TChar,TDouble -> code#d2i; - | TLong,TDouble -> - code#d2l; - (* from float *) - | TDouble,TFloat -> - code#f2d - | TInt,TFloat -> + code#i2c; + | TChar,TFloat -> code#f2i; - | TLong,TFloat -> - code#f2l; - (* from int *) + code#i2c; + | TChar,(TByte | TShort | TInt) -> + code#i2c; + | TChar,TLong -> + code#l2i; + code#i2c; | TBool,TInt -> ignore(code#get_stack#pop); code#get_stack#push TBool; - | TByte,TInt -> - code#i2b TByte - | TChar,TInt -> - code#i2c - | TDouble,TInt -> - code#i2d; - | TFloat,TInt -> - code#i2f - | TLong,TInt -> - code#i2l; - | TShort,TInt -> - code#i2s - (* from long *) - | TDouble,TLong -> - code#l2d; - | TFloat,TLong -> - code#l2f - | TInt,TLong -> - code#l2i; - (* widening *) - | TInt,(TByte | TShort | TChar) -> - (* No cast, but rewrite stack top *) - ignore(code#get_stack#pop); - code#get_stack#push jsig; | TObject(path1,_),TObject(path2,_) when path1 = path2 -> () | TObject((["java";"lang"],"String"),_),_ when allow_to_string -> @@ -458,13 +624,9 @@ class builder jc name jsig = object(self) | TObject(path,_),TTypeParameter _ -> code#checkcast path | TMethod _,TMethod _ -> - if jsig <> jsig' then self#adapt_method jsig; - | TMethod _,TObject((["java";"lang";"invoke"],"MethodHandle"),_) -> - self#adapt_method jsig; - | TObject((["java";"lang";"invoke"],"MethodHandle"),_),TMethod _ -> () | TMethod _,_ -> - code#checkcast (["java";"lang";"invoke"],"MethodHandle"); + code#checkcast NativeSignatures.haxe_function_path; | TArray(jsig1,_),TArray(jsig2,_) when jsig1 = jsig2 -> () | TArray _,_ -> @@ -485,42 +647,58 @@ class builder jc name jsig = object(self) **) method start_branch = let save = code#get_stack#save in - let old_terminated = terminated in + let old_terminated = code#is_terminated in (fun () -> code#get_stack#restore save; - terminated <- old_terminated; + code#set_terminated old_terminated; ) (** Generates code which executes [f_if()] and then branches into [f_then()] and [f_else()]. **) - method if_then_else (f_if : unit -> jbranchoffset ref) (f_then : unit -> unit) (f_else : unit -> unit) = - let jump_then = f_if () in + method if_then_else (f_if : jbranchoffset ref -> unit) (f_then : unit -> unit) (f_else : unit -> unit) = + self#if_then_else_labeled (fun label_then label_else -> + label_else#apply f_if + ) f_then f_else + + method if_then_else_labeled (f_if : label -> label -> unit) (f_then : unit -> unit) (f_else : unit -> unit) = + let label_then = self#spawn_label "then" in + let label_else = self#spawn_label "else" in + let label_exit = self#spawn_label "exit" in + f_if label_then label_else; + label_then#here; let restore = self#start_branch in let pop = self#push_scope in f_then(); pop(); - let r_then = ref code#get_fp in let term_then = self#is_terminated in - if not term_then then code#goto r_then; - jump_then := code#get_fp - !jump_then; + if not self#is_terminated then label_exit#goto; restore(); - self#add_stack_frame; - let pop = self#push_scope in + label_else#here; f_else(); - pop(); - self#set_terminated (term_then && self#is_terminated); - r_then := code#get_fp - !r_then; - if not self#is_terminated then self#add_stack_frame + if term_then && self#is_terminated then + self#set_terminated true + else begin + self#set_terminated false; + label_exit#here + end (** Generates code which executes [f_if()] and then branches into [f_then()], if the condition holds. **) - method if_then (f_if : unit -> jbranchoffset ref) (f_then : unit -> unit) = - let jump_then = f_if () in + method if_then (f_if : jbranchoffset ref -> unit) (f_then : unit -> unit) = + self#if_then_labeled (fun _ label_else -> label_else#apply f_if) f_then + + method if_then_labeled (f_if : label -> label -> unit) (f_then : unit -> unit) = + let label_then = self#spawn_label "then" in + let label_else = self#spawn_label "else" in + f_if label_then label_else; + label_then#here; let restore = self#start_branch in let pop = self#push_scope in f_then(); pop(); restore(); - jump_then := code#get_fp - !jump_then; - self#add_stack_frame + label_else#here + + method spawn_label (name : string) = + new label (self :> builder) name (** Returns an instruction offset and emits a goto instruction to it if this method isn't terminated. @@ -546,6 +724,109 @@ class builder jc name jsig = object(self) if not term then self#add_stack_frame; + method string_switch + (need_val : bool) + (load : (unit -> unit)) + (cases : (string list * (unit -> unit)) list) + (def : (unit -> unit) option) + = + let buckets = HashtblList.create () in + let exprs = List.mapi (fun index (sl,f) -> + List.iter (fun s -> + HashtblList.add buckets (java_hash s) (s,index); + ) sl; + (f,List.length sl) + ) cases in + let cases = HashtblList.as_list buckets in + let exprs = Array.of_list exprs in + let def = match def with + | None when need_val -> + Some (fun () -> + self#string "Match failure"; + self#invokestatic (["haxe";"jvm"],"Exception") "wrap" (method_sig [object_sig] (Some exception_sig)); + self#get_code#athrow; + ) + | _ -> + def + in + let label_def = self#spawn_label "default" in + let label_exit = self#spawn_label "exit" in + (* all strings can be null and we're not supposed to cause NPEs here... *) + load(); + label_def#apply (self#get_code#if_null string_sig); + (* switch *) + load(); + self#invokevirtual string_path "hashCode" (method_sig [] (Some TInt)); + let exprs = Array.map (fun e -> e,self#spawn_label "case-expr") exprs in + let jump_table = List.map (fun (hash,l) -> hash,self#spawn_label "hash-match") cases in + let sorted_jump_table = List.map (fun (hash,label) -> hash,label#mk_offset) jump_table in + let sorted_jump_table = Array.of_list sorted_jump_table in + Array.sort (fun (i1,_) (i2,_) -> compare i1 i2) sorted_jump_table; + code#lookupswitch label_def#mk_offset sorted_jump_table; + let restore = self#start_branch in + (* cases *) + let rec loop cases jumps = match cases,jumps with + | (_,l) :: cases,(_,label) :: jumps -> + label#here; + List.iter (fun (s,i) -> + restore(); + let pop_scope = self#push_scope in + let (f,num_jumps),label_expr = exprs.(i) in + load(); + self#string s; + self#invokevirtual string_path "equals" (method_sig [object_sig] (Some TBool)); + if num_jumps = 1 then begin + self#if_then + (code#if_ CmpEq) + (fun () -> + f(); + if not self#is_terminated then label_exit#goto; + ) + end else + label_expr#apply (code#if_ CmpNe); + pop_scope(); + ) l; + label_def#goto; + loop cases jumps + | [],[] -> + () + | _ -> + die "" __LOC__ + in + loop cases jump_table; + (* exprs *) + Array.iter (fun ((f,num_jumps),label_expr) -> + if num_jumps <> 1 then begin + restore(); + label_expr#here; + let pop_scope = self#push_scope in + f(); + pop_scope(); + if not self#is_terminated then label_exit#goto; + end; + ) exprs; + (* default *) + begin match def with + | None -> + () + | Some f -> + restore(); + label_def#here; + let pop_scope = self#push_scope in + f(); + pop_scope(); + if not self#is_terminated then label_exit#goto; + end; + if label_exit#was_jumped_to then label_exit#here; + if def = None then begin + self#set_terminated false; + label_def#here; + end else if label_exit#was_jumped_to then + self#set_terminated false + else + self#set_terminated true + + (** Emits a tableswitch or lookupswitch instruction, depending on which one makes more sense. @@ -553,73 +834,84 @@ class builder jc name jsig = object(self) If [is_exhaustive] is true and [def] is None, the first case is used as the default case. **) - method int_switch (is_exhaustive : bool) (cases : (Int32.t list * (unit -> unit)) list) (def : (unit -> unit) option) = - let def,cases = match def,cases with - | None,(_,ec) :: cases when is_exhaustive -> - Some ec,cases + method int_switch (need_val : bool) (cases : (Int32.t list * (unit -> unit)) list) (def : (unit -> unit) option) = + let def = match def with + | None when need_val -> + Some (fun () -> + self#string "Match failure"; + self#invokestatic (["haxe";"jvm"],"Exception") "wrap" (method_sig [object_sig] (Some exception_sig)); + self#get_code#athrow; + ) | _ -> - def,cases + def in let flat_cases = DynArray.create () in let case_lut = ref Int32Map.empty in - let fp = code#get_fp in - let imin = ref Int32.min_int in - let imax = ref Int32.max_int in + let imin = ref Int64.max_int in + let imax = ref Int64.min_int in let cases = List.map (fun (il,f) -> let rl = List.map (fun i32 -> - let r = ref fp in - if i32 < !imin then imin := i32; - if i32 > !imax then imax := i32; - DynArray.add flat_cases (i32,r); + let r = self#spawn_label "case" in + let i64 = Int64.of_int32 i32 in + if i64 < !imin then imin := i64; + if i64 > !imax then imax := i64; + DynArray.add flat_cases (i32,r#mk_offset); case_lut := Int32Map.add i32 r !case_lut; r ) il in (rl,f) ) cases in - let offset_def = ref fp in + let label_def = self#spawn_label "default" in (* No idea what's a good heuristic here... *) - let diff = Int32.sub !imax !imin in - let use_tableswitch = diff < (Int32.of_int (DynArray.length flat_cases + 10)) && diff >= Int32.zero (* #8388 *) in + let diff = Int64.sub !imax !imin in + let use_tableswitch = + diff < (Int64.of_int (DynArray.length flat_cases + 10)) && + diff >= Int64.zero (* #8388 *) + in if use_tableswitch then begin - let offsets = Array.init (Int32.to_int (Int32.sub !imax !imin) + 1) (fun i -> - try Int32Map.find (Int32.add (Int32.of_int i) !imin) !case_lut - with Not_found -> offset_def + let imin = Int64.to_int32 !imin in + let imax = Int64.to_int32 !imax in + let offsets = Array.init (Int32.to_int (Int32.sub imax imin) + 1) (fun i -> + try Int32Map.find (Int32.add (Int32.of_int i) imin) !case_lut + with Not_found -> label_def ) in - code#tableswitch offset_def !imin !imax offsets + code#tableswitch label_def#mk_offset imin imax (Array.map (fun label -> label#mk_offset) offsets) end else begin let a = DynArray.to_array flat_cases in Array.sort (fun (i1,_) (i2,_) -> compare i1 i2) a; - code#lookupswitch offset_def a; + code#lookupswitch label_def#mk_offset a; end; let restore = self#start_branch in - let offset_exit = ref code#get_fp in - let def_term,r_def = match def with + let label_exit = self#spawn_label "exit" in + begin match def with | None -> - true,ref 0 + () | Some f -> - offset_def := code#get_fp - !offset_def; - self#add_stack_frame; + label_def#here; let pop_scope = self#push_scope in f(); pop_scope(); - self#is_terminated,self#maybe_make_jump - in - let rec loop acc cases = match cases with + if not self#is_terminated then label_exit#goto; + end; + let rec loop cases = match cases with | (rl,f) :: cases -> restore(); - self#add_stack_frame; - List.iter (fun r -> r := code#get_fp - !r) rl; + List.iter (fun label -> label#here) rl; let pop_scope = self#push_scope in f(); pop_scope(); - let r = if cases = [] then ref 0 else self#maybe_make_jump in - loop ((self#is_terminated,r) :: acc) cases + if cases <> [] && not self#is_terminated then label_exit#goto; + loop cases | [] -> - List.rev acc + () in - let rl = loop [] cases in - self#close_jumps (def <> None) ((def_term,if def = None then offset_def else r_def) :: rl); - if def = None then code#get_fp else !offset_exit + loop cases; + if label_exit#was_jumped_to then label_exit#here; + if def = None then begin + self#set_terminated false; + label_def#here; + end else if label_exit#was_jumped_to then + self#set_terminated false (** Adds a local with a given [name], signature [jsig] and an [init_state]. This function returns a tuple consisting of: @@ -694,14 +986,14 @@ class builder jc name jsig = object(self) let rec loop locals = match locals with | [(_,_,jsig)] -> jsig | _ :: locals -> loop locals - | [] -> assert false + | [] -> die "" __LOC__ in loop locals method set_this_initialized = let rec loop acc locals = match locals with | [(init,name,_)] -> List.rev ((init,name,jc#get_jsig) :: acc) - | [] -> assert false + | [] -> die "" __LOC__ | l :: locals -> loop (l :: acc) locals in locals <- loop [] locals @@ -774,10 +1066,10 @@ class builder jc name jsig = object(self) Array.of_list (List.rev (snd stack_map)) method get_code = code - method is_terminated = terminated + method is_terminated = code#is_terminated method get_name = name method get_jsig = jsig - method set_terminated b = terminated <- b + method set_terminated b = code#set_terminated b method private get_jcode (config : export_config) = let attributes = DynArray.create () in @@ -788,6 +1080,29 @@ class builder jc name jsig = object(self) if Array.length stack_map_table > 0 then DynArray.add attributes (AttributeStackMapTable stack_map_table); let exceptions = Array.of_list (List.rev exceptions) in + if config.export_debug then begin match debug_locals with + | [] -> + () + | _ -> + let type_locals = DynArray.create () in + let map (fp,length,name,jsig,index) = + let ld = { + ld_start_pc = fp; + ld_length = length; + ld_name_index = jc#get_pool#add_string name; + ld_descriptor_index = jc#get_pool#add_string (generate_signature false jsig); + ld_index = index; + } in + if has_type_parameter jsig then DynArray.add type_locals {ld with ld_descriptor_index = jc#get_pool#add_string (generate_signature true jsig)}; + ld + in + let locals = Array.of_list (List.map map debug_locals) in + DynArray.add attributes (AttributeLocalVariableTable locals); + if DynArray.length type_locals > 0 then begin + let locals = DynArray.to_array type_locals in + DynArray.add attributes (AttributeLocalVariableTypeTable locals); + end + end; let attributes = List.map (JvmAttribute.write_attribute jc#get_pool) (DynArray.to_list attributes) in { code_max_stack = code#get_max_stack_size; @@ -808,13 +1123,6 @@ class builder jc name jsig = object(self) end; if Hashtbl.length thrown_exceptions > 0 then self#add_attribute (AttributeExceptions (Array.of_list (Hashtbl.fold (fun k _ c -> k :: c) thrown_exceptions []))); - if config.export_debug then begin match debug_locals with - | [] -> - () - | _ -> - let a = Array.of_list debug_locals in - self#add_attribute (AttributeLocalVariableTable a); - end; let attributes = self#export_attributes jc#get_pool in let offset_name = jc#get_pool#add_string name in let jsig = generate_method_signature false jsig in @@ -841,4 +1149,58 @@ class builder jc name jsig = object(self) field_descriptor_index = offset_desc; field_attributes = attributes; } +end + +and label (jm : builder) (name : string) = object(self) + + val code = jm#get_code + + val mutable state = LabelNotSet (ref []) + val mutable was_jumped_to = false + + method was_jumped_to = was_jumped_to + + method get_offset = match state with + | LabelSet fp -> fp + | LabelNotSet _ -> failwith (Printf.sprintf "Trying to get offset of unset label %s" name) + + method mk_offset = + let r = ref code#get_fp in + was_jumped_to <- true; + begin match state with + | LabelNotSet l -> + l := r :: !l + | LabelSet fp' -> + r := fp' - !r + end; + r + + method apply (f : jbranchoffset ref -> unit) = + f self#mk_offset + + method if_ (cmp : jcmp) = + code#if_ cmp self#mk_offset + + method if_null jsig = + code#if_null jsig self#mk_offset + + method if_nonnull jsig = + code#if_nonnull jsig self#mk_offset + + method goto = + code#goto self#mk_offset + + method at fp = match state with + | LabelNotSet l -> + if fp = code#get_fp then jm#add_stack_frame; + List.iter (fun r -> + r := fp - !r + ) !l; + state <- LabelSet fp + | LabelSet _ -> + if fp <> self#get_offset then + failwith (Printf.sprintf "Trying to instantiate label %s again" name) + + method here = + self#at code#get_fp end \ No newline at end of file diff --git a/src/generators/jvm/jvmSignature.ml b/src/generators/jvm/jvmSignature.ml index 62c776e8f12dc098f838c61bec6c3de097f59cc6..8edfbd54fc7fea9f4e624f865faf4fc884bc7749 100644 --- a/src/generators/jvm/jvmSignature.ml +++ b/src/generators/jvm/jvmSignature.ml @@ -49,123 +49,11 @@ and jsignature = (* ( jsignature list ) ReturnDescriptor (| V | jsignature) *) and jmethod_signature = jsignature list * jsignature option -let s_wildcard = function - | WExtends -> "WExtends" - | WSuper -> "WSuper" - | WNone -> "WNone" - -let rec s_signature_kind = function - | TByte -> "TByte" - | TChar -> "TChar" - | TDouble -> "TDouble" - | TFloat -> "TFloat" - | TInt -> "TInt" - | TLong -> "TLong" - | TShort -> "TShort" - | TBool -> "TBool" - | TObject(path,params) -> Printf.sprintf "TObject(%s,[%s])" (Globals.s_type_path path) (String.concat "," (List.map s_signature_param_kind params)) - | TObjectInner _ -> "TObjectInner" - | TArray(jsig,io) -> Printf.sprintf "TArray(%s,%s)" (s_signature_kind jsig) (Option.map_default string_of_int "None" io) - | TMethod(jsigs,jsig) -> Printf.sprintf "TMethod([%s],%s)" (String.concat "," (List.map s_signature_kind jsigs)) (Option.map_default s_signature_kind "None" jsig) - | TTypeParameter name -> Printf.sprintf "TTypeParameter(%s)" name - | TUninitialized io -> Printf.sprintf "TUninitilaized(%s)" (Option.map_default string_of_int "None" io) - -and s_signature_param_kind = function - | TAny -> "TAny" - | TType(wc,jsig) -> Printf.sprintf "TType(%s,%s)" (s_wildcard wc) (s_signature_kind jsig) - -let encode_path (pack,name) = - String.concat "/" (pack @ [name]) - -let rec write_param full ch param = match param with - | TAny -> write_byte ch (Char.code '*') - | TType(w, s) -> - begin match w with - | WExtends -> write_byte ch (Char.code '+') - | WSuper -> write_byte ch (Char.code '-') - | WNone -> () - end; - write_signature full ch s - -and write_signature full ch jsig = match jsig with - | TByte -> write_byte ch (Char.code 'B') - | TChar -> write_byte ch (Char.code 'C') - | TDouble -> write_byte ch (Char.code 'D') - | TFloat -> write_byte ch (Char.code 'F') - | TInt -> write_byte ch (Char.code 'I') - | TLong -> write_byte ch (Char.code 'J') - | TShort -> write_byte ch (Char.code 'S') - | TBool -> write_byte ch (Char.code 'Z') - | TObject(path, params) -> - write_byte ch (Char.code 'L'); - write_string ch (encode_path path); - if params <> [] && full then begin - write_byte ch (Char.code '<'); - List.iter (write_param full ch) params; - write_byte ch (Char.code '>') - end; - write_byte ch (Char.code ';') - | TObjectInner(pack, inners) -> - write_byte ch (Char.code 'L'); - List.iter (fun p -> - write_string ch p; - write_byte ch (Char.code '/') - ) pack; - let first = ref true in - List.iter (fun (name,params) -> - (if !first then first := false else write_byte ch (Char.code '.')); - write_string ch name; - if params <> [] then begin - write_byte ch (Char.code '<'); - List.iter (write_param full ch) params; - write_byte ch (Char.code '>') - end; - ) inners; - write_byte ch (Char.code ';') - | TArray(s,size) -> - write_byte ch (Char.code '['); - begin match size with - | Some size -> - write_string ch (string_of_int size); - | None -> () - end; - write_signature full ch s - | TMethod _ -> - write_signature full ch (TObject((["java";"lang";"invoke"],"MethodHandle"),[])) - | TTypeParameter name -> - if full then begin - write_byte ch (Char.code 'T'); - write_string ch name; - write_byte ch (Char.code ';') - end else - write_string ch "Ljava/lang/Object;" - | TUninitialized _ -> - () - -let generate_signature full jsig = - let ch = IO.output_bytes () in - write_signature full ch jsig; - Bytes.unsafe_to_string (IO.close_out ch) - -let generate_method_signature full jsig = - let ch = IO.output_bytes () in - begin match jsig with - | TMethod(args, ret) -> - write_byte ch (Char.code '('); - List.iter (write_signature full ch) args; - write_byte ch (Char.code ')'); - begin match ret with - | None -> write_byte ch (Char.code 'V') - | Some jsig -> write_signature full ch jsig - end - | _ -> - write_signature full ch jsig; - end; - Bytes.unsafe_to_string (IO.close_out ch) - -let signature_size = function - | TDouble | TLong -> 2 - | _ -> 1 +let rec has_type_parameter = function + | TTypeParameter _ -> true + | TArray(jsig,_) -> has_type_parameter jsig + | TObject(_,jsigs) -> List.exists (function TType(_,jsig) -> has_type_parameter jsig | _ -> false) jsigs + | _ -> false module NativeSignatures = struct let object_path = ["java";"lang"],"Object" @@ -180,9 +68,6 @@ module NativeSignatures = struct let character_path = ["java";"lang"],"Character" let character_sig = TObject(character_path,[]) - let method_handle_path = (["java";"lang";"invoke"],"MethodHandle") - let method_handle_sig = TObject(method_handle_path,[]) - let method_type_path = (["java";"lang";"invoke"],"MethodType") let method_type_sig = TObject(method_type_path,[]) @@ -200,7 +85,7 @@ module NativeSignatures = struct let haxe_dynamic_object_path = ["haxe";"jvm"],"DynamicObject" let haxe_dynamic_object_sig = TObject(haxe_dynamic_object_path,[]) - let haxe_exception_path = ["haxe";"jvm"],"Exception" + let haxe_exception_path = ["haxe"],"Exception" let haxe_exception_sig = TObject(haxe_exception_path,[]) let haxe_object_path = ["haxe";"jvm"],"Object" @@ -212,6 +97,9 @@ module NativeSignatures = struct let exception_path = (["java";"lang"],"Exception") let exception_sig = TObject(exception_path,[]) + let runtime_exception_path = (["java";"lang"],"RuntimeException") + let runtime_exception_sig = TObject(runtime_exception_path,[]) + let retention_path = (["java";"lang";"annotation"],"Retention") let retention_sig = TObject(retention_path,[]) @@ -227,8 +115,17 @@ module NativeSignatures = struct let haxe_empty_constructor_path = (["haxe";"jvm"],"EmptyConstructor") let haxe_empty_constructor_sig = TObject(haxe_empty_constructor_path,[]) + let haxe_function_path = (["haxe";"jvm"],"Function") + let haxe_function_sig = TObject(haxe_function_path,[]) + + let void_path = ["java";"lang"],"Void" + let void_sig = TObject(void_path,[]) + (* numeric *) + let number_path = ["java";"lang"],"Number" + let number_sig = TObject(number_path,[]) + let byte_path = ["java";"lang"],"Byte" let byte_sig = TObject(byte_path,[]) @@ -291,4 +188,147 @@ module NativeSignatures = struct true | _ -> false -end \ No newline at end of file +end + +let equals_at_runtime jsig1 jsig2 = match jsig1,jsig2 with + | TByte,TByte + | TChar,TChar + | TDouble,TDouble + | TFloat,TFloat + | TInt,TInt + | TLong,TLong + | TShort,TShort + | TBool,TBool + | TObjectInner _,TObjectInner _ + | TArray _,TArray _ + | TMethod _,TMethod _ + | TTypeParameter _,TTypeParameter _ + | TUninitialized _,TUninitialized _ -> + true + | TObject(path1,_),TObject(path2,_) -> + path1 = path2 + | TObject(path,_),TTypeParameter _ + | TTypeParameter _,TObject(path,_) -> + path = NativeSignatures.object_path + | _ -> false + +let s_wildcard = function + | WExtends -> "WExtends" + | WSuper -> "WSuper" + | WNone -> "WNone" + +let rec s_signature_kind = function + | TByte -> "TByte" + | TChar -> "TChar" + | TDouble -> "TDouble" + | TFloat -> "TFloat" + | TInt -> "TInt" + | TLong -> "TLong" + | TShort -> "TShort" + | TBool -> "TBool" + | TObject(path,params) -> Printf.sprintf "TObject(%s,[%s])" (Globals.s_type_path path) (String.concat "," (List.map s_signature_param_kind params)) + | TObjectInner _ -> "TObjectInner" + | TArray(jsig,io) -> Printf.sprintf "TArray(%s,%s)" (s_signature_kind jsig) (Option.map_default string_of_int "None" io) + | TMethod(jsigs,jsig) -> Printf.sprintf "TMethod([%s],%s)" (String.concat "," (List.map s_signature_kind jsigs)) (Option.map_default s_signature_kind "None" jsig) + | TTypeParameter name -> Printf.sprintf "TTypeParameter(%s)" name + | TUninitialized io -> Printf.sprintf "TUninitilaized(%s)" (Option.map_default string_of_int "None" io) + +and s_signature_param_kind = function + | TAny -> "TAny" + | TType(wc,jsig) -> Printf.sprintf "TType(%s,%s)" (s_wildcard wc) (s_signature_kind jsig) + +let encode_path (pack,name) = + String.concat "/" (pack @ [name]) + +let rec write_param full ch param = match param with + | TAny -> write_byte ch (Char.code '*') + | TType(w, s) -> + begin match w with + | WExtends -> write_byte ch (Char.code '+') + | WSuper -> write_byte ch (Char.code '-') + | WNone -> () + end; + write_signature full ch s + +and write_signature full ch jsig = match jsig with + | TByte -> write_byte ch (Char.code 'B') + | TChar -> write_byte ch (Char.code 'C') + | TDouble -> write_byte ch (Char.code 'D') + | TFloat -> write_byte ch (Char.code 'F') + | TInt -> write_byte ch (Char.code 'I') + | TLong -> write_byte ch (Char.code 'J') + | TShort -> write_byte ch (Char.code 'S') + | TBool -> write_byte ch (Char.code 'Z') + | TObject(path, params) -> + write_byte ch (Char.code 'L'); + write_string ch (encode_path path); + if params <> [] && full then begin + write_byte ch (Char.code '<'); + List.iter (write_param full ch) params; + write_byte ch (Char.code '>') + end; + write_byte ch (Char.code ';') + | TObjectInner(pack, inners) -> + write_byte ch (Char.code 'L'); + List.iter (fun p -> + write_string ch p; + write_byte ch (Char.code '/') + ) pack; + let first = ref true in + List.iter (fun (name,params) -> + (if !first then first := false else write_byte ch (Char.code '.')); + write_string ch name; + if params <> [] then begin + write_byte ch (Char.code '<'); + List.iter (write_param full ch) params; + write_byte ch (Char.code '>') + end; + ) inners; + write_byte ch (Char.code ';') + | TArray(s,size) -> + write_byte ch (Char.code '['); + begin match size with + | Some size -> + write_string ch (string_of_int size); + | None -> () + end; + write_signature full ch s + | TMethod _ -> + write_signature full ch NativeSignatures.haxe_function_sig + | TTypeParameter name -> + if full then begin + write_byte ch (Char.code 'T'); + write_string ch name; + write_byte ch (Char.code ';') + end else + write_string ch "Ljava/lang/Object;" + | TUninitialized io -> + write_string ch "uninitialized"; + match io with + | None -> write_string ch " this" + | Some i -> write_string ch (Printf.sprintf "(%i)" i) + +let generate_signature full jsig = + let ch = IO.output_bytes () in + write_signature full ch jsig; + Bytes.unsafe_to_string (IO.close_out ch) + +let generate_method_signature full jsig = + let ch = IO.output_bytes () in + begin match jsig with + | TMethod(args, ret) -> + write_byte ch (Char.code '('); + List.iter (write_signature full ch) args; + write_byte ch (Char.code ')'); + begin match ret with + | None -> write_byte ch (Char.code 'V') + | Some jsig -> write_signature full ch jsig + end + | _ -> + write_signature full ch jsig; + end; + Bytes.unsafe_to_string (IO.close_out ch) + +let signature_size = function + | TDouble | TLong -> 2 + | _ -> 1 \ No newline at end of file diff --git a/src/generators/jvm/jvmVerificationTypeInfo.ml b/src/generators/jvm/jvmVerificationTypeInfo.ml index bfd756db748dbb2b52a990787291d6f160fa9c3a..14235a912ab53395387454bcbd2bf4b50acb36ae 100644 --- a/src/generators/jvm/jvmVerificationTypeInfo.ml +++ b/src/generators/jvm/jvmVerificationTypeInfo.ml @@ -37,12 +37,12 @@ let of_signature pool jsig = match jsig with | TLong -> VLong | TDouble -> VDouble | TObject(path,_) -> VObject (pool#add_path path) - | TMethod _ -> VObject (pool#add_path (["java";"lang";"invoke"],"MethodHandle")) + | TMethod _ -> VObject (pool#add_path NativeSignatures.haxe_function_path) | TArray _ -> VObject (pool#add_path ([],generate_signature false jsig)) | TTypeParameter _ -> VObject (pool#add_path (["java";"lang"],"Object")) | TUninitialized (Some i) -> VUninitialized i | TUninitialized None -> VUninitializedThis - | _ -> assert false + | _ -> Globals.die "" __LOC__ let to_string vtt = match vtt with | VTop -> "top" diff --git a/src/macro/eval/evalArray.ml b/src/macro/eval/evalArray.ml index 6e2166286894b8b2a7625293886fe601358f088d..1790f115dbc0b4aa2a93c9841d989303d1d8ec9e 100644 --- a/src/macro/eval/evalArray.ml +++ b/src/macro/eval/evalArray.ml @@ -141,6 +141,10 @@ let remove a equals x = true end +let contains a equals x = + let i = indexOf a equals x 0 in + i >= 0 + let reverse a = a.avalues <- ExtArray.Array.rev (Array.sub a.avalues 0 a.alength) diff --git a/src/macro/eval/evalContext.ml b/src/macro/eval/evalContext.ml index 97a5d633806c6b18cb4e473a2842d5d3fd003607..956a22326d4ba63d7343ac6cf9b75d7562442653 100644 --- a/src/macro/eval/evalContext.ml +++ b/src/macro/eval/evalContext.ml @@ -59,6 +59,10 @@ type env_info = { kind : env_kind; (* The name of capture variables. Maps local slots to variable names. Only filled in debug mode. *) capture_infos : (int,var_info) Hashtbl.t; + (* The number of local variables. *) + num_locals : int; + (* The number of capture variables. *) + num_captures : int; } (* Per-environment debug information. These values are only modified while debugging. *) @@ -285,7 +289,7 @@ and context = { } module GlobalState = struct - let get_ctx_ref : (unit -> context) ref = ref (fun() -> assert false) + let get_ctx_ref : (unit -> context) ref = ref (fun() -> die "" __LOC__) let sid : int ref = ref (-1) @@ -405,17 +409,19 @@ let no_debug = { debug_pos = null_pos; } -let create_env_info static pfile kind capture_infos = +let create_env_info static pfile kind capture_infos num_locals num_captures = let info = { static = static; kind = kind; pfile = hash pfile; - pfile_unique = hash (Path.unique_full_path pfile); + pfile_unique = hash (Path.UniqueKey.to_string (Path.UniqueKey.create pfile)); capture_infos = capture_infos; + num_locals = num_locals; + num_captures = num_captures; } in info -let push_environment ctx info num_locals num_captures = +let push_environment ctx info = let eval = get_eval ctx in let timer = if ctx.detail_times then Timer.timer ["macro";"execution";kind_name eval info.kind] @@ -427,15 +433,15 @@ let push_environment ctx info num_locals num_captures = else no_debug in - let locals = if num_locals = 0 then + let locals = if info.num_locals = 0 then empty_array else - Array.make num_locals vnull + Array.make info.num_locals vnull in - let captures = if num_captures = 0 then + let captures = if info.num_captures = 0 then empty_array else - Array.make num_captures vnull + Array.make info.num_captures vnull in let stack_depth = match eval.env with | None -> 1; diff --git a/src/macro/eval/evalDebugMisc.ml b/src/macro/eval/evalDebugMisc.ml index 73d9277ea849413a77207676ca3c79cef6a218b4..3b350e4db2f61fb311524b56e7bc84343d85a4dd 100644 --- a/src/macro/eval/evalDebugMisc.ml +++ b/src/macro/eval/evalDebugMisc.ml @@ -43,7 +43,7 @@ let iter_breakpoints ctx f = ) ctx.debug.breakpoints let add_breakpoint ctx file line column condition = - let hash = hash (Path.unique_full_path (Common.find_file (ctx.curapi.get_com()) file)) in + let hash = hash (Path.UniqueKey.to_string (Path.UniqueKey.create (Common.find_file (ctx.curapi.get_com()) file))) in let h = try Hashtbl.find ctx.debug.breakpoints hash with Not_found -> @@ -56,7 +56,7 @@ let add_breakpoint ctx file line column condition = breakpoint let delete_breakpoint ctx file line = - let hash = hash (Path.unique_full_path (Common.find_file (ctx.curapi.get_com()) file)) in + let hash = hash (Path.UniqueKey.to_string (Path.UniqueKey.create (Common.find_file (ctx.curapi.get_com()) file))) in let h = Hashtbl.find ctx.debug.breakpoints hash in Hashtbl.remove h line @@ -72,7 +72,7 @@ let find_breakpoint ctx sid = ); raise Not_found with Exit -> - match !found with None -> assert false | Some breakpoint -> breakpoint + match !found with None -> die "" __LOC__ | Some breakpoint -> breakpoint (* Helper *) @@ -81,7 +81,7 @@ exception Parse_expr_error of string let parse_expr ctx s p = let error s = raise (Parse_expr_error s) in match ParserEntry.parse_expr_string (ctx.curapi.get_com()).Common.defines s p error true with - | ParseSuccess data | ParseDisplayFile(data,_) -> data + | ParseSuccess(data,_,_) -> data | ParseError(_,(msg,_),_) -> error (Parser.error_msg msg) (* Vars *) @@ -114,7 +114,7 @@ let get_capture_slot_by_name capture_infos name = ) capture_infos; raise Not_found with Exit -> - match !ret with None -> assert false | Some name -> name + match !ret with None -> die "" __LOC__ | Some name -> name let get_variable env capture_infos scopes name env = try @@ -142,7 +142,7 @@ let resolve_ident ctx env s = let rec loop env = match env.env_info.kind with | EKLocalFunction _ -> begin match env.env_parent with - | None -> assert false + | None -> die "" __LOC__ | Some env -> loop env end | EKMethod _ -> env diff --git a/src/macro/eval/evalDebugSocket.ml b/src/macro/eval/evalDebugSocket.ml index a459dbcfcc498d154d015486071253a76308fa4c..c097712b01960ae7bf7636e9cb0dbc20509cf921 100644 --- a/src/macro/eval/evalDebugSocket.ml +++ b/src/macro/eval/evalDebugSocket.ml @@ -14,6 +14,32 @@ open EvalDebugMisc (* Printing *) + +let handle_in_temp_thread ctx env f = + let channel = Event.new_channel () in + let _ = EvalThread.spawn ctx (fun () -> + let eval = get_eval ctx in + eval.env <- Some env; + let v = try + f() + with + | RunTimeException(v,stack,p) -> + prerr_endline (EvalExceptions.get_exc_error_message ctx v stack p); + vnull + | exc -> + prerr_endline (Printexc.to_string exc); + vnull + in + Event.poll (Event.send channel v) + ) in + Event.sync (Event.receive channel) + +let thread_safe_value_string env v = + let ctx = get_ctx() in + match handle_in_temp_thread ctx env (fun () -> VString (EvalPrinting.s_value 0 v)) with + | VString s -> s.sstring + | _ -> die "" __LOC__ + let var_to_json name value vio env = let jv t v num_children = let id = if num_children = 0 then 0 else (get_ctx()).debug.debug_context#add_value value env in @@ -95,7 +121,7 @@ let var_to_json name value vio env = | VArray va -> jv "Array" (array_elems (EvalArray.to_list va)) va.alength | VVector vv -> jv "Vector" (array_elems (Array.to_list vv)) (Array.length vv) | VInstance vi -> - let class_name () = EvalDebugMisc.safe_call env.env_eval EvalPrinting.value_string v in + let class_name () = thread_safe_value_string env v in let num_children,class_name = match vi.ikind with | IMutex _ -> 1,class_name() | IThread _ -> 1,class_name() @@ -301,25 +327,6 @@ let output_inner_vars v env = let vars = List.map (fun (n,v) -> var_to_json n v None env) children in JArray vars -let handle_in_temp_thread ctx env f = - let channel = Event.new_channel () in - let _ = EvalThread.spawn ctx (fun () -> - let eval = get_eval ctx in - eval.env <- Some env; - let v = try - f() - with - | RunTimeException(v,stack,p) -> - prerr_endline (EvalExceptions.get_exc_error_message ctx v stack p); - vnull - | exc -> - prerr_endline (Printexc.to_string exc); - vnull - in - Event.poll (Event.send channel v) - ) in - Event.sync (Event.receive channel) - module ValueCompletion = struct let prototype_instance_fields proto = let rec loop acc proto = @@ -333,28 +340,34 @@ module ValueCompletion = struct loop IntMap.empty proto let prototype_static_fields proto = - IntMap.fold (fun name _ acc -> IntMap.add name (name,"field",None) acc) proto.pnames IntMap.empty - + IntMap.fold (fun name offset acc -> + let v = proto.pfields.(offset) in + let kind = match v with + | VFunction _ -> "method" + | _ -> "field" + in + IntMap.add name (name,kind,None) acc + ) proto.pnames IntMap.empty let to_json l = JArray (List.map (fun (n,k,column) -> - let fields = ["label",JString (rev_hash n);"kind",JString k] in + let fields = ["label",JString (rev_hash n);"type",JString k] in let fields = match column with None -> fields | Some column -> ("start",JInt column) :: fields in JObject fields ) l) let collect_idents ctx env = let acc = Hashtbl.create 0 in - let add key = + let add key kind = if not (Hashtbl.mem acc key) then - Hashtbl.add acc key (key,"value",None) + Hashtbl.add acc key (key,kind,None) in (* 0. Extra locals *) - IntMap.iter (fun key _ -> add key) env.env_extra_locals; + IntMap.iter (fun key _ -> add key "variable") env.env_extra_locals; (* 1. Variables *) let rec loop scopes = match scopes with | scope :: scopes -> - Hashtbl.iter (fun key _ -> add (hash key)) scope.local_ids; + Hashtbl.iter (fun key _ -> add (hash key) "variable") scope.local_ids; loop scopes | [] -> () @@ -362,7 +375,7 @@ module ValueCompletion = struct loop env.env_debug.scopes; (* 2. Captures *) Hashtbl.iter (fun slot vi -> - add (hash vi.vi_name) + add (hash vi.vi_name) "variable" ) env.env_info.capture_infos; (* 3. Instance *) if not env.env_info.static then begin @@ -370,7 +383,7 @@ module ValueCompletion = struct begin match v with | VInstance vi -> let fields = prototype_instance_fields vi.iproto in - IntMap.iter (fun key _ -> add key) fields + IntMap.iter (fun key (_,kind,_) -> add key kind) fields | _ -> () end @@ -380,7 +393,7 @@ module ValueCompletion = struct | EKMethod(i1,_) -> let proto = get_static_prototype_raise ctx i1 in let fields = prototype_static_fields proto in - IntMap.iter (fun key _ -> add key) fields + IntMap.iter (fun key (_,kind,_) -> add key kind) fields | _ -> raise Not_found end; @@ -388,7 +401,18 @@ module ValueCompletion = struct begin match ctx.toplevel with | VObject o -> let fields = object_fields o in - List.iter (fun (n,_) -> add n) fields + List.iter (fun (n,v) -> + let kind = match v with + | VPrototype proto -> + begin match proto.pkind with + | PClass _ -> "class" + | PEnum _ -> "enum" + | _ -> "class" (* ? *) + end + | _ -> "module" + in + add n kind + ) fields | _ -> () end; @@ -487,8 +511,13 @@ module ValueCompletion = struct with _ -> save(); raise Exit - end; + end + let get_completion ctx text column env = + if text = "" then + collect_idents ctx env + else + get_completion ctx text column env end type handler_context = { @@ -601,7 +630,7 @@ let handler = let file = hctx.jsonrpc#get_string_param "file" in let bps = hctx.jsonrpc#get_array_param "breakpoints" in let bps = List.map (parse_breakpoint hctx) bps in - let hash = hash (Path.unique_full_path (Common.find_file (hctx.ctx.curapi.get_com()) file)) in + let hash = hash (Path.UniqueKey.to_string (Path.UniqueKey.create (Common.find_file (hctx.ctx.curapi.get_com()) file))) in let h = try let h = Hashtbl.find hctx.ctx.debug.breakpoints hash in diff --git a/src/macro/eval/evalEmitter.ml b/src/macro/eval/evalEmitter.ml index 241f4e7a60257cd9799c8232943b2cfda405b201..751facce666ca1b76ac3b3e426682a6ce2e0fbce 100644 --- a/src/macro/eval/evalEmitter.ml +++ b/src/macro/eval/evalEmitter.ml @@ -353,7 +353,7 @@ let emit_special_super_call fnew execs env = (* This isn't very elegant, but it's probably a rare case to extend these types. *) begin match vthis,vi' with | VInstance vi,VInstance vi' -> vi.ikind <- vi'.ikind - | _ -> assert false + | _ -> die "" __LOC__ end; vnull @@ -714,12 +714,6 @@ let emit_neg exec p env = match exec env with (* Function *) -type env_creation = { - ec_info : env_info; - ec_num_locals : int; - ec_num_captures : int; -} - let execute_set_local i env v = env.env_locals.(i) <- v @@ -743,21 +737,21 @@ let process_arguments fl vl env = [@@inline] let create_function_noret ctx eci exec fl vl = - let env = push_environment ctx eci.ec_info eci.ec_num_locals eci.ec_num_captures in + let env = push_environment ctx eci in process_arguments fl vl env; let v = exec env in pop_environment ctx env; v let create_function ctx eci exec fl vl = - let env = push_environment ctx eci.ec_info eci.ec_num_locals eci.ec_num_captures in + let env = push_environment ctx eci in process_arguments fl vl env; let v = try exec env with Return v -> v in pop_environment ctx env; v let create_closure_noret ctx eci refs exec fl vl = - let env = push_environment ctx eci.ec_info eci.ec_num_locals eci.ec_num_captures in + let env = push_environment ctx eci in Array.iter (fun (i,vr) -> env.env_captures.(i) <- vr) refs; process_arguments fl vl env; let v = exec env in @@ -765,7 +759,7 @@ let create_closure_noret ctx eci refs exec fl vl = v let create_closure refs ctx eci exec fl vl = - let env = push_environment ctx eci.ec_info eci.ec_num_locals eci.ec_num_captures in + let env = push_environment ctx eci in Array.iter (fun (i,vr) -> env.env_captures.(i) <- vr) refs; process_arguments fl vl env; let v = try exec env with Return v -> v in @@ -774,7 +768,7 @@ let create_closure refs ctx eci exec fl vl = let emit_closure ctx mapping eci hasret exec fl env = let refs = Array.map (fun (i,slot) -> i,emit_capture_read slot env) mapping in - let create = match hasret,eci.ec_num_captures with + let create = match hasret,eci.num_captures with | true,0 -> create_function | false,0 -> create_function_noret | _ -> create_closure refs diff --git a/src/macro/eval/evalExceptions.ml b/src/macro/eval/evalExceptions.ml index 90b20f37143d22dad2a7454be7bf81d5be64e022..773b8af34301505dc5b86a0b3175ba094d1da416 100644 --- a/src/macro/eval/evalExceptions.ml +++ b/src/macro/eval/evalExceptions.ml @@ -112,7 +112,7 @@ let build_exception_stack ctx env = List.rev acc else match env'.env_parent with | Some env -> loop acc env - | None -> assert false + | None -> die "" __LOC__ in let d = match eval.env with | Some env -> loop [] env @@ -142,7 +142,7 @@ let catch_exceptions ctx ?(final=(fun() -> ())) f p = Option.may (build_exception_stack ctx) env; eval.env <- env; if is v key_haxe_macro_Error then begin - let v1 = field v key_message in + let v1 = field v key_exception_message in let v2 = field v key_pos in GlobalState.get_ctx_ref := prev; final(); diff --git a/src/macro/eval/evalHash.ml b/src/macro/eval/evalHash.ml index 3d4981a494a7163b262f896f0a49f8c4a8e5dc0c..f63329f55eb790523beb7cef6d7ada4eb291f704 100644 --- a/src/macro/eval/evalHash.ml +++ b/src/macro/eval/evalHash.ml @@ -40,6 +40,7 @@ let key_get = hash "get" let key_pos = hash "pos" let key_len = hash "len" let key_message = hash "message" +let key_exception_message = hash "__exceptionMessage" let key_Array = hash "Array" let key_eval_Vector = hash "eval.Vector" let key_String = hash "String" @@ -107,12 +108,11 @@ let key_haxe_macro_DisplayKind = hash "haxe.macro.DisplayKind" let key_haxe_macro_Message = hash "haxe.macro.Message" let key_haxe_macro_FunctionKind = hash "haxe.macro.FunctionKind" let key_haxe_macro_StringLiteralKind = hash "haxe.macro.StringLiteralKind" -let key_haxe_CallStack = hash "haxe.CallStack" let key___init__ = hash "__init__" let key_new = hash "new" let key_questionmark = hash "?" let key_haxe_StackItem = hash "haxe.StackItem" -let key_sys_net__Socket_NativeSocket = hash "sys.net._Socket.NativeSocket" +let key_eval_vm_NativeSocket = hash "eval.vm.NativeSocket" let key_ip = hash "ip" let key_port = hash "port" let key_sys_net_Socket = hash "sys.net.Socket" @@ -125,8 +125,16 @@ let key_haxe_zip_Compress = hash "haxe.zip.Compress" let key_haxe_zip_Uncompress = hash "haxe.zip.Uncompress" let key_done = hash "done" let key_eval_toplevel = hash "eval-toplevel" +let key_haxe_iterators_array_key_value_iterator = hash "haxe.iterators.ArrayKeyValueIterator" let key_haxe_iterators_map_key_value_iterator = hash "haxe.iterators.MapKeyValueIterator" let key_sys_net_Mutex = hash "sys.thread.Mutex" let key_sys_net_Lock = hash "sys.thread.Lock" let key_sys_net_Tls = hash "sys.thread.Tls" let key_sys_net_Deque = hash "sys.thread.Deque" + +let key_mbedtls_Config = hash "mbedtls.Config" +let key_mbedtls_CtrDrbg = hash "mbedtls.CtrDrbg" +let key_mbedtls_Entropy = hash "mbedtls.Entropy" +let key_mbedtls_PkContext = hash "mbedtls.PkContext" +let key_mbedtls_Ssl = hash "mbedtls.Ssl" +let key_mbedtls_X509Crt = hash "mbedtls.X509Crt" diff --git a/src/macro/eval/evalJit.ml b/src/macro/eval/evalJit.ml index d91818bc4cc5e7ee3fa2f0a9bff051040b2d723f..1fa1d9246a3d1a0b35358eb7c2fd93eb387914ca 100644 --- a/src/macro/eval/evalJit.ml +++ b/src/macro/eval/evalJit.ml @@ -31,7 +31,7 @@ open EvalMisc let rope_path t = match follow t with | TInst({cl_path=path},_) | TEnum({e_path=path},_) | TAbstract({a_path=path},_) -> s_type_path path | TDynamic _ -> "Dynamic" - | TFun _ | TAnon _ | TMono _ | TType _ | TLazy _ -> assert false + | TFun _ | TAnon _ | TMono _ | TType _ | TLazy _ -> die "" __LOC__ let eone = mk (TConst(TInt (Int32.one))) t_dynamic null_pos @@ -41,7 +41,7 @@ let eval_const = function | TFloat f -> vfloat (float_of_string f) | TBool b -> vbool b | TNull -> vnull - | TThis | TSuper -> assert false + | TThis | TSuper -> die "" __LOC__ let is_int t = match follow t with | TAbstract({a_path=[],"Int"},_) -> true @@ -106,7 +106,7 @@ let rec op_assign ctx jit e1 e2 = match e1.eexpr with end | _ -> - assert false + die "" __LOC__ and op_assign_op jit op e1 e2 prefix = match e1.eexpr with | TLocal var -> @@ -142,7 +142,7 @@ and op_assign_op jit op e1 e2 prefix = match e1.eexpr with emit_array_read_write exec1 ea1.epos exec2 ea2.epos exec3 op prefix end | _ -> - assert false + die "" __LOC__ and op_incr jit e1 prefix p = op_assign_op jit (get_binop_fun OpAdd p) e1 eone prefix @@ -258,7 +258,7 @@ and jit_expr jit return e = h := IntMap.add i exec !h; if i > !max then max := i; if i < !min then min := i; - | _ -> assert false + | _ -> die "" __LOC__ ) el; pop_scope jit; ) cases; @@ -277,7 +277,7 @@ and jit_expr jit return e = let exec = jit_expr jit return e in List.iter (fun e -> match e.eexpr with | TConst (TString s) -> h := PMap.add s exec !h; - | _ -> assert false + | _ -> die "" __LOC__ ) el; pop_scope jit; ) cases; @@ -342,7 +342,7 @@ and jit_expr jit return e = | e :: el -> loop (jit_expr jit false e :: acc) el | [] -> - assert false + die "" __LOC__ in let el = loop [] el in pop_scope jit; @@ -365,7 +365,7 @@ and jit_expr jit return e = in let length = Array.length a in match loop (length - 1) [] with - | [] -> assert false + | [] -> die "" __LOC__ | [f] -> f | fl -> step fl in @@ -439,7 +439,7 @@ and jit_expr jit return e = | FStatic({cl_path=[],"StringTools"},{cf_name="fastCodeAt"}) -> begin match execs with | [exec1;exec2] -> emit_string_cca exec1 exec2 e.epos - | _ -> assert false + | _ -> die "" __LOC__ end | FEnum({e_path=path},ef) -> let key = path_hash path in @@ -479,7 +479,7 @@ and jit_expr jit return e = let v = lazy (match Lazy.force fnew with VFunction (f,_) -> f | v -> cannot_call v e.epos) in emit_super_call v execs e.epos end - | _ -> assert false + | _ -> die "" __LOC__ end | _ -> match e1.eexpr,el with @@ -613,7 +613,7 @@ and jit_expr jit return e = | OpShr -> emit_op_shr e.epos exec1 exec2 | OpUShr -> emit_op_ushr e.epos exec1 exec2 | OpMod -> emit_op_mod e.epos exec1 exec2 - | _ -> assert false + | _ -> die "" __LOC__ end end | TUnop(op,flag,v1) -> @@ -684,11 +684,8 @@ and jit_tfunction jit static pos tf = pop_scope jit; fl,exec -and get_env_creation jit static file info = { - ec_info = create_env_info static file info jit.capture_infos; - ec_num_locals = jit.max_num_locals; - ec_num_captures = Hashtbl.length jit.captures; -} +and get_env_creation jit static file info = + create_env_info static file info jit.capture_infos jit.max_num_locals (Hashtbl.length jit.captures) (* Creates a [EvalValue.vfunc] of function [tf], which can be [static] or not. *) let jit_tfunction ctx key_type key_field tf static pos = diff --git a/src/macro/eval/evalJitContext.ml b/src/macro/eval/evalJitContext.ml index c6870c776765b33cfcac1832b0d8425de4b4270f..baa405508e8bfbad99028dfef9e41e0ad954f399 100644 --- a/src/macro/eval/evalJitContext.ml +++ b/src/macro/eval/evalJitContext.ml @@ -73,7 +73,7 @@ let pop_scope jit = match jit.scopes with jit.scopes <- tl; jit.num_locals <- jit.num_locals - (num_locals scope); | [] -> - assert false + Globals.die "" __LOC__ (* Increases number of locals and updates maximum number of locals if necessary *) let increase_num_locals jit = @@ -91,7 +91,7 @@ let add_capture jit var declared = (* Adds variable [var] to the current top scope of context [jit]. *) let add_local jit var = match jit.scopes with - | [] -> assert false + | [] -> Globals.die "" __LOC__ | scope :: _ -> let i = Hashtbl.length scope.locals in Hashtbl.add scope.locals var.v_id i; @@ -126,7 +126,7 @@ let declare_arg jit var = (* Declares a variable for `this` in context [jit]. *) let declare_local_this jit = match jit.scopes with - | [] -> assert false + | [] -> Globals.die "" __LOC__ | scope :: _ -> let i = Hashtbl.length scope.locals in Hashtbl.add scope.locals 0 i; diff --git a/src/macro/eval/evalMain.ml b/src/macro/eval/evalMain.ml index 1a61082a6e1ce416099fa8af104b4bf31fe692d1..886b5a0ee9b5c51041848e652280e3d46fcced17 100644 --- a/src/macro/eval/evalMain.ml +++ b/src/macro/eval/evalMain.ml @@ -149,15 +149,15 @@ let call_path ctx path f vl api = let old = ctx.curapi in ctx.curapi <- api; let path = match List.rev path with - | [] -> assert false + | [] -> die "" __LOC__ | name :: path -> List.rev path,name in catch_exceptions ctx ~final:(fun () -> ctx.curapi <- old) (fun () -> let vtype = get_static_prototype_as_value ctx (path_hash path) api.pos in let vfield = field vtype (hash f) in let p = api.pos in - let info = create_env_info true p.pfile EKEntrypoint (Hashtbl.create 0) in - let env = push_environment ctx info 0 0 in + let info = create_env_info true p.pfile EKEntrypoint (Hashtbl.create 0) 0 0 in + let env = push_environment ctx info in env.env_leave_pmin <- p.pmin; env.env_leave_pmax <- p.pmax; let v = call_value_on vtype vfield vl in @@ -316,7 +316,7 @@ let value_signature v = addc 'B'; adds (rev_hash path) | VPrototype _ -> - assert false + die "" __LOC__ | VFunction _ | VFieldClosure _ -> (* Custom format: enumerate functions as F0, F1 etc. *) cache v (fun () -> @@ -361,7 +361,7 @@ let setup get_api = in let v = VFunction (f,b) in Hashtbl.replace GlobalState.macro_lib n v - | _ -> assert false + | _ -> die "" __LOC__ ) api; Globals.macro_platform := Globals.Eval @@ -380,18 +380,18 @@ let compiler_error msg pos = let vi = encode_instance key_haxe_macro_Error in match vi with | VInstance i -> - set_instance_field i key_message (EvalString.create_unknown msg); + set_instance_field i key_exception_message (EvalString.create_unknown msg); set_instance_field i key_pos (encode_pos pos); exc vi | _ -> - assert false + die "" __LOC__ let rec value_to_expr v p = let path i = let mt = IntMap.find i (get_ctx()).type_cache in let make_path t = let rec loop = function - | [] -> assert false + | [] -> die "" __LOC__ | [name] -> (EConst (Ident name),p) | name :: l -> (EField (loop l,name),p) in @@ -422,7 +422,7 @@ let rec value_to_expr v p = let expr = path e.epath in let name = match proto.pkind with | PEnum names -> fst (List.nth names e.eindex) - | _ -> assert false + | _ -> die "" __LOC__ in (EField (expr, name), p) in @@ -534,9 +534,9 @@ let handle_decoding_error f v t = end | TInst _ | TAbstract _ | TFun _ -> (* TODO: might need some more of these, not sure *) - assert false + die "" __LOC__ | TMono r -> - begin match !r with + begin match r.tm_type with | None -> () | Some t -> loop tabs t v end diff --git a/src/macro/eval/evalMisc.ml b/src/macro/eval/evalMisc.ml index 86dbf27af84dd774f640fdaae8ac0bebcb6a17ed..e889608646f14f744bcacea60c27a5e9ebbb4318 100644 --- a/src/macro/eval/evalMisc.ml +++ b/src/macro/eval/evalMisc.ml @@ -253,4 +253,4 @@ let get_binop_fun op p = match op with | OpShr -> op_shr p | OpUShr -> op_ushr p | OpMod -> op_mod p - | OpAssign | OpBoolAnd | OpBoolOr | OpAssignOp _ | OpInterval | OpArrow | OpIn -> assert false + | OpAssign | OpBoolAnd | OpBoolOr | OpAssignOp _ | OpInterval | OpArrow | OpIn -> die "" __LOC__ diff --git a/src/macro/eval/evalPrinting.ml b/src/macro/eval/evalPrinting.ml index 3c0ce3cda6538a968a4b7608df3df25313eb08db..4c3c0912b541521023ddad6537889056a1382e3e 100644 --- a/src/macro/eval/evalPrinting.ml +++ b/src/macro/eval/evalPrinting.ml @@ -25,7 +25,6 @@ open EvalField open EvalHash open EvalString -let rempty = create_ascii "" let rbropen = create_ascii "{" let rbrclose = create_ascii "}" let rbkopen = create_ascii "[" @@ -64,14 +63,14 @@ let rec s_object depth o = create_with_length s (try UTF8.length s with _ -> String.length s) and s_array depth va = - join rempty [ + join empty_string [ rbkopen; EvalArray.join va (s_value depth) rcomma; rbkclose; ] and s_vector depth vv = - join rempty [ + join empty_string [ rbkopen; EvalArray.join (EvalArray.create vv) (s_value depth) rcomma; rbkclose; @@ -90,7 +89,7 @@ and s_enum_value depth ve = match ve.eargs with | [||] -> create_ascii name | vl -> - join rempty [ + join empty_string [ create_ascii name; rpopen; join rcomma (Array.to_list (Array.map (s_value (depth + 1)) vl)); @@ -98,9 +97,9 @@ and s_enum_value depth ve = ] and s_proto_kind proto = match proto.pkind with - | PClass _ -> join rempty [create_ascii "Class<"; s_hash proto.ppath; rgt] - | PEnum _ -> join rempty [create_ascii "Enum<"; s_hash proto.ppath; rgt] - | PInstance | PObject -> assert false + | PClass _ -> join empty_string [create_ascii "Class<"; s_hash proto.ppath; rgt] + | PEnum _ -> join empty_string [create_ascii "Enum<"; s_hash proto.ppath; rgt] + | PInstance | PObject -> die "" __LOC__ and s_value depth v = let call_to_string () = diff --git a/src/macro/eval/evalPrototype.ml b/src/macro/eval/evalPrototype.ml index a22c12f7858b5a7f4fac6a272129d052b0886bcc..25ea18e32fa18cc78783329c69cfcb329723c8e9 100644 --- a/src/macro/eval/evalPrototype.ml +++ b/src/macro/eval/evalPrototype.ml @@ -33,8 +33,8 @@ let eval_expr ctx kind e = catch_exceptions ctx (fun () -> let jit,f = jit_expr ctx e in let num_captures = Hashtbl.length jit.captures in - let info = create_env_info true e.epos.pfile kind jit.capture_infos in - let env = push_environment ctx info jit.max_num_locals num_captures in + let info = create_env_info true e.epos.pfile kind jit.capture_infos jit.max_num_locals num_captures in + let env = push_environment ctx info in Std.finally (fun _ -> pop_environment ctx env) f env ) e.Type.epos @@ -240,7 +240,7 @@ let create_static_prototype ctx mt = let pctx = PrototypeBuilder.create ctx key None (PClass []) meta in PrototypeBuilder.finalize pctx,[]; | _ -> - assert false + die "" __LOC__ in let rec loop v name path = match path with | [] -> @@ -341,6 +341,9 @@ let add_types ctx types ready = DynArray.add fl_static (create_static_prototype ctx mt); | TAbstractDecl a -> DynArray.add fl_static (create_static_prototype ctx mt); + (* Create a fake instance prototype for coreType abstracts in case something inspects them (#8778). *) + if Meta.has Meta.CoreType a.a_meta then + DynArray.add fl_instance (create_instance_prototype ctx {null_class with cl_path = a.a_path}) | _ -> () ) new_types; diff --git a/src/macro/eval/evalSsl.ml b/src/macro/eval/evalSsl.ml new file mode 100644 index 0000000000000000000000000000000000000000..3e22ec4dfd1845cef1216787ed445207f8d9479f --- /dev/null +++ b/src/macro/eval/evalSsl.ml @@ -0,0 +1,202 @@ +open EvalHash +open EvalValue +open EvalEncode +open EvalDecode +open EvalExceptions +open Mbedtls + +let as_x509_crt vthis = match vthis with + | VInstance {ikind = IMbedtlsX509Crt i} -> i + | _ -> unexpected_value vthis "X509Crt" + +let as_config vthis = match vthis with + | VInstance {ikind = IMbedtlsConfig i} -> i + | _ -> unexpected_value vthis "Config" + +let as_socket vthis = match vthis with + | VInstance {ikind = ISocket sock} -> sock + | _ -> unexpected_value vthis "NativeSocket" + +let as_ctr_drbg vthis = match vthis with + | VInstance {ikind = IMbedtlsCtrDrbg i} -> i + | _ -> unexpected_value vthis "CtrDrbg" + +let as_entropy vthis = match vthis with + | VInstance {ikind = IMbedtlsEntropy i} -> i + | _ -> unexpected_value vthis "Entropy" + +let as_pk_context vthis = match vthis with + | VInstance {ikind = IMbedtlsPkContext i} -> i + | _ -> unexpected_value vthis "PkContext" + +let as_ssl vthis = match vthis with + | VInstance {ikind = IMbedtlsSsl ctx} -> ctx + | _ -> unexpected_value vthis "Ssl" + +let init_constructors add = + add key_mbedtls_Config + (fun _ -> + let cfg = mbedtls_ssl_config_init() in + encode_instance key_mbedtls_Config ~kind:(IMbedtlsConfig cfg) + ); + add key_mbedtls_CtrDrbg + (fun _ -> + let ctr = mbedtls_ctr_drbg_init() in + encode_instance key_mbedtls_CtrDrbg ~kind:(IMbedtlsCtrDrbg ctr) + ); + add key_mbedtls_Entropy + (fun _ -> + let entropy = mbedtls_entropy_init() in + encode_instance key_mbedtls_Entropy ~kind:(IMbedtlsEntropy entropy) + ); + add key_mbedtls_PkContext + (fun _ -> + let pk = mbedtls_pk_init() in + encode_instance key_mbedtls_PkContext ~kind:(IMbedtlsPkContext pk) + ); + add key_mbedtls_Ssl + (fun _ -> + let ssl = mbedtls_ssl_init() in + encode_instance key_mbedtls_Ssl ~kind:(IMbedtlsSsl ssl) + ); + add key_mbedtls_X509Crt + (fun _ -> + let cert = mbedtls_x509_crt_init() in + encode_instance key_mbedtls_X509Crt ~kind:(IMbedtlsX509Crt cert) + ) + +let init_fields init_fields builtins = + let socket_send socket bytes = + Unix.send socket bytes 0 (Bytes.length bytes) [] + in + let socket_receive socket bytes = + Unix.recv socket bytes 0 (Bytes.length bytes) [] + in + let native_cert this = + as_x509_crt (EvalField.field this (hash "native")) + in + init_fields builtins (["sys";"ssl"],"Certificate") [] [ + "get_altNames",vifun0 (fun this -> + let x509_crt = native_cert this in + let a = hx_cert_get_alt_names x509_crt in + VArray (EvalArray.create (Array.map encode_string a)) + ); + "get_notAfter",vifun0 (fun this -> + let x509_crt = native_cert this in + let f = hx_cert_get_notafter x509_crt in + encode_instance key_Date ~kind:(IDate f) + ); + "get_notBefore",vifun0 (fun this -> + let x509_crt = native_cert this in + let f = hx_cert_get_notbefore x509_crt in + encode_instance key_Date ~kind:(IDate f) + ); + "issuer",vifun1 (fun this field -> + let x509_crt = native_cert this in + match hx_cert_get_issuer x509_crt (decode_string field) with + | Some s -> encode_string s + | None -> vnull + ); + "subject",vifun1 (fun this field -> + let x509_crt = native_cert this in + match hx_cert_get_subject x509_crt (decode_string field) with + | Some s -> encode_string s + | None -> vnull + ); + ]; + init_fields builtins (["sys";"ssl"],"Mbedtls") [ + "loadDefaults",vfun1 (fun this -> + vint (hx_cert_load_defaults (as_x509_crt this)); + ); + "setSocket",vfun2 (fun this socket -> + let ctx = as_ssl this in + let socket = as_socket socket in + mbedtls_ssl_set_bio ctx socket socket_send socket_receive; + vnull + ); + ] []; + init_fields builtins (["mbedtls"],"X509Crt") [] [ + "next",vifun0 (fun this -> + match mbedtls_x509_next (as_x509_crt this) with + | None -> vnull + | Some cert -> encode_instance key_mbedtls_X509Crt ~kind:(IMbedtlsX509Crt cert) + ); + "parse",vifun1 (fun this bytes -> + vint (mbedtls_x509_crt_parse (as_x509_crt this) (decode_bytes bytes)); + ); + "parse_file",vifun1 (fun this path -> + vint (mbedtls_x509_crt_parse_file (as_x509_crt this) (decode_string path)); + ); + "parse_path",vifun1 (fun this path -> + vint (mbedtls_x509_crt_parse_path (as_x509_crt this) (decode_string path)); + ); + ]; + init_fields builtins (["mbedtls"],"Config") [] [ + "authmode",vifun1 (fun this authmode -> + mbedtls_ssl_config_authmode (as_config this) (decode_int authmode); + vnull; + ); + "ca_chain",vifun1 (fun this ca_chain -> + mbedtls_ssl_conf_ca_chain (as_config this) (as_x509_crt ca_chain); + vnull; + ); + "defaults",vifun3 (fun this endpoint transport preset -> + vint (mbedtls_ssl_config_defaults (as_config this) (decode_int endpoint) (decode_int transport) (decode_int preset)); + ); + "rng",vifun1(fun this p_rng -> + mbedtls_ssl_config_rng (as_config this) (as_ctr_drbg p_rng); + vnull + ) + ]; + init_fields builtins (["mbedtls"],"CtrDrbg") [] [ + "random",vifun2 (fun this output output_len -> + vint (mbedtls_ctr_drbg_random (as_ctr_drbg this) (decode_bytes output) (decode_int output_len)); + ); + "seed",vifun2(fun this entropy custom -> + vint (mbedtls_ctr_drbg_seed (as_ctr_drbg this) (as_entropy entropy) (match custom with VString s -> Some s.sstring | _ -> None)) + ) + ]; + init_fields builtins (["mbedtls"],"Error") [ + "strerror",vfun1 (fun code -> encode_string (mbedtls_strerror (decode_int code))); + ] []; + init_fields builtins (["mbedtls"],"PkContext") [] [ + "parse_key",vifun2 (fun this key password -> + vint (mbedtls_pk_parse_key (as_pk_context this) (decode_bytes key) (match password with VNull -> None | _ -> Some (decode_string password))); + ); + "parse_keyfile",vifun2 (fun this path password -> + vint (mbedtls_pk_parse_keyfile (as_pk_context this) (decode_string path) (match password with VNull -> None | _ -> Some (decode_string password))); + ); + "parse_public_key",vifun1 (fun this key -> + vint (mbedtls_pk_parse_public_key (as_pk_context this) (decode_bytes key)); + ); + "parse_public_keyfile",vifun1 (fun this path -> + vint (mbedtls_pk_parse_public_keyfile (as_pk_context this) (decode_string path)); + ); + ]; + init_fields builtins (["mbedtls"],"Ssl") [] [ + "get_peer_cert",vifun0 (fun this -> + match mbedtls_ssl_get_peer_cert (as_ssl this) with + | None -> vnull + | Some cert -> encode_instance key_mbedtls_X509Crt ~kind:(IMbedtlsX509Crt cert) + ); + "handshake",vifun0 (fun this -> + vint (mbedtls_ssl_handshake (as_ssl this)); + ); + "read",vifun3(fun this buf pos len -> + vint (mbedtls_ssl_read (as_ssl this) (decode_bytes buf) (decode_int pos) (decode_int len);) + ); + "set_hostname",vifun1 (fun this hostname -> + vint (mbedtls_ssl_set_hostname (as_ssl this) (decode_string hostname)); + ); + "setup",vifun1 (fun this conf -> + vint (mbedtls_ssl_setup (as_ssl this) (as_config conf)) + ); + "write",vifun3(fun this buf pos len -> + vint (mbedtls_ssl_write (as_ssl this) (decode_bytes buf) (decode_int pos) (decode_int len);) + ); + ]; + let statics a = List.map (fun (s,i) -> s,vint i) (Array.to_list a) in + init_fields builtins (["mbedtls"],"SslAuthmode") (statics (hx_get_ssl_authmode_flags())) []; + init_fields builtins (["mbedtls"],"SslEndpoint") (statics (hx_get_ssl_endpoint_flags())) []; + init_fields builtins (["mbedtls"],"SslPreset") (statics (hx_get_ssl_preset_flags())) []; + init_fields builtins (["mbedtls"],"SslTransport") (statics (hx_get_ssl_transport_flags())) []; diff --git a/src/macro/eval/evalStdLib.ml b/src/macro/eval/evalStdLib.ml index 093406ae07d45fd03a26a2070524eafb9512b9e5..0dad11c50f0a3a9cc4adbc29b0add06c9d3c0d2a 100644 --- a/src/macro/eval/evalStdLib.ml +++ b/src/macro/eval/evalStdLib.ml @@ -152,6 +152,15 @@ module StdArray = struct vstring s ) + let keyValueIterator = vifun0 (fun vthis -> + let ctx = get_ctx() in + let path = key_haxe_iterators_array_key_value_iterator in + let vit = encode_instance path in + let fnew = get_instance_constructor ctx path null_pos in + ignore(call_value_on vit (Lazy.force fnew) [vthis]); + vit + ) + let lastIndexOf = vifun2 (fun vthis x fromIndex -> let this = this vthis in let last = this.alength - 1 in @@ -188,6 +197,11 @@ module StdArray = struct vbool (EvalArray.remove this equals x) ) + let contains = vifun1 (fun vthis x -> + let this = this vthis in + vbool (EvalArray.contains this equals x) + ) + let reverse = vifun0 (fun vthis -> let this = this vthis in EvalArray.reverse this; @@ -300,7 +314,7 @@ module StdBytes = struct let pos = decode_int pos in let len = decode_int len in let value = decode_int value in - (try Bytes.fill this pos len (char_of_int value) with _ -> outside_bounds()); + (try Bytes.fill this pos len (char_of_int (value land 0xFF)) with _ -> outside_bounds()); vnull ) @@ -532,7 +546,7 @@ module StdBytesBuffer = struct ) end -module StdCallStack = struct +module StdNativeStackTrace = struct let make_stack envs = let l = DynArray.create () in List.iter (fun (pos,kind) -> @@ -618,7 +632,7 @@ module StdCompress = struct | 2 -> Z_FULL_FLUSH | 3 -> Z_FINISH | 4 -> Z_PARTIAL_FLUSH - | _ -> assert false + | _ -> die "" __LOC__ in (this vthis).z_flush <- mode; vnull @@ -928,7 +942,9 @@ module StdEReg = struct let this = this vthis in let s = decode_string s in let pos = decode_int pos in - let len = default_int len (String.length s - pos) in + let len_default = String.length s - pos in + let len = default_int len len_default in + let len = if len < 0 then len_default else len in begin try if pos + len > String.length s then raise Not_found; let str = String.sub s 0 (pos + len) in @@ -952,7 +968,7 @@ module StdEReg = struct let split = vifun1 (fun vthis s -> let this = this vthis in let s = decode_string s in - if String.length s = 0 then encode_array [encode_string ""] + if String.length s = 0 then encode_array [v_empty_string] else begin let max = if this.r_global then -1 else 2 in let l = Pcre.full_split ~iflags:0x2000 ~max ~rex:this.r s in @@ -1071,7 +1087,7 @@ module StdFileInput = struct r := false; let pos = decode_int pos in let mode,_ = decode_enum mode in - seek_in ch (match mode with 0 -> pos | 1 -> pos_in ch + pos | 2 -> in_channel_length ch + pos | _ -> assert false); + seek_in ch (match mode with 0 -> pos | 1 -> pos_in ch + pos | 2 -> in_channel_length ch + pos | _ -> die "" __LOC__); vnull ) @@ -1123,7 +1139,7 @@ module StdFileOutput = struct let this = this vthis in let pos = decode_int pos in let mode,_ = decode_enum mode in - seek_out this (match mode with 0 -> pos | 1 -> pos_out this + pos | 2 -> out_channel_length this + pos | _ -> assert false); + seek_out this (match mode with 0 -> pos | 1 -> pos_out this + pos | 2 -> out_channel_length this + pos | _ -> die "" __LOC__); vnull ) @@ -1540,9 +1556,9 @@ module StdIntMap = struct let toString = vifun0 (fun vthis -> let this = this vthis in let l = IntHashtbl.fold (fun key vvalue acc -> - (join rempty [create_ascii (string_of_int key); create_ascii " => "; s_value 0 vvalue]) :: acc) this [] in + (join empty_string [create_ascii (string_of_int key); create_ascii " => "; s_value 0 vvalue]) :: acc) this [] in let s = join rcomma l in - let s = join rempty [rbropen;s;rbrclose] in + let s = join empty_string [rbropen;s;rbrclose] in vstring s ) @@ -1599,9 +1615,9 @@ module StdStringMap = struct let toString = vifun0 (fun vthis -> let this = this vthis in let l = StringHashtbl.fold (fun _ (key,vvalue) acc -> - (join rempty [key; create_ascii " => "; s_value 0 vvalue]) :: acc) this [] in + (join empty_string [key; create_ascii " => "; s_value 0 vvalue]) :: acc) this [] in let s = join rcomma l in - let s = join rempty [rbropen;s;rbrclose] in + let s = join empty_string [rbropen;s;rbrclose] in vstring s ) @@ -1657,9 +1673,9 @@ module StdObjectMap = struct let toString = vifun0 (fun vthis -> let this = this vthis in let l = ValueHashtbl.fold (fun key vvalue acc -> - (join rempty [s_value 0 key; create_ascii " => "; s_value 0 vvalue]) :: acc) this [] in + (join empty_string [s_value 0 key; create_ascii " => "; s_value 0 vvalue]) :: acc) this [] in let s = join rcomma l in - let s = join rempty [rbropen;s;rbrclose] in + let s = join empty_string [rbropen;s;rbrclose] in vstring s ) @@ -1990,7 +2006,7 @@ module StdSocket = struct let s = catch_unix_error Unix.string_of_inet_addr addr in match List.map Int32.of_string (ExtString.String.nsplit s ".") with | [a;b;c;d] -> Int32.add (Int32.add (Int32.add (Int32.shift_left a 24) (Int32.shift_left b 16)) (Int32.shift_left c 8)) d - | _ -> assert false + | _ -> die "" __LOC__ let this vthis = match vthis with | VInstance {ikind = ISocket sock} -> sock @@ -1999,7 +2015,7 @@ module StdSocket = struct let accept = vifun0 (fun vthis -> let this = this vthis in let socket,_ = catch_unix_error Unix.accept this in - encode_instance key_sys_net__Socket_NativeSocket ~kind:(ISocket socket) + encode_instance key_eval_vm_NativeSocket ~kind:(ISocket socket) ) let bind = vifun2 (fun vthis host port -> @@ -2030,7 +2046,7 @@ module StdSocket = struct key_ip,vint32 (inet_addr_to_int32 addr); key_port,vint port; ] - | _ -> assert false + | _ -> die "" __LOC__ ) let listen = vifun1 (fun vthis connections -> @@ -2047,7 +2063,7 @@ module StdSocket = struct key_ip,vint32 (inet_addr_to_int32 addr); key_port,vint port; ] - | _ -> assert false + | _ -> die "" __LOC__ ) let receive = vifun3 (fun vthis buf pos len -> @@ -2145,12 +2161,14 @@ module StdSocket = struct end module StdStd = struct - let is' = vfun2 (fun v t -> match t with + let isOfType = vfun2 (fun v t -> match t with | VNull -> vfalse | VPrototype proto -> vbool (is v proto.ppath) | _ -> vfalse ) + let is' = isOfType + let downcast = vfun2 (fun v t -> match t with | VPrototype proto -> if is v proto.ppath then v else vnull @@ -2190,7 +2208,7 @@ module StdString = struct let charAt = vifun1 (fun vthis index -> let this = this vthis in let i = decode_int index in - if i < 0 || i >= this.slength then encode_string "" + if i < 0 || i >= this.slength then v_empty_string else vstring (from_char_code (char_at this i)) ) @@ -2288,7 +2306,7 @@ module StdString = struct let cl_this = this.slength in let c_pos = decode_int pos in if c_pos >= cl_this then - encode_string "" + v_empty_string else begin let c_pos = if c_pos < 0 then begin let c_pos = this.slength + c_pos in @@ -2320,7 +2338,7 @@ module StdString = struct let c_first,c_last = if c_first > c_last then c_last,c_first else c_first,c_last in let c_last = if c_last > cl_this then cl_this else c_last in if c_first > cl_this || c_first = c_last then - encode_string "" + v_empty_string else begin begin let b_offset1 = get_offset this c_first in @@ -2377,7 +2395,7 @@ module StdStringBuf = struct let s = decode_vstring s in let c_pos = decode_int pos in let c_len = match len with - | VNull -> String.length s.sstring - c_pos + | VNull -> s.slength - c_pos | VInt32 i -> Int32.to_int i | _ -> unexpected_value len "int" in @@ -3117,7 +3135,7 @@ let init_constructors builtins = match vl with | [size] -> encode_vector_instance (Array.make (decode_int size) vnull) - | _ -> assert false + | _ -> die "" __LOC__ ); add key_Date (fun vl -> @@ -3128,24 +3146,24 @@ let init_constructors builtins = Unix.mktime {t with tm_sec=s;tm_min=mi;tm_hour=h;tm_mday=d;tm_mon=m;tm_year=y - 1900} ) () in encode_instance key_Date ~kind:(IDate (fst f)) - | _ -> assert false + | _ -> die "" __LOC__ end ); add key_EReg (fun vl -> match vl with | [r;opt] -> encode_instance key_EReg ~kind:(StdEReg.create (decode_string r) (decode_string opt)) - | _ -> assert false + | _ -> die "" __LOC__ ); add key_String (fun vl -> match vl with | [s] -> s - | _ -> assert false + | _ -> die "" __LOC__ ); add key_StringBuf (fun _ -> encode_instance key_StringBuf ~kind:(IBuffer (VStringBuffer.create()))); add key_haxe_Utf8 (fun vl -> match vl with | [size] -> encode_instance key_haxe_Utf8 ~kind:(IUtf8 (UTF8.Buf.create (default_int size 0))) - | _ -> assert false + | _ -> die "" __LOC__ ); add key_haxe_ds_StringMap (fun _ -> encode_string_map_direct (StringHashtbl.create ())); add key_haxe_ds_IntMap (fun _ -> encode_int_map_direct (IntHashtbl.create ())); @@ -3161,7 +3179,7 @@ let init_constructors builtins = Bytes.blit b 0 b' 0 blit_length; encode_bytes b' | _ -> - assert false + die "" __LOC__ ); add key_sys_io__Process_NativeProcess (fun vl -> match vl with @@ -3173,11 +3191,11 @@ let init_constructors builtins = | _ -> unexpected_value args "array" in encode_instance key_sys_io__Process_NativeProcess ~kind:(IProcess (try Process.run cmd args with Failure msg -> exc_string msg)) - | _ -> assert false + | _ -> die "" __LOC__ ); - add key_sys_net__Socket_NativeSocket + add key_eval_vm_NativeSocket (fun _ -> - encode_instance key_sys_net__Socket_NativeSocket ~kind:(ISocket ((catch_unix_error Unix.socket Unix.PF_INET Unix.SOCK_STREAM) 0)) + encode_instance key_eval_vm_NativeSocket ~kind:(ISocket ((catch_unix_error Unix.socket Unix.PF_INET Unix.SOCK_STREAM) 0)) ); add key_haxe_zip_Compress (fun vl -> match vl with @@ -3185,7 +3203,7 @@ let init_constructors builtins = let level = decode_int level in let z = Extc.zlib_deflate_init level in encode_instance key_haxe_zip_Compress ~kind:(IZip { z = z; z_flush = Extc.Z_NO_FLUSH }) - | _ -> assert false + | _ -> die "" __LOC__ ); add key_haxe_zip_Uncompress (fun vl -> match vl with @@ -3193,7 +3211,7 @@ let init_constructors builtins = let windowBits = default_int windowBits 15 in let z = Extc.zlib_inflate_init2 windowBits in encode_instance key_haxe_zip_Uncompress ~kind:(IZip { z = z; z_flush = Extc.Z_NO_FLUSH }) - | _ -> assert false + | _ -> die "" __LOC__ ); add key_eval_vm_Thread (fun vl -> match vl with @@ -3202,7 +3220,7 @@ let init_constructors builtins = if ctx.is_macro then exc_string "Creating threads in macros is not supported"; let thread = EvalThread.spawn ctx (fun () -> call_value f []) in encode_instance key_eval_vm_Thread ~kind:(IThread thread) - | _ -> assert false + | _ -> die "" __LOC__ ); add key_sys_net_Mutex (fun _ -> @@ -3228,7 +3246,8 @@ let init_constructors builtins = add key_sys_net_Deque (fun _ -> encode_instance key_sys_net_Deque ~kind:(IDeque (Deque.create())) - ) + ); + EvalSsl.init_constructors add let init_empty_constructors builtins = let h = builtins.empty_constructor_builtins in @@ -3236,7 +3255,7 @@ let init_empty_constructors builtins = Hashtbl.add h key_eval_Vector (fun () -> encode_vector_instance (Array.make 0 vnull)); Hashtbl.add h key_Date (fun () -> encode_instance key_Date ~kind:(IDate 0.)); Hashtbl.add h key_EReg (fun () -> encode_instance key_EReg ~kind:(IRegex {r = Pcre.regexp ""; r_rex_string = create_ascii "~//"; r_global = false; r_string = ""; r_groups = [||]})); - Hashtbl.add h key_String (fun () -> encode_string ""); + Hashtbl.add h key_String (fun () -> v_empty_string); Hashtbl.add h key_haxe_ds_StringMap (fun () -> encode_instance key_haxe_ds_StringMap ~kind:(IStringMap (StringHashtbl.create ()))); Hashtbl.add h key_haxe_ds_IntMap (fun () -> encode_instance key_haxe_ds_IntMap ~kind:(IIntMap (IntHashtbl.create ()))); Hashtbl.add h key_haxe_ds_ObjectMap (fun () -> encode_instance key_haxe_ds_ObjectMap ~kind:(IObjectMap (Obj.magic (ValueHashtbl.create 0)))); @@ -3254,12 +3273,14 @@ let init_standard_library builtins = "insert",StdArray.insert; "iterator",StdArray.iterator; "join",StdArray.join; + "keyValueIterator",StdArray.keyValueIterator; "lastIndexOf",StdArray.lastIndexOf; "map",StdArray.map; "pop",StdArray.pop; "push",StdArray.push; "remove",StdArray.remove; "resize",StdArray.resize; + "contains",StdArray.contains; "reverse",StdArray.reverse; "shift",StdArray.shift; "slice",StdArray.slice; @@ -3317,9 +3338,9 @@ let init_standard_library builtins = "addBytes",StdBytesBuffer.addBytes; "getBytes",StdBytesBuffer.getBytes; ]; - init_fields builtins (["haxe"],"CallStack") [ - "getCallStack",StdCallStack.getCallStack; - "getExceptionStack",StdCallStack.getExceptionStack; + init_fields builtins (["haxe"],"NativeStackTrace") [ + "_callStack",StdNativeStackTrace.getCallStack; + "exceptionStack",StdNativeStackTrace.getExceptionStack; ] []; init_fields builtins (["haxe";"zip"],"Compress") [ "run",StdCompress.run; @@ -3524,7 +3545,7 @@ let init_standard_library builtins = "encode",StdSha1.encode; "make",StdSha1.make; ] []; - init_fields builtins (["sys";"net";"_Socket"],"NativeSocket") [ + init_fields builtins (["eval";"vm"],"NativeSocket") [ "select",StdSocket.select; ] [ "accept",StdSocket.accept; @@ -3548,6 +3569,7 @@ let init_standard_library builtins = "instance",StdStd.instance; "int",StdStd.int; "is",StdStd.is'; + "isOfType",StdStd.isOfType; "parseFloat",StdStd.parseFloat; "parseInt",StdStd.parseInt; "string",StdStd.string; @@ -3660,4 +3682,5 @@ let init_standard_library builtins = ] [ "addChar",StdUtf8.addChar; "toString",StdUtf8.toString; - ] + ]; + EvalSsl.init_fields init_fields builtins \ No newline at end of file diff --git a/src/macro/eval/evalString.ml b/src/macro/eval/evalString.ml index 5522ad8ba58449c85700e4b617ac4223c961d2b4..fba780fc227df8062b31e6d920f145be079b7396 100644 --- a/src/macro/eval/evalString.ml +++ b/src/macro/eval/evalString.ml @@ -34,6 +34,10 @@ let create_with_length s length = { soffsets = []; } +let empty_string = create_ascii "" + +let v_empty_string = VString empty_string + let create_unknown s = vstring (create_with_length s (try UTF8.length s with _ -> String.length s)) @@ -124,7 +128,7 @@ let get_offset' s c_index = in b_offset,r | _ -> - assert false + Globals.die "" __LOC__ let get_offset s c_index = let b_offset,(cr_index,br_offset) = get_offset' s c_index in diff --git a/src/macro/eval/evalThread.ml b/src/macro/eval/evalThread.ml index 0d948c12a8075660f145652d296d605bc9e0b562..247199428bdfdb091a830661dfb2618cf2ab64fe 100644 --- a/src/macro/eval/evalThread.ml +++ b/src/macro/eval/evalThread.ml @@ -16,7 +16,7 @@ module Deque = struct Mutex.unlock this.dmutex let pop this blocking = - let rec loop () = + if not blocking then begin Mutex.lock this.dmutex; match this.dvalues with | v :: vl -> @@ -24,16 +24,41 @@ module Deque = struct Mutex.unlock this.dmutex; Some v | [] -> - if not blocking then begin - Mutex.unlock this.dmutex; - None - end else begin - Mutex.unlock this.dmutex; + Mutex.unlock this.dmutex; + None + end else begin + (* Optimistic first attempt with immediate lock. *) + Mutex.lock this.dmutex; + begin match this.dvalues with + | v :: vl -> + this.dvalues <- vl; + Mutex.unlock this.dmutex; + Some v + | [] -> + Mutex.unlock this.dmutex; + (* First attempt failed, let's be pessimistic now to avoid locks. *) + let rec loop () = Thread.yield(); - loop() - end - in - loop() + match this.dvalues with + | v :: vl -> + (* Only lock if there's a chance to have a value. This avoids high amounts of unneeded locking. *) + Mutex.lock this.dmutex; + (* We have to check again because the value could be gone by now. *) + begin match this.dvalues with + | v :: vl -> + this.dvalues <- vl; + Mutex.unlock this.dmutex; + Some v + | [] -> + Mutex.unlock this.dmutex; + loop() + end + | [] -> + loop() + in + loop() + end + end let push this i = Mutex.lock this.dmutex; diff --git a/src/macro/eval/evalValue.ml b/src/macro/eval/evalValue.ml index f3ed7cd107d0f36bbc68d7277ebde5299b525cbf..af94c20bcac70b6ca2cb1e4d9197c4d38e9c9dab 100644 --- a/src/macro/eval/evalValue.ml +++ b/src/macro/eval/evalValue.ml @@ -60,18 +60,18 @@ module StringHashtbl = struct end module IntHashtbl = struct - type 'value t = 'value IntMap.t ref - - let add this key v = this := IntMap.add key v !this - let copy this = ref !this - let create () = ref IntMap.empty - let find this key = IntMap.find key !this - let fold f this acc = IntMap.fold f !this acc - let is_empty this = IntMap.is_empty !this - let iter f this = IntMap.iter f !this - let mem this key = IntMap.mem key !this - let remove this key = this := IntMap.remove key !this - let clear this = this := IntMap.empty + type 'value t = (int, 'value) Hashtbl.t + + let add this key v = Hashtbl.replace this key v + let copy this = Hashtbl.copy this + let create () = Hashtbl.create 0 + let find this key = Hashtbl.find this key + let fold f this acc = Hashtbl.fold f this acc + let is_empty this = Hashtbl.length this = 0 + let iter f this = Hashtbl.iter f this + let mem this key = Hashtbl.mem this key + let remove this key = Hashtbl.remove this key + let clear this = Hashtbl.clear this end type vregex = { @@ -165,6 +165,13 @@ and vinstance_kind = | ITypeDecl of Type.module_type | ILazyType of (Type.tlazy ref) * (unit -> value) | IRef of Obj.t + (* SSL *) + | IMbedtlsConfig of Mbedtls.mbedtls_ssl_config + | IMbedtlsCtrDrbg of Mbedtls.mbedtls_ctr_drbg_context + | IMbedtlsEntropy of Mbedtls.mbedtls_entropy_context + | IMbedtlsPkContext of Mbedtls.mbedtls_pk_context + | IMbedtlsSsl of Mbedtls.mbedtls_ssl_context + | IMbedtlsX509Crt of Mbedtls.mbedtls_x509_crt | INormal and vinstance = { diff --git a/src/macro/macroApi.ml b/src/macro/macroApi.ml index 7065d9b3b368bf1250ba9b40cb8b11c32e02719e..bc835f62fbbe763287b97c243b25fe52c15af464 100644 --- a/src/macro/macroApi.ml +++ b/src/macro/macroApi.ml @@ -336,7 +336,7 @@ and encode_field (f:class_field) = encode_obj [ "name",encode_placed_name f.cff_name; "name_pos", encode_pos (pos f.cff_name); - "doc", null encode_string f.cff_doc; + "doc", null encode_string (gen_doc_text_opt f.cff_doc); "pos", encode_pos f.cff_pos; "kind", encode_enum IField tag pl; "meta", encode_meta_content f.cff_meta; @@ -406,7 +406,7 @@ and encode_message msg = let tag, pl = match msg with | CMInfo(msg,p) -> 0, [(encode_string msg); (encode_pos p)] | CMWarning(msg,p) -> 1, [(encode_string msg); (encode_pos p)] - | CMError(_,_) -> assert false + | CMError(_,_) -> Globals.die "" __LOC__ in encode_enum ~pos:None IMessage tag pl @@ -472,7 +472,7 @@ and encode_expr e = encode_obj [ "name",encode_placed_name v; "name_pos",encode_pos (pos v); - "type",encode_ctype t; + "type",null encode_ctype t; "expr",loop e; "pos",encode_pos p ] @@ -609,12 +609,11 @@ let decode_opt_array f v = let rec decode_path t = let p = field t "pos" in - { - tpackage = List.map decode_string (decode_array (field t "pack")); - tname = decode_string (field t "name"); - tparams = decode_opt_array decode_tparam (field t "params"); - tsub = opt decode_string (field t "sub"); - },if p = vnull then Globals.null_pos else decode_pos p + let pack = List.map decode_string (decode_array (field t "pack")) + and name = decode_string (field t "name") + and params = decode_opt_array decode_tparam (field t "params") + and sub = opt decode_string (field t "sub") in + mk_type_path ~params ?sub (pack,name), if p = vnull then Globals.null_pos else decode_pos p and decode_tparam v = match decode_enum v with @@ -673,6 +672,8 @@ and decode_meta_entry v = and decode_meta_content m = decode_opt_array decode_meta_entry m +and decode_doc = opt (fun s -> { doc_own = Some (decode_string s); doc_inherited = [] }) + and decode_field v = let fkind = match decode_enum (field v "kind") with | 0, [t;e] -> @@ -687,7 +688,7 @@ and decode_field v = let pos = decode_pos (field v "pos") in { cff_name = (decode_string (field v "name"),decode_pos_default (field v "name_pos") pos); - cff_doc = opt decode_string (field v "doc"); + cff_doc = decode_doc (field v "doc"); cff_pos = pos; cff_kind = fkind; cff_access = List.map decode_access (opt_list decode_array (field v "access")); @@ -789,7 +790,7 @@ and decode_expr v = ESwitch (loop e,cases,opt (fun v -> (if field v "expr" = vnull then None else Some (decode_expr v)),Globals.null_pos) eo) | 17, [e;catches] -> let catches = List.map (fun c -> - ((decode_placed_name (field c "name_pos") (field c "name")),(decode_ctype (field c "type")),loop (field c "expr"),maybe_decode_pos (field c "pos")) + ((decode_placed_name (field c "name_pos") (field c "name")),(opt decode_ctype (field c "type")),loop (field c "expr"),maybe_decode_pos (field c "pos")) ) (decode_array catches) in ETry (loop e, catches) | 18, [e] -> @@ -880,7 +881,7 @@ let rec encode_mtype t fields = "module", encode_string (s_type_path i.mt_module.m_path); "isPrivate", vbool i.mt_private; "meta", encode_meta i.mt_meta (fun m -> i.mt_meta <- m); - "doc", null encode_string i.mt_doc; + "doc", null encode_string (get_own_doc_opt i.mt_doc); "params", encode_type_params i.mt_params; ] @ fields) @@ -916,7 +917,7 @@ and encode_efield f = "namePos", encode_pos f.ef_name_pos; "index", vint f.ef_index; "meta", encode_meta f.ef_meta (fun m -> f.ef_meta <- m); - "doc", null encode_string f.ef_doc; + "doc", null encode_string (get_own_doc_opt f.ef_doc); "params", encode_type_params f.ef_params; ] @@ -934,7 +935,7 @@ and encode_cfield f = "kind", encode_field_kind f.cf_kind; "pos", encode_pos f.cf_pos; "namePos",encode_pos f.cf_name_pos; - "doc", null encode_string f.cf_doc; + "doc", null encode_string (get_own_doc_opt f.cf_doc); "overloads", encode_ref f.cf_overloads (encode_and_map_array encode_cfield) (fun() -> "overloads"); "isExtern", vbool (has_class_field_flag f CfExtern); "isFinal", vbool (has_class_field_flag f CfFinal); @@ -1047,8 +1048,8 @@ and encode_abref ab = and encode_type t = let rec loop = function | TMono r -> - (match !r with - | None -> 0, [encode_ref r (fun r -> match !r with None -> vnull | Some t -> encode_type t) (fun() -> "")] + (match r.tm_type with + | None -> 0, [encode_ref r (fun r -> match r.tm_type with None -> vnull | Some t -> encode_type t) (fun() -> "")] | Some t -> loop t) | TEnum (e, pl) -> 1 , [encode_ref e encode_tenum (fun() -> s_type_path e.e_path); encode_tparams pl] @@ -1083,7 +1084,7 @@ and encode_type t = and encode_lazy_type t = let rec loop = function | TMono r -> - (match !r with + (match r.tm_type with | Some t -> loop t | _ -> encode_type t) | TLazy f -> @@ -1307,7 +1308,7 @@ let decode_cfield v = cf_type = decode_type (field v "type"); cf_pos = decode_pos (field v "pos"); cf_name_pos = decode_pos (field v "namePos"); - cf_doc = opt decode_string (field v "doc"); + cf_doc = decode_doc (field v "doc"); cf_meta = []; (* TODO *) cf_kind = decode_field_kind (field v "kind"); cf_params = decode_type_params (field v "params"); @@ -1329,7 +1330,7 @@ let decode_efield v = ef_name_pos = decode_pos (field v "namePos"); ef_index = decode_int (field v "index"); ef_meta = []; (* TODO *) - ef_doc = opt decode_string (field v "doc"); + ef_doc = decode_doc (field v "doc"); ef_params = decode_type_params (field v "params") } @@ -1413,7 +1414,7 @@ let decode_type_def v = let pos = decode_pos (field v "pos") in let isExtern = decode_opt_bool (field v "isExtern") in let fields = List.map decode_field (decode_array (field v "fields")) in - let doc = opt decode_string (field v "doc") in + let doc = decode_doc (field v "doc") in let mk fl dl = { d_name = name; @@ -1517,6 +1518,19 @@ let rec make_const e = let macro_api ccom get_api = [ + "contains_display_position", vfun1 (fun p -> + let p = decode_pos p in + let display_pos = DisplayPosition.display_position in + let same_file() = + let dfile = display_pos#get.pfile in + dfile = p.pfile + || ( + (Filename.is_relative p.pfile || Filename.is_relative dfile) + && (Path.UniqueKey.create dfile = Path.UniqueKey.create p.pfile) + ) + in + vbool (display_pos#enclosed_in p && same_file()) + ); "current_pos", vfun0 (fun() -> encode_pos (get_api()).pos ); @@ -1711,7 +1725,7 @@ let macro_api ccom get_api = vnull ); "setCurrentClass", vfun1 (fun c -> - Genjs.set_current_class js_ctx (match decode_type_decl c with TClassDecl c -> c | _ -> assert false); + Genjs.set_current_class js_ctx (match decode_type_decl c with TClassDecl c -> c | _ -> Globals.die "" __LOC__); vnull ); ] in @@ -1783,7 +1797,7 @@ let macro_api ccom get_api = let follow_once t = match t with | TMono r -> - (match !r with + (match r.tm_type with | None -> t | Some t -> t) | TAbstract (a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> @@ -1799,19 +1813,6 @@ let macro_api ccom get_api = ); "follow", vfun2 (fun v once -> let t = decode_type v in - let follow_once t = - match t with - | TMono r -> - (match !r with - | None -> t - | Some t -> t) - | TAbstract _ | TEnum _ | TInst _ | TFun _ | TAnon _ | TDynamic _ -> - t - | TType (t,tl) -> - apply_params t.t_params tl t.t_type - | TLazy f -> - lazy_type f - in encode_type (if decode_opt_bool once then follow_once t else follow t) ); "get_build_fields", vfun0 (fun() -> @@ -1927,7 +1928,7 @@ let macro_api ccom get_api = let cs = match CompilationServer.get() with Some cs -> cs | None -> failwith "compilation server not running" in List.iter (fun v -> let s = decode_string v in - let s = Path.unique_full_path s in + let s = Path.UniqueKey.create s in cs#taint_modules s; cs#remove_files s; ) (decode_array a); @@ -1964,6 +1965,18 @@ let macro_api ccom get_api = ); vnull ); + "timer", vfun1 (fun id -> + let full_id = (Option.default [] (Timer.current_id())) @ [decode_string id] in + let stop = Timer.timer full_id in + vfun0 (fun() -> stop(); vnull) + ); + "map_anon_ref", vfun2 (fun a_ref fn -> + let a = decode_ref a_ref + and fn = prepare_callback fn 1 in + match map (fun t -> decode_type (fn [encode_type t])) (TAnon a) with + | TAnon a -> encode_ref a encode_tanon (fun() -> "") + | _ -> Globals.die "" __LOC__ + ) ] diff --git a/src/optimization/analyzer.ml b/src/optimization/analyzer.ml index 90c65b6f0ceade3fdbb1cad5f9a68e4db95be1fb..14601e02f721d7d0d7d8a7687251239ac0b9d2dd 100644 --- a/src/optimization/analyzer.ml +++ b/src/optimization/analyzer.ml @@ -129,7 +129,7 @@ module Ssa = struct add_ssa_edge ctx.graph v' bb true i; {e with eexpr = TLocal v'} | _ -> - assert false + die "" __LOC__ ) el edge.cfg_to.bb_incoming in let ephi = {ecall with eexpr = TCall(ephi,el)} in set_var_value ctx.graph v0 bb true i; @@ -302,7 +302,7 @@ module DataFlow (M : DataFlowApi) = struct match e.eexpr with | TBinop(OpAssign,{eexpr = TLocal v},{eexpr = TCall({eexpr = TConst (TString "phi")},el)}) -> set_lattice_cell v (visit_phi bb v el) - | _ -> assert false + | _ -> die "" __LOC__ ) bb.bb_phi in let rec loop () = match !cfg_work_list,!ssa_work_list with @@ -517,7 +517,7 @@ end) (* Propagates local variables to other local variables. - Respects scopes on targets where it matters (all except JS and As3). + Respects scopes on targets where it matters (all except JS). *) module CopyPropagation = DataFlow(struct open BasicBlock @@ -1005,7 +1005,7 @@ module Run = struct in (try loop tf.tf_expr with Exit -> mk (TCall(e,[])) tf.tf_type e.epos) | _ -> - assert false + die "" __LOC__ end in e @@ -1081,7 +1081,7 @@ module Run = struct let e = run_on_expr actx e in let e = match e.eexpr with | TFunction tf -> tf.tf_expr - | _ -> assert false + | _ -> die "" __LOC__ in c.cl_init <- Some e end @@ -1098,9 +1098,9 @@ module Run = struct let com = ctx.Typecore.com in let config = get_base_config com in with_timer config.detail_times ["other"] (fun () -> - let cfl = if config.optimize && config.purity_inference then with_timer config.detail_times ["optimize";"purity-inference"] (fun () -> Purity.infer com) else [] in - List.iter (run_on_type ctx config) types; - List.iter (fun cf -> cf.cf_meta <- List.filter (fun (m,_,_) -> m <> Meta.Pure) cf.cf_meta) cfl + if config.optimize && config.purity_inference then + with_timer config.detail_times ["optimize";"purity-inference"] (fun () -> Purity.infer com); + List.iter (run_on_type ctx config) types ) end ;; diff --git a/src/optimization/analyzerConfig.ml b/src/optimization/analyzerConfig.ml index 1c11aeee5c58852c59d310e62f70485c85bf5464..c0e0a01f77c806c277ed496c367eb3cf49b34ee9 100644 --- a/src/optimization/analyzerConfig.ml +++ b/src/optimization/analyzerConfig.ml @@ -64,7 +64,7 @@ let is_ignored meta = let get_base_config com = { - optimize = Common.raw_defined com "analyzer-optimize"; + optimize = Common.defined com Define.AnalyzerOptimize; const_propagation = not (Common.raw_defined com "analyzer-no-const-propagation"); copy_propagation = not (Common.raw_defined com "analyzer-no-copy-propagation"); local_dce = not (Common.raw_defined com "analyzer-no-local-dce"); diff --git a/src/optimization/analyzerTexpr.ml b/src/optimization/analyzerTexpr.ml index db634382c9fb2d49c55292609afe1a2024a2dc88..389a338cc051516c28cee69bbdc112356903b1f9 100644 --- a/src/optimization/analyzerTexpr.ml +++ b/src/optimization/analyzerTexpr.ml @@ -154,14 +154,14 @@ let type_change_ok com t1 t2 = true else begin let rec map t = match t with - | TMono r -> (match !r with None -> t_dynamic | Some t -> map t) + | TMono r -> (match r.tm_type with None -> t_dynamic | Some t -> map t) | _ -> Type.map map t in let t1 = map t1 in let t2 = map t2 in let rec is_nullable_or_whatever = function | TMono r -> - (match !r with None -> false | Some t -> is_nullable_or_whatever t) + (match r.tm_type with None -> false | Some t -> is_nullable_or_whatever t) | TAbstract ({ a_path = ([],"Null") },[_]) -> true | TLazy f -> @@ -193,122 +193,6 @@ let dynarray_map f d = let dynarray_mapi f d = DynArray.iteri (fun i e -> DynArray.unsafe_set d i (f i e)) d -module TexprKindMapper = struct - type kind = - | KRead (* Expression is read. *) - | KAccess (* Structure of expression is accessed. *) - | KWrite (* Expression is lhs of =. *) - | KReadWrite (* Expression is lhs of += .*) - | KStore (* Expression is stored (via =, += or in array/object declaration). *) - | KEq (* Expression is lhs or rhs of == or != *) - | KEqNull (* Expression is lhs or rhs of == null or != null *) - | KCalled (* Expression is being called. *) - | KCallArgument (* Expression is call argument (leaves context). *) - | KReturn (* Expression is returned (leaves context). *) - | KThrow (* Expression is thrown (leaves context). *) - - let rec map kind f e = match e.eexpr with - | TConst _ - | TLocal _ - | TBreak - | TContinue - | TTypeExpr _ - | TIdent _ -> - e - | TArray(e1,e2) -> - let e1 = f KAccess e1 in - let e2 = f KRead e2 in - { e with eexpr = TArray (e1,e2) } - | TBinop(OpAssign,e1,e2) -> - let e1 = f KWrite e1 in - let e2 = f KStore e2 in - { e with eexpr = TBinop(OpAssign,e1,e2) } - | TBinop(OpAssignOp op,e1,e2) -> - let e1 = f KReadWrite e1 in - let e2 = f KStore e2 in - { e with eexpr = TBinop(OpAssignOp op,e1,e2) } - | TBinop((OpEq | OpNotEq) as op,e1,e2) -> - let e1,e2 = match (Texpr.skip e1).eexpr,(Texpr.skip e2).eexpr with - | TConst TNull,TConst TNull -> - let e1 = f KRead e1 in - let e2 = f KRead e2 in - e1,e2 - | TConst TNull,_ -> - let e1 = f KRead e1 in - let e2 = f KEqNull e2 in - e1,e2 - | _,TConst TNull -> - let e1 = f KEqNull e1 in - let e2 = f KRead e2 in - e1,e2 - | _ -> - let e1 = f KEq e1 in - let e2 = f KEq e2 in - e1,e2 - in - {e with eexpr = TBinop(op,e1,e2)} - | TBinop(op,e1,e2) -> - let e1 = f KRead e1 in - let e2 = f KRead e2 in - { e with eexpr = TBinop(op,e1,e2) } - | TFor (v,e1,e2) -> - let e1 = f KRead e1 in - { e with eexpr = TFor (v,e1,f KRead e2) } - | TWhile (e1,e2,flag) -> - let e1 = f KRead e1 in - { e with eexpr = TWhile (e1,f KRead e2,flag) } - | TThrow e1 -> - { e with eexpr = TThrow (f KThrow e1) } - | TEnumParameter (e1,ef,i) -> - { e with eexpr = TEnumParameter(f KAccess e1,ef,i) } - | TEnumIndex e1 -> - { e with eexpr = TEnumIndex (f KAccess e1) } - | TField (e1,v) -> - { e with eexpr = TField (f KAccess e1,v) } - | TParenthesis e1 -> - { e with eexpr = TParenthesis (f kind e1) } - | TUnop (op,pre,e1) -> - { e with eexpr = TUnop (op,pre,f KRead e1) } - | TArrayDecl el -> - { e with eexpr = TArrayDecl (List.map (f KStore) el) } - | TNew (t,pl,el) -> - { e with eexpr = TNew (t,pl,List.map (f KCallArgument) el) } - | TBlock el -> - let rec loop acc el = match el with - | [e] -> f kind e :: acc - | e1 :: el -> loop (f KRead e1 :: acc) el - | [] -> [] - in - let el = List.rev (loop [] el) in - { e with eexpr = TBlock el } - | TObjectDecl el -> - { e with eexpr = TObjectDecl (List.map (fun (v,e) -> v, f KStore e) el) } - | TCall (e1,el) -> - let e1 = f KCalled e1 in - { e with eexpr = TCall (e1, List.map (f KCallArgument) el) } - | TVar (v,eo) -> - { e with eexpr = TVar (v, match eo with None -> None | Some e -> Some (f KStore e)) } - | TFunction fu -> - { e with eexpr = TFunction { fu with tf_expr = f KRead fu.tf_expr } } - | TIf (ec,e1,e2) -> - let ec = f KRead ec in - let e1 = f kind e1 in - { e with eexpr = TIf (ec,e1,match e2 with None -> None | Some e -> Some (f kind e)) } - | TSwitch (e1,cases,def) -> - let e1 = f KRead e1 in - let cases = List.map (fun (el,e2) -> List.map (f KRead) el, f kind e2) cases in - { e with eexpr = TSwitch (e1, cases, match def with None -> None | Some e -> Some (f kind e)) } - | TTry (e1,catches) -> - let e1 = f kind e1 in - { e with eexpr = TTry (e1, List.map (fun (v,e) -> v, f kind e) catches) } - | TReturn eo -> - { e with eexpr = TReturn (match eo with None -> None | Some e -> Some (f KReturn e)) } - | TCast (e1,t) -> - { e with eexpr = TCast (f kind e1,t) } - | TMeta (m,e1) -> - {e with eexpr = TMeta(m,f kind e1)} -end - (* This module rewrites some expressions to reduce the amount of special cases for subsequent analysis. After analysis it restores some of these expressions back to their original form. @@ -638,8 +522,12 @@ module Fusion = struct let state = new fusion_state in state#infer_from_texpr e; (* Handles block-level expressions, e.g. by removing side-effect-free ones and recursing into compound constructs like - array or object declarations. The resulting element list is reversed. *) - let rec block_element acc el = match el with + array or object declarations. The resulting element list is reversed. + INFO: `el` is a reversed list of expressions in a block. + *) + let rec block_element ?(loop_bottom=false) acc el = match el with + | {eexpr = TBinop(OpAssign, { eexpr = TLocal v1 }, { eexpr = TLocal v2 })} :: el when v1 == v2 -> + block_element acc el | {eexpr = TBinop((OpAssign | OpAssignOp _),_,_) | TUnop((Increment | Decrement),_,_)} as e1 :: el -> block_element (e1 :: acc) el | {eexpr = TLocal _} as e1 :: el when not config.local_dce -> @@ -667,6 +555,11 @@ module Fusion = struct | Some e -> block_element acc (e :: el) end + | ({eexpr = TSwitch(e1,cases,def)} as e) :: el -> + begin match Optimizer.check_constant_switch e1 cases def with + | Some e -> block_element acc (e :: el) + | None -> block_element (e :: acc) el + end (* no-side-effect composites *) | {eexpr = TParenthesis e1 | TMeta(_,e1) | TCast(e1,None) | TField(e1,_) | TUnop(_,_,e1)} :: el -> block_element acc (e1 :: el) @@ -684,6 +577,8 @@ module Fusion = struct block_element acc (e1 :: el) | {eexpr = TBlock []} :: el -> block_element acc el + | { eexpr = TContinue } :: el when loop_bottom -> + block_element [] el | e1 :: el -> block_element (e1 :: acc) el | [] -> @@ -698,7 +593,10 @@ module Fusion = struct let b = num_uses <= 1 && num_writes = 0 && can_be_used_as_value && - not (ExtType.has_variable_semantics v.v_type) && + not ( + ExtType.has_variable_semantics v.v_type && + (match e.eexpr with TLocal { v_kind = VUser _ } -> false | _ -> true) + ) && (is_compiler_generated || config.optimize && config.fusion && config.user_var_fusion && not has_type_params) in if config.fusion_debug then begin @@ -738,7 +636,7 @@ module Fusion = struct in let e,_ = map_values check_assign e1 in let e = match !e' with - | None -> assert false + | None -> die "" __LOC__ | Some(e1,f) -> begin match e1.eexpr with | TLocal v -> state#change_writes v (- !i + 1) @@ -1042,31 +940,35 @@ module Fusion = struct acc in let rec loop e = match e.eexpr with + | TWhile(condition,{ eexpr = TBlock el; etype = t; epos = p },flag) -> + let condition = loop condition + and body = block true el t p in + { e with eexpr = TWhile(condition,body,flag) } | TBlock el -> - let el = List.rev_map loop el in - let el = block_element [] el in - (* fuse flips element order, but block_element doesn't care and flips it back *) - let el = fuse [] el in - let el = block_element [] el in - let rec fuse_loop el = - state#reset; - let el = fuse [] el in - let el = block_element [] el in - if state#did_change then fuse_loop el else el - in - let el = fuse_loop el in - {e with eexpr = TBlock el} + block false el e.etype e.epos | TCall({eexpr = TIdent s},_) when is_really_unbound s -> e | _ -> Type.map_expr loop e + and block loop_body el t p = + let el = List.rev_map loop el in + let el = block_element ~loop_bottom:loop_body [] el in + (* fuse flips element order, but block_element doesn't care and flips it back *) + let el = fuse [] el in + let el = block_element [] el in + let rec fuse_loop el = + state#reset; + let el = fuse [] el in + let el = block_element [] el in + if state#did_change then fuse_loop el else el + in + let el = fuse_loop el in + mk (TBlock el) t p in loop e end module Cleanup = struct - open TexprKindMapper - let apply com e = let if_or_op e e1 e2 e3 = match (Texpr.skip e1).eexpr,(Texpr.skip e3).eexpr with | TUnop(Not,Prefix,e1),TConst (TBool true) -> optimize_binop {e with eexpr = TBinop(OpBoolOr,e1,e2)} OpBoolOr e1 e2 @@ -1133,15 +1035,7 @@ module Cleanup = struct | _ -> Type.map_expr loop e in - let e = loop e in - let rec loop kind e = match kind,e.eexpr with - | KEqNull,TField(e1,FClosure(Some(c,tl),cf)) -> - let e1 = loop KAccess e1 in - {e with eexpr = TField(e1,FInstance(c,tl,cf))} - | _ -> - TexprKindMapper.map kind loop e - in - TexprKindMapper.map KRead loop e + loop e end module Purity = struct @@ -1196,7 +1090,7 @@ module Purity = struct taint node; raise Exit - let apply_to_field com is_ctor c cf = + let apply_to_field com is_ctor is_static c cf = let node = get_node c cf in let check_field c cf = let node' = get_node c cf in @@ -1216,8 +1110,9 @@ module Purity = struct taint_raise node end and loop e = match e.eexpr with - | TMeta((Meta.Pure,_,_),_) -> - () + | TMeta((Meta.Pure,_,_) as m,_) -> + if get_purity_from_meta [m] = Impure then taint_raise node + else () | TThrow _ -> taint_raise node; | TBinop((OpAssign | OpAssignOp _),e1,e2) -> @@ -1252,6 +1147,8 @@ module Purity = struct match cf.cf_kind with | Method MethDynamic | Var _ -> taint node; + | Method MethNormal when not (is_static || is_ctor || has_class_field_flag cf CfFinal) -> + taint node | _ -> match cf.cf_expr with | None -> @@ -1270,9 +1167,9 @@ module Purity = struct () let apply_to_class com c = - List.iter (apply_to_field com false c) c.cl_ordered_fields; - List.iter (apply_to_field com false c) c.cl_ordered_statics; - (match c.cl_constructor with Some cf -> apply_to_field com true c cf | None -> ()) + List.iter (apply_to_field com false false c) c.cl_ordered_fields; + List.iter (apply_to_field com false true c) c.cl_ordered_statics; + (match c.cl_constructor with Some cf -> apply_to_field com true false c cf | None -> ()) let infer com = Hashtbl.clear node_lut; @@ -1286,12 +1183,10 @@ module Purity = struct end | _ -> () ) com.types; - Hashtbl.fold (fun _ node acc -> + Hashtbl.iter (fun _ node -> match node.pn_purity with - | Pure | MaybePure -> - node.pn_field.cf_meta <- (Meta.Pure,[EConst(Ident "true"),node.pn_field.cf_pos],node.pn_field.cf_pos) :: node.pn_field.cf_meta; - node.pn_field :: acc - | _ -> - acc - ) node_lut []; + | Pure | MaybePure when not (List.exists (fun (m,_,_) -> m = Meta.Pure) node.pn_field.cf_meta) -> + node.pn_field.cf_meta <- (Meta.Pure,[EConst(Ident "true"),node.pn_field.cf_pos],node.pn_field.cf_pos) :: node.pn_field.cf_meta + | _ -> () + ) node_lut; end diff --git a/src/optimization/analyzerTexprTransformer.ml b/src/optimization/analyzerTexprTransformer.ml index 81433348dfbe2bcfdd277b3b5c5efc9e8d0c97d7..ccc7f58d5eb2a87c15615fb1043dedbba439f8c7 100644 --- a/src/optimization/analyzerTexprTransformer.ml +++ b/src/optimization/analyzerTexprTransformer.ml @@ -120,7 +120,7 @@ let rec func ctx bb tf t p = | TBinop(op,e1,e2) -> let bb,e1,e2 = match ordered_value_list bb [e1;e2] with | bb,[e1;e2] -> bb,e1,e2 - | _ -> assert false + | _ -> die "" __LOC__ in bb,{e with eexpr = TBinop(op,e1,e2)} | TUnop(op,flag,e1) -> @@ -141,7 +141,7 @@ let rec func ctx bb tf t p = | TArray(e1,e2) -> let bb,e1,e2 = match ordered_value_list bb [e1;e2] with | bb,[e1;e2] -> bb,e1,e2 - | _ -> assert false + | _ -> die "" __LOC__ in bb,{e with eexpr = TArray(e1,e2)} | TMeta(m,e1) -> @@ -257,7 +257,7 @@ let rec func ctx bb tf t p = if bb == g.g_unreachable then raise Exit; loop2 bb el | [] -> - assert false + die "" __LOC__ in let bb,e = loop2 bb el in loop bb e @@ -319,7 +319,7 @@ let rec func ctx bb tf t p = let bb,el = ordered_value_list !bb (e1 :: el) in match el with | e1 :: el -> bb,{e with eexpr = TCall(e1,el)} - | _ -> assert false + | _ -> die "" __LOC__ and array_assign_op bb op e ea e1 e2 e3 = let bb,e1 = bind_to_temp bb false e1 in let bb,e2 = bind_to_temp bb false e2 in @@ -540,7 +540,7 @@ let rec func ctx bb tf t p = | TContinue -> begin match !bb_continue with | Some bb_continue -> add_cfg_edge bb bb_continue CFGGoto - | _ -> assert false + | _ -> die "" __LOC__ end; add_terminator bb e | TThrow e1 -> @@ -583,7 +583,7 @@ let rec func ctx bb tf t p = | TBinop(OpAssign,({eexpr = TArray(e1,e2)} as ea),e3) -> let bb,e1,e2,e3 = match ordered_value_list bb [e1;e2;e3] with | bb,[e1;e2;e3] -> bb,e1,e2,e3 - | _ -> assert false + | _ -> die "" __LOC__ in add_texpr bb {e with eexpr = TBinop(OpAssign,{ea with eexpr = TArray(e1,e2)},e3)}; bb @@ -617,7 +617,7 @@ let rec func ctx bb tf t p = | TObjectDecl fl -> block_el bb (List.map snd fl) | TFor _ | TWhile(_,_,DoWhile) -> - assert false + die "" __LOC__ and block_el bb el = match !b_try_stack with | [] -> @@ -739,7 +739,7 @@ and func ctx i = let op = match op with | OpAdd -> Increment | OpSub -> Decrement - | _ -> assert false + | _ -> die "" __LOC__ in {e with eexpr = TUnop(op,Prefix,e1)} | _ -> {e with eexpr = TBinop(OpAssignOp op,e1,e3)} diff --git a/src/optimization/analyzerTypes.ml b/src/optimization/analyzerTypes.ml index 7028e59f74dc8f694830411ecb810ef77725a0ba..ed2df6f46e7741de60dc55904b5c093fedf7c962 100644 --- a/src/optimization/analyzerTypes.ml +++ b/src/optimization/analyzerTypes.ml @@ -241,7 +241,7 @@ module Graph = struct in match (get_texpr bb is_phi i).eexpr with | TVar(_,Some e) | TBinop(OpAssign,_,e) -> e - | _ -> assert false + | _ -> die "" __LOC__ let add_var_origin g v v_origin = (get_var_info g v).vi_origin <- v_origin @@ -381,7 +381,7 @@ module Graph = struct (bbi_desc,bbi.semi) ) (a,a.label.semi) worklist) | [] -> - assert false + die "" __LOC__ in let eval v = let bbi = get_info v in @@ -393,7 +393,7 @@ module Graph = struct in let rec loop nodes' = match nodes' with | [_] -> () - | [] -> assert false + | [] -> die "" __LOC__ | w :: nodes' -> let semi = List.fold_left (fun acc v -> min acc (eval v.cfg_from.bb_id).semi) w.semi w.bb.bb_incoming diff --git a/src/optimization/dce.ml b/src/optimization/dce.ml index d1d8374dfdb67b674f93ff6d7d387c28c0d8a72b..e199f038c0848334099e88fa656d31ec35206c07 100644 --- a/src/optimization/dce.ml +++ b/src/optimization/dce.ml @@ -97,6 +97,12 @@ let keep_whole_enum dce en = Meta.has_one_of keep_metas en.e_meta || not (dce.full || is_std_file dce en.e_module.m_extra.m_file || has_meta Meta.Dce en.e_meta) +let mk_used_meta pos = + Meta.Used,[],(mk_zero_range_pos pos) + +let mk_keep_meta pos = + Meta.Keep,[],(mk_zero_range_pos pos) + (* Check if a field is kept. `keep_field` is checked to determine the DCE entry points, i.e. all fields that have `@:keep` or kept for other reasons. @@ -105,7 +111,7 @@ let keep_whole_enum dce en = let rec keep_field dce cf c is_static = Meta.has_one_of (Meta.Used :: keep_metas) cf.cf_meta || cf.cf_name = "__init__" - || not (is_physical_field cf) + || has_class_field_flag cf CfExtern || (not is_static && overrides_extern_field cf c) || ( cf.cf_name = "new" @@ -148,7 +154,7 @@ and check_and_add_feature dce s = and mark_field dce c cf stat = let add cf = if not (Meta.has Meta.Used cf.cf_meta) then begin - cf.cf_meta <- (Meta.Used,[],cf.cf_pos) :: cf.cf_meta; + cf.cf_meta <- (mk_used_meta cf.cf_pos) :: cf.cf_meta; dce.added_fields <- (c,cf,stat) :: dce.added_fields; dce.marked_fields <- cf :: dce.marked_fields; check_feature dce (Printf.sprintf "%s.%s" (s_type_path c.cl_path) cf.cf_name); @@ -195,13 +201,13 @@ let rec update_marked_class_fields dce c = (* mark a class as kept. If the class has fields marked as @:?keep, make sure to keep them *) and mark_class dce c = if not (Meta.has Meta.Used c.cl_meta) then begin - c.cl_meta <- (Meta.Used,[],c.cl_pos) :: c.cl_meta; + c.cl_meta <- (mk_used_meta c.cl_pos) :: c.cl_meta; check_feature dce (Printf.sprintf "%s.*" (s_type_path c.cl_path)); update_marked_class_fields dce c; end let rec mark_enum dce e = if not (Meta.has Meta.Used e.e_meta) then begin - e.e_meta <- (Meta.Used,[],e.e_pos) :: e.e_meta; + e.e_meta <- (mk_used_meta e.e_pos) :: e.e_meta; check_and_add_feature dce "has_enum"; check_feature dce (Printf.sprintf "%s.*" (s_type_path e.e_path)); PMap.iter (fun _ ef -> mark_t dce ef.ef_pos ef.ef_type) e.e_constrs; @@ -209,7 +215,7 @@ end and mark_abstract dce a = if not (Meta.has Meta.Used a.a_meta) then begin check_feature dce (Printf.sprintf "%s.*" (s_type_path a.a_path)); - a.a_meta <- (Meta.Used,[],a.a_pos) :: a.a_meta + a.a_meta <- (mk_used_meta a.a_pos) :: a.a_meta end (* mark a type as kept *) @@ -219,7 +225,7 @@ and mark_t dce p t = begin match follow t with | TInst({cl_kind = KTypeParameter tl} as c,pl) -> if not (Meta.has Meta.Used c.cl_meta) then begin - c.cl_meta <- (Meta.Used,[],c.cl_pos) :: c.cl_meta; + c.cl_meta <- (mk_used_meta c.cl_pos) :: c.cl_meta; List.iter (mark_t dce p) tl; end; List.iter (mark_t dce p) pl @@ -301,7 +307,7 @@ let rec to_string dce t = match t with else to_string dce (Abstract.get_underlying_type a tl) | TMono r -> - (match !r with + (match r.tm_type with | Some t -> to_string dce t | _ -> ()) | TLazy f -> @@ -437,6 +443,9 @@ and expr_field dce e fa is_call_expr = | FDynamic _ -> check_and_add_feature dce "dynamic_read"; check_and_add_feature dce ("dynamic_read." ^ n); + | FClosure _ -> + check_and_add_feature dce "closure_read"; + check_and_add_feature dce ("closure_read." ^ n); | _ -> ()); begin match follow e.etype, fa with | TInst(c,_), _ @@ -779,7 +788,7 @@ let sweep dce com = end; in (* add :keep so subsequent filter calls do not process class fields again *) - c.cl_meta <- (Meta.Keep,[],c.cl_pos) :: c.cl_meta; + c.cl_meta <- (mk_keep_meta c.cl_pos) :: c.cl_meta; c.cl_ordered_statics <- List.filter (fun cf -> let b = keep_field dce cf c true in if not b then begin @@ -830,7 +839,7 @@ let run com main mode = com = com; full = full; dependent_types = Hashtbl.create 0; - std_dirs = if full then [] else List.map Path.unique_full_path com.std_path; + std_dirs = if full then [] else List.map Path.get_full_path com.std_path; debug = Common.defined com Define.DceDebug; added_fields = []; follow_expr = expr; @@ -843,7 +852,7 @@ let run com main mode = } in begin match main with | Some {eexpr = TCall({eexpr = TField(e,(FStatic(c,cf)))},_)} | Some {eexpr = TBlock ({ eexpr = TCall({eexpr = TField(e,(FStatic(c,cf)))},_)} :: _)} -> - cf.cf_meta <- (Meta.Keep,[],cf.cf_pos) :: cf.cf_meta + cf.cf_meta <- (mk_keep_meta cf.cf_pos) :: cf.cf_meta | _ -> () end; diff --git a/src/optimization/inline.ml b/src/optimization/inline.ml index 21d157fd3dd3db0d885346d3544727acab794bfe..b2d9ad8c35f81c13b325f7e7e13bd45226927ed2 100644 --- a/src/optimization/inline.ml +++ b/src/optimization/inline.ml @@ -108,7 +108,7 @@ let api_inline2 com c field params p = let api_inline ctx c field params p = let mk_typeexpr path = - let m = (try Hashtbl.find ctx.g.modules path with Not_found -> assert false) in + let m = (try Hashtbl.find ctx.g.modules path with Not_found -> die "" __LOC__) in add_dependency ctx.m.curmod m; ExtList.List.find_map (function | TClassDecl cl when cl.cl_path = path -> Some (make_static_this cl p) @@ -124,7 +124,7 @@ let api_inline ctx c field params p = let tint = ctx.com.basic.tint in match c.cl_path, field, params with - | ([],"Std"),"is",[o;t] | (["js"],"Boot"),"__instanceof",[o;t] when ctx.com.platform = Js -> + | ([],"Std"),("is" | "isOfType"),[o;t] | (["js"],"Boot"),"__instanceof",[o;t] when ctx.com.platform = Js -> let is_trivial e = match e.eexpr with | TConst _ | TLocal _ -> true @@ -136,7 +136,12 @@ let api_inline ctx c field params p = mk (TBinop (Ast.OpEq, tof, (mk (TConst (TString t)) tstring p))) tbool p in - (match t.eexpr with + let rec skip_cast = function + | { eexpr = TCast (e, None) } -> skip_cast e + | e -> e + in + + (match (skip_cast t).eexpr with (* generate simple typeof checks for basic types *) | TTypeExpr (TClassDecl ({ cl_path = [],"String" })) -> Some (typeof "string") | TTypeExpr (TAbstractDecl ({ a_path = [],"Bool" })) -> Some (typeof "boolean") @@ -152,8 +157,8 @@ let api_inline ctx c field params p = if not (Common.defined ctx.com Define.JsEnumsAsArrays) then Some iof else begin - let enum = mk (TField (o, FDynamic "__enum__")) (mk_mono()) p in - let null = mk (TConst TNull) (mk_mono()) p in + let enum = mk (TField (o, FDynamic "__enum__")) t_dynamic p in + let null = mk (TConst TNull) t_dynamic p in let not_enum = mk (TBinop (Ast.OpEq, enum, null)) tbool p in Some (mk (TBinop (Ast.OpBoolAnd, iof, not_enum)) tbool p) end @@ -189,7 +194,7 @@ let api_inline ctx c field params p = TInst(cl,[t]) | TInst({ cl_path = [],"Array" }, [t]), TAbstractDecl(a) -> TAbstract(a,[t]) - | _ -> assert false + | _ -> die "" __LOC__ in Some ({ (mk_untyped_call "__array__" p args) with etype = t }) with | Exit -> @@ -223,7 +228,7 @@ let inline_default_config cf t = | Some (csup,spl) -> let spl = (match apply_params c.cl_params pl (TInst (csup,spl)) with | TInst (_,pl) -> pl - | _ -> assert false + | _ -> die "" __LOC__ ) in let ct, cpl = get_params csup spl in c.cl_params @ ct, pl @ cpl @@ -239,6 +244,28 @@ let inline_default_config cf t = let tparams = fst tparams @ cf.cf_params in tparams <> [], apply_params tparams tmonos +let inline_config cls_opt cf call_args return_type = + match cls_opt with + | Some ({cl_kind = KAbstractImpl _}) when Meta.has Meta.Impl cf.cf_meta -> + let t = if cf.cf_name = "_new" then + return_type + else if call_args = [] then + error "Invalid abstract implementation function" cf.cf_pos + else + follow (List.hd call_args).etype + in + begin match t with + | TAbstract(a,pl) -> + let has_params = a.a_params <> [] || cf.cf_params <> [] in + let monos = List.map (fun _ -> mk_mono()) cf.cf_params in + let map_type = fun t -> apply_params a.a_params pl (apply_params cf.cf_params monos t) in + Some (has_params,map_type) + | _ -> + None + end + | _ -> + None + let inline_metadata e meta = let inline_meta e meta = match meta with | (Meta.Deprecated | Meta.Pure),_,_ -> mk (TMeta(meta,e)) e.etype e.epos @@ -407,10 +434,12 @@ class inline_state ctx ethis params cf f p = object(self) let dynamic_e = follow e.etype == t_dynamic in let e = if dynamic_v <> dynamic_e then mk (TCast(e,None)) v.v_type e.epos else e in let e = match e.eexpr, opt with - | TConst TNull , Some c -> c + | TConst TNull , Some c -> + (* issue #9357 *) + {c with epos = e.epos} | _ , Some c when (match c.eexpr with TConst TNull -> false | _ -> true) && (not ctx.com.config.pf_static || is_nullable v.v_type) -> l.i_force_temp <- true; - l.i_default_value <- Some c; + l.i_default_value <- Some {c with epos = e.epos}; e | _ -> e in @@ -477,6 +506,17 @@ class inline_state ctx ethis params cf f p = object(self) with Not_found -> e end + (* + This case is a hack for https://github.com/HaxeFoundation/haxe/issues/9355 + on top of a hack for https://github.com/HaxeFoundation/haxe/issues/2401 + *) + | TCall({eexpr = TField(_,FStatic({cl_path=[],"Std"},{cf_name = "string"}))} as e1,[e2]) -> + let e2' = inline_params true false e2 in + let e2' = + if fast_eq (follow e2.etype) (follow e2'.etype) then e2' + else {e2 with eexpr = TCast (e2',None) } + in + {e with eexpr = TCall(e1,[e2'])} | TCall(e1,el) -> let e1 = inline_params true false e1 in let el = List.map (inline_params false false) el in @@ -485,6 +525,8 @@ class inline_state ctx ethis params cf f p = object(self) let e1 = inline_params false true e1 in let e2 = inline_params false false e2 in {e with eexpr = TBinop(op,e1,e2)} + | TUnop((Increment | Decrement) as op,flag,e1) -> + {e with eexpr = TUnop(op,flag,inline_params false true e1)} | _ -> Type.map_expr (inline_params false false) e in let e = (if PMap.is_empty subst then e else inline_params false false e) in @@ -580,7 +622,7 @@ class inline_state ctx ethis params cf f p = object(self) | TVar (v, Some { eexpr = TConst _ }) -> (try let data = Hashtbl.find locals v.v_id in - if data.i_read = 0 && not data.i_write then mk (TBlock []) e.etype e.epos + if data.i_read = 0 && data.i_called = 0 && not data.i_write then mk (TBlock []) e.etype e.epos else Type.map_expr drop_unused_vars e with Not_found -> Type.map_expr drop_unused_vars e @@ -711,7 +753,7 @@ let rec type_inline ctx cf f ethis params tret config p ?(self_calling_closure=f if term then t := e.etype; [e] | ({ eexpr = TIf (cond,e1,None) } as e) :: l when term && has_term_return e1 -> - loop [{ e with eexpr = TIf (cond,e1,Some (mk (TBlock l) e.etype e.epos)); epos = punion e.epos (match List.rev l with e :: _ -> e.epos | [] -> assert false) }] + loop [{ e with eexpr = TIf (cond,e1,Some (mk (TBlock l) e.etype e.epos)); epos = punion e.epos (match List.rev l with e :: _ -> e.epos | [] -> die "" __LOC__) }] | e :: l -> let e = map false false e in e :: loop l diff --git a/src/optimization/inlineConstructors.ml b/src/optimization/inlineConstructors.ml index 27f73bff100c6193e0888013bb679c96d999fef2..4f623ae6c88d5c943003d8685e4eb6863c85fb5a 100644 --- a/src/optimization/inlineConstructors.ml +++ b/src/optimization/inlineConstructors.ml @@ -421,7 +421,7 @@ let inline_constructors ctx e = | None -> let rve = make_expr_for_rev_list rvel rve.etype rve.epos in begin match lvel with - | [] -> assert false + | [] -> die "" __LOC__ | e::el -> let e = mk (TBinop(OpAssign, e, rve)) e.etype e.epos in (e::el), None diff --git a/src/optimization/optimizer.ml b/src/optimization/optimizer.ml index c7ae725285951abe4557fb350b809a9aecc96236..cd73d52c7903468ec2a3dc95692b015b89d1b558 100644 --- a/src/optimization/optimizer.ml +++ b/src/optimization/optimizer.ml @@ -133,6 +133,9 @@ let sanitize_expr com e = let e1 = if loop e1 true then parent e1 else e1 in let e2 = if loop e2 false then parent e2 else e2 in { e with eexpr = TBinop (op,e1,e2) } + | TUnop (Not,Prefix,{ eexpr = (TUnop (Not,Prefix,e1)) | (TParenthesis { eexpr = TUnop (Not,Prefix,e1) }) }) + when ExtType.is_bool (Abstract.follow_with_abstracts_without_null e1.etype) -> + e1 | TUnop (op,mode,e1) -> let rec loop ee = match ee.eexpr with @@ -157,7 +160,13 @@ let sanitize_expr com e = { e with eexpr = TFor (v,e1,e2) } | TFunction f -> let f = (match f.tf_expr.eexpr with - | TBlock _ -> f + | TBlock exprs -> + if ExtType.is_void (follow f.tf_type) then + match List.rev exprs with + | { eexpr = TReturn None } :: rest -> { f with tf_expr = { f.tf_expr with eexpr = TBlock (List.rev rest) } } + | _ -> f + else + f | _ -> { f with tf_expr = block f.tf_expr } ) in { e with eexpr = TFunction f } @@ -228,6 +237,23 @@ let check_enum_construction_args el i = ) (true,0) el in b +let check_constant_switch e1 cases def = + let rec loop e1 cases = match cases with + | (el,e) :: cases -> + if List.exists (Texpr.equal e1) el then Some e + else loop e1 cases + | [] -> + begin match def with + | None -> None + | Some e -> Some e + end + in + match Texpr.skip e1 with + | {eexpr = TConst ct} as e1 when (match ct with TSuper | TThis -> false | _ -> true) -> + loop e1 cases + | _ -> + None + let reduce_control_flow ctx e = match e.eexpr with | TIf ({ eexpr = TConst (TBool t) },e1,e2) -> (if t then e1 else match e2 with None -> { e with eexpr = TBlock [] } | Some e -> e) @@ -236,23 +262,10 @@ let reduce_control_flow ctx e = match e.eexpr with | NormalWhile -> { e with eexpr = TBlock [] } (* erase sub *) | DoWhile -> e) (* we cant remove while since sub can contain continue/break *) | TSwitch (e1,cases,def) -> - let e = match Texpr.skip e1 with - | {eexpr = TConst ct} as e1 when (match ct with TSuper | TThis -> false | _ -> true) -> - let rec loop cases = match cases with - | (el,e) :: cases -> - if List.exists (Texpr.equal e1) el then e - else loop cases - | [] -> - begin match def with - | None -> e - | Some e -> e - end - in - loop cases - | _ -> - e - in - e + begin match check_constant_switch e1 cases def with + | Some e -> e + | None -> e + end | TBinop (op,e1,e2) -> optimize_binop e op e1 e2 | TUnop (op,flag,esub) -> @@ -264,6 +277,15 @@ let reduce_control_flow ctx e = match e.eexpr with | TEnumParameter({eexpr = TParenthesis {eexpr = TCall({eexpr = TField(_,FEnum(_,ef1))},el)}},ef2,i) when ef1 == ef2 && check_enum_construction_args el i -> (try List.nth el i with Failure _ -> e) + | TCast(e1,None) -> + (* TODO: figure out what's wrong with these targets *) + let require_cast = match ctx.com.platform with + | Cpp | Flash -> true + | Java -> defined ctx.com Define.Jvm + | Cs -> defined ctx.com Define.EraseGenerics || defined ctx.com Define.FastCast + | _ -> false + in + Texpr.reduce_unsafe_casts ~require_cast e e.etype | _ -> e @@ -277,16 +299,17 @@ let rec reduce_loop ctx e = | { eexpr = TFunction func } as ef -> let cf = mk_field "" ef.etype e.epos null_pos in let ethis = mk (TConst TThis) t_dynamic e.epos in - let rt = (match follow ef.etype with TFun (_,rt) -> rt | _ -> assert false) in + let rt = (match follow ef.etype with TFun (_,rt) -> rt | _ -> die "" __LOC__) in let inl = (try type_inline ctx cf func ethis el rt None e.epos ~self_calling_closure:true false with Error (Custom _,_) -> None) in (match inl with | None -> reduce_expr ctx e | Some e -> reduce_loop ctx e) - | {eexpr = TField(ef,(FStatic(_,cf) | FInstance(_,_,cf)))} when cf.cf_kind = Method MethInline && not (rec_stack_memq cf inline_stack) -> + | {eexpr = TField(ef,(FStatic(cl,cf) | FInstance(cl,_,cf)))} when cf.cf_kind = Method MethInline && not (rec_stack_memq cf inline_stack) -> begin match cf.cf_expr with | Some {eexpr = TFunction tf} -> - let rt = (match follow e1.etype with TFun (_,rt) -> rt | _ -> assert false) in - let inl = (try type_inline ctx cf tf ef el rt None e.epos false with Error (Custom _,_) -> None) in + let config = inline_config (Some cl) cf el e.etype in + let rt = (match follow e1.etype with TFun (_,rt) -> rt | _ -> die "" __LOC__) in + let inl = (try type_inline ctx cf tf ef el rt config e.epos false with Error (Custom _,_) -> None) in (match inl with | None -> reduce_expr ctx e | Some e -> @@ -746,12 +769,12 @@ let optimize_completion_expr e args = (ESwitch (e,cases,def),p) | ETry (et,cl) -> let et = loop et in - let cl = List.map (fun ((n,pn),(t,pt),e,p) -> + let cl = List.map (fun ((n,pn),th,e,p) -> let old = save() in - decl n (Some t) None; + decl n (Option.map fst th) None; let e = loop e in old(); - (n,pn), (t,pt), e, p + (n,pn), th, e, p ) cl in (ETry (et,cl),p) | ECall(e1,el) when DisplayPosition.display_position#enclosed_in p -> diff --git a/src/optimization/optimizerTexpr.ml b/src/optimization/optimizerTexpr.ml index 96977ff04e29e9bd4e08ccb6652586d0ac626e1d..027530289cb8f007c11f7b3acc89e5284d433d05 100644 --- a/src/optimization/optimizerTexpr.ml +++ b/src/optimization/optimizerTexpr.ml @@ -52,6 +52,7 @@ let create_affection_checker () = let rec might_be_affected e = let rec loop e = match e.eexpr with | TConst _ | TFunction _ | TTypeExpr _ -> () + | TLocal {v_capture = true} -> raise Exit | TLocal v when Hashtbl.mem modified_locals v.v_id -> raise Exit | TField(e1,fa) when not (is_read_only_field_access e1 fa) -> raise Exit | TCall _ | TNew _ -> raise Exit @@ -149,12 +150,12 @@ let optimize_binop e op e1 e2 = let fa = (match ca with | TFloat a -> float_of_string a | TInt a -> Int32.to_float a - | _ -> assert false + | _ -> die "" __LOC__ ) in let fb = (match cb with | TFloat b -> float_of_string b | TInt b -> Int32.to_float b - | _ -> assert false + | _ -> die "" __LOC__ ) in let fop op = check_float op fa fb in let ebool t = @@ -206,11 +207,16 @@ let optimize_binop e op e1 e2 = | OpEq -> { e with eexpr = TConst (TBool (f1 == f2)) } | OpNotEq -> { e with eexpr = TConst (TBool (f1 != f2)) } | _ -> e) - | _, TCall ({ eexpr = TField (_,FEnum _) },_) | TCall ({ eexpr = TField (_,FEnum _) },_), _ -> - (match op with - | OpAssign -> e + | e1, TCall ({ eexpr = TField (_,FEnum _) },el) | TCall ({ eexpr = TField (_,FEnum _) },el),e1 -> + begin match op,e1 with + | (OpEq | OpNotEq),TConst TNull -> + let e0 = {e with eexpr = TConst (TBool (op = OpNotEq))} in + {e with eexpr = TBlock (el @ [e0])} + | OpAssign,_ -> + e | _ -> - error "You cannot directly compare enums with arguments. Use either `switch`, `match` or `Type.enumEq`" e.epos) + error "You cannot directly compare enums with arguments. Use either `switch`, `match` or `Type.enumEq`" e.epos + end | _ -> e) diff --git a/src/syntax/dune b/src/syntax/dune new file mode 100644 index 0000000000000000000000000000000000000000..53619bb2e799886df1550dc44b05eaea80bcf58f --- /dev/null +++ b/src/syntax/dune @@ -0,0 +1,5 @@ +(rule + (targets grammar.ml) + (deps grammar.mly) + (action (run %{bin:camlp5o} -impl grammar.mly -o %{targets})) +) \ No newline at end of file diff --git a/src/syntax/grammar.mly b/src/syntax/grammar.mly index 9a5e3b8950003a95aeb462cc61f8ca7519e04b29..8fc2976e14ef3686c19333cee52f2b183eb08094 100644 --- a/src/syntax/grammar.mly +++ b/src/syntax/grammar.mly @@ -114,21 +114,18 @@ let rec parse_file s = | [< '(Kwd Package,_); pack = parse_package; s >] -> begin match s with parser | [< '(Const(Ident _),p) when pack = [] >] -> error (Custom "Package name must start with a lowercase character") p - | [< psem = semicolon; l = parse_type_decls TCAfterImport psem.pmax pack []; '(Eof,_) >] -> pack , l + | [< psem = semicolon; l = parse_type_decls TCAfterImport psem.pmax pack [] >] -> pack , l end - | [< l = parse_type_decls TCBeforePackage (-1) [] []; '(Eof,_) >] -> [] , l + | [< l = parse_type_decls TCBeforePackage (-1) [] [] >] -> [] , l and parse_type_decls mode pmax pack acc s = - try - check_type_decl_completion mode pmax s; - match s with parser - | [< (v,p) = parse_type_decl mode >] -> - let mode = match v with - | EImport _ | EUsing _ -> TCAfterImport - | _ -> TCAfterType - in - parse_type_decls mode p.pmax pack ((v,p) :: acc) s - | [< >] -> List.rev acc + check_type_decl_completion mode pmax s; + let result = try + begin match s with parser + | [< cff = parse_type_decl mode >] -> Success cff + | [< '(Eof,p) >] -> End p + | [< >] -> Error "" + end with | TypePath ([],Some (name,false),b,p) -> (* resolve imports *) @@ -142,6 +139,18 @@ and parse_type_decls mode pmax pack acc s = ) acc; raise (TypePath (pack,Some(name,true),b,p)) | Stream.Error msg when !in_display_file -> + Error msg + in + match result with + | Success (td,p) -> + let mode = match td with + | EImport _ | EUsing _ -> TCAfterImport + | _ -> TCAfterType + in + parse_type_decls mode p.pmax pack ((td,p) :: acc) s + | End _ -> + List.rev acc + | Error msg -> handle_stream_error msg s; ignore(resume false false s); parse_type_decls mode (last_pos s).pmax pack acc s @@ -150,13 +159,13 @@ and parse_abstract doc meta flags = parser | [< '(Kwd Abstract,p1); name = type_name; tl = parse_constraint_params; st = parse_abstract_subtype; sl = plist parse_abstract_relations; s >] -> let fl,p2 = match s with parser | [< '(BrOpen,_); fl, p2 = parse_class_fields false p1 >] -> fl,p2 - | [< >] -> syntax_error (Expected ["{"]) s ([],last_pos s) + | [< >] -> syntax_error (Expected ["{";"to";"from"]) s ([],last_pos s) in let flags = List.map decl_flag_to_abstract_flag flags in let flags = (match st with None -> flags | Some t -> AbOver t :: flags) in ({ d_name = name; - d_doc = doc; + d_doc = doc_from_string_opt doc; d_meta = meta; d_params = tl; d_flags = flags @ sl; @@ -176,7 +185,7 @@ and parse_type_decl mode s = | [< name = type_name; tl = parse_constraint_params; '(BrOpen,_); l = plist parse_enum; '(BrClose,p2) >] -> (EEnum { d_name = name; - d_doc = doc; + d_doc = doc_from_string_opt doc; d_meta = meta; d_params = tl; d_flags = List.map decl_flag_to_enum_flag c; @@ -218,7 +227,7 @@ and parse_type_decl mode s = let fl, p2 = parse_class_fields false p1 s in (EClass { d_name = name; - d_doc = doc; + d_doc = doc_from_string_opt doc; d_meta = meta; d_params = tl; d_flags = List.map decl_flag_to_class_flag c @ n @ hl; @@ -230,7 +239,7 @@ and parse_type_decl mode s = | [< >] -> ()); (ETypedef { d_name = name; - d_doc = doc; + d_doc = doc_from_string_opt doc; d_meta = meta; d_params = tl; d_flags = List.map decl_flag_to_enum_flag c; @@ -345,16 +354,6 @@ and parse_abstract_subtype s = and parse_package s = psep Dot lower_ident_or_macro s -and parse_class_fields tdecl p1 s = - let l = parse_class_field_resume tdecl s in - let p2 = (match s with parser - | [< '(BrClose,p2) >] -> p2 - | [< >] -> - (* We don't want to register this as a syntax error because it's part of the logic in display mode *) - if !in_display then (pos (last_token s)) else error (Expected ["}"]) (next_pos s) - ) in - l, p2 - and resume tdecl fdecl s = (* look for next variable/function or next type declaration *) let rec junk k = @@ -417,18 +416,38 @@ and resume tdecl fdecl s = in loop 1 -and parse_class_field_resume tdecl s = - if not (!in_display_file) then - plist (parse_class_field tdecl) s - else try - let c = parse_class_field tdecl s in - c :: parse_class_field_resume tdecl s - with - | Stream.Error msg -> +and parse_class_field_resume acc tdecl s = + let result = try + begin match s with parser + | [< cff = parse_class_field tdecl >] -> Success cff + | [< '(BrClose,p) >] -> End p + | [< >] -> Error "" + end + with Stream.Error msg -> + Error msg + in + match result with + | Success cff -> + parse_class_field_resume (cff :: acc) tdecl s + | End p -> + List.rev acc,p + | Error msg -> handle_stream_error msg s; - if resume tdecl true s then parse_class_field_resume tdecl s else [] - | Stream.Failure -> - if resume tdecl true s then parse_class_field_resume tdecl s else [] + if resume tdecl true s then + parse_class_field_resume acc tdecl s + else + acc,last_pos s + +and parse_class_fields tdecl p1 s = + if not (!in_display_file) then begin + let acc = plist (parse_class_field tdecl) s in + let p2 = (match s with parser + | [< '(BrClose,p2) >] -> p2 + | [< >] -> error (Expected ["}"]) (next_pos s) + ) in + acc,p2 + end else + parse_class_field_resume [] tdecl s and parse_common_flags = parser | [< '(Kwd Private,p); l = parse_common_flags >] -> (DPrivate,p) :: l @@ -593,12 +612,7 @@ and parse_type_path2 p0 pack name p1 s = | Some p -> punion p p1 in if !in_display_file && display_position#enclosed_in p then begin - { - tpackage = List.rev pack; - tname = name; - tsub = None; - tparams = []; - },p + mk_type_path (List.rev pack,name), p end else f() in @@ -631,12 +645,9 @@ and parse_type_path2 p0 pack name p1 s = end | [< >] -> [],p2 ) in - { - tpackage = List.rev pack; - tname = name; - tparams = params; - tsub = sub; - },punion (match p0 with None -> p1 | Some p -> p) p2 + let tp = mk_type_path ~params ?sub (List.rev pack,name) + and pos = punion (match p0 with None -> p1 | Some p -> p) p2 in + tp,pos and type_name = parser | [< '(Const (Ident name),p); s >] -> @@ -650,6 +661,8 @@ and parse_type_path_or_const plt = parser (* we can't allow (expr) here *) | [< '(BkOpen,p1); e = parse_array_decl p1 >] -> TPExpr (e) | [< t = parse_complex_type >] -> TPType t + | [< '(Unop op,p1); '(Const c,p2) >] -> TPExpr (make_unop op (EConst c,p2) p1) + | [< '(Binop OpSub,p1); '(Const c,p2) >] -> TPExpr (make_unop Neg (EConst c,p2) p1) | [< '(Const c,p) >] -> TPExpr (EConst c,p) | [< '(Kwd True,p) >] -> TPExpr (EConst (Ident "true"),p) | [< '(Kwd False,p) >] -> TPExpr (EConst (Ident "false"),p) @@ -714,7 +727,7 @@ and parse_type_anonymous s = match s with parser | [< name, p1 = ident; t = parse_type_hint; s >] -> let opt,p1 = match p0 with - | Some p -> true,p + | Some p -> true,punion p p1 | None -> false,p1 in let p2 = pos (last_token s) in @@ -757,7 +770,7 @@ and parse_enum s = ) in { ec_name = name,p1; - ec_doc = doc; + ec_doc = doc_from_string_opt doc; ec_meta = meta; ec_args = args; ec_params = params; @@ -868,7 +881,7 @@ and parse_class_field tdecl s = in { cff_name = name; - cff_doc = doc; + cff_doc = doc_from_string_opt doc; cff_meta = meta; cff_access = al; cff_pos = pos; @@ -1108,14 +1121,14 @@ and parse_macro_expr p = parser | [< '(DblDot,_); t = parse_complex_type >] -> let _, to_type, _ = reify !in_macro in let t = to_type t p in - (ECheckType (t,(CTPath { tpackage = ["haxe";"macro"]; tname = "Expr"; tsub = Some "ComplexType"; tparams = [] },null_pos)),p) + (ECheckType (t,(CTPath (mk_type_path ~sub:"ComplexType" (["haxe";"macro"],"Expr")),null_pos)),p) | [< '(Kwd Var,p1); vl = psep Comma (parse_var_decl false) >] -> reify_expr (EVars vl,p1) !in_macro | [< '(Kwd Final,p1); vl = psep Comma (parse_var_decl true) >] -> reify_expr (EVars vl,p1) !in_macro | [< d = parse_class None [] [] false >] -> let _,_,to_type = reify !in_macro in - (ECheckType (to_type d,(CTPath { tpackage = ["haxe";"macro"]; tname = "Expr"; tsub = Some "TypeDefinition"; tparams = [] },null_pos)),p) + (ECheckType (to_type d,(CTPath (mk_type_path ~sub:"TypeDefinition" (["haxe";"macro"],"Expr")),null_pos)),p) | [< e = secure_expr >] -> reify_expr e !in_macro @@ -1236,7 +1249,7 @@ and expr = parser | [< '(PClose,p2); er = arrow_expr; >] -> arrow_function p1 [] er s | [< '(Question,p2); al = psep Comma parse_fun_param; '(PClose,_); er = arrow_expr; >] -> - let al = (match al with | (np,_,_,topt,e) :: al -> (np,true,[],topt,e) :: al | _ -> assert false ) in + let al = (match al with | (np,_,_,topt,e) :: al -> (np,true,[],topt,e) :: al | _ -> die "" __LOC__ ) in arrow_function p1 al er s | [< e = expr; s >] -> (match s with parser | [< '(PClose,p2); s >] -> expr_next (EParenthesis e, punion p1 p2) s @@ -1361,7 +1374,7 @@ and expr_next' e1 = parser | [< '(BrOpen,p1) when is_dollar_ident e1; eparam = expr; '(BrClose,p2); s >] -> (match fst e1 with | EConst(Ident n) -> expr_next (EMeta((Meta.from_string n,[],snd e1),eparam), punion p1 p2) s - | _ -> assert false) + | _ -> die "" __LOC__) | [< '(Dot,p); e = parse_field e1 p >] -> e | [< '(POpen,p1); e = parse_call_params (fun el p2 -> (ECall(e1,el)),punion (pos e1) p2) p1; s >] -> expr_next e s | [< '(BkOpen,p1); e2 = secure_expr; s >] -> @@ -1452,7 +1465,8 @@ and parse_switch_cases eswitch cases = parser and parse_catch etry = parser | [< '(Kwd Catch,p); '(POpen,_); name, pn = dollar_ident; s >] -> match s with parser - | [< t,pt = parse_type_hint; '(PClose,_); e = secure_expr >] -> ((name,pn),(t,pt),e,punion p (pos e)),(pos e) + | [< t,pt = parse_type_hint; '(PClose,_); e = secure_expr >] -> ((name,pn),(Some (t,pt)),e,punion p (pos e)),(pos e) + | [< '(PClose,_); e = secure_expr >] -> ((name,pn),None,e,punion p (pos e)),(pos e) | [< '(_,p) >] -> error Missing_type p and parse_catches etry catches pmax = parser @@ -1529,7 +1543,7 @@ let rec validate_macro_cond s e = match fst e with | _ -> syntax_error (Custom ("Invalid conditional expression")) ~pos:(Some (pos e)) s ((EConst (Ident "false"),(pos e))) let parse_macro_ident t p s = - if t = "display" then Hashtbl.replace special_identifier_files (Path.unique_full_path p.pfile) t; + if t = "display" then Hashtbl.replace special_identifier_files (Path.UniqueKey.create p.pfile) t; let e = (EConst (Ident t),p) in None, e diff --git a/src/syntax/lexer.ml b/src/syntax/lexer.ml index 4ceb8bcbb30dfd89e7f99aaffe2e08f1531b00f1..641c8c48fa7fa29a91c5906fdb0ef291b04b5a72 100644 --- a/src/syntax/lexer.ml +++ b/src/syntax/lexer.ml @@ -226,7 +226,15 @@ let resolve_pos file = f let find_file file = - try Hashtbl.find all_files file with Not_found -> try resolve_pos file with Sys_error _ -> make_file file + try + Hashtbl.find all_files file + with Not_found -> + try + let f = resolve_pos file in + Hashtbl.add all_files file f; + f + with Sys_error _ -> + make_file file let find_pos p = find_line p.pmin (find_file p.pfile) @@ -256,6 +264,8 @@ let get_error_pos printer p = Printf.sprintf "%s character%s" (printer p.pfile l1) s end else Printf.sprintf "%s lines %d-%d" (printer p.pfile l1) l1 l2 +;; +Globals.get_error_pos_ref := get_error_pos let reset() = Buffer.reset buf let contents() = Buffer.contents buf @@ -320,7 +330,7 @@ let rec skip_header lexbuf = | 0xfeff -> skip_header lexbuf | "#!", Star (Compl ('\n' | '\r')) -> skip_header lexbuf | "" | eof -> () - | _ -> assert false + | _ -> die "" __LOC__ let rec token lexbuf = match%sedlex lexbuf with @@ -486,7 +496,7 @@ and comment lexbuf = | "*/" -> lexeme_end lexbuf | '*' -> store lexbuf; comment lexbuf | Plus (Compl ('*' | '\n' | '\r')) -> store lexbuf; comment lexbuf - | _ -> assert false + | _ -> die "" __LOC__ and string lexbuf = match%sedlex lexbuf with @@ -497,7 +507,7 @@ and string lexbuf = | '\\' -> store lexbuf; string lexbuf | '"' -> lexeme_end lexbuf | Plus (Compl ('"' | '\\' | '\r' | '\n')) -> store lexbuf; string lexbuf - | _ -> assert false + | _ -> die "" __LOC__ and string2 lexbuf = match%sedlex lexbuf with @@ -514,7 +524,7 @@ and string2 lexbuf = (try code_string lexbuf 0 with Exit -> error Unclosed_code pmin); string2 lexbuf; | Plus (Compl ('\'' | '\\' | '\r' | '\n' | '$')) -> store lexbuf; string2 lexbuf - | _ -> assert false + | _ -> die "" __LOC__ and code_string lexbuf open_braces = match%sedlex lexbuf with @@ -548,7 +558,7 @@ and code_string lexbuf open_braces = code_string lexbuf open_braces | "//", Star (Compl ('\n' | '\r')) -> store lexbuf; code_string lexbuf open_braces | Plus (Compl ('/' | '"' | '\'' | '{' | '}' | '\n' | '\r')) -> store lexbuf; code_string lexbuf open_braces - | _ -> assert false + | _ -> die "" __LOC__ and regexp lexbuf = match%sedlex lexbuf with @@ -563,7 +573,7 @@ and regexp lexbuf = | '\\', Compl '\\' -> error (Invalid_character (Uchar.to_int (lexeme_char lexbuf 0))) (lexeme_end lexbuf - 1) | '/' -> regexp_options lexbuf, lexeme_end lexbuf | Plus (Compl ('\\' | '/' | '\r' | '\n')) -> store lexbuf; regexp lexbuf - | _ -> assert false + | _ -> die "" __LOC__ and regexp_options lexbuf = match%sedlex lexbuf with @@ -572,7 +582,7 @@ and regexp_options lexbuf = l ^ regexp_options lexbuf | 'a'..'z' -> error Invalid_option (lexeme_start lexbuf) | "" -> "" - | _ -> assert false + | _ -> die "" __LOC__ and not_xml ctx depth in_open = let lexbuf = ctx.lexbuf in @@ -616,7 +626,7 @@ and not_xml ctx depth in_open = store lexbuf; not_xml ctx depth in_open | _ -> - assert false + die "" __LOC__ let rec sharp_token lexbuf = match%sedlex lexbuf with diff --git a/src/syntax/parser.ml b/src/syntax/parser.ml index ea46c7b32e4b58a30dfdace898dea51e45f2c79e..b43b8889e19d50e08641094a4ef914a00b6f7349 100644 --- a/src/syntax/parser.ml +++ b/src/syntax/parser.ml @@ -51,6 +51,11 @@ type syntax_completion = | SCTypeDecl of type_decl_completion_mode | SCAfterTypeFlag of decl_flag list +type 'a sequence_parsing_result = + | Success of 'a + | End of pos + | Error of string + exception Error of error_msg * pos exception TypePath of string list * (string * bool) option * bool (* in import *) * pos exception SyntaxCompletion of syntax_completion * DisplayTypes.completion_subject @@ -77,10 +82,8 @@ type parser_display_information = { } type 'a parse_result = - (* Parsed display file. There can be errors. *) - | ParseDisplayFile of 'a * parser_display_information (* Parsed non-display-file without errors. *) - | ParseSuccess of 'a + | ParseSuccess of 'a * bool * parser_display_information (* Parsed non-display file with errors *) | ParseError of 'a * parse_error * parse_error list @@ -89,7 +92,7 @@ let syntax_completion kind so p = let error m p = raise (Error (m,p)) -let special_identifier_files : (string,string) Hashtbl.t = Hashtbl.create 0 +let special_identifier_files : (Path.UniqueKey.t,string) Hashtbl.t = Hashtbl.create 0 let decl_flag_to_class_flag (flag,p) = match flag with | DPrivate -> HPrivate @@ -270,7 +273,7 @@ let rec make_meta name params ((v,p2) as e) p1 = | _ -> EMeta((name,params,p1),e),punion p1 p2 let make_is e (t,p_t) p p_is = - let e_is = EField((EConst(Ident "Std"),null_pos),"is"),p_is in + let e_is = EField((EConst(Ident "Std"),null_pos),"isOfType"),p_is in let e2 = expr_of_type_path (t.tpackage,t.tname) p_t in ECall(e_is,[e;e2]),p diff --git a/src/syntax/parserEntry.ml b/src/syntax/parserEntry.ml index b1bf0bd86af3f89f5110e86f0252cc3552ab30e8..b34a418ea15423a6374626ac0ca1cf3880ed11f4 100644 --- a/src/syntax/parserEntry.ml +++ b/src/syntax/parserEntry.ml @@ -32,7 +32,7 @@ type small_type = | TVersion of (version * version * version) * (version list option) let is_true = function - | TBool false | TNull | TFloat 0. | TString "" -> false + | TBool false | TNull | TFloat 0. -> false | _ -> true let s_small_type v = @@ -119,30 +119,7 @@ and eval_binop_exprs ctx e1 e2 = | TString s, (TVersion _ as v2) -> (parse_version s (snd e1), v2) | v1, v2 -> (v1, v2) -class condition_handler_nop = object(self) - val null = EConst(Ident "null"),null_pos - - method cond_if (e : expr) = - () - - method cond_else = - () - - method cond_elseif (e : expr) = - () - - method cond_end = - () - - method get_current_condition : expr = - null - - method get_conditions : expr list = - [] -end - -class condition_Handler = object(self) - inherit condition_handler_nop +class condition_handler = object(self) val mutable conditional_expressions = [] val mutable conditional_stack = [] val mutable depths = [] @@ -176,13 +153,13 @@ class condition_Handler = object(self) | e :: el -> conditional_stack <- (self#negate e) :: el | [] -> - assert false + die "" __LOC__ method cond_elseif (e : expr) = self#cond_else; self#cond_if' e; match depths with - | [] -> assert false + | [] -> die "" __LOC__ | depth :: depths' -> depths <- (depth + 1) :: depths' @@ -192,7 +169,7 @@ class condition_Handler = object(self) else loop (d - 1) (List.tl el) in match depths with - | [] -> assert false + | [] -> die "" __LOC__ | depth :: depths' -> conditional_stack <- loop depth conditional_stack; depths <- depths' @@ -226,8 +203,6 @@ class dead_block_collector conds = object(self) DynArray.to_list dead_blocks end -let nop_handler = new condition_handler_nop - (* parse main *) let parse ctx code file = let old = Lexer.save() in @@ -238,7 +213,7 @@ let parse ctx code file = let old_macro = !in_macro in code_ref := code; in_display := display_position#get <> null_pos; - in_display_file := !in_display && Path.unique_full_path file = (display_position#get).pfile; + in_display_file := !in_display && display_position#is_in_file file; syntax_errors := []; let restore = (fun () -> @@ -259,7 +234,7 @@ let parse ctx code file = error (Custom line) p in - let conds = if !in_display_file then new condition_Handler else nop_handler in + let conds = new condition_handler in let dbc = new dead_block_collector conds in let sraw = Stream.from (fun _ -> Some (Lexer.sharp_token code)) in let rec next_token() = process_token (Lexer.token code) @@ -273,7 +248,12 @@ let parse ctx code file = if l > 0 && s.[0] = '*' then last_doc := Some (String.sub s 1 (l - (if l > 1 && s.[l-1] = '*' then 2 else 1)), (snd tk).pmin); tk | CommentLine s -> - if !in_display_file && display_position#enclosed_in (pos tk) then syntax_completion SCComment None (pos tk); + if !in_display_file then begin + let p = pos tk in + (* Completion at the / should not pick up the comment (issue #9133) *) + let p = if is_completion() then {p with pmin = p.pmin + 1} else p in + if display_position#enclosed_in p then syntax_completion SCComment None (pos tk); + end; next_token() | Sharp "end" -> (match !mstack with @@ -385,10 +365,11 @@ let parse ctx code file = let was_display_file = !in_display_file in restore(); Lexer.restore old; + let pdi = {pd_errors = List.rev !syntax_errors;pd_dead_blocks = dbc#get_dead_blocks;pd_conditions = conds#get_conditions} in if was_display_file then - ParseDisplayFile(l,{pd_errors = List.rev !syntax_errors;pd_dead_blocks = dbc#get_dead_blocks;pd_conditions = conds#get_conditions}) + ParseSuccess(l,true,pdi) else begin match List.rev !syntax_errors with - | [] -> ParseSuccess l + | [] -> ParseSuccess(l,false,pdi) | error :: errors -> ParseError(l,error,errors) end with @@ -421,8 +402,9 @@ let parse_string com s p error inlined = syntax_errors := old_syntax_errors; Lexer.restore old in - Lexer.init p.pfile; - if not inlined then begin + if inlined then + Lexer.init p.pfile + else begin display_position#reset; in_display_file := false; end; @@ -447,6 +429,5 @@ let parse_expr_string com s p error inl = | _ -> raise Exit in match parse_string com (head ^ s ^ ";}") p error inl with - | ParseSuccess data -> ParseSuccess(extract_expr data) + | ParseSuccess(data,is_display_file,pdi) -> ParseSuccess(extract_expr data,is_display_file,pdi) | ParseError(data,error,errors) -> ParseError(extract_expr data,error,errors) - | ParseDisplayFile(data,pdi) -> ParseDisplayFile(extract_expr data,pdi) diff --git a/src/syntax/reification.ml b/src/syntax/reification.ml index 83305aa2c9fefc6cd1feef4e62f0c9fb90e5f283..7157ccfb1ab75f2d97f3afb2c5ea64cc891955ff 100644 --- a/src/syntax/reification.ml +++ b/src/syntax/reification.ml @@ -195,7 +195,7 @@ let reify in_macro = in let fields = [ Some ("name", to_placed_name f.cff_name); - (match f.cff_doc with None -> None | Some s -> Some ("doc", to_string s p)); + (match f.cff_doc with None -> None | Some d -> Some ("doc", to_string (gen_doc_text d) p)); (match f.cff_access with [] -> None | l -> Some ("access", to_array to_access l p)); Some ("kind", to_kind f.cff_kind); Some ("pos", to_pos f.cff_pos); @@ -305,7 +305,7 @@ let reify in_macro = expr "ESwitch" [loop e1;to_array scase cases p;to_opt (fun (e,_) -> to_opt to_expr e) def p] | ETry (e1,catches) -> let scatch ((n,_),t,e,_) p = - to_obj [("name",to_string n p);("type",to_ctype t p);("expr",loop e)] p + to_obj [("name",to_string n p);("type",to_opt to_ctype t p);("expr",loop e)] p in expr "ETry" [loop e1;to_array scatch catches p] | EReturn eo -> @@ -388,11 +388,11 @@ let reify in_macro = "kind", mk_enum "TypeDefKind" "TDClass" [(match !ext with None -> (EConst (Ident "null"),p) | Some t -> t);(EArrayDecl (List.rev !impl),p);to_bool !interf p;to_bool !final p] p; "fields", (EArrayDecl (List.map (fun f -> to_cfield f p) d.d_data),p) ] p - | _ -> assert false + | _ -> die "" __LOC__ in (fun e -> to_expr e (snd e)), to_ctype, to_type_def let reify_expr e in_macro = let to_expr,_,_ = reify in_macro in let e = to_expr e in - (ECheckType (e,(CTPath { tpackage = ["haxe";"macro"]; tname = "Expr"; tsub = None; tparams = [] },null_pos)),pos e) + (ECheckType (e,(CTPath (mk_type_path (["haxe";"macro"],"Expr")),null_pos)),pos e) diff --git a/src/typing/calls.ml b/src/typing/calls.ml index 6822979169f6eb431456b7199348f852c07f2652..07afbc3ee5d423781c1784bec5e17d44597819a8 100644 --- a/src/typing/calls.ml +++ b/src/typing/calls.ml @@ -44,37 +44,20 @@ let make_call ctx e params t ?(force_inline=false) p = if List.exists has_override c.cl_descendants then error (Printf.sprintf "Cannot force inline-call to %s because it is overridden" f.cf_name) p ) end; - let config = match cl with - | Some ({cl_kind = KAbstractImpl _}) when Meta.has Meta.Impl f.cf_meta -> - let t = if f.cf_name = "_new" then - t - else if params = [] then - error "Invalid abstract implementation function" f.cf_pos - else - follow (List.hd params).etype - in - begin match t with - | TAbstract(a,pl) -> - let has_params = a.a_params <> [] || f.cf_params <> [] in - let monos = List.map (fun _ -> mk_mono()) f.cf_params in - let map_type = fun t -> apply_params a.a_params pl (apply_params f.cf_params monos t) in - Some (has_params,map_type) - | _ -> - None - end - | _ -> - None - in + let config = Inline.inline_config cl f params t in ignore(follow f.cf_type); (* force evaluation *) (match cl, ctx.curclass.cl_kind, params with | Some c, KAbstractImpl _, { eexpr = TLocal { v_meta = v_meta } } :: _ when c == ctx.curclass -> if f.cf_name <> "_new" && has_meta Meta.This v_meta - && not (assign_to_this_is_allowed ctx) && has_class_field_flag f CfModifiesThis then - error ("Abstract 'this' value can only be modified inside an inline function. '" ^ f.cf_name ^ "' modifies 'this'") p; + if assign_to_this_is_allowed ctx then + (* Current method needs to infer CfModifiesThis flag, since we are calling a method, which modifies `this` *) + add_class_field_flag ctx.curfield CfModifiesThis + else + error ("Abstract 'this' value can only be modified inside an inline function. '" ^ f.cf_name ^ "' modifies 'this'") p; | _ -> () ); let params = List.map (ctx.g.do_optimize ctx) params in @@ -107,7 +90,7 @@ let mk_array_get_call ctx (cf,tf,r,e1,e2o) c ebase p = match cf.cf_expr with make_call ctx ef [ebase;e1] r p let mk_array_set_call ctx (cf,tf,r,e1,e2o) c ebase p = - let evalue = match e2o with None -> assert false | Some e -> e in + let evalue = match e2o with None -> die "" __LOC__ | Some e -> e in match cf.cf_expr with | None -> if not (Meta.has Meta.NoExpr cf.cf_meta) then display_error ctx "Recursive array set method" p; @@ -118,12 +101,41 @@ let mk_array_set_call ctx (cf,tf,r,e1,e2o) c ebase p = let ef = mk (TField(et,(FStatic(c,cf)))) tf p in make_call ctx ef [ebase;e1;evalue] r p +let rec needs_temp_var e = + match e.eexpr with + | TLocal _ | TTypeExpr _ | TConst _ -> false + | TField (e, _) | TParenthesis e -> needs_temp_var e + | _ -> true + let call_to_string ctx ?(resume=false) e = - (* Ignore visibility of the toString field. *) - ctx.meta <- (Meta.PrivateAccess,[],e.epos) :: ctx.meta; - let acc = type_field (TypeFieldConfig.create resume) ctx e "toString" e.epos MCall in - ctx.meta <- List.tl ctx.meta; - !build_call_ref ctx acc [] (WithType.with_type ctx.t.tstring) e.epos + let gen_to_string e = + (* Ignore visibility of the toString field. *) + ctx.meta <- (Meta.PrivateAccess,[],e.epos) :: ctx.meta; + let acc = type_field (TypeFieldConfig.create resume) ctx e "toString" e.epos MCall in + ctx.meta <- List.tl ctx.meta; + !build_call_ref ctx acc [] (WithType.with_type ctx.t.tstring) e.epos + in + if ctx.com.config.pf_static && not (is_nullable e.etype) then + gen_to_string e + else begin (* generate `if(e == null) 'null' else e.toString()` *) + let string_null = mk (TConst (TString "null")) ctx.t.tstring e.epos in + if needs_temp_var e then + let tmp = alloc_var VGenerated "tmp" e.etype e.epos in + let tmp_local = mk (TLocal tmp) tmp.v_type tmp.v_pos in + let check_null = mk (TBinop (OpEq, tmp_local, mk (TConst TNull) tmp.v_type tmp.v_pos)) ctx.t.tbool e.epos in + { + eexpr = TBlock([ + mk (TVar (tmp, Some e)) tmp.v_type tmp.v_pos; + mk (TIf (check_null, string_null, Some (gen_to_string tmp_local))) ctx.t.tstring tmp.v_pos; + + ]); + etype = ctx.t.tstring; + epos = e.epos; + } + else + let check_null = mk (TBinop (OpEq, e, mk (TConst TNull) e.etype e.epos)) ctx.t.tbool e.epos in + mk (TIf (check_null, string_null, Some (gen_to_string e))) ctx.t.tstring e.epos + end let rec unify_call_args' ctx el args r callp inline force_inline = let in_call_args = ctx.in_call_args in @@ -173,7 +185,7 @@ let rec unify_call_args' ctx el args r callp inline force_inline = | TAbstract({a_path=(["haxe";"extern"],"Rest")},[t]) -> (try List.map (fun e -> type_against name t e,false) el with WithTypeError(ul,p) -> arg_error ul name false p) | _ -> - assert false + die "" __LOC__ end | [],(_,false,_) :: _ -> call_error (Not_enough_arguments args) callp @@ -268,7 +280,7 @@ let unify_field_call ctx fa el args ret p inline = in el,tf,mk_call | _ -> - assert false + die "" __LOC__ in let maybe_raise_unknown_ident cerr p = let rec loop err = @@ -339,7 +351,7 @@ let type_generic_function ctx (e,fa) el ?(using_param=None) with_type p = let c,tl,cf,stat = match fa with | FInstance(c,tl,cf) -> c,tl,cf,false | FStatic(c,cf) -> c,[],cf,true - | _ -> assert false + | _ -> die "" __LOC__ in if cf.cf_params = [] then error "Function has no type parameters and cannot be generic" p; let monos = List.map (fun _ -> mk_mono()) cf.cf_params in @@ -349,7 +361,7 @@ let type_generic_function ctx (e,fa) el ?(using_param=None) with_type p = let args,ret = match t,using_param with | TFun((_,_,ta) :: args,ret),Some e -> let ta = if not (Meta.has Meta.Impl cf.cf_meta) then ta - else match follow ta with TAbstract(a,tl) -> Abstract.get_underlying_type a tl | _ -> assert false + else match follow ta with TAbstract(a,tl) -> Abstract.get_underlying_type a tl | _ -> die "" __LOC__ in (* manually unify first argument *) unify ctx e.etype ta p; @@ -378,7 +390,7 @@ let type_generic_function ctx (e,fa) el ?(using_param=None) with_type p = display_error ctx "Conflicting field was defined here" pcf; raise err in - let cf2 = try + let c, cf2 = try let cf2 = if stat then let cf2 = PMap.find name c.cl_statics in unify_existing_field cf2.cf_type cf2.cf_pos; @@ -388,7 +400,7 @@ let type_generic_function ctx (e,fa) el ?(using_param=None) with_type p = unify_existing_field cf2.cf_type cf2.cf_pos; cf2 in - cf2 + c, cf2 (* java.Lib.array() relies on the ability to shadow @:generic function for certain types see https://github.com/HaxeFoundation/haxe/issues/8393#issuecomment-508685760 @@ -398,43 +410,68 @@ let type_generic_function ctx (e,fa) el ?(using_param=None) with_type p = else error ("Cannot specialize @:generic because the generated function name is already used: " ^ name) p *) with Not_found -> - let cf2 = mk_field name (map_monos cf.cf_type) cf.cf_pos cf.cf_name_pos in + let finalize_field c cf2 = + ignore(follow cf.cf_type); + let rec check e = match e.eexpr with + | TNew({cl_kind = KTypeParameter _} as c,_,_) when not (TypeloadCheck.is_generic_parameter ctx c) -> + display_error ctx "Only generic type parameters can be constructed" e.epos; + display_error ctx "While specializing this call" p; + | _ -> + Type.iter check e + in + cf2.cf_expr <- (match cf.cf_expr with + | None -> + display_error ctx "Recursive @:generic function" p; None; + | Some e -> + let e = Generic.generic_substitute_expr gctx e in + check e; + Some e + ); + cf2.cf_kind <- cf.cf_kind; + if not (has_class_field_flag cf CfPublic) then remove_class_field_flag cf2 CfPublic; + let metadata = List.filter (fun (m,_,_) -> match m with + | Meta.Generic -> false + | _ -> true + ) cf.cf_meta in + cf2.cf_meta <- (Meta.NoCompletion,[],p) :: (Meta.NoUsing,[],p) :: (Meta.GenericInstance,[],p) :: metadata + in + let mk_cf2 name = + mk_field name (map_monos cf.cf_type) cf.cf_pos cf.cf_name_pos + in if stat then begin - c.cl_statics <- PMap.add name cf2 c.cl_statics; - c.cl_ordered_statics <- cf2 :: c.cl_ordered_statics + if Meta.has Meta.GenericClassPerMethod c.cl_meta then begin + let c = Generic.static_method_container gctx c cf p in + try + let cf2 = PMap.find cf.cf_name c.cl_statics in + unify_existing_field cf2.cf_type cf2.cf_pos; + c, cf2 + with Not_found -> + let cf2 = mk_cf2 cf.cf_name in + c.cl_statics <- PMap.add cf2.cf_name cf2 c.cl_statics; + c.cl_ordered_statics <- cf2 :: c.cl_ordered_statics; + finalize_field c cf2; + c, cf2 + end else begin + let cf2 = mk_cf2 name in + c.cl_statics <- PMap.add cf2.cf_name cf2 c.cl_statics; + c.cl_ordered_statics <- cf2 :: c.cl_ordered_statics; + finalize_field c cf2; + c, cf2 + end end else begin + let cf2 = mk_cf2 name in if List.memq cf c.cl_overrides then c.cl_overrides <- cf2 :: c.cl_overrides; - c.cl_fields <- PMap.add name cf2 c.cl_fields; - c.cl_ordered_fields <- cf2 :: c.cl_ordered_fields - end; - ignore(follow cf.cf_type); - let rec check e = match e.eexpr with - | TNew({cl_kind = KTypeParameter _} as c,_,_) when not (TypeloadCheck.is_generic_parameter ctx c) -> - display_error ctx "Only generic type parameters can be constructed" e.epos; - display_error ctx "While specializing this call" p; - | _ -> - Type.iter check e - in - cf2.cf_expr <- (match cf.cf_expr with - | None -> - display_error ctx "Recursive @:generic function" p; None; - | Some e -> - let e = Generic.generic_substitute_expr gctx e in - check e; - Some e - ); - cf2.cf_kind <- cf.cf_kind; - if not (has_class_field_flag cf CfPublic) then remove_class_field_flag cf2 CfPublic; - let metadata = List.filter (fun (m,_,_) -> match m with - | Meta.Generic -> false - | _ -> true - ) cf.cf_meta in - cf2.cf_meta <- (Meta.NoCompletion,[],p) :: (Meta.NoUsing,[],p) :: (Meta.GenericInstance,[],p) :: metadata; - cf2 + c.cl_fields <- PMap.add cf2.cf_name cf2 c.cl_fields; + c.cl_ordered_fields <- cf2 :: c.cl_ordered_fields; + finalize_field c cf2; + c, cf2 + end in let e = match c.cl_kind with | KAbstractImpl(a) -> type_type ctx a.a_path p + | _ when stat -> + Builder.make_typeexpr (TClassDecl c) e.epos | _ -> e in let fa = if stat then FStatic (c,cf2) else FInstance (c,tl,cf2) in @@ -447,7 +484,7 @@ let rec acc_get ctx g p = match g with | AKNo f -> error ("Field " ^ f ^ " cannot be accessed for reading") p | AKExpr e -> e - | AKSet _ | AKAccess _ | AKFieldSet _ -> assert false + | AKSet _ | AKAccess _ | AKFieldSet _ -> die "" __LOC__ | AKUsing (et,c,cf,e,_) when ctx.in_display -> (* Generate a TField node so we can easily match it for position/usage completion (issue #1968) *) let ec = type_module_type ctx (TClassDecl c) None p in @@ -481,7 +518,7 @@ let rec acc_get ctx g p = tf_expr = mk (TReturn (Some ecallb)) t_dynamic p; }) twrap p in make_call ctx ewrap [e] tcallb p - | _ -> assert false) + | _ -> die "" __LOC__) | AKInline (e,f,fmode,t) -> (* do not create a closure for static calls *) let cmode,apply_params = match fmode with @@ -497,7 +534,7 @@ let rec acc_get ctx g p = | FInstance (c,tl,f) -> (FClosure (Some (c,tl),f),(fun t -> t)) | _ -> - assert false + die "" __LOC__ in ignore(follow f.cf_type); (* force computing *) begin match f.cf_kind,f.cf_expr with @@ -589,7 +626,7 @@ let rec build_call ?(mode=MGet) ctx acc el (with_type:WithType.t) p = (match et.eexpr with | TField(ec,fa) -> type_generic_function ctx (ec,fa) el ~using_param:(Some eparam) with_type p - | _ -> assert false) + | _ -> die "" __LOC__) | AKUsing (et,cl,ef,eparam,force_inline) -> begin match ef.cf_kind with | Method MethMacro -> @@ -612,9 +649,9 @@ let rec build_call ?(mode=MGet) ctx acc el (with_type:WithType.t) p = let ef = prepare_using_field ef in begin match unify_call_args ctx el args r p (ef.cf_kind = Method MethInline) (is_forced_inline (Some cl) ef) with | el,TFun(args,r) -> el,args,r,eparam - | _ -> assert false + | _ -> die "" __LOC__ end - | _ -> assert false + | _ -> die "" __LOC__ in make_call ctx ~force_inline et (eparam :: params) r p end @@ -644,11 +681,11 @@ let rec build_call ?(mode=MGet) ctx acc el (with_type:WithType.t) p = e else match c.cl_super with - | None -> assert false + | None -> die "" __LOC__ | Some (csup,_) -> loop csup in loop c - | _ -> assert false)) + | _ -> die "" __LOC__)) in ctx.macro_depth <- ctx.macro_depth - 1; ctx.with_type_stack <- List.tl ctx.with_type_stack; @@ -676,7 +713,7 @@ let rec build_call ?(mode=MGet) ctx acc el (with_type:WithType.t) p = e | AKNo _ | AKSet _ | AKAccess _ | AKFieldSet _ -> ignore(acc_get ctx acc p); - assert false + die "" __LOC__ | AKExpr e -> let rec loop t = match follow t with | TFun (args,r) -> @@ -691,7 +728,7 @@ let rec build_call ?(mode=MGet) ctx acc el (with_type:WithType.t) p = end | _ -> let el, tfunc = unify_call_args ctx el args r p false false in - let r = match tfunc with TFun(_,r) -> r | _ -> assert false in + let r = match tfunc with TFun(_,r) -> r | _ -> die "" __LOC__ in mk (TCall (e,el)) r p end | TAbstract(a,tl) when Meta.has Meta.Callable a.a_meta -> @@ -745,40 +782,45 @@ let type_bind ctx (e : texpr) (args,ret) params p = loop args params given_args (missing_args @ [v,o]) (ordered_args @ [vexpr v]) | (n,o,t) :: args , param :: params -> let e = type_expr ctx param (WithType.with_argument t n) in - let e = AbstractCast.cast_or_unify ctx t e p in + let e = AbstractCast.cast_or_unify ctx t e (pos param) in let v = alloc_var VGenerated (alloc_name n) t (pos param) in loop args params (given_args @ [v,o,Some e]) missing_args (ordered_args @ [vexpr v]) in let given_args,missing_args,ordered_args = loop args params [] [] [] in - let rec gen_loc_name n = - let name = if n = 0 then "f" else "f" ^ (string_of_int n) in - if List.exists (fun (n,_,_) -> name = n) args then gen_loc_name (n + 1) else name - in - let loc = alloc_var VGenerated (gen_loc_name 0) e.etype e.epos in - let given_args = (loc,false,Some e) :: given_args in - let inner_fun_args l = List.map (fun (v,o) -> v.v_name, o, v.v_type) l in - let t_inner = TFun(inner_fun_args missing_args, ret) in - let call = make_call ctx (vexpr loc) ordered_args ret p in - let e_ret = match follow ret with - | TAbstract ({a_path = [],"Void"},_) -> - call - | TMono _ -> - mk (TReturn (Some call)) t_dynamic p; + let var_decls = List.map (fun (v,_,e_opt) -> mk (TVar(v,e_opt)) ctx.t.tvoid v.v_pos) given_args in + let e,var_decls = + let is_immutable_method cf = + match cf.cf_kind with Method k -> k <> MethDynamic | _ -> false + in + match e.eexpr with + | TFunction _ | TLocal { v_kind = VUser TVOLocalFunction } -> + e,var_decls + | TField(_,(FStatic(_,cf) | FInstance(_,_,cf))) when is_immutable_method cf -> + e,var_decls | _ -> - mk (TReturn (Some call)) t_dynamic p; + let e_var = alloc_var VGenerated "`" e.etype e.epos in + (mk (TLocal e_var) e.etype e.epos), (mk (TVar(e_var,Some e)) ctx.t.tvoid e.epos) :: var_decls + in + let call = make_call ctx e ordered_args ret p in + let body = + if ExtType.is_void (follow ret) then call + else mk (TReturn(Some call)) ret p + in + let arg_default optional t = + if optional then Some (Texpr.Builder.make_null t null_pos) + else None in - let func = mk (TFunction { - tf_args = List.map (fun (v,o) -> v, if o then Some (Texpr.Builder.make_null v.v_type null_pos) else None) missing_args; + let fn = { + tf_args = List.map (fun (v,o) -> v,arg_default o v.v_type) missing_args; tf_type = ret; - tf_expr = e_ret; - }) t_inner p in - let outer_fun_args l = List.map (fun (v,o,_) -> v.v_name, o, v.v_type) l in - let func = mk (TFunction { - tf_args = List.map (fun (v,_,_) -> v,None) given_args; - tf_type = t_inner; - tf_expr = mk (TReturn (Some func)) t_inner p; - }) (TFun(outer_fun_args given_args, t_inner)) p in - make_call ctx func (List.map (fun (_,_,e) -> (match e with Some e -> e | None -> assert false)) given_args) t_inner p + tf_expr = body; + } in + let t = TFun(List.map (fun (v,o) -> v.v_name,o,v.v_type) missing_args,ret) in + { + eexpr = TBlock (var_decls @ [mk (TFunction fn) t p]); + etype = t; + epos = p; + } let array_access ctx e1 e2 mode p = let has_abstract_array_access = ref false in @@ -796,7 +838,7 @@ let array_access ctx e1 e2 mode p = end | _ -> raise Not_found) with Not_found -> - unify ctx e2.etype ctx.t.tint e2.epos; + let base_ok = ref true in let rec loop ?(skip_abstract=false) et = match skip_abstract,follow et with | _, TInst ({ cl_array_access = Some t; cl_params = pl },tl) -> @@ -814,12 +856,31 @@ let array_access ctx e1 e2 mode p = | _, _ -> let pt = mk_mono() in let t = ctx.t.tarray pt in - (try unify_raise ctx et t p - with Error(Unify _,_) -> if not ctx.untyped then begin - if !has_abstract_array_access then error ("No @:arrayAccess function accepts an argument of " ^ (s_type (print_context()) e2.etype)) e1.epos - else error ("Array access is not allowed on " ^ (s_type (print_context()) e1.etype)) e1.epos - end); + begin try + unify_raise ctx et t p + with Error(Unify _,_) -> + if not ctx.untyped then begin + let msg = if !has_abstract_array_access then + "No @:arrayAccess function accepts an argument of " ^ (s_type (print_context()) e2.etype) + else + "Array access is not allowed on " ^ (s_type (print_context()) e1.etype) + in + base_ok := false; + raise_or_display_message ctx msg e1.epos; + end + end; pt in let pt = loop e1.etype in - AKExpr (mk (TArray (e1,e2)) pt p) \ No newline at end of file + if !base_ok then unify ctx e2.etype ctx.t.tint e2.epos; + AKExpr (mk (TArray (e1,e2)) pt p) + +(* + given chain of fields as the `path` argument and an `access_mode->access_kind` getter for some starting expression as `e`, + return a new `access_mode->access_kind` getter for the whole field access chain. +*) +let field_chain ctx path e = + List.fold_left (fun e (f,_,p) -> + let e = acc_get ctx (e MGet) p in + type_field_default_cfg ctx e f p + ) e path diff --git a/src/typing/fields.ml b/src/typing/fields.ml index 4d8b1fe9a2c11d96fdf199a97aa6c7b87160ca92..838375617db7ff7fe39fac1d23c6765c33b3b1af 100644 --- a/src/typing/fields.ml +++ b/src/typing/fields.ml @@ -119,7 +119,7 @@ let field_type ctx c pl f p = apply_params l monos f.cf_type let fast_enum_field e ef p = - let et = mk (TTypeExpr (TEnumDecl e)) (TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics e) }) p in + let et = mk (TTypeExpr (TEnumDecl e)) (mk_anon (ref (EnumStatics e))) p in TField (et,FEnum (e,ef)) let get_constructor ctx c params p = @@ -134,7 +134,7 @@ let get_constructor ctx c params p = let check_constructor_access ctx c f p = if (Meta.has Meta.CompilerGenerated f.cf_meta) then display_error ctx (error_msg (No_constructor (TClassDecl c))) p; - if not (can_access ctx c f true || is_parent c ctx.curclass) && not ctx.untyped then display_error ctx (Printf.sprintf "Cannot access private constructor of %s" (s_class_path c)) p + if not (can_access ctx c f true || extends ctx.curclass c) && not ctx.untyped then display_error ctx (Printf.sprintf "Cannot access private constructor of %s" (s_class_path c)) p let check_no_closure_meta ctx fa mode p = if mode <> MCall && not (DisplayPosition.display_position#enclosed_in p) then begin @@ -166,7 +166,7 @@ let field_access ctx mode f fmode t e p = | TAnon a -> (match !(a.a_status) with | EnumStatics en -> - let c = (try PMap.find f.cf_name en.e_constrs with Not_found -> assert false) in + let c = (try PMap.find f.cf_name en.e_constrs with Not_found -> die "" __LOC__) in let fmode = FEnum (en,c) in AKExpr (mk (TField (e,fmode)) t p) | _ -> fnormal()) @@ -192,7 +192,7 @@ let field_access ctx mode f fmode t e p = | FInstance (c,tl,cf) -> FClosure (Some (c,tl),cf) | FStatic _ | FEnum _ -> fmode | FAnon f -> FClosure (None, f) - | FDynamic _ | FClosure _ -> assert false + | FDynamic _ | FClosure _ -> die "" __LOC__ ) in AKExpr (mk (TField (e,cmode)) t p) | _ -> normal()) @@ -201,7 +201,7 @@ let field_access ctx mode f fmode t e p = match (match mode with MGet | MCall -> v.v_read | MSet -> v.v_write) with | AccNo when not (Meta.has Meta.PrivateAccess ctx.meta) -> (match follow e.etype with - | TInst (c,_) when is_parent c ctx.curclass || can_access ctx c { f with cf_flags = unset_flag f.cf_flags (int_of_class_field_flag CfPublic) } false -> normal() + | TInst (c,_) when extends ctx.curclass c || can_access ctx c { f with cf_flags = unset_flag f.cf_flags (int_of_class_field_flag CfPublic) } false -> normal() | TAnon a -> (match !(a.a_status) with | Opened when mode = MSet -> @@ -232,7 +232,7 @@ let field_access ctx mode f fmode t e p = | AccCall -> let m = (match mode with MSet -> "set_" | _ -> "get_") ^ f.cf_name in let is_abstract_this_access () = match e.eexpr,ctx.curfun with - | TTypeExpr (TClassDecl ({cl_kind = KAbstractImpl _} as c)),(FunMemberAbstract | FunMemberAbstractLocal) -> + | TTypeExpr (TClassDecl ({cl_kind = KAbstractImpl _} as c)),(FunMemberAbstract | FunMemberAbstractLocal) when Meta.has Meta.Impl f.cf_meta -> c == ctx.curclass | _ -> false @@ -250,18 +250,17 @@ let field_access ctx mode f fmode t e p = | _ -> false ) in - if bypass_accessor then - let prefix = (match ctx.com.platform with Flash when Common.defined ctx.com Define.As3 -> "$" | _ -> "") in + if bypass_accessor then ( (match e.eexpr with TLocal _ when Common.defined ctx.com Define.Haxe3Compat -> ctx.com.warning "Field set has changed here in Haxe 4: call setter explicitly to keep Haxe 3.x behaviour" p | _ -> ()); if not (is_physical_field f) then begin display_error ctx "This field cannot be accessed because it is not a real variable" p; display_error ctx "Add @:isVar here to enable it" f.cf_pos; end; - AKExpr (mk (TField (e,if prefix = "" then fmode else FDynamic (prefix ^ f.cf_name))) t p) - else if is_abstract_this_access() then begin + AKExpr (mk (TField (e,fmode)) t p) + ) else if is_abstract_this_access() then begin let this = get_this ctx p in if mode = MSet then begin - let c,a = match ctx.curclass with {cl_kind = KAbstractImpl a} as c -> c,a | _ -> assert false in + let c,a = match ctx.curclass with {cl_kind = KAbstractImpl a} as c -> c,a | _ -> die "" __LOC__ in let f = PMap.find m c.cl_statics in (* we don't have access to the type parameters here, right? *) (* let t = apply_params a.a_params pl (field_type ctx c [] f p) in *) @@ -283,7 +282,10 @@ let field_access ctx mode f fmode t e p = | AccInline -> AKInline (e,f,fmode,t) | AccCtor -> - if ctx.curfun = FunConstructor then normal() else AKNo f.cf_name + (match ctx.curfun, fmode with + | FunConstructor, FInstance(c,_,_) when c == ctx.curclass -> normal() + | _ -> AKNo f.cf_name + ) | AccRequire (r,msg) -> match msg with | None -> error_require r p @@ -321,7 +323,7 @@ let rec using_field ctx mode e i p = | _ -> () ) monos cf.cf_params; let et = type_module_type ctx (TClassDecl c) None p in - ImportHandling.maybe_mark_import_position ctx pc; + ImportHandling.mark_import_position ctx pc; AKUsing (mk (TField (et,FStatic (c,cf))) t p,c,cf,e,false) | _ -> raise Not_found @@ -344,7 +346,7 @@ let rec using_field ctx mode e i p = let acc = loop ctx.g.global_using in (match acc with | AKUsing (_,c,_,_,_) -> add_dependency ctx.m.curmod c.cl_module - | _ -> assert false); + | _ -> die "" __LOC__); acc with Not_found -> if not !check_constant_struct then raise Not_found; @@ -484,7 +486,7 @@ let rec type_field cfg ctx e i p mode = end; let fmode, ft = (match !(a.a_status) with | Statics c -> FStatic (c,f), field_type ctx c [] f p - | EnumStatics e -> FEnum (e,try PMap.find f.cf_name e.e_constrs with Not_found -> assert false), Type.field_type f + | EnumStatics e -> FEnum (e,try PMap.find f.cf_name e.e_constrs with Not_found -> die "" __LOC__), Type.field_type f | _ -> match f.cf_params with | [] -> @@ -524,9 +526,9 @@ let rec type_field cfg ctx e i p mode = cf_kind = Var { v_read = AccNormal; v_write = (match mode with MSet -> AccNormal | MGet | MCall -> AccNo) }; } in let x = ref Opened in - let t = TAnon { a_fields = PMap.add i f PMap.empty; a_status = x } in + let t = mk_anon ~fields:(PMap.add i f PMap.empty) x in ctx.opened <- x :: ctx.opened; - r := Some t; + Monomorph.bind r t; field_access ctx mode f (FAnon f) (Type.field_type f) e p | TAbstract (a,pl) -> let static_abstract_access_through_instance = ref false in @@ -545,6 +547,9 @@ let rec type_field cfg ctx e i p mode = let et = type_module_type ctx (TClassDecl c) None p in let field_expr f t = mk (TField (et,FStatic (c,f))) t p in (match mode, f.cf_kind with + | (MGet | MCall), Var {v_read = AccCall } when ctx.in_display && DisplayPosition.display_position#enclosed_in p -> + let ef = field_expr f (field_type f) in + AKExpr(ef) | (MGet | MCall), Var {v_read = AccCall } -> (* getter call *) let getter = PMap.find ("get_" ^ f.cf_name) c.cl_statics in @@ -605,7 +610,7 @@ let rec type_field cfg ctx e i p mode = let ef = mk (TField (et,FStatic (c,cf))) t p in let r = match follow t with | TFun(_,r) -> r - | _ -> assert false + | _ -> die "" __LOC__ in if is_write then AKFieldSet(e,ef,i,r) @@ -621,3 +626,54 @@ let rec type_field cfg ctx e i p mode = try using_field ctx mode e i p with Not_found -> no_field() let type_field_default_cfg = type_field TypeFieldConfig.default + +(** + Generates a list of fields for `@:structInit` class `c` with type params `tl` + as it's needed for anonymous object syntax. +*) +let get_struct_init_anon_fields c tl = + let args = + match c.cl_constructor with + | Some cf -> + (match follow cf.cf_type with + | TFun (args,_) -> + Some (match cf.cf_expr with + | Some { eexpr = TFunction fn } -> + List.map (fun (name,_,t) -> + let t = apply_params c.cl_params tl t in + try + let v,_ = List.find (fun (v,_) -> v.v_name = name) fn.tf_args in + name,t,v.v_pos + with Not_found -> + name,t,cf.cf_name_pos + ) args + | _ -> + List.map + (fun (name,_,t) -> + let t = apply_params c.cl_params tl t in + try + let cf = PMap.find name c.cl_fields in + name,t,cf.cf_name_pos + with Not_found -> + name,t,cf.cf_name_pos + ) args + ) + | _ -> None + ) + | _ -> None + in + match args with + | Some args -> + List.fold_left (fun fields (name,t,p) -> + let cf = mk_field name t p p in + PMap.add cf.cf_name cf fields + ) PMap.empty args + | _ -> + PMap.fold (fun cf fields -> + match cf.cf_kind with + | Var _ -> + let cf = {cf with cf_type = apply_params c.cl_params tl cf.cf_type} in + PMap.add cf.cf_name cf fields + | _ -> + fields + ) c.cl_fields PMap.empty \ No newline at end of file diff --git a/src/typing/finalization.ml b/src/typing/finalization.ml index 98af5a36a6afbb826514961d8bdc3b9a1b11b5cb..7133434043cb686e5e530dbcdb1a2769395272c1 100644 --- a/src/typing/finalization.ml +++ b/src/typing/finalization.ml @@ -13,7 +13,7 @@ let get_main ctx types = match ctx.com.main_class with | None -> None | Some cl -> - let t = Typeload.load_type_def ctx null_pos { tpackage = fst cl; tname = snd cl; tparams = []; tsub = None } in + let t = Typeload.load_type_def ctx null_pos (mk_type_path cl) in let fmode, ft, r = (match t with | TEnumDecl _ | TTypeDecl _ | TAbstractDecl _ -> error ("Invalid -main : " ^ s_type_path cl ^ " is not a class") null_pos @@ -32,10 +32,10 @@ let get_main ctx types = (* add haxe.EntryPoint.run() call *) let main = (try let et = List.find (fun t -> t_path t = (["haxe"],"EntryPoint")) types in - let ec = (match et with TClassDecl c -> c | _ -> assert false) in + let ec = (match et with TClassDecl c -> c | _ -> die "" __LOC__) in let ef = PMap.find "run" ec.cl_statics in let p = null_pos in - let et = mk (TTypeExpr et) (TAnon { a_fields = PMap.empty; a_status = ref (Statics ec) }) p in + let et = mk (TTypeExpr et) (mk_anon (ref (Statics ec))) p in let call = mk (TCall (mk (TField (et,FStatic (ec,ef))) ef.cf_type p,[])) ctx.t.tvoid p in mk (TBlock [main;call]) ctx.t.tvoid p with Not_found -> @@ -117,7 +117,7 @@ let sort_types com modules = | TClassDecl c -> loop_class p c | TEnumDecl e -> loop_enum p e | TAbstractDecl a -> loop_abstract p a - | TTypeDecl _ -> assert false) + | TTypeDecl _ -> die "" __LOC__) | TNew (c,_,_) -> iter (walk_expr p) e; loop_class p c; diff --git a/src/typing/forLoop.ml b/src/typing/forLoop.ml index e84b9722f8800c19c948ed5d0f0a96b4d9185067..51e64caf0a533f88c83a5b2055b7f9972e896314 100644 --- a/src/typing/forLoop.ml +++ b/src/typing/forLoop.ml @@ -9,13 +9,42 @@ open Error open Texpr.Builder let optimize_for_loop_iterator ctx v e1 e2 p = - let c,tl = (match follow e1.etype with TInst (c,pl) -> c,pl | _ -> raise Exit) in + let c,tl = + let rec get_class_and_params e = + match follow e.etype with + | TInst (c,pl) -> c,pl + | _ -> + match e.eexpr with + | TCast (e,None) -> + get_class_and_params e + | TCall ({ eexpr = TField (_, FInstance (c,pl,cf)) }, _) -> + let t = apply_params c.cl_params pl cf.cf_type in + (match follow t with + | TFun (_, t) -> + (match follow t with + | TInst (c,pl) -> c,pl + | _ -> raise Exit + ) + | _ -> raise Exit + ) + | _ -> raise Exit + in + get_class_and_params e1 + in let _, _, fhasnext = (try raw_class_field (fun cf -> apply_params c.cl_params tl cf.cf_type) c tl "hasNext" with Not_found -> raise Exit) in if fhasnext.cf_kind <> Method MethInline then raise Exit; - let tmp = gen_local ctx e1.etype e1.epos in - let eit = mk (TLocal tmp) e1.etype p in + let it_type = TInst(c,tl) in + let tmp = gen_local ctx it_type e1.epos in + let eit = mk (TLocal tmp) it_type p in let ehasnext = make_call ctx (mk (TField (eit,FInstance (c, tl, fhasnext))) (TFun([],ctx.t.tbool)) p) [] ctx.t.tbool p in - let enext = mk (TVar (v,Some (make_call ctx (mk (TField (eit,quick_field_dynamic eit.etype "next")) (TFun ([],v.v_type)) p) [] v.v_type p))) ctx.t.tvoid p in + let fa_next = + try + match raw_class_field (fun cf -> apply_params c.cl_params tl cf.cf_type) c tl "next" with + | _, _, fa -> FInstance (c, tl, fa) + with Not_found -> + quick_field_dynamic eit.etype "next" + in + let enext = mk (TVar (v,Some (make_call ctx (mk (TField (eit,fa_next)) (TFun ([],v.v_type)) p) [] v.v_type p))) ctx.t.tvoid p in let eblock = (match e2.eexpr with | TBlock el -> { e2 with eexpr = TBlock (enext :: el) } | _ -> mk (TBlock [enext;e2]) ctx.t.tvoid p @@ -238,7 +267,7 @@ module IterationKind = struct let t_void = ctx.t.tvoid in let t_int = ctx.t.tint in let mk_field e n = - TField (e,try quick_field e.etype n with Not_found -> assert false) + TField (e,try quick_field e.etype n with Not_found -> die "" __LOC__) in let get_array_length arr p = mk (mk_field arr "length") ctx.com.basic.tint p @@ -301,13 +330,13 @@ module IterationKind = struct | IteratorIntConst(a,b,ascending) -> check_loop_var_modification [v] e2; if not ascending then error "Cannot iterate backwards" p; - let v_index = gen_local ctx t_int p in - let evar_index = mk (TVar(v_index,Some a)) t_void p in - let ev_index = make_local v_index p in + let v_index = gen_local ctx t_int a.epos in + let evar_index = mk (TVar(v_index,Some a)) t_void a.epos in + let ev_index = make_local v_index v_index.v_pos in let op1,op2 = if ascending then (OpLt,Increment) else (OpGt,Decrement) in - let econd = binop op1 ev_index b ctx.t.tbool p in - let ev_incr = mk (TUnop(op2,Postfix,ev_index)) t_int p in - let evar = mk (TVar(v,Some ev_incr)) t_void p in + let econd = binop op1 ev_index b ctx.t.tbool (punion v.v_pos b.epos) in + let ev_incr = mk (TUnop(op2,Postfix,ev_index)) t_int (punion a.epos b.epos) in + let evar = mk (TVar(v,Some ev_incr)) t_void (punion v.v_pos a.epos) in let e2 = concat evar e2 in let ewhile = mk (TWhile(econd,e2,NormalWhile)) t_void p in mk (TBlock [ @@ -316,15 +345,15 @@ module IterationKind = struct ]) t_void p | IteratorInt(a,b) -> check_loop_var_modification [v] e2; - let v_index = gen_local ctx t_int p in - let evar_index = mk (TVar(v_index,Some a)) t_void p in - let ev_index = make_local v_index p in + let v_index = gen_local ctx t_int a.epos in + let evar_index = mk (TVar(v_index,Some a)) t_void a.epos in + let ev_index = make_local v_index v_index.v_pos in let v_b = gen_local ctx b.etype b.epos in - let evar_b = mk (TVar (v_b,Some b)) t_void p in + let evar_b = mk (TVar (v_b,Some b)) t_void b.epos in let ev_b = make_local v_b b.epos in - let econd = binop OpLt ev_index ev_b ctx.t.tbool p in - let ev_incr = mk (TUnop(Increment,Postfix,ev_index)) t_int p in - let evar = mk (TVar(v,Some ev_incr)) t_void p in + let econd = binop OpLt ev_index ev_b ctx.t.tbool (punion v.v_pos b.epos) in + let ev_incr = mk (TUnop(Increment,Postfix,ev_index)) t_int (punion a.epos b.epos) in + let evar = mk (TVar(v,Some ev_incr)) t_void (punion v.v_pos a.epos) in let e2 = concat evar e2 in let ewhile = mk (TWhile(econd,e2,NormalWhile)) t_void p in mk (TBlock [ @@ -347,7 +376,7 @@ module IterationKind = struct begin try optimize_for_loop_iterator ctx v e1 e2 p with Exit -> mk (TFor(v,e1,e2)) t_void p end | IteratorGenericStack c -> - let tcell = (try (PMap.find "head" c.cl_fields).cf_type with Not_found -> assert false) in + let tcell = (try (PMap.find "head" c.cl_fields).cf_type with Not_found -> die "" __LOC__) in let cell = gen_local ctx tcell p in let cexpr = mk (TLocal cell) tcell p in let evar = mk (TVar (v,Some (mk (mk_field cexpr "elt") pt p))) t_void v.v_pos in @@ -471,11 +500,12 @@ let type_for_loop ctx handle_display it e2 p = mk (TFor (i,iterator.it_expr,e2)) ctx.t.tvoid p end | IKKeyValue((ikey,pkey,dkokey),(ivalue,pvalue,dkovalue)) -> - let e1,pt = IterationKind.check_iterator ctx "keyValueIterator" e1 e1.epos in - begin match follow e1.etype with - | TDynamic _ | TMono _ -> display_error ctx "You can't iterate on a Dynamic value, please specify KeyValueIterator or KeyValueIterable" e1.epos; + (match follow e1.etype with + | TDynamic _ | TMono _ -> + display_error ctx "You can't iterate on a Dynamic value, please specify KeyValueIterator or KeyValueIterable" e1.epos; | _ -> () - end; + ); + let e1,pt = IterationKind.check_iterator ctx "keyValueIterator" e1 e1.epos in let vtmp = gen_local ctx e1.etype e1.epos in let etmp = make_local vtmp vtmp.v_pos in let ehasnext = !build_call_ref ctx (type_field_default_cfg ctx etmp "hasNext" etmp.epos MCall) [] WithType.value etmp.epos in diff --git a/src/typing/generic.ml b/src/typing/generic.ml index c22e714b9f56f50b4fba24cb13fd88e428bc326a..5d5bcf2afa906cb4a3df548b60679e6bb639c704 100644 --- a/src/typing/generic.ml +++ b/src/typing/generic.ml @@ -31,28 +31,35 @@ let make_generic ctx ps pt p = | (_,t1) :: l1 , t2 :: l2 -> let t,eo = generic_check_const_expr ctx t2 in (t1,(t,eo)) :: loop l1 l2 - | _ -> assert false + | _ -> die "" __LOC__ in let name = String.concat "_" (List.map2 (fun (s,_) t -> let rec subst s = "_" ^ string_of_int (Char.code (String.get (Str.matched_string s) 0)) ^ "_" in let ident_safe = Str.global_substitute (Str.regexp "[^a-zA-Z0-9_]") subst in let s_type_path_underscore (p,s) = match p with [] -> s | _ -> String.concat "_" p ^ "_" ^ s in - let rec loop top t = match follow t with + let rec loop top t = match t with | TInst(c,tl) -> (match c.cl_kind with | KExpr e -> ident_safe (Ast.Printer.s_expr e) - | _ -> (ident_safe (s_type_path_underscore c.cl_path)) ^ (loop_tl tl)) - | TEnum(en,tl) -> (s_type_path_underscore en.e_path) ^ (loop_tl tl) + | _ -> (ident_safe (s_type_path_underscore c.cl_path)) ^ (loop_tl top tl)) + | TType (td,tl) -> (s_type_path_underscore td.t_path) ^ (loop_tl top tl) + | TEnum(en,tl) -> (s_type_path_underscore en.e_path) ^ (loop_tl top tl) | TAnon(a) -> "anon_" ^ String.concat "_" (PMap.foldi (fun s f acc -> (s ^ "_" ^ (loop false (follow f.cf_type))) :: acc) a.a_fields []) | TFun(args, return_type) -> "func_" ^ (String.concat "_" (List.map (fun (_, _, t) -> loop false t) args)) ^ "_" ^ (loop false return_type) - | TAbstract(a,tl) -> (s_type_path_underscore a.a_path) ^ (loop_tl tl) - | _ when not top -> "_" (* allow unknown/incompatible types as type parameters to retain old behavior *) - | TMono _ -> raise (Generic_Exception (("Could not determine type for parameter " ^ s), p)) + | TAbstract(a,tl) -> (s_type_path_underscore a.a_path) ^ (loop_tl top tl) + | _ when not top -> + follow_or t top (fun() -> "_") (* allow unknown/incompatible types as type parameters to retain old behavior *) + | TMono { tm_type = None } -> raise (Generic_Exception (("Could not determine type for parameter " ^ s), p)) | TDynamic _ -> "Dynamic" - | t -> raise (Generic_Exception (("Unsupported type parameter: " ^ (s_type (print_context()) t) ^ ")"), p)) - and loop_tl tl = match tl with + | t -> + follow_or t top (fun() -> raise (Generic_Exception (("Unsupported type parameter: " ^ (s_type (print_context()) t) ^ ")"), p))) + and loop_tl top tl = match tl with | [] -> "" - | tl -> "_" ^ String.concat "_" (List.map (loop false) tl) + | tl -> "_" ^ String.concat "_" (List.map (loop top) tl) + and follow_or t top or_fn = + let ft = follow_once t in + if ft == t then or_fn() + else loop top ft in loop true t ) ps pt) @@ -138,6 +145,31 @@ let get_short_name = Printf.sprintf "Hx___short___hx_type_%i" !i ) +let static_method_container gctx c cf p = + let ctx = gctx.ctx in + let pack = fst c.cl_path in + let name = (snd c.cl_path) ^ "_" ^ cf.cf_name ^ "_" ^ gctx.name in + try + let t = Typeload.load_instance ctx (mk_type_path (pack,name),p) true in + match t with + | TInst(cg,_) -> cg + | _ -> error ("Cannot specialize @:generic static method because the generated type name is already used: " ^ name) p + with Error(Module_not_found path,_) when path = (pack,name) -> + let m = (try Hashtbl.find ctx.g.modules (Hashtbl.find ctx.g.types_module c.cl_path) with Not_found -> die "" __LOC__) in + let mg = { + m_id = alloc_mid(); + m_path = (pack,name); + m_types = []; + m_extra = module_extra (s_type_path (pack,name)) m.m_extra.m_sign 0. MFake m.m_extra.m_check_policy; + } in + gctx.mg <- Some mg; + let cg = mk_class mg (pack,name) c.cl_pos c.cl_name_pos in + mg.m_types <- [TClassDecl cg]; + Hashtbl.add ctx.g.modules mg.m_path mg; + add_dependency mg m; + add_dependency ctx.m.curmod mg; + cg + let rec build_generic ctx c p tl = let pack = fst c.cl_path in let recurse = ref false in @@ -161,12 +193,12 @@ let rec build_generic ctx c p tl = let gctx = make_generic ctx c.cl_params tl p in let name = (snd c.cl_path) ^ "_" ^ gctx.name in try - let t = Typeload.load_instance ctx ({ tpackage = pack; tname = name; tparams = []; tsub = None },p) false in + let t = Typeload.load_instance ctx (mk_type_path (pack,name),p) false in match t with | TInst({ cl_kind = KGenericInstance (csup,_) },_) when c == csup -> t | _ -> error ("Cannot specialize @:generic because the generated type name is already used: " ^ name) p with Error(Module_not_found path,_) when path = (pack,name) -> - let m = (try Hashtbl.find ctx.g.modules (Hashtbl.find ctx.g.types_module c.cl_path) with Not_found -> assert false) in + let m = (try Hashtbl.find ctx.g.modules (Hashtbl.find ctx.g.types_module c.cl_path) with Not_found -> die "" __LOC__) in (* let ctx = { ctx with m = { ctx.m with module_types = m.m_types @ ctx.m.module_types } } in *) ignore(c.cl_build()); (* make sure the super class is already setup *) let mg = { @@ -176,7 +208,7 @@ let rec build_generic ctx c p tl = m_extra = module_extra (s_type_path (pack,name)) m.m_extra.m_sign 0. MFake m.m_extra.m_check_policy; } in gctx.mg <- Some mg; - let cg = mk_class mg (pack,name) c.cl_pos null_pos in + let cg = mk_class mg (pack,name) c.cl_pos c.cl_name_pos in mg.m_types <- [TClassDecl cg]; Hashtbl.add ctx.g.modules mg.m_path mg; add_dependency mg m; @@ -192,7 +224,7 @@ let rec build_generic ctx c p tl = | TType (t,tl) -> add_dep t.t_module tl | TAbstract (a,tl) -> add_dep a.a_module tl | TMono r -> - (match !r with + (match r.tm_type with | None -> () | Some t -> loop t) | TLazy f -> @@ -217,7 +249,7 @@ let rec build_generic ctx c p tl = | TInst(c,tl) as t -> let t2 = TInst({c with cl_module = mg;},tl) in (t,(t2,None)) :: subst,(s,t2) :: params - | _ -> assert false + | _ -> die "" __LOC__ ) ([],[]) cf_old.cf_params in let gctx = {gctx with subst = param_subst @ gctx.subst} in let cf_new = {cf_old with cf_pos = cf_old.cf_pos} in (* copy *) @@ -227,7 +259,7 @@ let rec build_generic ctx c p tl = let tl1 = List.map (generic_substitute_type gctx) tl1 in c.cl_kind <- KTypeParameter tl1; s,t - | _ -> assert false + | _ -> die "" __LOC__ ) params; let f () = let t = generic_substitute_type gctx cf_old.cf_type in @@ -273,7 +305,7 @@ let rec build_generic ctx c p tl = | KGeneric -> (match build_generic ctx cs p pl with | TInst (cs,pl) -> Some (cs,pl) - | _ -> assert false) + | _ -> die "" __LOC__) | _ -> Some(cs,pl) ); TypeloadFunction.add_constructor ctx cg false p; @@ -290,7 +322,7 @@ let rec build_generic ctx c p tl = cg.cl_implements <- List.map (fun (i,tl) -> (match follow (generic_substitute_type gctx (TInst (i, List.map (generic_substitute_type gctx) tl))) with | TInst (i,tl) -> i, tl - | _ -> assert false) + | _ -> die "" __LOC__) ) c.cl_implements; cg.cl_ordered_fields <- List.map (fun f -> let f = build_field f in @@ -298,7 +330,7 @@ let rec build_generic ctx c p tl = f ) c.cl_ordered_fields; cg.cl_overrides <- List.map (fun f -> - try PMap.find f.cf_name cg.cl_fields with Not_found -> assert false + try PMap.find f.cf_name cg.cl_fields with Not_found -> die "" __LOC__ ) c.cl_overrides; (* In rare cases the class name can become too long, so let's shorten it (issue #3090). *) if String.length (snd cg.cl_path) > 254 then begin diff --git a/src/typing/macroContext.ml b/src/typing/macroContext.ml index a4d809a657e000fd57e6da6a890ee5a6fa92a3ac..a076a3ce9f1175006432b33bbeedf5a81ef1d7c9 100644 --- a/src/typing/macroContext.ml +++ b/src/typing/macroContext.ml @@ -121,16 +121,15 @@ let typing_timer ctx need_type f = exit(); raise e -let load_macro_ref : (typer -> bool -> path -> string -> pos -> (typer * ((string * bool * t) list * t * tclass * Type.tclass_field) * (Interp.value list -> Interp.value option))) ref = ref (fun _ _ _ _ -> assert false) +let load_macro_ref : (typer -> bool -> path -> string -> pos -> (typer * ((string * bool * t) list * t * tclass * Type.tclass_field) * (Interp.value list -> Interp.value option))) ref = ref (fun _ _ _ _ -> die "" __LOC__) let make_macro_api ctx p = let parse_expr_string s p inl = typing_timer ctx false (fun() -> try begin match ParserEntry.parse_expr_string ctx.com.defines s p error inl with - | ParseSuccess data -> data - | ParseDisplayFile(data,_) when inl -> data (* ignore errors when inline-parsing in display file *) - | ParseDisplayFile _ -> assert false (* cannot happen because ParserEntry.parse_string sets `display_position := null_pos;` *) + | ParseSuccess(data,true,_) when inl -> data (* ignore errors when inline-parsing in display file *) + | ParseSuccess(data,_,_) -> data | ParseError _ -> raise MacroApi.Invalid_expr end with Exit -> @@ -139,10 +138,9 @@ let make_macro_api ctx p = let parse_metadata s p = try match ParserEntry.parse_string ctx.com.defines (s ^ " typedef T = T") null_pos error false with - | ParseSuccess(_,[ETypedef t,_]) -> t.d_meta - | ParseDisplayFile _ -> assert false (* cannot happen because null_pos is used *) + | ParseSuccess((_,[ETypedef t,_]),_,_) -> t.d_meta | ParseError(_,_,_) -> error "Malformed metadata string" p - | _ -> assert false + | _ -> die "" __LOC__ with _ -> error "Malformed metadata string" p in @@ -154,9 +152,9 @@ let make_macro_api ctx p = let path = parse_path s in let tp = match List.rev (fst path) with | s :: sl when String.length s > 0 && (match s.[0] with 'A'..'Z' -> true | _ -> false) -> - { tpackage = List.rev sl; tname = s; tparams = []; tsub = Some (snd path) } + mk_type_path ~sub:(snd path) (List.rev sl,s) | _ -> - { tpackage = fst path; tname = snd path; tparams = []; tsub = None } + mk_type_path path in try let m = Some (Typeload.load_instance ctx (tp,p) true) in @@ -234,10 +232,9 @@ let make_macro_api ctx p = typing_timer ctx false (fun() -> let v = (match v with None -> None | Some s -> match ParserEntry.parse_string ctx.com.defines ("typedef T = " ^ s) null_pos error false with - | ParseSuccess(_,[ETypedef { d_data = ct },_]) -> Some ct - | ParseDisplayFile _ -> assert false (* cannot happen because null_pos is used *) + | ParseSuccess((_,[ETypedef { d_data = ct },_]),_,_) -> Some ct | ParseError(_,(msg,p),_) -> Parser.error msg p (* p is null_pos, but we don't have anything else here... *) - | _ -> assert false + | _ -> die "" __LOC__ ) in let tp = get_type_patch ctx t (Some (f,s)) in match v with @@ -251,9 +248,9 @@ let make_macro_api ctx p = tp.tp_meta <- tp.tp_meta @ (List.map (fun (m,el,_) -> (m,el,p)) ml); ); MacroApi.set_js_generator = (fun gen -> - Path.mkdir_from_path ctx.com.file; - let js_ctx = Genjs.alloc_ctx ctx.com (get_es_version ctx.com) in ctx.com.js_gen <- Some (fun() -> + Path.mkdir_from_path ctx.com.file; + let js_ctx = Genjs.alloc_ctx ctx.com (get_es_version ctx.com) in let t = macro_timer ctx ["jsGenerator"] in gen js_ctx; t() @@ -302,8 +299,8 @@ let make_macro_api ctx p = | Some (_,_,fields) -> Interp.encode_array (List.map Interp.encode_field fields) ); MacroApi.define_type = (fun v mdep -> - let cttype = { tpackage = ["haxe";"macro"]; tname = "Expr"; tparams = []; tsub = Some ("TypeDefinition") } in - let mctx = (match ctx.g.macros with None -> assert false | Some (_,mctx) -> mctx) in + let cttype = mk_type_path ~sub:"TypeDefinition" (["haxe";"macro"],"Expr") in + let mctx = (match ctx.g.macros with None -> die "" __LOC__ | Some (_,mctx) -> mctx) in let ttype = Typeload.load_instance mctx (cttype,p) false in let f () = Interp.decode_type_def v in let m, tdef, pos = safe_decode ctx v "TypeDefinition" ttype p f in @@ -362,7 +359,7 @@ let make_macro_api ctx p = MacroApi.current_module = (fun() -> ctx.m.curmod ); - MacroApi.current_macro_module = (fun () -> assert false); + MacroApi.current_macro_module = (fun () -> die "" __LOC__); MacroApi.use_cache = (fun() -> !macro_enable_cache ); @@ -417,14 +414,18 @@ let rec init_macro_interp ctx mctx mint = and flush_macro_context mint ctx = let t = macro_timer ctx ["flush"] in - let mctx = (match ctx.g.macros with None -> assert false | Some (_,mctx) -> mctx) in + let mctx = (match ctx.g.macros with None -> die "" __LOC__ | Some (_,mctx) -> mctx) in ctx.g.do_finalize mctx; let _, types, modules = ctx.g.do_generate mctx in mctx.com.types <- types; mctx.com.Common.modules <- modules; (* we should maybe ensure that all filters in Main are applied. Not urgent atm *) - let expr_filters = [VarLazifier.apply mctx.com;AbstractCast.handle_abstract_casts mctx; CapturedVars.captured_vars mctx.com;] in - + let expr_filters = [ + VarLazifier.apply mctx.com; + AbstractCast.handle_abstract_casts mctx; + Exceptions.filter mctx; + CapturedVars.captured_vars mctx.com; + ] in (* some filters here might cause side effects that would break compilation server. let's save the minimal amount of information we need @@ -432,14 +433,30 @@ and flush_macro_context mint ctx = let minimal_restore t = match t with | TClassDecl c -> - let meta = c.cl_meta in - let path = c.cl_path in - c.cl_restore <- (fun() -> c.cl_meta <- meta; c.cl_path <- path); + let mk_field_restore f = + let e = f.cf_expr in + (fun () -> f.cf_expr <- e) + in + let meta = c.cl_meta + and path = c.cl_path + and field_restores = List.map mk_field_restore c.cl_ordered_fields + and static_restores = List.map mk_field_restore c.cl_ordered_statics + and ctor_restore = Option.map mk_field_restore c.cl_constructor + in + c.cl_restore <- (fun() -> + c.cl_meta <- meta; + c.cl_path <- path; + Option.may (fun fn -> fn()) ctor_restore; + List.iter (fun fn -> fn()) field_restores; + List.iter (fun fn -> fn()) static_restores; + ); | _ -> () in let type_filters = [ - Filters.add_field_inits (StringMap.empty) mctx; + Filters.remove_generic_base mctx; + Exceptions.patch_constructors mctx; + Filters.add_field_inits (RenameVars.init mctx.com) mctx; minimal_restore; Filters.apply_native_paths mctx ] in @@ -519,17 +536,17 @@ let load_macro_module ctx cpath display p = }; mloaded,(fun () -> mctx.com.display <- old) -let load_macro ctx display cpath f p = +let load_macro' ctx display cpath f p = let api, mctx = get_macro_context ctx p in let mint = Interp.get_ctx() in - let cpath, sub = (match List.rev (fst cpath) with + let mpath, sub = (match List.rev (fst cpath) with | name :: pack when name.[0] >= 'A' && name.[0] <= 'Z' -> (List.rev pack,name), Some (snd cpath) | _ -> cpath, None ) in let (meth,mloaded) = try Hashtbl.find mctx.com.cached_macros (cpath,f) with Not_found -> let t = macro_timer ctx ["typing";s_type_path cpath ^ "." ^ f] in - let mloaded,restore = load_macro_module ctx cpath display p in - let mt = Typeload.load_type_def mctx p { tpackage = fst cpath; tname = snd cpath; tparams = []; tsub = sub } in + let mloaded,restore = load_macro_module ctx mpath display p in + let mt = Typeload.load_type_def mctx p (mk_type_path ?sub mpath) in let cl, meth = (match mt with | TClassDecl c -> mctx.g.do_finalize mctx; @@ -537,8 +554,7 @@ let load_macro ctx display cpath f p = | _ -> error "Macro should be called on a class" p ) in api.MacroApi.current_macro_module <- (fun() -> mloaded); - if not (Common.defined ctx.com Define.NoDeprecationWarnings) then - DeprecationCheck.check_cf mctx.com meth p; + DeprecationCheck.check_cf mctx.com meth p; let meth = (match follow meth.cf_type with TFun (args,ret) -> (args,ret,cl,meth),mloaded | _ -> error "Macro call should be a method" p) in restore(); if not ctx.in_macro then flush_macro_context mint ctx; @@ -555,11 +571,17 @@ let load_macro ctx display cpath f p = meth in add_dependency ctx.m.curmod mloaded; + meth + +let load_macro ctx display cpath f p = + let meth = load_macro' ctx display cpath f p in + let api, mctx = get_macro_context ctx p in + let _,_,{cl_path = cpath},_ = meth in let call args = if ctx.com.verbose then Common.log ctx.com ("Calling macro " ^ s_type_path cpath ^ "." ^ f ^ " (" ^ p.pfile ^ ":" ^ string_of_int (Lexer.get_error_line p) ^ ")"); let t = macro_timer ctx ["execution";s_type_path cpath ^ "." ^ f] in incr stats.s_macros_called; - let r = Interp.call_path (Interp.get_ctx()) ((fst cpath) @ [(match sub with None -> snd cpath | Some s -> s)]) f args api in + let r = Interp.call_path (Interp.get_ctx()) ((fst cpath) @ [snd cpath]) f args api in t(); if ctx.com.verbose then Common.log ctx.com ("Exiting macro " ^ s_type_path cpath ^ "." ^ f); r @@ -574,7 +596,7 @@ type macro_arg_type = let type_macro ctx mode cpath f (el:Ast.expr list) p = let mctx, (margs,mret,mclass,mfield), call_macro = load_macro ctx (mode = MDisplay) cpath f p in let mpos = mfield.cf_pos in - let ctexpr = { tpackage = ["haxe";"macro"]; tname = "Expr"; tparams = []; tsub = None } in + let ctexpr = mk_type_path (["haxe";"macro"],"Expr") in let expr = Typeload.load_instance mctx (ctexpr,p) false in (match mode with | MDisplay -> @@ -582,18 +604,19 @@ let type_macro ctx mode cpath f (el:Ast.expr list) p = | MExpr -> unify mctx mret expr mpos; | MBuild -> - let ctfields = { tpackage = []; tname = "Array"; tparams = [TPType (CTPath { tpackage = ["haxe";"macro"]; tname = "Expr"; tparams = []; tsub = Some "Field" },null_pos)]; tsub = None } in + let params = [TPType (CTPath (mk_type_path ~sub:"Field" (["haxe";"macro"],"Expr")),null_pos)] in + let ctfields = mk_type_path ~params ([],"Array") in let tfields = Typeload.load_instance mctx (ctfields,p) false in unify mctx mret tfields mpos | MMacroType -> - let cttype = { tpackage = ["haxe";"macro"]; tname = "Type"; tparams = []; tsub = None } in + let cttype = mk_type_path (["haxe";"macro"],"Type") in let ttype = Typeload.load_instance mctx (cttype,p) false in try unify_raise mctx mret ttype mpos; (* TODO: enable this again in the future *) (* ctx.com.warning "Returning Type from @:genericBuild macros is deprecated, consider returning ComplexType instead" p; *) with Error (Unify _,_) -> - let cttype = { tpackage = ["haxe";"macro"]; tname = "Expr"; tparams = []; tsub = Some ("ComplexType") } in + let cttype = mk_type_path ~sub:"ComplexType" (["haxe";"macro"],"Expr") in let ttype = Typeload.load_instance mctx (cttype,p) false in unify_raise mctx mret ttype mpos; ); @@ -670,7 +693,7 @@ let type_macro ctx mode cpath f (el:Ast.expr list) p = | TArray ({ eexpr = TArrayDecl [e] }, { eexpr = TConst (TInt index) }) -> List.nth el (Int32.to_int index), e (* added by unify_call_args *) | TConst TNull -> (EConst (Ident "null"),e.epos), e - | _ -> assert false + | _ -> die "" __LOC__ ) in let ictx = Interp.get_ctx() in match mct with @@ -702,7 +725,7 @@ let type_macro ctx mode cpath f (el:Ast.expr list) p = "Array",(fun () -> let fields = if v = Interp.vnull then (match ctx.get_build_infos() with - | None -> assert false + | None -> die "" __LOC__ | Some (_,_,fields) -> fields) else List.map Interp.decode_field (Interp.decode_array v) @@ -742,9 +765,8 @@ let call_init_macro ctx e = let e = try if String.get e (String.length e - 1) = ';' then error "Unexpected ;" p; begin match ParserEntry.parse_expr_string ctx.com.defines e p error false with - | ParseSuccess data -> data + | ParseSuccess(data,_,_) -> data | ParseError(_,(msg,p),_) -> (Parser.error msg p) - | ParseDisplayFile _ -> assert false (* cannot happen *) end with err -> display_error ctx ("Could not parse `" ^ e ^ "`") p; @@ -778,7 +800,7 @@ let setup() = Interp.setup Interp.macro_api let type_stored_expr ctx e1 = - let id = match e1 with (EConst (Int s),_) -> int_of_string s | _ -> assert false in + let id = match e1 with (EConst (Int s),_) -> int_of_string s | _ -> die "" __LOC__ in get_stored_typed_expr ctx.com id ;; diff --git a/src/typing/magicTypes.ml b/src/typing/magicTypes.ml index 3afc6f1eb5963619f87a51b864f8ad3ea9a362f6..f9c63060849cd04f5d0d8d9fc28a3a6db573591c 100644 --- a/src/typing/magicTypes.ml +++ b/src/typing/magicTypes.ml @@ -20,7 +20,7 @@ let extend_remoting ctx c t p async prot = let new_name = (if async then "Async_" else "Remoting_") ^ t.tname in (* check if the proxy already exists *) let t = (try - load_type_def ctx p { tpackage = fst path; tname = new_name; tparams = []; tsub = None } + load_type_def ctx p (mk_type_path (fst path,new_name)) with Error (Module_not_found _,p2) when p == p2 -> (* build it *) @@ -32,10 +32,10 @@ let extend_remoting ctx c t p async prot = | e -> ctx.com.package_rules <- rules; raise e) in ctx.com.package_rules <- rules; let base_fields = [ - { cff_name = "__cnx",null_pos; cff_pos = p; cff_doc = None; cff_meta = []; cff_access = []; cff_kind = FVar (Some (CTPath { tpackage = ["haxe";"remoting"]; tname = if async then "AsyncConnection" else "Connection"; tparams = []; tsub = None },null_pos),None) }; + { cff_name = "__cnx",null_pos; cff_pos = p; cff_doc = None; cff_meta = []; cff_access = []; cff_kind = FVar (Some (CTPath (mk_type_path (["haxe";"remoting"],if async then "AsyncConnection" else "Connection")),null_pos),None) }; { cff_name = "new",null_pos; cff_pos = p; cff_doc = None; cff_meta = []; cff_access = [APublic,null_pos]; cff_kind = FFun { f_args = [("c",null_pos),false,[],None,None]; f_type = None; f_expr = Some (EBinop (OpAssign,(EConst (Ident "__cnx"),p),(EConst (Ident "c"),p)),p); f_params = [] } }; ] in - let tvoid = CTPath { tpackage = []; tname = "Void"; tparams = []; tsub = None } in + let tvoid = CTPath (mk_type_path ([],"Void")) in let build_field is_public acc f = if fst f.cff_name = "new" then acc diff --git a/src/typing/matcher.ml b/src/typing/matcher.ml index 1f087035fe0d59a6a7b2ed96b916a7c87b737939..70687bb3bf638444d24635a6eab3c4091d113f25 100644 --- a/src/typing/matcher.ml +++ b/src/typing/matcher.ml @@ -46,14 +46,17 @@ let unapply_type_parameters params monos = List.iter2 (fun (_,t1) t2 -> match t2,follow t2 with | TMono m1,TMono m2 -> - unapplied := (m1,!m1) :: !unapplied; - m1 := Some t1; + unapplied := (m1,m1.tm_type) :: !unapplied; + Monomorph.bind m1 t1; | _ -> () ) params monos; !unapplied let reapply_type_parameters unapplied = - List.iter (fun (m,o) -> m := o) unapplied + List.iter (fun (m,o) -> match o with + | None -> Monomorph.unbind m + | Some t -> Monomorph.bind m t + ) unapplied let get_general_module_type ctx mt p = let rec loop = function @@ -156,7 +159,7 @@ module Pattern = struct mutable current_locals : (string, tvar * pos) PMap.t; mutable in_reification : bool; is_postfix_match : bool; - unapply_type_parameters : unit -> (Type.t option ref * Type.t option) list; + unapply_type_parameters : unit -> (tmono * Type.t option) list; } exception Bad_pattern of string @@ -174,7 +177,7 @@ module Pattern = struct let tcl = get_general_module_type ctx mt p in match tcl with | TAbstract(a,_) -> unify ctx (TAbstract(a,[mk_mono()])) t p - | _ -> assert false + | _ -> die "" __LOC__ let rec make pctx toplevel t e = let ctx = pctx.ctx in @@ -206,10 +209,8 @@ module Pattern = struct v in let con_enum en ef p = - if not (Common.defined ctx.com Define.NoDeprecationWarnings) then begin - DeprecationCheck.check_enum pctx.ctx.com en p; - DeprecationCheck.check_ef pctx.ctx.com ef p; - end; + DeprecationCheck.check_enum pctx.ctx.com en p; + DeprecationCheck.check_ef pctx.ctx.com ef p; ConEnum(en,ef),p in let con_static c cf p = ConStatic(c,cf),p in @@ -233,6 +234,9 @@ module Pattern = struct raise (Bad_pattern "Only inline or read-only (default, never) fields can be used as a pattern") | TTypeExpr mt -> PatConstructor(con_type_expr mt e.epos,[]) + | TMeta((Meta.Deprecated,_,_) as m, e1) -> + DeprecationCheck.check_meta pctx.ctx.com [m] "field" e1.epos; + loop e1 | _ -> raise Exit in @@ -241,10 +245,27 @@ module Pattern = struct let display_mode () = if pctx.is_postfix_match then DKMarked else DKPattern toplevel in + let catch_errors () = + let old = ctx.on_error in + ctx.on_error <- (fun _ _ _ -> + raise Exit + ); + (fun () -> + ctx.on_error <- old + ) + in let try_typing e = let old = ctx.untyped in ctx.untyped <- true; - let e = try type_expr ctx e (WithType.with_type t) with exc -> ctx.untyped <- old; raise exc in + let restore = catch_errors () in + let e = try + type_expr ctx e (WithType.with_type t) + with exc -> + restore(); + ctx.untyped <- old; + raise exc + in + restore(); ctx.untyped <- old; let pat = check_expr e in begin match pat with @@ -258,15 +279,7 @@ module Pattern = struct try_typing (EConst (Ident s),p) with | Exit | Bad_pattern _ -> - let restore = - let old = ctx.on_error in - ctx.on_error <- (fun _ _ _ -> - raise Exit - ); - (fun () -> - ctx.on_error <- old - ) - in + let restore = catch_errors () in begin try let mt = module_type_of_type t in let e_mt = TyperBase.type_module_type ctx mt None p in @@ -312,7 +325,7 @@ module Pattern = struct let p = pos e in let e = Texpr.type_constant ctx.com.basic ct p in unify_expected e.etype; - let ct = match e.eexpr with TConst ct -> ct | _ -> assert false in + let ct = match e.eexpr with TConst ct -> ct | _ -> die "" __LOC__ in PatConstructor(con_const ct p,[]) | EConst (Ident i) -> begin match follow t with @@ -337,7 +350,7 @@ module Pattern = struct | TFun(args,r) -> unify_expected r; args - | _ -> assert false + | _ -> die "" __LOC__ in let rec loop el tl = match el,tl with | [EConst (Ident "_"),p],(_,_,t) :: tl -> @@ -534,7 +547,7 @@ module Case = struct let e2 = collapse_case el in EBinop(OpOr,e,e2),punion (pos e) (pos e2) | [] -> - assert false + die "" __LOC__ in let e = collapse_case el in let monos = List.map (fun _ -> mk_mono()) ctx.type_params in @@ -560,7 +573,9 @@ module Case = struct ignore(unapply_type_parameters ctx.type_params monos); let eg = match eg with | None -> None - | Some e -> Some (type_expr ctx e WithType.value) + | Some e -> + let e = type_expr ctx e WithType.value in + Some (AbstractCast.cast_or_unify ctx ctx.t.tbool e e.epos) in let eo = match eo_ast,with_type with | None,WithType.WithType(t,_) -> @@ -823,7 +838,7 @@ module Useless = struct | [],_,_ -> List.rev pAcc,List.rev qAcc,List.rev rAcc | _ -> - assert false + die "" __LOC__ in loop [] [] [] pM qM rM @@ -849,7 +864,7 @@ module Useless = struct let rec loop acc k l = match l with | x :: l when i = k -> x,(List.rev acc) @ l @ q | x :: l -> loop (x :: acc) (k + 1) l - | [] -> assert false + | [] -> die "" __LOC__ in loop [] 0 l in @@ -866,7 +881,7 @@ module Useless = struct let p = punion (pos pat1) (pos pat2) in let et = combine (et,p) (et3,p) in (i + 1,et) - | _ -> assert false + | _ -> die "" __LOC__ ) (0,True) r) end | (pat :: pl) -> @@ -1220,7 +1235,7 @@ module Compile = struct let patterns = make_offset_list 0 num_extractors pat pat_any @ patterns in (left,right,subjects,((case,bindings,patterns) :: cases),ex_bindings) | _,[] -> - assert false + die "" __LOC__ ) (0,num_extractors,[],[],[]) cases (List.rev extractors) in let dt = compile mctx ((subject :: List.rev ex_subjects) @ subjects) (List.rev cases) in let bindings = List.map (fun (a,b,c,_,_) -> (a,b,c)) bindings in @@ -1276,7 +1291,7 @@ module TexprConverter = struct if top then loop false s e1 else loop false (Printf.sprintf "{ %s: %s }" (field_name fa) s) e1 | TEnumParameter(e1,ef,i) -> - let arity = match follow ef.ef_type with TFun(args,_) -> List.length args | _ -> assert false in + let arity = match follow ef.ef_type with TFun(args,_) -> List.length args | _ -> die "" __LOC__ in let l = make_offset_list i (arity - i - 1) s "_" in loop false (Printf.sprintf "%s(%s)" ef.ef_name (String.concat ", " l)) e1 | TLocal v -> @@ -1436,7 +1451,7 @@ module TexprConverter = struct let v_lookup = ref IntMap.empty in let com = ctx.com in let p = dt.dt_pos in - let c_type = match follow (Typeload.load_instance ctx ({ tpackage = ["std"]; tname="Type"; tparams=[]; tsub = None},p) true) with TInst(c,_) -> c | t -> assert false in + let c_type = match follow (Typeload.load_instance ctx (mk_type_path (["std"],"Type"),p) true) with TInst(c,_) -> c | t -> die "" __LOC__ in let mk_index_call e = if not ctx.in_macro && not ctx.com.display.DisplayMode.dms_full_typing then (* If we are in display mode there's a chance that these fields don't exist. Let's just use a @@ -1613,7 +1628,7 @@ module Match = struct let tmono,with_type,allow_min_void = match with_type with | WithType.WithType(t,src) -> (match follow t, src with - | TMono _, Some ImplicitReturn -> Some t, WithType.Value src, true + | ((TMono _) | (TAbstract({a_path=[],"Void"},_))), Some ImplicitReturn -> Some t, WithType.Value src, true | TMono _, _ -> Some t,WithType.value,false | _ -> None,with_type,false) | _ -> None,with_type,false diff --git a/src/typing/nullSafety.ml b/src/typing/nullSafety.ml index 7c0ab17f1c8f46e425eb3d10014efab3f9f1a533..baa259864fde56a888ea7f4676659b59279ea14b 100644 --- a/src/typing/nullSafety.ml +++ b/src/typing/nullSafety.ml @@ -34,6 +34,7 @@ type safety_mode = | SMOff | SMLoose | SMStrict + | SMStrictThreaded (** Terminates compiler process and prints user-friendly instructions about filing an issue in compiler repo. @@ -48,7 +49,7 @@ let fail ?msg hxpos mlpos = | (file, line, _, _) -> Printf.eprintf "%s\n" msg; Printf.eprintf "%s:%d\n" file line; - assert false + die "" __LOC__ (** Returns human-readable string representation of specified type @@ -71,7 +72,7 @@ let is_string_type t = *) let rec is_nullable_type = function | TMono r -> - (match !r with None -> false | Some t -> is_nullable_type t) + (match r.tm_type with None -> false | Some t -> is_nullable_type t) | TAbstract ({ a_path = ([],"Null") },[t]) -> true | TAbstract (a,tl) when not (Meta.has Meta.CoreType a.a_meta) -> @@ -136,18 +137,18 @@ type safety_subject = *) | SNotSuitable -let rec get_subject loose_safety expr = +let rec get_subject mode expr = match (reveal_expr expr).eexpr with | TLocal v -> SLocalVar v.v_id - | TField ({ eexpr = TTypeExpr _ }, FStatic (cls, field)) when loose_safety || (has_class_field_flag field CfFinal) -> + | TField ({ eexpr = TTypeExpr _ }, FStatic (cls, field)) when (mode <> SMStrictThreaded) || (has_class_field_flag field CfFinal) -> SFieldOfClass (cls.cl_path, [field.cf_name]) - | TField ({ eexpr = TConst TThis }, (FInstance (_, _, field) | FAnon field)) when loose_safety || (has_class_field_flag field CfFinal) -> + | TField ({ eexpr = TConst TThis }, (FInstance (_, _, field) | FAnon field)) when (mode <> SMStrictThreaded) || (has_class_field_flag field CfFinal) -> SFieldOfThis [field.cf_name] - | TField ({ eexpr = TLocal v }, (FInstance (_, _, field) | FAnon field)) when loose_safety || (has_class_field_flag field CfFinal) -> + | TField ({ eexpr = TLocal v }, (FInstance (_, _, field) | FAnon field)) when (mode <> SMStrictThreaded) || (has_class_field_flag field CfFinal) -> SFieldOfLocalVar (v.v_id, [field.cf_name]) - | TField (e, (FInstance (_, _, field) | FAnon field)) when loose_safety -> - (match get_subject loose_safety e with + | TField (e, (FInstance (_, _, field) | FAnon field)) when (mode <> SMStrictThreaded) -> + (match get_subject mode e with | SFieldOfClass (path, fields) -> SFieldOfClass (path, field.cf_name :: fields) | SFieldOfThis fields -> SFieldOfThis (field.cf_name :: fields) | SFieldOfLocalVar (var_id, fields) -> SFieldOfLocalVar (var_id, field.cf_name :: fields) @@ -155,15 +156,51 @@ let rec get_subject loose_safety expr = ) |_ -> SNotSuitable -let rec is_suitable loose_safety expr = +(** + Check if provided expression is a subject to null safety. + E.g. a call cannot be such a subject, because we cannot track null-state of the call result. +*) +let rec is_suitable mode expr = match (reveal_expr expr).eexpr with | TField ({ eexpr = TConst TThis }, FInstance _) | TField ({ eexpr = TLocal _ }, (FInstance _ | FAnon _)) | TField ({ eexpr = TTypeExpr _ }, FStatic _) | TLocal _ -> true - | TField (target, (FInstance _ | FStatic _ | FAnon _)) when loose_safety -> is_suitable loose_safety target + | TField (target, (FInstance _ | FStatic _ | FAnon _)) when mode <> SMStrictThreaded -> is_suitable mode target |_ -> false +(** + Returns a list of metadata attached to `callee` arguments. + E.g. for + ``` + function(@:meta1 a:Type1, b:Type2, @:meta2 c:Type3) + ``` + will return `[ [@:meta1], [], [@:meta2] ]` +*) +let get_arguments_meta callee expected_args_count = + let rec empty_list n = + if n <= 0 then [] + else [] :: (empty_list (n - 1)) + in + match callee.eexpr with + | TField (_, FAnon field) + | TField (_, FClosure (_,field)) + | TField (_, FStatic (_, field)) + | TField (_, FInstance (_, _, field)) -> + (try + match get_meta Meta.HaxeArguments field.cf_meta with + | _,[EFunction(_,{ f_args = args }),_],_ when expected_args_count = List.length args -> + List.map (fun (_,_,m,_,_) -> m) args + | _ -> + raise Not_found + with Not_found -> + empty_list expected_args_count + ) + | TFunction { tf_args = args } when expected_args_count = List.length args -> + List.map (fun (v,_) -> v.v_meta) args + | _ -> + empty_list expected_args_count + class unificator = object(self) val stack = new_rec_stack() @@ -194,9 +231,9 @@ class unificator = self#unify (lazy_type f) b | _, TLazy f -> self#unify a (lazy_type f) | TMono t, _ -> - (match !t with None -> () | Some t -> self#unify t b) + (match t.tm_type with None -> () | Some t -> self#unify t b) | _, TMono t -> - (match !t with None -> () | Some t -> self#unify a t) + (match t.tm_type with None -> () | Some t -> self#unify a t) | TType (t,tl), _ -> self#unify_rec a b (fun() -> self#unify (apply_params t.t_params tl t.t_type) b) | _, TType (t,tl) -> @@ -300,7 +337,7 @@ let is_trace expr = *) let rec unfold_null t = match t with - | TMono r -> (match !r with None -> t | Some t -> unfold_null t) + | TMono r -> (match r.tm_type with None -> t | Some t -> unfold_null t) | TAbstract ({ a_path = ([],"Null") }, [t]) -> unfold_null t | TLazy f -> unfold_null (lazy_type f) | TType (t,tl) -> unfold_null (apply_params t.t_params tl t.t_type) @@ -326,7 +363,7 @@ let rec can_pass_type src dst = else (* TODO *) match dst with - | TMono r -> (match !r with None -> true | Some t -> can_pass_type src t) + | TMono r -> (match r.tm_type with None -> true | Some t -> can_pass_type src t) | TEnum (_, params) -> true | TInst _ -> true | TType (t, tl) -> can_pass_type src (apply_params t.t_params tl t.t_type) @@ -341,7 +378,7 @@ let rec can_pass_type src dst = Collect nullable local vars which are checked against `null`. Returns a tuple of (vars_checked_to_be_null * vars_checked_to_be_not_null) in case `condition` evaluates to `true`. *) -let rec process_condition loose_safety condition (is_nullable_expr:texpr->bool) callback = +let rec process_condition mode condition (is_nullable_expr:texpr->bool) callback = let nulls = ref [] and not_nulls = ref [] in let add to_nulls expr = @@ -352,17 +389,17 @@ let rec process_condition loose_safety condition (is_nullable_expr:texpr->bool) let rec traverse positive e = match e.eexpr with | TUnop (Not, Prefix, e) -> traverse (not positive) e - | TBinop (OpEq, { eexpr = TConst TNull }, checked_expr) when is_suitable loose_safety checked_expr -> + | TBinop (OpEq, { eexpr = TConst TNull }, checked_expr) when is_suitable mode checked_expr -> add positive checked_expr - | TBinop (OpEq, checked_expr, { eexpr = TConst TNull }) when is_suitable loose_safety checked_expr -> + | TBinop (OpEq, checked_expr, { eexpr = TConst TNull }) when is_suitable mode checked_expr -> add positive checked_expr - | TBinop (OpNotEq, { eexpr = TConst TNull }, checked_expr) when is_suitable loose_safety checked_expr -> + | TBinop (OpNotEq, { eexpr = TConst TNull }, checked_expr) when is_suitable mode checked_expr -> add (not positive) checked_expr - | TBinop (OpNotEq, checked_expr, { eexpr = TConst TNull }) when is_suitable loose_safety checked_expr -> + | TBinop (OpNotEq, checked_expr, { eexpr = TConst TNull }) when is_suitable mode checked_expr -> add (not positive) checked_expr - | TBinop (OpEq, e, checked_expr) when is_suitable loose_safety checked_expr && not (is_nullable_expr e) -> + | TBinop (OpEq, e, checked_expr) when is_suitable mode checked_expr && not (is_nullable_expr e) -> if positive then not_nulls := checked_expr :: !not_nulls - | TBinop (OpEq, checked_expr, e) when is_suitable loose_safety checked_expr && not (is_nullable_expr e) -> + | TBinop (OpEq, checked_expr, e) when is_suitable mode checked_expr && not (is_nullable_expr e) -> if positive then not_nulls := checked_expr :: !not_nulls | TBinop (OpBoolAnd, left_expr, right_expr) when positive -> traverse positive left_expr; @@ -370,7 +407,7 @@ let rec process_condition loose_safety condition (is_nullable_expr:texpr->bool) | TBinop (OpBoolAnd, left_expr, right_expr) when not positive -> List.iter (fun e -> - let _, not_nulls = process_condition loose_safety left_expr is_nullable_expr callback in + let _, not_nulls = process_condition mode left_expr is_nullable_expr callback in List.iter (add true) not_nulls ) [left_expr; right_expr] @@ -380,7 +417,7 @@ let rec process_condition loose_safety condition (is_nullable_expr:texpr->bool) | TBinop (OpBoolOr, left_expr, right_expr) when positive -> List.iter (fun e -> - let nulls, _ = process_condition loose_safety left_expr is_nullable_expr callback in + let nulls, _ = process_condition mode left_expr is_nullable_expr callback in List.iter (add true) nulls ) [left_expr; right_expr] @@ -406,7 +443,7 @@ let rec contains_safe_meta metadata = match metadata with | [] -> false | (Meta.NullSafety, [], _) :: _ - | (Meta.NullSafety, [(EConst (Ident ("Loose" | "Strict")), _)], _) :: _ -> true + | (Meta.NullSafety, [(EConst (Ident ("Loose" | "Strict" | "StrictThreaded")), _)], _) :: _ -> true | _ :: rest -> contains_safe_meta rest let safety_enabled meta = @@ -423,6 +460,8 @@ let safety_mode (metadata:Ast.metadata) = traverse (Some SMLoose) rest | _, (Meta.NullSafety, [(EConst (Ident "Strict"), _)], _) :: rest -> traverse (Some SMStrict) rest + | _, (Meta.NullSafety, [(EConst (Ident "StrictThreaded"), _)], _) :: rest -> + traverse (Some SMStrictThreaded) rest | _, _ :: rest -> traverse mode rest in @@ -430,16 +469,16 @@ let safety_mode (metadata:Ast.metadata) = | Some mode -> mode | None -> SMOff -let rec validate_safety_meta error (metadata:Ast.metadata) = +let rec validate_safety_meta report (metadata:Ast.metadata) = match metadata with | [] -> () | (Meta.NullSafety, args, pos) :: rest -> (match args with - | ([] | [(EConst (Ident ("Off" | "Loose" | "Strict")), _)]) -> () - | _ -> error "Invalid argument for @:nullSafety meta" pos + | ([] | [(EConst (Ident ("Off" | "Loose" | "Strict" | "StrictThreaded")), _)]) -> () + | _ -> add_error report "Invalid argument for @:nullSafety meta" pos ); - validate_safety_meta error rest - | _ :: rest -> validate_safety_meta error rest + validate_safety_meta report rest + | _ :: rest -> validate_safety_meta report rest (** Check if specified `field` represents a `var` field which will exist at runtime. @@ -450,16 +489,6 @@ let should_be_initialized field = | Var _ -> Meta.has Meta.IsVar field.cf_meta | _ -> false -(** - Check if `field` is overridden in subclasses -*) -let is_overridden cls field = - let rec loop_inheritance c = - (PMap.mem field.cf_name c.cl_fields) - || List.exists (fun d -> loop_inheritance d) c.cl_descendants; - in - List.exists (fun d -> loop_inheritance d) cls.cl_descendants - (** Check if all items of the `needle` list exist in the same order in the beginning of the `haystack` list. *) @@ -504,7 +533,7 @@ class immediate_execution = (* known to be pure *) | { cl_path = ([], "Array") }, _ -> true (* try to analyze function code *) - | _, ({ cf_expr = (Some { eexpr = TFunction fn }) } as field) when (has_class_field_flag field CfFinal) || not (is_overridden cls field) -> + | _, ({ cf_expr = (Some { eexpr = TFunction fn }) } as field) when (has_class_field_flag field CfFinal) || not (FiltersCommon.is_overridden cls field) -> if arg_num < 0 || arg_num >= List.length fn.tf_args then false else begin @@ -638,31 +667,67 @@ class safety_scope (mode:safety_mode) (scope_type:scope_type) (safe_locals:(safe match self#get_subject expr with | SNotSuitable -> () | subj -> - let remove safe_subj safe_fields fields = + (* + If this is an assignment to a field, drop all safe field accesses first, + because it could alter an object of those field accesses. + *) + (match subj with + | SFieldOfClass _ | SFieldOfLocalVar _ | SFieldOfThis _ -> self#drop_safe_fields_in_strict_mode + | _ -> () + ); + let add_to_remove safe_subj safe_fields fields to_remove = if list_starts_with_list (List.rev safe_fields) (List.rev fields) then - Hashtbl.remove safe_locals safe_subj + safe_subj :: to_remove + else + to_remove in - Hashtbl.iter - (fun safe_subj safe_expr -> - match safe_subj, subj with - | SFieldOfLocalVar (safe_id, _), SLocalVar v_id when safe_id = v_id -> - Hashtbl.remove safe_locals safe_subj - | SFieldOfLocalVar (safe_id, safe_fields), SFieldOfLocalVar (v_id, fields) when safe_id = v_id -> - remove safe_subj safe_fields fields - | SFieldOfClass (safe_path, safe_fields), SFieldOfClass (path, fields) when safe_path = path -> - remove safe_subj safe_fields fields - | SFieldOfClass (safe_path, safe_fields), SFieldOfClass (path, fields) when safe_path = path -> - remove safe_subj safe_fields fields - | SFieldOfThis safe_fields, SFieldOfThis fields -> - remove safe_subj safe_fields fields - | _ -> () + let remove_list = + Hashtbl.fold + (fun safe_subj safe_expr to_remove -> + match safe_subj, subj with + | SFieldOfLocalVar (safe_id, _), SLocalVar v_id when safe_id = v_id -> + safe_subj :: to_remove + | SFieldOfLocalVar (safe_id, safe_fields), SFieldOfLocalVar (v_id, fields) when safe_id = v_id -> + add_to_remove safe_subj safe_fields fields to_remove + | SFieldOfClass (safe_path, safe_fields), SFieldOfClass (path, fields) when safe_path = path -> + add_to_remove safe_subj safe_fields fields to_remove + | SFieldOfClass (safe_path, safe_fields), SFieldOfClass (path, fields) when safe_path = path -> + add_to_remove safe_subj safe_fields fields to_remove + | SFieldOfThis safe_fields, SFieldOfThis fields -> + add_to_remove safe_subj safe_fields fields to_remove + | _ -> to_remove + ) + safe_locals [] + in + List.iter (Hashtbl.remove safe_locals) remove_list + (** + Should be called upon a call. + In Strict mode making a call removes all field accesses from safety. + *) + method call_made = + self#drop_safe_fields_in_strict_mode + (** + Un-safe all field accesses if safety mode is one of strict modes + *) + method private drop_safe_fields_in_strict_mode = + match mode with + | SMOff | SMLoose -> () + | SMStrict | SMStrictThreaded -> + let remove_list = + Hashtbl.fold + (fun subj expr to_remove -> + match subj with + | SFieldOfLocalVar _ | SFieldOfClass _ | SFieldOfThis _ -> subj :: to_remove + | _ -> to_remove ) - (Hashtbl.copy safe_locals) + safe_locals [] + in + List.iter (Hashtbl.remove safe_locals) remove_list (** Wrapper for `get_subject` function *) method private get_subject = - get_subject (mode <> SMStrict) + get_subject mode end (** @@ -765,12 +830,12 @@ class local_safety (mode:safety_mode) = | TWhile (condition, body, DoWhile) -> let original_safe_locals = self#get_safe_locals_copy in condition_callback condition; - let (_, not_nulls) = process_condition (mode <> SMStrict) condition is_nullable_expr (fun _ -> ()) in + let (_, not_nulls) = process_condition mode condition is_nullable_expr (fun _ -> ()) in body_callback (fun () -> List.iter (fun not_null -> - match get_subject (mode <> SMStrict) not_null with + match get_subject mode not_null with | SNotSuitable -> () | subj -> if Hashtbl.mem original_safe_locals subj then @@ -781,7 +846,7 @@ class local_safety (mode:safety_mode) = body | TWhile (condition, body, NormalWhile) -> condition_callback condition; - let (nulls, not_nulls) = process_condition (mode <> SMStrict) condition is_nullable_expr (fun _ -> ()) in + let (nulls, not_nulls) = process_condition mode condition is_nullable_expr (fun _ -> ()) in (** execute `body` with known not-null variables *) List.iter self#get_current_scope#add_to_safety not_nulls; body_callback @@ -833,7 +898,7 @@ class local_safety (mode:safety_mode) = | TIf (condition, if_body, else_body) -> condition_callback condition; let (_, not_nulls) = - process_condition (mode <> SMStrict) condition is_nullable_expr (fun _ -> ()) + process_condition mode condition is_nullable_expr (fun _ -> ()) in (* Don't touch expressions, which already was safe before this `if` *) let filter = List.filter (fun e -> not (self#is_safe e)) in @@ -842,7 +907,7 @@ class local_safety (mode:safety_mode) = { eexpr = TUnop (Not, Prefix, condition); etype = condition.etype; epos = condition.epos } in let (_, else_not_nulls) = - process_condition (mode <> SMStrict) not_condition is_nullable_expr (fun _ -> ()) + process_condition mode not_condition is_nullable_expr (fun _ -> ()) in let else_not_nulls = filter else_not_nulls in (** execute `if_body` with known not-null variables *) @@ -873,7 +938,7 @@ class local_safety (mode:safety_mode) = *) method process_and left_expr right_expr is_nullable_expr (callback:texpr->unit) = callback left_expr; - let (_, not_nulls) = process_condition (mode <> SMStrict) left_expr is_nullable_expr (fun e -> ()) in + let (_, not_nulls) = process_condition mode left_expr is_nullable_expr (fun e -> ()) in List.iter self#get_current_scope#add_to_safety not_nulls; callback right_expr; List.iter self#get_current_scope#remove_from_safety not_nulls @@ -881,7 +946,7 @@ class local_safety (mode:safety_mode) = Handle boolean OR outside of `if` condition. *) method process_or left_expr right_expr is_nullable_expr (callback:texpr->unit) = - let (nulls, _) = process_condition (mode <> SMStrict) left_expr is_nullable_expr callback in + let (nulls, _) = process_condition mode left_expr is_nullable_expr callback in List.iter self#get_current_scope#add_to_safety nulls; callback right_expr; List.iter self#get_current_scope#remove_from_safety nulls @@ -889,7 +954,7 @@ class local_safety (mode:safety_mode) = Remove subject from the safety list if a nullable value is assigned or if an object with safe field is reassigned. *) method handle_assignment is_nullable_expr left_expr (right_expr:texpr) = - if is_suitable (mode <> SMStrict) left_expr then + if is_suitable mode left_expr then self#get_current_scope#reassigned left_expr; if is_nullable_expr right_expr then match left_expr.eexpr with @@ -911,6 +976,8 @@ class local_safety (mode:safety_mode) = | _ -> () else if is_nullable_type left_expr.etype then self#get_current_scope#add_to_safety left_expr + method call_made = + self#get_current_scope#call_made end (** @@ -1041,6 +1108,7 @@ class expr_checker mode immediate_execution report = | TThrow expr -> self#check_throw expr e.epos | TCast (expr, _) -> self#check_cast expr e.etype e.epos | TMeta (m, _) when contains_unsafe_meta [m] -> () + | TMeta ((Meta.NullSafety, _, _) as m, e) -> validate_safety_meta report [m]; self#check_expr e | TMeta (_, e) -> self#check_expr e | TEnumIndex idx -> self#check_enum_index idx e.epos | TEnumParameter (e, _, _) -> self#check_expr e (** Checking enum value itself is not needed here because this expr always follows after TEnumIndex *) @@ -1236,7 +1304,7 @@ class expr_checker mode immediate_execution report = local_safety#process_and left_expr right_expr self#is_nullable_expr self#check_expr | OpBoolOr -> local_safety#process_or left_expr right_expr self#is_nullable_expr self#check_expr - (* String concatination is safe if one of operands is safe *) + (* String concatenation is safe if one of operands is safe *) | OpAdd | OpAssignOp OpAdd when is_string_type left_expr.etype || is_string_type right_expr.etype -> check_both(); @@ -1245,7 +1313,10 @@ class expr_checker mode immediate_execution report = | OpAssign -> check_both(); if not (self#can_pass_expr right_expr left_expr.etype p) then - self#error "Cannot assign nullable value here." [p; right_expr.epos; left_expr.epos] + match left_expr.eexpr with + | TLocal v when contains_unsafe_meta v.v_meta -> () + | _ -> + self#error "Cannot assign nullable value here." [p; right_expr.epos; left_expr.epos] else local_safety#handle_assignment self#is_nullable_expr left_expr right_expr; | _-> @@ -1273,10 +1344,6 @@ class expr_checker mode immediate_execution report = | Some e -> let local = { eexpr = TLocal v; epos = v.v_pos; etype = v.v_type } in self#check_binop OpAssign local e p - (* self#check_expr e; - local_safety#handle_assignment self#is_nullable_expr local e; - if not (self#can_pass_expr e v.v_type p) then - self#error "Cannot assign nullable value to not-nullable variable." p; *) (** Make sure nobody tries to access a field on a nullable value *) @@ -1285,7 +1352,7 @@ class expr_checker mode immediate_execution report = if self#is_nullable_expr target then self#error ("Cannot access \"" ^ accessed_field_name access ^ "\" of a nullable value.") [p; target.epos]; (** - Check constructor invocation: don't pass nulable values to not-nullable arguments + Check constructor invocation: don't pass nullable values to not-nullable arguments *) method private check_new e_new = match e_new.eexpr with @@ -1320,7 +1387,7 @@ class expr_checker mode immediate_execution report = | _ -> self#check_expr callee ); - match follow callee.etype with + (match follow callee.etype with | TFun (types, _) -> if is_trace callee then let real_args = @@ -1338,32 +1405,45 @@ class expr_checker mode immediate_execution report = | _ -> args in List.iter self#check_expr real_args - else + else begin self#check_args callee args types + end | _ -> List.iter self#check_expr args + ); + local_safety#call_made (** Check if specified expressions can be passed to a call which expects `types`. *) - method private check_args ?(arg_num=0) callee args types = - match (args, types) with - | (arg :: args, (arg_name, optional, t) :: types) -> - if not optional && not (self#can_pass_expr arg t arg.epos) then begin - let fn_str = match symbol_name callee with "" -> "" | name -> " of function \"" ^ name ^ "\"" - and arg_str = if arg_name = "" then "" else " \"" ^ arg_name ^ "\"" in - self#error ("Cannot pass nullable value to not-nullable argument" ^ arg_str ^ fn_str ^ ".") [arg.epos; callee.epos] - end; - (match arg.eexpr with - | TFunction fn -> - self#check_function ~immediate_execution:(immediate_execution#check callee arg_num) fn - | _ -> - self#check_expr arg - ); - self#check_args ~arg_num:(arg_num + 1) callee args types; - | _ -> () + method private check_args callee args types = + let rec traverse arg_num args types meta = + match (args, types, meta) with + | (arg :: args, (arg_name, optional, t) :: types, arg_meta :: meta) -> + let unsafe_argument = contains_unsafe_meta arg_meta in + if + not optional && not unsafe_argument + && not (self#can_pass_expr arg t arg.epos) + then begin + let fn_str = match symbol_name callee with "" -> "" | name -> " of function \"" ^ name ^ "\"" + and arg_str = if arg_name = "" then "" else " \"" ^ arg_name ^ "\"" in + self#error ("Cannot pass nullable value to not-nullable argument" ^ arg_str ^ fn_str ^ ".") [arg.epos; callee.epos] + end; + (match arg.eexpr with + | TFunction fn -> + self#check_function ~immediate_execution:(immediate_execution#check callee arg_num) fn + | TCast(e,None) when unsafe_argument && fast_eq arg.etype t -> + self#check_expr e + | _ -> + self#check_expr arg + ); + traverse (arg_num + 1) args types meta; + | _ -> () + in + let meta = get_arguments_meta callee (List.length types) in + traverse 0 args types meta end -class class_checker cls immediate_execution report = +class class_checker cls immediate_execution report = let cls_meta = cls.cl_meta @ (match cls.cl_kind with KAbstractImpl a -> a.a_meta | _ -> []) in object (self) val is_safe_class = (safety_enabled cls_meta) @@ -1373,9 +1453,11 @@ class class_checker cls immediate_execution report = Entry point for checking a class *) method check = + validate_safety_meta report cls_meta; if is_safe_class && (not cls.cl_extern) && (not cls.cl_interface) then self#check_var_fields; let check_field is_static f = + validate_safety_meta report f.cf_meta; match (safety_mode (cls_meta @ f.cf_meta)) with | SMOff -> () | mode -> @@ -1448,6 +1530,7 @@ class class_checker cls immediate_execution report = *) method check_var_fields = let check_field is_static field = + validate_safety_meta report field.cf_meta; if should_be_initialized field then if not (is_nullable_type field.cf_type) && self#is_in_safety field then match field.cf_expr with diff --git a/src/typing/typeload.ml b/src/typing/typeload.ml index 20c1252c7fb877ea4e48404afd15f70248144574..b6756ccf7325942964819cdba3c178c1fa52c4f5 100644 --- a/src/typing/typeload.ml +++ b/src/typing/typeload.ml @@ -36,7 +36,7 @@ open Filename let build_count = ref 0 -let type_function_params_rec = ref (fun _ _ _ _ -> assert false) +let type_function_params_rec = ref (fun _ _ _ _ -> die "" __LOC__) let check_field_access ctx cff = let display_access = ref None in @@ -85,13 +85,26 @@ let find_type_in_module m tname = not infos.mt_private && snd infos.mt_path = tname ) m.m_types +(* raises Type_not_found *) +let find_type_in_module_raise m tname p = + try + List.find (fun mt -> + let infos = t_infos mt in + if snd infos.mt_path = tname then + if infos.mt_private then + raise_error (Type_not_found (m.m_path,tname,Private_type)) p + else + true + else + false + ) m.m_types + with Not_found -> + raise_error (Type_not_found (m.m_path,tname,Not_defined)) p + (* raises Module_not_found or Type_not_found *) let load_type_raise ctx mpath tname p = let m = ctx.g.do_load_module ctx mpath p in - try - find_type_in_module m tname - with Not_found -> - raise_error (Type_not_found(mpath,tname)) p + find_type_in_module_raise m tname p (* raises Not_found *) let load_type ctx mpath tname p = try @@ -101,67 +114,121 @@ with Error((Module_not_found _ | Type_not_found _),p2) when p = p2 -> (** since load_type_def and load_instance are used in PASS2, they should not access the structure of a type **) +let find_type_in_current_module_context ctx pack name = + let no_pack = pack = [] in + let path_matches t2 = + let tp = t_path t2 in + (* see also https://github.com/HaxeFoundation/haxe/issues/9150 *) + tp = (pack,name) || (no_pack && snd tp = name) + in + try + (* Check the types in our own module *) + List.find path_matches ctx.m.curmod.m_types + with Not_found -> + (* Check the local imports *) + let t,pi = List.find (fun (t2,pi) -> path_matches t2) ctx.m.module_types in + ImportHandling.mark_import_position ctx pi; + t + +let find_in_wildcard_imports ctx mname p f = + let rec loop l = + match l with + | [] -> + raise Not_found + | (pack,ppack) :: l -> + begin + try + let path = (pack,mname) in + let m = + try + ctx.g.do_load_module ctx path p + with Error (Module_not_found mpath,_) when mpath = path -> + raise Not_found + in + let r = f m ~resume:true in + ImportHandling.mark_import_position ctx ppack; + r + with Not_found -> + loop l + end + in + loop ctx.m.wildcard_packages + +(* TODO: move these generic find functions into a separate module *) +let find_in_modules_starting_from_current_package ~resume ctx mname p f = + let rec loop l = + let path = (List.rev l,mname) in + match l with + | [] -> + let m = + try + ctx.g.do_load_module ctx path p + with Error (Module_not_found mpath,_) when resume && mpath = path -> + raise Not_found + in + f m ~resume:resume + | _ :: sl -> + try + let m = + try + ctx.g.do_load_module ctx path p + with Error (Module_not_found mpath,_) when mpath = path -> + raise Not_found + in + f m ~resume:true; + with Not_found -> + loop sl + in + let pack = fst ctx.m.curmod.m_path in + loop (List.rev pack) + +let find_in_unqualified_modules ctx name p f ~resume = + try + find_in_wildcard_imports ctx name p f + with Not_found -> + find_in_modules_starting_from_current_package ctx name p f ~resume:resume + +let load_unqualified_type_def ctx mname tname p = + let find_type m ~resume = + if resume then + find_type_in_module m tname + else + find_type_in_module_raise m tname p + in + find_in_unqualified_modules ctx mname p find_type ~resume:false + +let load_module ctx path p = + try + ctx.g.do_load_module ctx path p + with Error (Module_not_found mpath,_) as exc when mpath = path -> + match path with + | ("std" :: pack, name) -> + ctx.g.do_load_module ctx (pack,name) p + | _ -> + raise exc + +let load_qualified_type_def ctx pack mname tname p = + let m = load_module ctx (pack,mname) p in + find_type_in_module_raise m tname p + (* load a type or a subtype definition *) let load_type_def ctx p t = - let no_pack = t.tpackage = [] in - if t = Parser.magic_type_path then raise_fields (DisplayToplevel.collect ctx TKType NoValue) CRTypeHint (DisplayTypes.make_subject None p); + if t = Parser.magic_type_path then + raise_fields (DisplayToplevel.collect ctx TKType NoValue true) CRTypeHint (DisplayTypes.make_subject None p); (* The type name is the module name or the module sub-type name *) let tname = (match t.tsub with None -> t.tname | Some n -> n) in + try (* If there's a sub-type, there's no reason to look in our module or its imports *) if t.tsub <> None then raise Not_found; - let path_matches t2 = - let tp = t_path t2 in - tp = (t.tpackage,tname) || (no_pack && snd tp = tname) - in - try - (* Check the types in our own module *) - List.find path_matches ctx.m.curmod.m_types - with Not_found -> - (* Check the local imports *) - let t,pi = List.find (fun (t2,pi) -> path_matches t2) ctx.m.module_types in - ImportHandling.mark_import_position ctx.com pi; - t - with - | Not_found when no_pack -> - (* Unqualified *) - begin try - let rec loop l = match l with - | [] -> - raise Exit - | (pack,ppack) :: l -> - begin try - let mt = load_type ctx (pack,t.tname) tname p in - ImportHandling.mark_import_position ctx.com ppack; - mt - with Not_found -> - loop l - end - in - (* Check wildcard packages by using their package *) - loop ctx.m.wildcard_packages - with Exit -> - let rec loop l = match l with - | [] -> - load_type_raise ctx ([],t.tname) tname p - | _ :: sl as l -> - (try load_type ctx (List.rev l,t.tname) tname p with Not_found -> loop sl) - in - (* Check our current module's path and its parent paths *) - loop (List.rev (fst ctx.m.curmod.m_path)) - end - | Not_found -> - (* Qualified *) - try - (* Try loading the fully qualified module *) - load_type_raise ctx (t.tpackage,t.tname) tname p - with Error((Module_not_found _ | Type_not_found _),_) as exc -> match t.tpackage with - | "std" :: l -> - load_type_raise ctx (l,t.tname) tname p - | _ -> - raise exc + find_type_in_current_module_context ctx t.tpackage tname + with Not_found -> + if t.tpackage = [] then + load_unqualified_type_def ctx t.tname tname p + else + load_qualified_type_def ctx t.tpackage t.tname tname p (* let load_type_def ctx p t = let timer = Timer.timer ["typing";"load_type_def"] in @@ -202,11 +269,15 @@ let check_param_constraints ctx types t pl c p = ) ctl -let generate_value_meta com co fadd args = +let generate_args_meta com cls_opt add_meta args = let values = List.fold_left (fun acc ((name,p),_,_,_,eo) -> match eo with Some e -> ((name,p,NoQuotes),e) :: acc | _ -> acc) [] args in - match values with + (match values with | [] -> () - | _ -> fadd (Meta.Value,[EObjectDecl values,null_pos],null_pos) + | _ -> add_meta (Meta.Value,[EObjectDecl values,null_pos],null_pos) + ); + if List.exists (fun (_,_,m,_,_) -> m <> []) args then + let fn = { f_params = []; f_args = args; f_type = None; f_expr = None } in + add_meta (Meta.HaxeArguments,[EFunction(FKAnonymous,fn),null_pos],null_pos) let is_redefined ctx cf1 fields p = try @@ -233,7 +304,7 @@ let make_extension_type ctx tl = in let fields = List.fold_left mk_extension PMap.empty tl in let tl = List.map (fun (t,_) -> t) tl in - let ta = TAnon { a_fields = fields; a_status = ref (Extend tl); } in + let ta = mk_anon ~fields (ref (Extend tl)) in ta (* build an instance from a full type *) @@ -249,8 +320,8 @@ let rec load_instance' ctx (t,p) allow_no_params = | TClassDecl {cl_kind = KGeneric} -> true,false | TClassDecl {cl_kind = KGenericBuild _} -> false,true | TTypeDecl td -> - if not (Common.defined ctx.com Define.NoDeprecationWarnings) then - begin try + DeprecationCheck.if_enabled ctx.com (fun() -> + try let msg = match Meta.get Meta.Deprecated td.t_meta with | _,[EConst(String(s,_)),_],_ -> s | _ -> "This typedef is deprecated in favor of " ^ (s_type (print_context()) td.t_type) @@ -258,7 +329,7 @@ let rec load_instance' ctx (t,p) allow_no_params = DeprecationCheck.warn_deprecation ctx.com msg p with Not_found -> () - end; + ); false,false | _ -> false,false in @@ -272,7 +343,7 @@ let rec load_instance' ctx (t,p) allow_no_params = let t = mk_mono() in if c.cl_kind <> KTypeParameter [] || is_generic then delay ctx PCheckConstraint (fun() -> check_param_constraints ctx types t (!pl) c p); t; - | _ -> assert false + | _ -> die "" __LOC__ ) types; f (!pl) end else if path = ([],"Dynamic") then @@ -324,7 +395,7 @@ let rec load_instance' ctx (t,p) allow_no_params = t ) "constraint" in TLazy r - | _ -> assert false + | _ -> die "" __LOC__ in t :: loop tl1 tl2 is_rest | [],[] -> @@ -378,12 +449,12 @@ and load_complex_type' ctx allow_display (t,p) = ) r.fitems in raise_fields l (CRStructExtension true) r.fsubject ) tl in - let tr = ref None in + let tr = Monomorph.create() in let t = TMono tr in let r = exc_protect ctx (fun r -> r := lazy_processing (fun() -> t); let ta = make_extension_type ctx tl in - tr := Some ta; + Monomorph.bind tr ta; ta ) "constraint" in TLazy r @@ -398,7 +469,7 @@ and load_complex_type' ctx allow_display (t,p) = error "Loop found in cascading signatures definitions. Please change order/import" p | TAnon a2 -> PMap.iter (fun _ cf -> ignore(is_redefined ctx cf a2.a_fields p)) a.a_fields; - TAnon { a_fields = (PMap.foldi PMap.add a.a_fields a2.a_fields); a_status = ref (Extend [t]); } + mk_anon ~fields:(PMap.foldi PMap.add a.a_fields a2.a_fields) (ref (Extend [t])) | _ -> error "Can only extend structures" p in let loop (t,p) = match follow t with @@ -420,11 +491,11 @@ and load_complex_type' ctx allow_display (t,p) = ) r.fitems in raise_fields l (CRStructExtension false) r.fsubject ) tl in - let tr = ref None in + let tr = Monomorph.create() in let t = TMono tr in let r = exc_protect ctx (fun r -> r := lazy_processing (fun() -> t); - tr := Some (match il with + Monomorph.bind tr (match il with | [i] -> mk_extension i | _ -> @@ -434,7 +505,7 @@ and load_complex_type' ctx allow_display (t,p) = t ) "constraint" in TLazy r - | _ -> assert false + | _ -> die "" __LOC__ end | CTAnonymous l -> let displayed_field = ref None in @@ -564,6 +635,9 @@ and init_meta_overloads ctx co cf = | (Meta.Overload,[(EFunction (kind,f),p)],_) -> (match kind with FKNamed _ -> error "Function name must not be part of @:overload" p | _ -> ()); (match f.f_expr with Some (EBlock [], _) -> () | _ -> error "Overload must only declare an empty method body {}" p); + (match cf.cf_kind with + | Method MethInline -> error "Cannot @:overload inline function" p + | _ -> ()); let old = ctx.type_params in (match cf.cf_params with | [] -> () @@ -571,14 +645,22 @@ and init_meta_overloads ctx co cf = let params = (!type_function_params_rec) ctx f cf.cf_name p in ctx.type_params <- params @ ctx.type_params; let topt = function None -> error "Explicit type required" p | Some t -> load_complex_type ctx true t in - let args = List.map (fun ((a,_),opt,_,t,cto) -> a,opt || cto <> None,topt t) f.f_args in + let args = + List.map + (fun ((a,_),opt,_,t,cto) -> + let t = if opt then ctx.t.tnull (topt t) else topt t in + let opt = opt || cto <> None in + a,opt,t + ) + f.f_args + in let cf = { cf with cf_type = TFun (args,topt f.f_type); cf_params = params; cf_meta = cf_meta} in - generate_value_meta ctx.com co (fun meta -> cf.cf_meta <- meta :: cf.cf_meta) f.f_args; + generate_args_meta ctx.com co (fun meta -> cf.cf_meta <- meta :: cf.cf_meta) f.f_args; overloads := cf :: !overloads; ctx.type_params <- old; false | (Meta.Overload,[],_) when ctx.com.config.pf_overload -> - let topt (n,_,t) = match t with | TMono t when !t = None -> error ("Explicit type required for overload functions\nFor function argument '" ^ n ^ "'") cf.cf_pos | _ -> () in + let topt (n,_,t) = match t with | TMono t when t.tm_type = None -> error ("Explicit type required for overload functions\nFor function argument '" ^ n ^ "'") cf.cf_pos | _ -> () in (match follow cf.cf_type with | TFun (args,_) -> List.iter topt args | _ -> () (* could be a variable *)); @@ -617,27 +699,27 @@ let hide_params ctx = *) let load_core_type ctx name = let show = hide_params ctx in - let t = load_instance ctx ({ tpackage = []; tname = name; tparams = []; tsub = None; },null_pos) false in + let t = load_instance ctx (mk_type_path ([],name),null_pos) false in show(); add_dependency ctx.m.curmod (match t with | TInst (c,_) -> c.cl_module | TType (t,_) -> t.t_module | TAbstract (a,_) -> a.a_module | TEnum (e,_) -> e.e_module - | _ -> assert false); + | _ -> die "" __LOC__); t let t_iterator ctx = let show = hide_params ctx in - match load_type_def ctx null_pos { tpackage = []; tname = "Iterator"; tparams = []; tsub = None } with + match load_type_def ctx null_pos (mk_type_path ([],"Iterator")) with | TTypeDecl t -> show(); add_dependency ctx.m.curmod t.t_module; - if List.length t.t_params <> 1 then assert false; + if List.length t.t_params <> 1 then die "" __LOC__; let pt = mk_mono() in apply_params t.t_params [pt] t.t_type, pt | _ -> - assert false + die "" __LOC__ (* load either a type t or Null if not defined @@ -677,7 +759,7 @@ let field_to_type_path ctx e = | [name; sub] -> f :: pack, name, Some sub | _ -> - assert false + die "" __LOC__ in { tpackage=pack; tname=name; tparams=[]; tsub=sub } | _,pos -> @@ -749,8 +831,8 @@ let load_core_class ctx c = c ) in let tpath = match c.cl_kind with - | KAbstractImpl a -> { tpackage = fst a.a_path; tname = snd a.a_path; tparams = []; tsub = None; } - | _ -> { tpackage = fst c.cl_path; tname = snd c.cl_path; tparams = []; tsub = None; } + | KAbstractImpl a -> mk_type_path a.a_path + | _ -> mk_type_path c.cl_path in let t = load_instance ctx2 (tpath,c.cl_pos) true in flush_pass ctx2 PFinal "core_final"; @@ -758,7 +840,7 @@ let load_core_class ctx c = | TInst (ccore,_) | TAbstract({a_impl = Some ccore}, _) -> ccore | _ -> - assert false + die "" __LOC__ let init_core_api ctx c = let ccore = load_core_class ctx c in @@ -776,7 +858,7 @@ let init_core_api ctx c = end | t1,t2 -> Printf.printf "%s %s" (s_type (print_context()) t1) (s_type (print_context()) t2); - assert false + die "" __LOC__ ) ccore.cl_params c.cl_params; with Invalid_argument _ -> error "Class must have the same number of type parameters as core type" c.cl_pos @@ -837,12 +919,12 @@ let string_list_of_expr_path (e,p) = let handle_using ctx path p = let t = match List.rev path with | (s1,_) :: (s2,_) :: sl -> - if is_lower_ident s2 then { tpackage = (List.rev (s2 :: List.map fst sl)); tname = s1; tsub = None; tparams = [] } - else { tpackage = List.rev (List.map fst sl); tname = s2; tsub = Some s1; tparams = [] } + if is_lower_ident s2 then mk_type_path ((List.rev (s2 :: List.map fst sl)),s1) + else mk_type_path ~sub:s1 (List.rev (List.map fst sl),s2) | (s1,_) :: sl -> - { tpackage = List.rev (List.map fst sl); tname = s1; tsub = None; tparams = [] } + mk_type_path (List.rev (List.map fst sl),s1) | [] -> - DisplayException.raise_fields (DisplayToplevel.collect ctx TKType NoValue) CRUsing (DisplayTypes.make_subject None {p with pmin = p.pmax}); + DisplayException.raise_fields (DisplayToplevel.collect ctx TKType NoValue true) CRUsing (DisplayTypes.make_subject None {p with pmin = p.pmax}); in let types = (match t.tsub with | None -> diff --git a/src/typing/typeloadCheck.ml b/src/typing/typeloadCheck.ml index 5c34080842364d6f37572349321035c925b937bc..22a26e8a1caf37f4a7b6b3fa3e456c2f4931e2b4 100644 --- a/src/typing/typeloadCheck.ml +++ b/src/typing/typeloadCheck.ml @@ -107,7 +107,7 @@ let valid_redefinition ctx f1 t1 f2 t2 = (* child, parent *) let msg = if !i = 0 then Invalid_return_type else Invalid_function_argument(!i,List.length args1) in raise (Unify_error (Cannot_unify (t1,t2) :: msg :: l))) | _ -> - assert false + die "" __LOC__ end | _,(Var { v_write = AccNo | AccNever }) -> (* write variance *) @@ -149,14 +149,18 @@ let get_native_name meta = error "String expected" mp let check_native_name_override ctx child base = - let error() = - display_error ctx ("Field " ^ child.cf_name ^ " has different @:native value than in superclass") child.cf_pos; - display_error ctx ("Base field is defined here") base.cf_pos + let error base_pos child_pos = + display_error ctx ("Field " ^ child.cf_name ^ " has different @:native value than in superclass") child_pos; + display_error ctx ("Base field is defined here") base_pos in try - let native_name = fst (get_native_name child.cf_meta) in - try if fst (get_native_name base.cf_meta) <> native_name then error() - with Not_found -> error() + let child_name, child_pos = get_native_name child.cf_meta in + try + let base_name, base_pos = get_native_name base.cf_meta in + if base_name <> child_name then + error base_pos child_pos + with Not_found -> + error base.cf_name_pos child_pos with Not_found -> () let check_overriding ctx c f = @@ -165,7 +169,7 @@ let check_overriding ctx c f = if List.memq f c.cl_overrides then display_error ctx ("Field " ^ f.cf_name ^ " is declared 'override' but doesn't override any field") f.cf_pos | _ when c.cl_extern && Meta.has Meta.CsNative c.cl_meta -> () (* -net-lib specific: do not check overrides on extern CsNative classes *) | Some (csup,params) -> - let p = f.cf_pos in + let p = f.cf_name_pos in let i = f.cf_name in let check_field f get_super_field is_overload = try (if is_overload && not (Meta.has Meta.Overload f.cf_meta) then @@ -197,7 +201,7 @@ let check_overriding ctx c f = with Unify_error l -> display_error ctx ("Field " ^ i ^ " overrides parent class with different or incomplete type") p; - display_error ctx ("Base field is defined here") f2.cf_pos; + display_error ctx ("Base field is defined here") f2.cf_name_pos; display_error ctx (error_msg (Unify l)) p; with Not_found -> @@ -322,7 +326,7 @@ module Inheritance = struct let check_extends ctx c t p = match follow t with | TInst (csup,params) -> if is_basic_class_path csup.cl_path && not (c.cl_extern && csup.cl_extern) then error "Cannot extend basic class" p; - if is_parent c csup then error "Recursive class" p; + if extends csup c then error "Recursive class" p; begin match csup.cl_kind with | KTypeParameter _ -> if is_generic_parameter ctx csup then error "Extending generic type parameters is no longer allowed in Haxe 4" p; @@ -332,7 +336,7 @@ module Inheritance = struct | _ -> error "Should extend by using a class" p let rec check_interface ctx c intf params = - let p = c.cl_pos in + let p = c.cl_name_pos in let rec check_field i f = (if ctx.com.config.pf_overload then List.iter (function @@ -351,12 +355,8 @@ module Inheritance = struct else t2, f2 in - if ctx.com.display.dms_collect_data then begin - let h = ctx.com.display_information in - h.interface_field_implementations <- (intf,f,c,Some f2) :: h.interface_field_implementations; - end; ignore(follow f2.cf_type); (* force evaluation *) - let p = (match f2.cf_expr with None -> p | Some e -> e.epos) in + let p = f2.cf_name_pos in let mkind = function | MethNormal | MethInline -> 0 | MethDynamic -> 1 @@ -379,7 +379,7 @@ module Inheritance = struct | Not_found when not c.cl_interface -> let msg = if !is_overload then let ctx = print_context() in - let args = match follow f.cf_type with | TFun(args,_) -> String.concat ", " (List.map (fun (n,o,t) -> (if o then "?" else "") ^ n ^ " : " ^ (s_type ctx t)) args) | _ -> assert false in + let args = match follow f.cf_type with | TFun(args,_) -> String.concat ", " (List.map (fun (n,o,t) -> (if o then "?" else "") ^ n ^ " : " ^ (s_type ctx t)) args) | _ -> die "" __LOC__ in "No suitable overload for " ^ i ^ "( " ^ args ^ " ), as needed by " ^ s_type_path intf.cl_path ^ " was found" else ("Field " ^ i ^ " needed by " ^ s_type_path intf.cl_path ^ " is missing") @@ -436,7 +436,7 @@ module Inheritance = struct List.find path_matches ctx.m.curmod.m_types with Not_found -> let t,pi = List.find (fun (lt,_) -> path_matches lt) ctx.m.module_types in - ImportHandling.mark_import_position ctx.com pi; + ImportHandling.mark_import_position ctx pi; t in { t with tpackage = fst (t_path lt) },p @@ -475,7 +475,7 @@ module Inheritance = struct c.cl_array_access <- Some t; (fun () -> ()) | TInst (intf,params) -> - if is_parent c intf then error "Recursive class" p; + if extends intf c then error "Recursive class" p; if c.cl_interface then error "Interfaces cannot implement another interface (use extends instead)" p; if not intf.cl_interface then error "You can only implement an interface" p; c.cl_implements <- (intf, params) :: c.cl_implements; diff --git a/src/typing/typeloadFields.ml b/src/typing/typeloadFields.ml index c8c3f4521c882c613ac634a3be5e191eda21cafc..d23356f853f536a43b902e96fdcac61c56922f4f 100644 --- a/src/typing/typeloadFields.ml +++ b/src/typing/typeloadFields.ml @@ -29,6 +29,18 @@ open CompletionItem.ClassFieldOrigin open Common open Error +class context_init = object(self) + val mutable l = [] + + method add (f : unit -> unit) = + l <- f :: l + + method run = + let l' = l in + l <- []; + List.iter (fun f -> f()) (List.rev l') +end + type class_init_ctx = { tclass : tclass; (* I don't trust ctx.curclass because it's mutable. *) is_lib : bool; @@ -37,7 +49,7 @@ type class_init_ctx = { is_class_debug : bool; extends_public : bool; abstract : tabstract option; - context_init : unit -> unit; + context_init : context_init; mutable has_display_field : bool; mutable delayed_expr : (typer * tlazy ref option) list; mutable force_constructor : bool; @@ -103,11 +115,13 @@ let dump_field_context fctx = ] -let is_java_native_function meta = try +let is_java_native_function ctx meta pos = try match Meta.get Meta.Native meta with - | (Meta.Native,[],_) -> true + | (Meta.Native,[],_) -> + ctx.com.warning "@:native metadata for jni functions is deprecated. Use @:java.native instead." pos; + true | _ -> false - with | Not_found -> false + with | Not_found -> Meta.has Meta.NativeJni meta (**** end of strict meta handling *****) @@ -125,7 +139,10 @@ let get_struct_init_super_info ctx c p = let args = (try get_method_args ctor with Not_found -> []) in let tl,el = List.fold_left (fun (args,exprs) (v,value) -> - let opt = match value with Some _ -> true | None -> false in + let opt = match value with + | Some _ -> true + | None -> Meta.has Meta.Optional v.v_meta + in let t = if opt then ctx.t.tnull v.v_type else v.v_type in (v.v_name,opt,t) :: args,(mk (TLocal v) v.v_type p) :: exprs ) ([],[]) args @@ -159,6 +176,7 @@ let ensure_struct_init_constructor ctx c ast_fields p = let params = List.map snd c.cl_params in let ethis = mk (TConst TThis) (TInst(c,params)) p in let args,el,tl = List.fold_left (fun (args,el,tl) cf -> match cf.cf_kind with + | Var { v_write = AccNever } -> args,el,tl | Var _ -> let has_default_expr = field_has_default_expr cf.cf_name in let opt = has_default_expr || (Meta.has Meta.Optional cf.cf_meta) in @@ -166,6 +184,8 @@ let ensure_struct_init_constructor ctx c ast_fields p = let v = alloc_var VGenerated cf.cf_name t p in let ef = mk (TField(ethis,FInstance(c,params,cf))) cf.cf_type p in let ev = mk (TLocal v) v.v_type p in + if opt && not (Meta.has Meta.Optional v.v_meta) then + v.v_meta <- (Meta.Optional,[],null_pos) :: v.v_meta; (* this.field = *) let assign_expr = mk (TBinop(OpAssign,ef,ev)) cf.cf_type p in let e = @@ -202,8 +222,6 @@ let transform_abstract_field com this_t a_t a f = let p = f.cff_pos in match f.cff_kind with | FProp ((("get" | "never"),_),(("set" | "never"),_),_,_) when not stat -> - (* TODO: hack to avoid issues with abstract property generation on As3 *) - if Common.defined com Define.As3 then f.cff_access <- (AExtern,null_pos) :: f.cff_access; { f with cff_access = (AStatic,null_pos) :: f.cff_access; cff_meta = (Meta.Impl,[],null_pos) :: f.cff_meta } | FProp _ when not stat -> error "Member property accessors must be get/set or never" p; @@ -325,6 +343,11 @@ type enum_abstract_mode = | EAInt of int ref | EAOther +type enum_constructor_visibility = + | VUnknown + | VPublic of placed_access + | VPrivate of placed_access + let build_enum_abstract ctx c a fields p = let mode = if does_unify a.a_this ctx.t.tint then EAInt (ref 0) @@ -334,7 +357,31 @@ let build_enum_abstract ctx c a fields p = List.iter (fun field -> match field.cff_kind with | FVar(ct,eo) when not (List.mem_assoc AStatic field.cff_access) -> - field.cff_access <- [AStatic,null_pos; if (List.mem_assoc APrivate field.cff_access) then (APrivate,null_pos) else (APublic,null_pos)]; + let check_visibility_conflict visibility p1 = + match visibility with + | VUnknown -> + () + | VPublic(access,p2) | VPrivate(access,p2) -> + display_error ctx (Printf.sprintf "Conflicting access modifier %s" (Ast.s_access access)) p1; + display_error ctx "Conflicts with this" p2; + in + let rec loop visibility acc = match acc with + | (AExtern,p) :: acc -> + display_error ctx "extern modifier is not allowed on enum abstract fields" p; + loop visibility acc + | (APrivate,p) as access :: acc -> + check_visibility_conflict visibility p; + loop (VPrivate access) acc + | (APublic,p) as access :: acc -> + check_visibility_conflict visibility p; + loop (VPublic access) acc + | _ :: acc -> + loop visibility acc + | [] -> + visibility + in + let visibility = loop VUnknown field.cff_access in + field.cff_access <- [AStatic,null_pos; match visibility with VPublic acc | VPrivate acc -> acc | VUnknown -> (APublic,null_pos)]; field.cff_meta <- (Meta.Enum,[],null_pos) :: (Meta.Impl,[],null_pos) :: field.cff_meta; let ct = match ct with | Some _ -> ct @@ -392,7 +439,7 @@ let build_module_def ctx mt meta fvars context_init fbuild = if ctx.in_macro then error "You cannot use @:build inside a macro : make sure that your type is not used in macro" p; let old = ctx.get_build_infos in ctx.get_build_infos <- (fun() -> Some (mt, List.map snd (t_infos mt).mt_params, fvars())); - context_init(); + context_init#run; let r = try apply_macro ctx MBuild s el p with e -> ctx.get_build_infos <- old; raise e in ctx.get_build_infos <- old; (match r with @@ -404,7 +451,7 @@ let build_module_def ctx mt meta fvars context_init fbuild = | TClassDecl ({cl_kind = KAbstractImpl a} as c) -> (* if p <> null_pos && not (Define.is_haxe3_compat ctx.com.defines) then ctx.com.warning "`@:enum abstract` is deprecated in favor of `enum abstract`" p; *) - context_init(); + context_init#run; let e = build_enum_abstract ctx c a (fvars()) p in fbuild e; | _ -> @@ -460,7 +507,7 @@ let create_class_context ctx c context_init p = tthis = (match abstract with | Some a -> (match a.a_this with - | TMono r when !r = None -> TAbstract (a,List.map snd c.cl_params) + | TMono r when r.tm_type = None -> TAbstract (a,List.map snd c.cl_params) | t -> t) | None -> TInst (c,List.map snd c.cl_params)); on_error = (fun ctx msg ep -> @@ -590,6 +637,24 @@ let type_opt (ctx,cctx) p t = | _ -> load_type_hint ctx p t +let transform_field (ctx,cctx) c f fields p = + let f = match cctx.abstract with + | Some a -> + let a_t = TExprToExpr.convert_type' (TAbstract(a,List.map snd a.a_params)) in + let this_t = TExprToExpr.convert_type' a.a_this in (* TODO: better pos? *) + transform_abstract_field ctx.com this_t a_t a f + | None -> + f + in + if List.mem_assoc AMacro f.cff_access then + (match ctx.g.macros with + | Some (_,mctx) when Hashtbl.mem mctx.g.types_module c.cl_path -> + (* assume that if we had already a macro with the same name, it has not been changed during the @:build operation *) + if not (List.exists (fun f2 -> f2.cff_name = f.cff_name && List.mem_assoc AMacro f2.cff_access) (!fields)) then + error "Class build macro cannot return a macro function when the class has already been compiled into the macro context" p + | _ -> ()); + f + let build_fields (ctx,cctx) c fields = let fields = ref fields in let get_fields() = !fields in @@ -598,24 +663,7 @@ let build_fields (ctx,cctx) c fields = build_module_def ctx (TClassDecl c) c.cl_meta get_fields cctx.context_init (fun (e,p) -> match e with | EVars [_,_,Some (CTAnonymous f,p),None] -> - let f = List.map (fun f -> - let f = match cctx.abstract with - | Some a -> - let a_t = TExprToExpr.convert_type' (TAbstract(a,List.map snd a.a_params)) in - let this_t = TExprToExpr.convert_type' a.a_this in (* TODO: better pos? *) - transform_abstract_field ctx.com this_t a_t a f - | None -> - f - in - if List.mem_assoc AMacro f.cff_access then - (match ctx.g.macros with - | Some (_,mctx) when Hashtbl.mem mctx.g.types_module c.cl_path -> - (* assume that if we had already a macro with the same name, it has not been changed during the @:build operation *) - if not (List.exists (fun f2 -> f2.cff_name = f.cff_name && List.mem_assoc AMacro f2.cff_access) (!fields)) then - error "Class build macro cannot return a macro function when the class has already been compiled into the macro context" p - | _ -> ()); - f - ) f in + let f = List.map (fun f -> transform_field (ctx,cctx) c f fields p) f in fields := f | _ -> error "Class build macro must return a single variable with anonymous fields" p ); @@ -628,7 +676,7 @@ let bind_type (ctx,cctx,fctx) cf r p = let rec is_full_type t = match t with | TFun (args,ret) -> is_full_type ret && List.for_all (fun (_,_,t) -> is_full_type t) args - | TMono r -> (match !r with None -> false | Some t -> is_full_type t) + | TMono r -> (match r.tm_type with None -> false | Some t -> is_full_type t) | TAbstract _ | TInst _ | TEnum _ | TLazy _ | TDynamic _ | TAnon _ | TType _ -> true in let force_macro () = @@ -743,7 +791,7 @@ let bind_var (ctx,cctx,fctx) cf e = (* type constant init fields (issue #1956) *) if not !return_partial_type || (match fst e with EConst _ -> true | _ -> false) then begin r := lazy_processing (fun() -> t); - cctx.context_init(); + cctx.context_init#run; if ctx.com.verbose then Common.log ctx.com ("Typing " ^ (if ctx.in_macro then "macro " else "") ^ s_type_path c.cl_path ^ "." ^ cf.cf_name); let e = TypeloadFunction.type_var_field ctx t e fctx.is_static fctx.is_display_field p in let maybe_run_analyzer e = match e.eexpr with @@ -872,6 +920,17 @@ let check_abstract (ctx,cctx,fctx) c cf fd t ret p = a.a_from_field <- (TLazy r,cf) :: a.a_from_field; | (Meta.To,_,_) :: _ -> if fctx.is_macro then error (cf.cf_name ^ ": Macro cast functions are not supported") p; + (match cf.cf_kind, cf.cf_type with + | Var _, _ -> + error "@:to meta should be used on methods" p + | Method _, TFun(args, _) when not fctx.is_abstract_member && List.length args <> 1 -> + if not (Meta.has Meta.MultiType a.a_meta) then (* TODO: get rid of this check once multitype is removed *) + error ("static @:to method should have one argument") p + | Method _, TFun(args, _) when fctx.is_abstract_member && List.length args <> 1 -> + if not (Meta.has Meta.MultiType a.a_meta) then (* TODO: get rid of this check once multitype is removed *) + error "@:to method should have no arguments" p + | _ -> () + ); (* TODO: this doesn't seem quite right... *) if not (Meta.has Meta.Impl cf.cf_meta) then cf.cf_meta <- (Meta.Impl,[],null_pos) :: cf.cf_meta; let resolve_m args = @@ -891,7 +950,7 @@ let check_abstract (ctx,cctx,fctx) c cf fd t ret p = (* delay ctx PFinal (fun () -> unify ctx m tthis f.cff_pos); *) let args = match follow (monomorphs a.a_params ctor.cf_type) with | TFun(args,_) -> List.map (fun (_,_,t) -> t) args - | _ -> assert false + | _ -> die "" __LOC__ in args end else @@ -998,7 +1057,7 @@ let create_method (ctx,cctx,fctx) c f fd p = if ctx.in_macro then begin (* a class with a macro cannot be extern in macro context (issue #2015) *) c.cl_extern <- false; - let texpr = CTPath { tpackage = ["haxe";"macro"]; tname = "Expr"; tparams = []; tsub = None } in + let texpr = CTPath (mk_type_path (["haxe";"macro"],"Expr")) in (* ExprOf type parameter might contain platform-specific type, let's replace it by Expr *) let no_expr_of (t,p) = match t with | CTPath { tpackage = ["haxe";"macro"]; tname = "Expr"; tsub = Some ("ExprOf"); tparams = [TPType _] } @@ -1012,7 +1071,7 @@ let create_method (ctx,cctx,fctx) c f fd p = f_expr = fd.f_expr; } end else - let tdyn = Some (CTPath { tpackage = []; tname = "Dynamic"; tparams = []; tsub = None },null_pos) in + let tdyn = Some (CTPath (mk_type_path ([],"Dynamic")),null_pos) in let to_dyn p t = match t with | { tpackage = ["haxe";"macro"]; tname = "Expr"; tsub = Some ("ExprOf"); tparams = [TPType t] } -> Some t | { tpackage = []; tname = ("ExprOf"); tsub = None; tparams = [TPType t] } -> Some t @@ -1046,7 +1105,10 @@ let create_method (ctx,cctx,fctx) c f fd p = end; let parent = (if not fctx.is_static then get_parent c (fst f.cff_name) else None) in let dynamic = List.mem_assoc ADynamic f.cff_access || (match parent with Some { cf_kind = Method MethDynamic } -> true | _ -> false) in - if fctx.is_inline && dynamic then error (fst f.cff_name ^ ": You can't have both 'inline' and 'dynamic'") p; + if fctx.is_inline && dynamic then error (fst f.cff_name ^ ": 'inline' is not allowed on 'dynamic' functions") p; + let is_override = Option.is_some fctx.override in + if (is_override && fctx.is_static) then error (fst f.cff_name ^ ": 'override' is not allowed on 'static' functions") p; + ctx.type_params <- if fctx.is_static && not fctx.is_abstract_member then params else params @ ctx.type_params; (* TODO is_lib: avoid forcing the return type to be typed *) let ret = if fctx.field_kind = FKConstructor then ctx.t.tvoid else type_opt (ctx,cctx) p fd.f_type in @@ -1090,14 +1152,14 @@ let create_method (ctx,cctx,fctx) c f fd p = with Not_found -> () ) parent; - generate_value_meta ctx.com (Some c) (fun meta -> cf.cf_meta <- meta :: cf.cf_meta) fd.f_args; + generate_args_meta ctx.com (Some c) (fun meta -> cf.cf_meta <- meta :: cf.cf_meta) fd.f_args; check_abstract (ctx,cctx,fctx) c cf fd t ret p; init_meta_overloads ctx (Some c) cf; ctx.curfield <- cf; let r = exc_protect ~force:false ctx (fun r -> if not !return_partial_type then begin r := lazy_processing (fun() -> t); - cctx.context_init(); + cctx.context_init#run; incr stats.s_methods_typed; if ctx.com.verbose then Common.log ctx.com ("Typing " ^ (if ctx.in_macro then "macro " else "") ^ s_type_path c.cl_path ^ "." ^ fst f.cff_name); let fmode = (match cctx.abstract with @@ -1110,9 +1172,9 @@ let create_method (ctx,cctx,fctx) c f fd p = if fctx.field_kind = FKConstructor then FunConstructor else if fctx.is_static then FunStatic else FunMember ) in begin match ctx.com.platform with - | Java when is_java_native_function cf.cf_meta -> + | Java when is_java_native_function ctx cf.cf_meta cf.cf_pos -> if fd.f_expr <> None then - ctx.com.warning "@:native function definitions shouldn't include an expression. This behaviour is deprecated." cf.cf_pos; + ctx.com.warning "@:java.native function definitions shouldn't include an expression. This behaviour is deprecated." cf.cf_pos; cf.cf_expr <- None; cf.cf_type <- t | _ -> @@ -1216,8 +1278,6 @@ let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p = ), p)) in let t2, f2 = get_overload overloads in - (* accessors must be public on As3 (issue #1872) *) - if Common.defined ctx.com Define.As3 then f2.cf_meta <- (Meta.Public,[],null_pos) :: f2.cf_meta; (match f2.cf_kind with | Method MethMacro -> display_error ctx (f2.cf_name ^ ": Macro methods cannot be used as property accessor") p; @@ -1235,7 +1295,7 @@ let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p = | Not_found -> if c.cl_interface then begin let cf = mk_field m t p null_pos in - cf.cf_meta <- [Meta.CompilerGenerated,[],null_pos]; + cf.cf_meta <- [Meta.CompilerGenerated,[],null_pos;Meta.NoCompletion,[],null_pos]; cf.cf_kind <- Method MethNormal; c.cl_fields <- PMap.add cf.cf_name cf c.cl_fields; c.cl_ordered_fields <- cf :: c.cl_ordered_fields; @@ -1288,7 +1348,7 @@ let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p = display_error ctx (name ^ ": Custom property accessor is no longer supported, please use `set`") pset; AccCall ) in - if (set = AccNormal && get = AccCall) || (set = AccNever && get = AccNever) then error (name ^ ": Unsupported property combination") p; + if (set = AccNever && get = AccNever) then error (name ^ ": Unsupported property combination") p; let cf = { (mk_field name ~public:(is_public (ctx,cctx) f.cff_access None) ret f.cff_pos (pos f.cff_name)) with cf_doc = f.cff_doc; @@ -1325,11 +1385,20 @@ let init_field (ctx,cctx,fctx) f = match (fst acc, f.cff_kind) with | APublic, _ | APrivate, _ | AStatic, _ | AFinal, _ | AExtern, _ -> () | ADynamic, FFun _ | AOverride, FFun _ | AMacro, FFun _ | AInline, FFun _ | AInline, FVar _ -> () - | _, FVar _ -> display_error ctx ("Invalid accessor '" ^ Ast.s_placed_access acc ^ "' for variable " ^ name) p - | _, FProp _ -> display_error ctx ("Invalid accessor '" ^ Ast.s_placed_access acc ^ "' for property " ^ name) p + | _, FVar _ -> display_error ctx ("Invalid accessor '" ^ Ast.s_placed_access acc ^ "' for variable " ^ name) (snd acc) + | _, FProp _ -> display_error ctx ("Invalid accessor '" ^ Ast.s_placed_access acc ^ "' for property " ^ name) (snd acc) ) f.cff_access; begin match fctx.override with - | Some _ -> (match c.cl_super with None -> error ("Invalid override on field '" ^ name ^ "': class has no super class") p | _ -> ()); + | Some _ -> + (match c.cl_super with + | None -> + let p = + try List.assoc AOverride f.cff_access + with Not_found -> p + in + error ("Invalid override on field '" ^ name ^ "': class has no super class") p + | _ -> () + ); | None -> () end; begin match cctx.abstract with @@ -1419,12 +1488,19 @@ let init_class ctx c p context_init herits fields = in let cl_if_feature = check_if_feature c.cl_meta in let cl_req = check_require c.cl_meta in + let has_init = ref false in List.iter (fun f -> let p = f.cff_pos in try let ctx,fctx = create_field_context (ctx,cctx) c f in if fctx.is_field_debug then print_endline ("Created field context: " ^ dump_field_context fctx); let cf = init_field (ctx,cctx,fctx) f in + if fctx.field_kind = FKInit then begin + if !has_init then + display_error ctx ("Duplicate class field declaration : " ^ (s_type_path c.cl_path) ^ "." ^ cf.cf_name) cf.cf_name_pos + else + has_init := true + end; if fctx.is_field_debug then print_endline ("Created field: " ^ Printer.s_tclass_field "" cf); if fctx.is_static && c.cl_interface && fctx.field_kind <> FKInit && not cctx.is_lib && not (c.cl_extern) then error "You can't declare static fields in interfaces" p; @@ -1474,7 +1550,7 @@ let init_class ctx c p context_init herits fields = | KAbstractImpl a -> "abstract",a.a_path | _ -> "class",c.cl_path in - display_error ctx ("Duplicate " ^ type_kind ^ " field declaration : " ^ s_type_path path ^ "." ^ cf.cf_name) p + display_error ctx ("Duplicate " ^ type_kind ^ " field declaration : " ^ s_type_path path ^ "." ^ cf.cf_name) cf.cf_name_pos else if fctx.do_add then add_field c cf (fctx.is_static || fctx.is_macro && ctx.in_macro) end @@ -1517,9 +1593,18 @@ let init_class ctx c p context_init herits fields = (* make sure a default contructor with same access as super one will be added to the class structure at some point. *) - let has_struct_init = Meta.has Meta.StructInit c.cl_meta in + let has_struct_init, struct_init_pos = + try + let _,_,p = Meta.get Meta.StructInit c.cl_meta in + true, p + with Not_found -> + false, null_pos + in if has_struct_init then - ensure_struct_init_constructor ctx c fields p; + if c.cl_interface then + display_error ctx "@:structInit is not allowed on interfaces" struct_init_pos + else + ensure_struct_init_constructor ctx c fields p; begin match cctx.uninitialized_final with | Some pf when c.cl_constructor = None -> display_error ctx "This class has uninitialized final vars, which requires a constructor" p; @@ -1546,4 +1631,4 @@ let init_class ctx c p context_init herits fields = (match r with | None -> () | Some r -> delay ctx PTypeField (fun() -> ignore(lazy_type r))) - ) cctx.delayed_expr \ No newline at end of file + ) cctx.delayed_expr diff --git a/src/typing/typeloadFunction.ml b/src/typing/typeloadFunction.ml index e85a9164a714e35eb8b41c041695c05394c1dea4..4db0d8b33957042ffa2bbcccbd4ccc53ad73d6e1 100644 --- a/src/typing/typeloadFunction.ml +++ b/src/typing/typeloadFunction.ml @@ -82,6 +82,7 @@ let type_function_arg_value ctx t c do_display = let rec loop e = match e.eexpr with | TConst _ -> Some e | TField({eexpr = TTypeExpr _},FEnum _) -> Some e + | TField({eexpr = TTypeExpr _},FStatic({cl_kind = KAbstractImpl a},cf)) when Meta.has Meta.Enum a.a_meta && Meta.has Meta.Enum cf.cf_meta -> Some e | TCast(e,None) -> loop e | _ -> if ctx.com.display.dms_kind = DMNone || ctx.com.display.dms_inline && ctx.com.display.dms_error_policy = EPCollect then @@ -254,7 +255,7 @@ let add_constructor ctx c force_constructor p = let null () = Some (Texpr.Builder.make_null v.v_type v.v_pos) in match ctx.com.platform, def with | _, Some _ when not ctx.com.config.pf_static -> v, null() - | Flash, Some ({eexpr = TConst (TString _)}) -> v, null() + | Flash, Some ({eexpr = TConst (TString _)}) when not csup.cl_extern -> v, null() | Cpp, Some ({eexpr = TConst (TString _)}) -> v, def | Cpp, Some _ -> { v with v_type = ctx.t.tnull v.v_type }, null() | _ -> v, def @@ -274,7 +275,7 @@ let add_constructor ctx c force_constructor p = in map_arg (alloc_var (VUser TVOArgument) n (if o then ctx.t.tnull t else t) p,def) (* TODO: var pos *) ) args - | _ -> assert false + | _ -> die "" __LOC__ ) in let p = c.cl_pos in let vars = List.map (fun (v,def) -> alloc_var (VUser TVOArgument) v.v_name (apply_params csup.cl_params cparams v.v_type) v.v_pos, def) args in diff --git a/src/typing/typeloadModule.ml b/src/typing/typeloadModule.ml index 4e880a9a4e1bb1824e1b81ddc4a9cb5f5a261d79..bfada116b3ab2d9f52a64bcb7858fb2484810de6 100644 --- a/src/typing/typeloadModule.ml +++ b/src/typing/typeloadModule.ml @@ -39,7 +39,7 @@ let make_module ctx mpath file loadp = m_id = alloc_mid(); m_path = mpath; m_types = []; - m_extra = module_extra (Path.unique_full_path file) (Define.get_signature ctx.com.defines) (file_time file) (if ctx.in_macro then MMacro else MCode) (get_policy ctx mpath); + m_extra = module_extra (Path.get_full_path file) (Define.get_signature ctx.com.defines) (file_time file) (if ctx.in_macro then MMacro else MCode) (get_policy ctx mpath); } in m @@ -113,7 +113,7 @@ module StrictMeta = struct let left_side = match ctx.com.platform with | Cs -> field | Java -> (ECall(field,[]),pos) - | _ -> assert false + | _ -> die "" __LOC__ in let left = type_expr ctx left_side NoValue in @@ -129,9 +129,9 @@ module StrictMeta = struct | TTypeExpr(md) -> ECall(get_native_repr md texpr.epos, extra), texpr.epos | _ -> - display_error ctx "Unexpected expression" texpr.epos; assert false + display_error ctx "Unexpected expression" texpr.epos; die "" __LOC__ - let get_strict_meta ctx params pos = + let get_strict_meta ctx meta params pos = let pf = ctx.com.platform in let changed_expr, fields_to_check, ctype = match params with | [ECall(ef, el),p] -> @@ -166,7 +166,7 @@ module StrictMeta = struct let texpr = type_expr ctx changed_expr NoValue in let with_type_expr = (ECheckType( (EConst (Ident "null"), pos), (ctype,null_pos) ), pos) in let extra = handle_fields ctx fields_to_check with_type_expr in - Meta.Meta, [make_meta ctx texpr extra], pos + meta, [make_meta ctx texpr extra], pos let check_strict_meta ctx metas = let pf = ctx.com.platform in @@ -174,8 +174,11 @@ module StrictMeta = struct | Cs | Java -> let ret = ref [] in List.iter (function + | Meta.AssemblyStrict,params,pos -> (try + ret := get_strict_meta ctx Meta.AssemblyMeta params pos :: !ret + with | Exit -> ()) | Meta.Strict,params,pos -> (try - ret := get_strict_meta ctx params pos :: !ret + ret := get_strict_meta ctx Meta.Meta params pos :: !ret with | Exit -> ()) | _ -> () ) metas; @@ -189,8 +192,13 @@ end let module_pass_1 ctx m tdecls loadp = let com = ctx.com in let decls = ref [] in - let make_path name priv = - if List.exists (fun (t,_) -> snd (t_path t) = name) !decls then error ("Type name " ^ name ^ " is already defined in this module") loadp; + let make_path name priv p = + List.iter (fun (t2,(_,p2)) -> + if snd (t_path t2) = name then begin + display_error ctx ("Type name " ^ name ^ " is already defined in this module") p; + error "Previous declaration here" p2; + end + ) !decls; if priv then (fst m.m_path @ ["_" ^ snd m.m_path], name) else (fst m.m_path, name) in let pt = ref None in @@ -209,7 +217,7 @@ let module_pass_1 ctx m tdecls loadp = let name = fst d.d_name in pt := Some p; let priv = List.mem HPrivate d.d_flags in - let path = make_path name priv in + let path = make_path name priv p in let c = mk_class m path p (pos d.d_name) in (* we shouldn't load any other type until we propertly set cl_build *) c.cl_build <- (fun() -> error (s_type_path c.cl_path ^ " is not ready to be accessed, separate your type declarations in several files") p); @@ -230,7 +238,7 @@ let module_pass_1 ctx m tdecls loadp = let name = fst d.d_name in pt := Some p; let priv = List.mem EPrivate d.d_flags in - let path = make_path name priv in + let path = make_path name priv p in if Meta.has (Meta.Custom ":fakeEnum") d.d_meta then error "@:fakeEnum enums is no longer supported in Haxe 4, use extern enum abstract instead" p; let e = { e_path = path; @@ -256,7 +264,7 @@ let module_pass_1 ctx m tdecls loadp = if has_meta Meta.Using d.d_meta then error "@:using on typedef is not allowed" p; pt := Some p; let priv = List.mem EPrivate d.d_flags in - let path = make_path name priv in + let path = make_path name priv p in let t = { t_path = path; t_module = m; @@ -272,7 +280,7 @@ let module_pass_1 ctx m tdecls loadp = (* failsafe in case the typedef is not initialized (see #3933) *) delay ctx PBuildModule (fun () -> match t.t_type with - | TMono r -> (match !r with None -> r := Some com.basic.tvoid | _ -> ()) + | TMono r -> (match r.tm_type with None -> Monomorph.bind r com.basic.tvoid | _ -> ()) | _ -> () ); decls := (TTypeDecl t, decl) :: !decls; @@ -281,7 +289,7 @@ let module_pass_1 ctx m tdecls loadp = let name = fst d.d_name in check_type_name name d.d_meta; let priv = List.mem AbPrivate d.d_flags in - let path = make_path name priv in + let path = make_path name priv p in let a = { a_path = path; a_private = priv; @@ -311,8 +319,8 @@ let module_pass_1 ctx m tdecls loadp = acc | fields -> let a_t = - let params = List.map (fun t -> TPType (CTPath { tname = fst t.tp_name; tparams = []; tsub = None; tpackage = [] },null_pos)) d.d_params in - CTPath { tpackage = []; tname = fst d.d_name; tparams = params; tsub = None },null_pos + let params = List.map (fun t -> TPType (CTPath (mk_type_path ([],fst t.tp_name)),null_pos)) d.d_params in + CTPath (mk_type_path ~params ([],fst d.d_name)),null_pos in let rec loop = function | [] -> a_t @@ -335,7 +343,7 @@ let module_pass_1 ctx m tdecls loadp = a.a_impl <- Some c; c.cl_kind <- KAbstractImpl a; c.cl_final <- true; - | _ -> assert false); + | _ -> die "" __LOC__); acc ) in decl :: acc @@ -344,30 +352,75 @@ let module_pass_1 ctx m tdecls loadp = let decls = List.rev !decls in decls, List.rev tdecls +let load_enum_field ctx e et is_flat index c = + let p = c.ec_pos in + let params = ref [] in + params := type_type_params ~enum_constructor:true ctx ([],fst c.ec_name) (fun() -> !params) c.ec_pos c.ec_params; + let params = !params in + let ctx = { ctx with type_params = params @ ctx.type_params } in + let rt = (match c.ec_type with + | None -> et + | Some (t,pt) -> + let t = load_complex_type ctx true (t,pt) in + (match follow t with + | TEnum (te,_) when te == e -> + () + | _ -> + error "Explicit enum type must be of the same enum type" pt); + t + ) in + let t = (match c.ec_args with + | [] -> rt + | l -> + is_flat := false; + let pnames = ref PMap.empty in + TFun (List.map (fun (s,opt,(t,tp)) -> + (match t with CTPath({tpackage=[];tname="Void"}) -> error "Arguments of type Void are not allowed in enum constructors" tp | _ -> ()); + if PMap.mem s (!pnames) then error ("Duplicate argument `" ^ s ^ "` in enum constructor " ^ fst c.ec_name) p; + pnames := PMap.add s () (!pnames); + s, opt, load_type_hint ~opt ctx p (Some (t,tp)) + ) l, rt) + ) in + let f = { + ef_name = fst c.ec_name; + ef_type = t; + ef_pos = p; + ef_name_pos = snd c.ec_name; + ef_doc = c.ec_doc; + ef_index = !index; + ef_params = params; + ef_meta = c.ec_meta; + } in + let cf = { + (mk_field f.ef_name f.ef_type p f.ef_name_pos) with + cf_kind = (match follow f.ef_type with + | TFun _ -> Method MethNormal + | _ -> Var { v_read = AccNormal; v_write = AccNo } + ); + cf_doc = f.ef_doc; + cf_params = f.ef_params; + } in + if ctx.is_display_file && DisplayPosition.display_position#enclosed_in f.ef_name_pos then + DisplayEmitter.display_enum_field ctx e f p; + f,cf + (* In this pass, we can access load and access other modules types, but we cannot follow them or access their structure since they have not been setup. We also build a context_init list that will be evaluated the first time we evaluate an expression into the context *) -let init_module_type ctx context_init do_init (decl,p) = +let init_module_type ctx context_init (decl,p) = let get_type name = - try List.find (fun t -> snd (t_infos t).mt_path = name) ctx.m.curmod.m_types with Not_found -> assert false - in - let check_path_display path p = match ctx.com.display.dms_kind with - (* We cannot use ctx.is_display_file because the import could come from an import.hx file. *) - | DMDiagnostics b when (b || DisplayPosition.display_position#is_in_file p.pfile) && Filename.basename p.pfile <> "import.hx" -> - ImportHandling.add_import_position ctx.com p path; - | DMStatistics -> - ImportHandling.add_import_position ctx.com p path; - | DMUsage _ -> - ImportHandling.add_import_position ctx.com p path; - if DisplayPosition.display_position#is_in_file p.pfile then DisplayPath.handle_path_display ctx path p - | _ -> - if DisplayPosition.display_position#is_in_file p.pfile then DisplayPath.handle_path_display ctx path p + try List.find (fun t -> snd (t_infos t).mt_path = name) ctx.m.curmod.m_types with Not_found -> die "" __LOC__ in - match decl with - | EImport (path,mode) -> + let commit_import path mode p = ctx.m.module_imports <- (path,mode) :: ctx.m.module_imports; + if Filename.basename p.pfile <> "import.hx" then ImportHandling.add_import_position ctx p path; + in + let check_path_display path p = + if DisplayPosition.display_position#is_in_file p.pfile then DisplayPath.handle_path_display ctx path p + in + let init_import path mode = check_path_display path p; let rec loop acc = function | x :: l when is_lower_ident (fst x) -> loop (x::acc) l @@ -382,7 +435,7 @@ let init_module_type ctx context_init do_init (decl,p) = | _ -> (match List.rev path with (* p spans `import |` (to the display position), so we take the pmax here *) - | [] -> DisplayException.raise_fields (DisplayToplevel.collect ctx TKType NoValue) CRImport (DisplayTypes.make_subject None {p with pmin = p.pmax}) + | [] -> DisplayException.raise_fields (DisplayToplevel.collect ctx TKType NoValue true) CRImport (DisplayTypes.make_subject None {p with pmin = p.pmax}) | (_,p) :: _ -> error "Module name must start with an uppercase letter" p)) | (tname,p2) :: rest -> let p1 = (match pack with [] -> p2 | (_,p1) :: _ -> p1) in @@ -450,23 +503,23 @@ let init_module_type ctx context_init do_init (decl,p) = with Not_found -> (* this might be a static property, wait later to check *) let tmain = get_type tname in - context_init := (fun() -> + context_init#add (fun() -> try add_static_init tmain name tsub with Not_found -> - error (s_type_path (t_infos tmain).mt_path ^ " has no field or subtype " ^ tsub) p - ) :: !context_init) + display_error ctx (s_type_path (t_infos tmain).mt_path ^ " has no field or subtype " ^ tsub) p + )) | (tsub,p2) :: (fname,p3) :: rest -> (match rest with | [] -> () | (n,p) :: _ -> error ("Unexpected " ^ n) p); let tsub = get_type tsub in - context_init := (fun() -> + context_init#add (fun() -> try add_static_init tsub name fname with Not_found -> - error (s_type_path (t_infos tsub).mt_path ^ " has no field " ^ fname) (punion p p3) - ) :: !context_init; + display_error ctx (s_type_path (t_infos tsub).mt_path ^ " has no field " ^ fname) (punion p p3) + ); ) | IAll -> let t = (match rest with @@ -474,7 +527,7 @@ let init_module_type ctx context_init do_init (decl,p) = | [tsub,_] -> get_type tsub | _ :: (n,p) :: _ -> error ("Unexpected " ^ n) p ) in - context_init := (fun() -> + context_init#add (fun() -> match resolve_typedef t with | TClassDecl c | TAbstractDecl {a_impl = Some c} -> @@ -484,16 +537,25 @@ let init_module_type ctx context_init do_init (decl,p) = PMap.iter (fun _ c -> if not (has_meta Meta.NoImportGlobal c.ef_meta) then ctx.m.module_globals <- PMap.add c.ef_name (TEnumDecl e,c.ef_name,p) ctx.m.module_globals) e.e_constrs | _ -> error "No statics to import from this type" p - ) :: !context_init + ) )) + in + match decl with + | EImport (path,mode) -> + begin try + init_import path mode; + commit_import path mode p; + with Error(err,p) -> + display_error ctx (Error.error_msg err) p + end | EUsing path -> check_path_display path p; let types,filter_classes = handle_using ctx path p in (* do the import first *) ctx.m.module_types <- (List.map (fun t -> t,p) types) @ ctx.m.module_types; - context_init := (fun() -> ctx.m.module_using <- filter_classes types @ ctx.m.module_using) :: !context_init + context_init#add (fun() -> ctx.m.module_using <- filter_classes types @ ctx.m.module_using) | EClass d -> - let c = (match get_type (fst d.d_name) with TClassDecl c -> c | _ -> assert false) in + let c = (match get_type (fst d.d_name) with TClassDecl c -> c | _ -> die "" __LOC__) in if ctx.is_display_file && DisplayPosition.display_position#enclosed_in (pos d.d_name) then DisplayEmitter.display_module_type ctx (match c.cl_kind with KAbstractImpl a -> TAbstractDecl a | _ -> TClassDecl c) (pos d.d_name); TypeloadCheck.check_global_metadata ctx c.cl_meta (fun m -> c.cl_meta <- m :: c.cl_meta) c.cl_module.m_path c.cl_path None; @@ -512,7 +574,7 @@ let init_module_type ctx context_init do_init (decl,p) = c.cl_build <- (fun()-> Building [c]); try List.iter (fun f -> f()) fl; - TypeloadFields.init_class ctx c p do_init d.d_flags d.d_data; + TypeloadFields.init_class ctx c p context_init d.d_flags d.d_data; c.cl_build <- (fun()-> Built); incr build_count; List.iter (fun (_,t) -> ignore(follow t)) c.cl_params; @@ -523,7 +585,7 @@ let init_module_type ctx context_init do_init (decl,p) = delay_late ctx PBuildClass (fun() -> ignore(c.cl_build())); in (match state with - | Built -> assert false + | Built -> die "" __LOC__ | Building cl -> if !build_count = !prev_build_count then error ("Loop in class building prevent compiler termination (" ^ String.concat "," (List.map (fun c -> s_type_path c.cl_path) cl) ^ ")") c.cl_pos; prev_build_count := !build_count; @@ -560,7 +622,7 @@ let init_module_type ctx context_init do_init (decl,p) = | _ -> () ); | EEnum d -> - let e = (match get_type (fst d.d_name) with TEnumDecl e -> e | _ -> assert false) in + let e = (match get_type (fst d.d_name) with TEnumDecl e -> e | _ -> die "" __LOC__) in if ctx.is_display_file && DisplayPosition.display_position#enclosed_in (pos d.d_name) then DisplayEmitter.display_module_type ctx (TEnumDecl e) (pos d.d_name); let ctx = { ctx with type_params = e.e_params } in @@ -586,8 +648,7 @@ let init_module_type ctx context_init do_init (decl,p) = } ) (!constructs) in - let init () = List.iter (fun f -> f()) !context_init in - TypeloadFields.build_module_def ctx (TEnumDecl e) e.e_meta get_constructs init (fun (e,p) -> + TypeloadFields.build_module_def ctx (TEnumDecl e) e.e_meta get_constructs context_init (fun (e,p) -> match e with | EVars [_,_,Some (CTAnonymous fields,p),None] -> constructs := List.map (fun f -> @@ -617,56 +678,8 @@ let init_module_type ctx context_init do_init (decl,p) = let is_flat = ref true in let fields = ref PMap.empty in List.iter (fun c -> - let p = c.ec_pos in - let params = ref [] in - params := type_type_params ~enum_constructor:true ctx ([],fst c.ec_name) (fun() -> !params) c.ec_pos c.ec_params; - let params = !params in - let ctx = { ctx with type_params = params @ ctx.type_params } in - let rt = (match c.ec_type with - | None -> et - | Some (t,pt) -> - let t = load_complex_type ctx true (t,pt) in - (match follow t with - | TEnum (te,_) when te == e -> - () - | _ -> - error "Explicit enum type must be of the same enum type" pt); - t - ) in - let t = (match c.ec_args with - | [] -> rt - | l -> - is_flat := false; - let pnames = ref PMap.empty in - TFun (List.map (fun (s,opt,(t,tp)) -> - (match t with CTPath({tpackage=[];tname="Void"}) -> error "Arguments of type Void are not allowed in enum constructors" tp | _ -> ()); - if PMap.mem s (!pnames) then error ("Duplicate argument `" ^ s ^ "` in enum constructor " ^ fst c.ec_name) p; - pnames := PMap.add s () (!pnames); - s, opt, load_type_hint ~opt ctx p (Some (t,tp)) - ) l, rt) - ) in if PMap.mem (fst c.ec_name) e.e_constrs then error ("Duplicate constructor " ^ fst c.ec_name) (pos c.ec_name); - let f = { - ef_name = fst c.ec_name; - ef_type = t; - ef_pos = p; - ef_name_pos = snd c.ec_name; - ef_doc = c.ec_doc; - ef_index = !index; - ef_params = params; - ef_meta = c.ec_meta; - } in - let cf = { - (mk_field f.ef_name f.ef_type p f.ef_name_pos) with - cf_kind = (match follow f.ef_type with - | TFun _ -> Method MethNormal - | _ -> Var { v_read = AccNormal; v_write = AccNo } - ); - cf_doc = f.ef_doc; - cf_params = f.ef_params; - } in - if ctx.is_display_file && DisplayPosition.display_position#enclosed_in f.ef_name_pos then - DisplayEmitter.display_enum_field ctx e f p; + let f,cf = load_enum_field ctx e et is_flat index c in e.e_constrs <- PMap.add f.ef_name f e.e_constrs; fields := PMap.add cf.cf_name cf !fields; incr index; @@ -675,10 +688,7 @@ let init_module_type ctx context_init do_init (decl,p) = e.e_names <- List.rev !names; e.e_extern <- e.e_extern; e.e_type.t_params <- e.e_params; - e.e_type.t_type <- TAnon { - a_fields = !fields; - a_status = ref (EnumStatics e); - }; + e.e_type.t_type <- mk_anon ~fields:!fields (ref (EnumStatics e)); if !is_flat then e.e_meta <- (Meta.FlatEnum,[],null_pos) :: e.e_meta; if (ctx.com.platform = Java || ctx.com.platform = Cs) && not e.e_extern then @@ -691,7 +701,7 @@ let init_module_type ctx context_init do_init (decl,p) = ) e.e_constrs ); | ETypedef d -> - let t = (match get_type (fst d.d_name) with TTypeDecl t -> t | _ -> assert false) in + let t = (match get_type (fst d.d_name) with TTypeDecl t -> t | _ -> die "" __LOC__) in if ctx.is_display_file && DisplayPosition.display_position#enclosed_in (pos d.d_name) then DisplayEmitter.display_module_type ctx (TTypeDecl t) (pos d.d_name); TypeloadCheck.check_global_metadata ctx t.t_meta (fun m -> t.t_meta <- m :: t.t_meta) t.t_module.m_path t.t_path None; @@ -711,7 +721,7 @@ let init_module_type ctx context_init do_init (decl,p) = if tt == t.t_type then error "Recursive typedef is not allowed" p; match tt with | TMono r -> - (match !r with + (match r.tm_type with | None -> () | Some t -> check_rec t) | TLazy f -> @@ -732,17 +742,17 @@ let init_module_type ctx context_init do_init (decl,p) = ) in (match t.t_type with | TMono r -> - (match !r with - | None -> r := Some tt; - | Some _ -> assert false); - | _ -> assert false); + (match r.tm_type with + | None -> Monomorph.bind r tt; + | Some _ -> die "" __LOC__); + | _ -> die "" __LOC__); if ctx.com.platform = Cs && t.t_meta <> [] then delay ctx PTypeField (fun () -> let metas = StrictMeta.check_strict_meta ctx t.t_meta in if metas <> [] then t.t_meta <- metas @ t.t_meta; ); | EAbstract d -> - let a = (match get_type (fst d.d_name) with TAbstractDecl a -> a | _ -> assert false) in + let a = (match get_type (fst d.d_name) with TAbstractDecl a -> a | _ -> die "" __LOC__) in if ctx.is_display_file && DisplayPosition.display_position#enclosed_in (pos d.d_name) then DisplayEmitter.display_module_type ctx (TAbstractDecl a) (pos d.d_name); TypeloadCheck.check_global_metadata ctx a.a_meta (fun m -> a.a_meta <- m :: a.a_meta) a.a_module.m_path a.a_path None; @@ -820,16 +830,13 @@ let module_pass_2 ctx m decls tdecls p = | (TAbstractDecl a, (EAbstract d, p)) -> a.a_params <- type_type_params ctx a.a_path (fun() -> a.a_params) p d.d_params; | _ -> - assert false + die "" __LOC__ ) decls; (* setup module types *) - let context_init = ref [] in - let do_init() = - match !context_init with - | [] -> () - | l -> context_init := []; List.iter (fun f -> f()) (List.rev l) - in - List.iter (init_module_type ctx context_init do_init) tdecls + let context_init = new TypeloadFields.context_init in + List.iter (init_module_type ctx context_init) tdecls; + (* Make sure that we actually init the context at some point (issue #9012) *) + delay ctx PConnectField (fun () -> context_init#run) (* Creates a module context for [m] and types [tdecls] using it. @@ -915,8 +922,7 @@ let handle_import_hx ctx m decls p = with Not_found -> if Sys.file_exists path then begin let _,r = match !TypeloadParse.parse_hook ctx.com path p with - | ParseSuccess data -> data - | ParseDisplayFile(data,_) -> data + | ParseSuccess(data,_,_) -> data | ParseError(_,(msg,p),_) -> Parser.error msg p in List.iter (fun (d,p) -> match d with EImport _ | EUsing _ -> () | _ -> error "Only import and using is allowed in import.hx files" p) r; @@ -943,7 +949,7 @@ let type_module ctx mpath file ?(dont_check_path=false) ?(is_extern=false) tdecl if is_extern then m.m_extra.m_kind <- MExtern else if not dont_check_path then Typecore.check_module_path ctx m.m_path p; begin if ctx.is_display_file then match ctx.com.display.dms_kind with | DMResolve s -> - DisplayPath.resolve_position_by_path ctx {tname = s; tpackage = []; tsub = None; tparams = []} p + DisplayPath.resolve_position_by_path ctx (mk_type_path ([],s)) p | _ -> () end; diff --git a/src/typing/typeloadParse.ml b/src/typing/typeloadParse.ml index 216622a9445c288048bb4d7e3dc648e67777ade2..cd650c49cf43c1cccb795fe674ab9a9eb50c23b7 100644 --- a/src/typing/typeloadParse.ml +++ b/src/typing/typeloadParse.ml @@ -21,6 +21,7 @@ open Globals open Ast +open Parser open DisplayTypes.DiagnosticsSeverity open DisplayTypes.DisplayMode open Common @@ -46,7 +47,7 @@ let parse_file_from_lexbuf com file p lexbuf = in begin match !Parser.display_mode,parse_result with | DMModuleSymbols (Some ""),_ -> () - | DMModuleSymbols filter,(ParseSuccess data | ParseDisplayFile(data,_)) when filter = None && DisplayPosition.display_position#is_in_file file -> + | DMModuleSymbols filter,(ParseSuccess(data,_,_)) when filter = None && DisplayPosition.display_position#is_in_file file -> let ds = DocumentSymbols.collect_module_symbols (filter = None) data in DisplayException.raise_module_symbols (DocumentSymbols.Printer.print_module_symbols com [file,ds] filter); | _ -> @@ -111,8 +112,8 @@ let resolve_module_file com m remap p = (* if we try to load a std.xxxx class and resolve a real std file, the package name is not valid, ignore *) (match fst m with | "std" :: _ -> - let file = Path.unique_full_path file in - if List.exists (fun path -> ExtString.String.starts_with file (try Path.unique_full_path path with _ -> path)) com.std_path then raise Not_found; + let file_key = Path.UniqueKey.create file in + if List.exists (fun path -> Path.UniqueKey.starts_with file_key (Path.UniqueKey.create path)) com.std_path then raise Not_found; | _ -> ()); if !forbid then begin let parse_result = (!parse_hook) com file p in @@ -125,11 +126,11 @@ let resolve_module_file com m remap p = | [] -> [] in let meta = match parse_result with - | ParseSuccess(_,decls) | ParseDisplayFile((_,decls),_) -> loop decls + | ParseSuccess((_,decls),_,_) -> loop decls | ParseError _ -> [] in if not (Meta.has Meta.NoPackageRestrict meta) then begin - let x = (match fst m with [] -> assert false | x :: _ -> x) in + let x = (match fst m with [] -> die "" __LOC__ | x :: _ -> x) in raise (Forbid_package ((x,m,p),[],platform_name_macro com)); end; end; @@ -181,7 +182,7 @@ module ConditionDisplay = struct cf_type = t; cf_pos = null_pos; cf_name_pos = null_pos; - cf_doc = Some ( + cf_doc = doc_from_string ( "Allows comparing defines (such as the version of a Haxelib or Haxe) with SemVer semantics. Both the define and the string passed to `version()` must be valid semantic versions. @@ -211,7 +212,7 @@ so it should be avoided if backwards-compatibility with earlier versions is need DisplayException.raise_hover (CompletionItem.make_ci_define n (match v with | TNull -> None | TString s -> Some (StringHelper.s_escape s) - | _ -> assert false + | _ -> die "" __LOC__ ) (tpair com.basic.tstring)) None p | _ -> () @@ -234,7 +235,7 @@ module PdiHandler = struct let is_true defines e = ParserEntry.is_true (ParserEntry.eval defines e) - let handle_pdi com file pdi = + let handle_pdi com pdi = let macro_defines = adapt_defines_to_macro_context com.defines in let check = (if com.display.dms_kind = DMHover then encloses_position_gt @@ -261,20 +262,10 @@ module PdiHandler = struct | _ -> () end; - let display_defines = {macro_defines with values = PMap.add "display" "1" macro_defines.values} in - let dead_blocks = List.filter (fun (_,e) -> not (is_true display_defines e)) pdi.pd_dead_blocks in - let sdi = com.shared.shared_display_information in - begin try - let dead_blocks2 = Hashtbl.find sdi.dead_blocks file in - (* Intersect *) - let dead_blocks2 = List.filter (fun (p,_) -> List.mem_assoc p dead_blocks) dead_blocks2 in - Hashtbl.replace sdi.dead_blocks file dead_blocks2 - with Not_found -> - Hashtbl.add sdi.dead_blocks file dead_blocks - end; + () end -let parse_module_file com file p = +let handle_parser_result com p result = let handle_parser_error msg p = let msg = Parser.error_msg msg in match com.display.dms_error_policy with @@ -282,20 +273,22 @@ let parse_module_file com file p = | EPIgnore -> () | EPCollect -> add_diagnostics_message com msg p DKParserError Error in - let pack,decls = match (!parse_hook) com file p with - | ParseSuccess data -> data - | ParseDisplayFile(data,pdi) -> - begin match pdi.pd_errors with - | (msg,p) :: _ -> handle_parser_error msg p - | [] -> () + match result with + | ParseSuccess(data,is_display_file,pdi) -> + if is_display_file then begin + begin match pdi.pd_errors with + | (msg,p) :: _ -> handle_parser_error msg p + | [] -> () + end; + PdiHandler.handle_pdi com pdi; end; - PdiHandler.handle_pdi com file pdi; data | ParseError(data,(msg,p),_) -> handle_parser_error msg p; data - in - pack,decls + +let parse_module_file com file p = + handle_parser_result com p ((!parse_hook) com file p) let parse_module' com m p = let remap = ref (fst m) in @@ -323,15 +316,20 @@ let parse_module ctx m p = d_meta = []; d_params = d.d_params; d_flags = if priv then [EPrivate] else []; - d_data = CTPath (if priv then { tpackage = []; tname = "Dynamic"; tparams = []; tsub = None; } else - { - tpackage = !remap; - tname = fst d.d_name; - tparams = List.map (fun tp -> - TPType (CTPath { tpackage = []; tname = fst tp.tp_name; tparams = []; tsub = None; },null_pos) - ) d.d_params; - tsub = None; - }),null_pos; + d_data = begin + let tp = + if priv then + mk_type_path ([],"Dynamic") + else + let params = + List.map (fun tp -> + TPType (CTPath (mk_type_path ([],fst tp.tp_name)),null_pos) + ) d.d_params + in + mk_type_path ~params (!remap,fst d.d_name) + in + CTPath (tp),null_pos; + end },p) :: acc in match t with diff --git a/src/typing/typer.ml b/src/typing/typer.ml index 1c9533e2d63ce42d5c0e87e5d15f9d845a1eb66f..369bc4e6925366cc51fb0a6b43da03419e588d01 100644 --- a/src/typing/typer.ml +++ b/src/typing/typer.ml @@ -33,10 +33,6 @@ open Calls (* ---------------------------------------------------------------------- *) (* TOOLS *) -let is_lower_ident s p = - try Ast.is_lower_ident s - with Invalid_argument msg -> error msg p - let check_assign ctx e = match e.eexpr with | TLocal {v_final = true} -> @@ -69,7 +65,7 @@ let rec classify t = | TInst ({ cl_kind = KTypeParameter ctl },_) when List.exists (fun t -> match classify t with KInt | KFloat -> true | _ -> false) ctl -> KNumParam t | TAbstract (a,[]) when List.exists (fun t -> match classify t with KString -> true | _ -> false) a.a_to -> KStrParam t | TInst ({ cl_kind = KTypeParameter ctl },_) when List.exists (fun t -> match classify t with KString -> true | _ -> false) ctl -> KStrParam t - | TMono r when !r = None -> KUnk + | TMono r when r.tm_type = None -> KUnk | TDynamic _ -> KDyn | _ -> KOther @@ -189,7 +185,7 @@ let rec unify_min_raise basic (el:texpr list) : t = (* prioritize the most generic definition *) tl := t :: !tl; | TLazy f -> loop (lazy_type f) - | TMono r -> (match !r with None -> () | Some t -> loop t) + | TMono r -> (match r.tm_type with None -> () | Some t -> loop t) | _ -> tl := t :: !tl) in loop t; @@ -252,7 +248,7 @@ let rec unify_min_raise basic (el:texpr list) : t = let t = try unify_min_raise basic el with Unify_error _ -> raise Not_found in PMap.add n (mk_field n t (List.hd el).epos null_pos) acc ) fields PMap.empty in - TAnon { a_fields = fields; a_status = ref Closed } + mk_anon ~fields (ref Closed) with Not_found -> (* Second pass: Get all base types (interfaces, super classes and their interfaces) of most general type. Then for each additional type filter all types that do not unify. *) @@ -391,7 +387,7 @@ let rec type_ident_raise ctx i p mode = let et = type_module_type ctx (TClassDecl c) None p in let fa = FStatic(c,cf) in let t = monomorphs cf.cf_params cf.cf_type in - ImportHandling.maybe_mark_import_position ctx pt; + ImportHandling.mark_import_position ctx pt; begin match cf.cf_kind with | Var {v_read = AccInline} -> AKInline(et,cf,fa,t) | _ -> AKExpr (mk (TField(et,fa)) t p) @@ -413,7 +409,7 @@ let rec type_ident_raise ctx i p mode = let et = type_module_type ctx t None p in let monos = List.map (fun _ -> mk_mono()) e.e_params in let monos2 = List.map (fun _ -> mk_mono()) ef.ef_params in - ImportHandling.maybe_mark_import_position ctx pt; + ImportHandling.mark_import_position ctx pt; wrap (mk (TField (et,FEnum (e,ef))) (enum_field_type ctx e ef monos monos2 p) p) with Not_found -> loop l @@ -422,7 +418,7 @@ let rec type_ident_raise ctx i p mode = with Not_found -> (* lookup imported globals *) let t, name, pi = PMap.find i ctx.m.module_globals in - ImportHandling.maybe_mark_import_position ctx pi; + ImportHandling.mark_import_position ctx pi; let e = type_module_type ctx t None p in type_field_default_cfg ctx e name p mode @@ -534,7 +530,7 @@ let rec type_binop ctx op e1 e2 is_assign_op with_type p = let e2 = e2 (WithType.with_type t) in begin match follow e1.etype with | TFun([_;_;(_,_,t)],_) -> unify ctx e2.etype t e2.epos; - | _ -> assert false + | _ -> die "" __LOC__ end; make_call ctx e1 [ethis;Texpr.Builder.make_string ctx.t fname null_pos;e2] t p | AKUsing(ef,_,_,et,_) -> @@ -547,7 +543,7 @@ let rec type_binop ctx op e1 e2 is_assign_op with_type p = in make_call ctx ef [et;e2] ret p | AKInline _ | AKMacro _ -> - assert false) + die "" __LOC__) | OpAssignOp (OpBoolAnd | OpBoolOr) -> error "The operators ||= and &&= are not supported" p | OpAssignOp op -> @@ -627,15 +623,50 @@ let rec type_binop ctx op e1 e2 is_assign_op with_type p = ]) t p | AKUsing(ef,c,cf,et,_) -> (* abstract setter + getter *) - let ta = match c.cl_kind with KAbstractImpl a -> TAbstract(a, List.map (fun _ -> mk_mono()) a.a_params) | _ -> assert false in + let ta = match c.cl_kind with KAbstractImpl a -> TAbstract(a, List.map (fun _ -> mk_mono()) a.a_params) | _ -> die "" __LOC__ in let ret = match follow ef.etype with | TFun([_;_],ret) -> ret - | _ -> error "Invalid field type for abstract setter" p + | _ -> error "Invalid field type for abstract setter" p in let l = save_locals ctx in - let v,is_temp = match et.eexpr with - | TLocal v when not (v.v_name = "this") -> v,false - | _ -> gen_local ctx ta ef.epos,true + let v,init_exprs,abstr_this_to_modify = match et.eexpr with + | TLocal v when not (Meta.has Meta.This v.v_meta) -> v,[],None + | _ -> + let v = gen_local ctx ta ef.epos in + (match et.eexpr with + | TLocal { v_meta = m } -> v.v_meta <- Meta.copy_from_to Meta.This m v.v_meta + | _ -> () + ); + let decl_v e = mk (TVar (v,Some e)) ctx.t.tvoid p in + let rec needs_temp_var e = + match e.eexpr with + | TConst TThis | TTypeExpr _ -> false + | TField (e1,(FInstance(_,_,cf) | FStatic(_,cf))) + when has_class_field_flag cf CfFinal -> + needs_temp_var e1 + | TParenthesis e1 -> + needs_temp_var e1 + | _ -> true + in + if has_class_field_flag cf CfModifiesThis then + match et.eexpr with + | TField (target,fa) when needs_temp_var target-> + let tmp = gen_local ctx target.etype target.epos in + let decl_tmp = mk (TVar (tmp,Some target)) ctx.t.tvoid target.epos in + let etmp = mk (TLocal tmp) tmp.v_type tmp.v_pos in + let athis = mk (TField (etmp,fa)) et.etype et.epos in + v,[decl_tmp; decl_v athis],(Some athis) + | TArray (target,index) when needs_temp_var target -> + let tmp = gen_local ctx target.etype target.epos in + let decl_tmp = mk (TVar (tmp,Some target)) ctx.t.tvoid target.epos in + let etmp = mk (TLocal tmp) tmp.v_type tmp.v_pos in + let athis = mk (TArray (etmp,index)) et.etype et.epos in + v,[decl_tmp; decl_v athis],(Some athis) + | _ -> + check_assign ctx et; + v,[decl_v et],(Some et) + else + v,[decl_v et],None in let ev = mk (TLocal v) ta p in (* this relies on the fact that cf_name is set_name *) @@ -644,13 +675,28 @@ let rec type_binop ctx op e1 e2 is_assign_op with_type p = unify ctx get.etype ret p; l(); let e_call = make_call ctx ef [ev;get] ret p in - if is_temp then - mk (TBlock [ - mk (TVar (v,Some et)) ctx.t.tvoid p; + let e_call = + (* + If this method modifies abstract `this`, we should also apply temp var + modifications to the original tempvar-ed expression. + Find code like `v = value` and change it to `et = v = value`, + where `v` is the temp var and `et` is the original expression stored to the temp var. + *) + match abstr_this_to_modify with + | None -> e_call - ]) ret p - else - e_call + | Some athis -> + let rec loop e = + match e.eexpr with + | TBinop(OpAssign,({ eexpr = TLocal v1 } as left),right) when v1 == v -> + let right = { e with eexpr = TBinop(OpAssign,left,loop right) } in + mk (TBinop(OpAssign,athis,right)) e.etype e.epos + | _ -> + map_expr loop e + in + loop e_call + in + mk (TBlock (init_exprs @ [e_call])) ret p | AKAccess(a,tl,c,ebase,ekey) -> let cf_get,tf_get,r_get,ekey,_ = AbstractCast.find_array_access ctx a tl ekey None p in (* bind complex keys to a variable so they do not make it into the output twice *) @@ -668,7 +714,7 @@ let rec type_binop ctx op e1 e2 is_assign_op with_type p = let eget = type_binop2 ctx op eget e2 true (WithType.with_type eget.etype) p in unify ctx eget.etype r_get p; let cf_set,tf_set,r_set,ekey,eget = AbstractCast.find_array_access ctx a tl ekey (Some eget) p in - let eget = match eget with None -> assert false | Some e -> e in + let eget = match eget with None -> die "" __LOC__ | Some e -> e in let et = type_module_type ctx (TClassDecl c) None p in let e = match cf_set.cf_expr,cf_get.cf_expr with | None,None -> @@ -691,7 +737,7 @@ let rec type_binop ctx op e1 e2 is_assign_op with_type p = | AKFieldSet _ -> error "Invalid operation" p | AKInline _ | AKMacro _ -> - assert false) + die "" __LOC__) | _ -> type_non_assign_op false @@ -902,14 +948,14 @@ and type_binop2 ?(abstract_overload_only=false) ctx op (e1 : texpr) (e2 : Ast.ex let t = Typeload.load_core_type ctx "IntIterator" in unify ctx e1.etype tint e1.epos; unify ctx e2.etype tint e2.epos; - mk (TNew ((match t with TInst (c,[]) -> c | _ -> assert false),[],[e1;e2])) t p + mk (TNew ((match t with TInst (c,[]) -> c | _ -> die "" __LOC__),[],[e1;e2])) t p | OpArrow -> error "Unexpected =>" p | OpIn -> error "Unexpected in" p | OpAssign | OpAssignOp _ -> - assert false + die "" __LOC__ in let find_overload a c tl left = let map = apply_params a.a_params tl in @@ -1012,7 +1058,7 @@ and type_binop2 ?(abstract_overload_only=false) ctx op (e1 : texpr) (e2 : Ast.ex loop ol end | _ -> - assert false + die "" __LOC__ end | [] -> raise Not_found @@ -1122,6 +1168,48 @@ and type_unop ctx op flag e p = let e = mk_array_get_call ctx (AbstractCast.find_array_access ctx a tl ekey None p) c ebase p in loop (AKExpr e) end + | AKUsing (emethod,cl,cf,etarget,force_inline) when (op = Decrement || op = Increment) && has_meta Meta.Impl cf.cf_meta -> + let l = save_locals ctx in + let init_tmp,etarget,eget = + match needs_temp_var etarget, fst e with + | true, EField (_, field_name) -> + let tmp = gen_local ctx etarget.etype p in + let tmp_ident = (EConst (Ident tmp.v_name), p) in + ( + mk (TVar (tmp, Some etarget)) ctx.t.tvoid p, + mk (TLocal tmp) tmp.v_type p, + (EField (tmp_ident,field_name), p) + ) + | _ -> (mk (TBlock []) ctx.t.tvoid p, etarget, e) + in + let op = (match op with Increment -> OpAdd | Decrement -> OpSub | _ -> die "" __LOC__) in + let one = (EConst (Int "1"),p) in + (match follow cf.cf_type with + | TFun (_, t) -> + (match flag with + | Prefix -> + let get = type_binop ctx op eget one false WithType.value p in + unify ctx get.etype t p; + l(); + let call_setter = make_call ctx emethod [etarget; get] t ~force_inline p in + mk (TBlock [init_tmp; call_setter]) t p + | Postfix -> + let get = type_expr ctx eget WithType.value in + let tmp_value = gen_local ctx t p in + let plusone = type_binop ctx op (EConst (Ident tmp_value.v_name),p) one false WithType.value p in + unify ctx get.etype t p; + l(); + mk (TBlock [ + init_tmp; + mk (TVar (tmp_value,Some get)) ctx.t.tvoid p; + make_call ctx emethod [etarget; plusone] t ~force_inline p; + mk (TLocal tmp_value) t p; + ]) t p + ) + | _ -> + l(); + die "" __LOC__ + ) | AKInline _ | AKUsing _ | AKMacro _ -> error "This kind of operation is not supported" p | AKFieldSet _ -> @@ -1130,7 +1218,7 @@ and type_unop ctx op flag e p = let l = save_locals ctx in let v = gen_local ctx e.etype p in let ev = mk (TLocal v) e.etype p in - let op = (match op with Increment -> OpAdd | Decrement -> OpSub | _ -> assert false) in + let op = (match op with Increment -> OpAdd | Decrement -> OpSub | _ -> die "" __LOC__) in let one = (EConst (Int "1"),p) in let eget = (EField ((EConst (Ident v.v_name),p),cf.cf_name),p) in match flag with @@ -1171,7 +1259,7 @@ and type_ident ctx i p mode = try let t = List.find (fun (i2,_) -> i2 = i) ctx.type_params in resolved_to_type_parameter := true; - let c = match follow (snd t) with TInst(c,_) -> c | _ -> assert false in + let c = match follow (snd t) with TInst(c,_) -> c | _ -> die "" __LOC__ in if TypeloadCheck.is_generic_parameter ctx c && Meta.has Meta.Const c.cl_meta then begin let e = type_module_type ctx (TClassDecl c) None p in AKExpr {e with etype = (snd t)} @@ -1197,7 +1285,7 @@ and type_ident ctx i p mode = match ctx.com.display.dms_kind with | DMNone -> raise (Error(err,p)) - | DMDiagnostics b when b || ctx.is_display_file -> + | DMDiagnostics _ -> DisplayToplevel.handle_unresolved_identifier ctx i p false; let t = mk_mono() in AKExpr (mk (TIdent i) t p) @@ -1211,214 +1299,84 @@ and type_ident ctx i p mode = end end -(* MORDOR *) -and handle_efield ctx e p mode = - let p0 = p in - (* - given chain of fields as the `path` argument and an `access_mode->access_kind` getter for some starting expression as `e`, - return a new `access_mode->access_kind` getter for the whole field access chain. +and handle_efield ctx e p0 mode = + let open TyperDotPath in - if `resume` is true, `Not_found` will be raised if the first field in chain fails to resolve, in all other - cases, normal type errors will be raised if a field can't be accessed. - *) - let fields ?(resume=false) path e = - let resume = ref resume in - let force = ref false in - let e = List.fold_left (fun e (f,_,p) -> - let e = acc_get ctx (e MGet) p in - let f = type_field (TypeFieldConfig.create !resume) ctx e f p in - force := !resume; - resume := false; - f - ) e path in - if !force then ignore(e MCall); (* not necessarily a call, but prevent #2602 among others *) - e - in - - (* - given a chain of identifiers (dot-path) represented as a list of (ident,starts_uppercase,pos) tuples, - resolve it into an `access_mode->access_kind` getter for the resolved expression - *) - let type_path path = - (* - this is an actual loop for processing a fully-qualified dot-path. - it relies on the fact that packages start with a lowercase letter, while modules and types - start with upper-case letters, so it processes path parts, accumulating lowercase package parts in `acc`, - until it encounters an upper-case part, which can mean either a module access or module's primary type access, - so it tries to figure out the type and and calls `fields` on it to resolve the rest of field access chain. - *) - let rec loop acc path = - match path with - | (_,false,_) as x :: path -> - (* part starts with lowercase - it's a package part, add it the accumulator and proceed *) - loop (x :: acc) path - - | (name,true,p) as x :: path -> - (* part starts with uppercase - it either points to a module or its main type *) - - (* acc is contains all the package parts now, so extract package from them *) - let pack = List.rev_map (fun (x,_,_) -> x) acc in - - (* default behaviour: try loading module's primary type (with the same name as module) - and resolve the rest of the field chain against its statics, or the type itself - if the rest of chain is empty *) - let def() = - try - let e = type_type ctx (pack,name) p in - fields path (fun _ -> AKExpr e) - with - Error (Module_not_found m,_) when m = (pack,name) -> - (* if it's not a module path after all, it could be an untyped field access that looks like - a dot-path, e.g. `untyped __global__.String`, add the whole path to the accumulator and - proceed to the untyped identifier resolution *) - loop ((List.rev path) @ x :: acc) [] - in - - (match path with - | (sname,true,p) :: path -> - (* next part starts with uppercase, meaning it can be either a module sub-type access - or static field access for the primary module type, so we have to do some guessing here - - In this block, `name` is the first first-uppercase part (possibly a module name), - and `sname` is the second first-uppsercase part (possibly a subtype name). *) - - (* get static field by `sname` from a given type `t`, if `resume` is true - raise Not_found *) - let get_static resume t = - fields ~resume ((sname,true,p) :: path) (fun _ -> AKExpr (type_module_type ctx t None p)) - in - - (* try accessing subtype or main class static field by `sname` in given module with path `m` *) - let check_module m = - try - let md = TypeloadModule.load_module ctx m p in - (* first look for existing subtype *) - (try - let t = List.find (fun t -> not (t_infos t).mt_private && t_path t = (fst m,sname)) md.m_types in - Some (fields path (fun _ -> AKExpr (type_module_type ctx t None p))) - with Not_found -> try - (* then look for main type statics *) - if fst m = [] then raise Not_found; (* ensure that we use def() to resolve local types first *) - let t = List.find (fun t -> not (t_infos t).mt_private && t_path t = m) md.m_types in - Some (get_static false t) - with Not_found -> - None) - with Error (Module_not_found m2,_) when m = m2 -> - None - in - - (match pack with - | [] -> - (* if there's no package specified... *) - (try - (* first try getting a type by `name` in current module types and current imports - and try accessing its static field by `sname` *) - let path_match t = snd (t_infos t).mt_path = name in - let t = - try - List.find path_match ctx.m.curmod.m_types (* types in this modules *) - with Not_found -> - let t,p = List.find (fun (t,_) -> path_match t) ctx.m.module_types in (* imported types *) - ImportHandling.maybe_mark_import_position ctx p; - t - in - get_static true t - with Not_found -> - (* if the static field (or the type) wasn't not found, look for a subtype instead - #1916 - look for subtypes/main-class-statics in modules of current package and its parent packages *) - let rec loop pack = - match check_module (pack,name) with - | Some r -> r - | None -> - match List.rev pack with - | [] -> def() - | _ :: l -> loop (List.rev l) - in - loop (fst ctx.m.curmod.m_path)) - | _ -> - (* if package was specified, treat it as fully-qualified access to either - a module subtype or a static field of module's primary type*) - match check_module (pack,name) with - | Some r -> r - | None -> def()); - | _ -> - (* no more parts or next part starts with lowercase - it's surely not a type name, - so do the default thing: resolve fields against primary module type *) - def()) - - | [] -> - (* If we get to here, it means that either there were no uppercase-first-letter parts, - or we couldn't find the specified module, so it's not a qualified dot-path after all. - And it's not a known identifier too, because otherwise `loop` wouldn't be called at all. - So this must be an untyped access (or a typo). Try resolving the first identifier with support - for untyped and resolve the rest of field chain against it. - - TODO: extract this into a separate function - *) - (match List.rev acc with - | [] -> assert false - | (name,flag,p) :: path -> - try - fields path (type_ident ctx name p) - with - Error (Unknown_ident _,p2) as e when p = p2 -> - try - (* try raising a more sensible error if there was an uppercase-first (module name) part *) - let path = ref [] in - let name , _ , _ = List.find (fun (name,flag,p) -> - if flag then - true - else begin - path := name :: !path; - false - end - ) (List.rev acc) in - raise (Error (Module_not_found (List.rev !path,name),p)) - with - Not_found -> - let sl = List.map (fun (n,_,_) -> n) (List.rev acc) in - (* if there was no module name part, last guess is that we're trying to get package completion *) - if ctx.in_display then begin - if is_legacy_completion ctx.com then raise (Parser.TypePath (sl,None,false,p)) - else DisplayToplevel.collect_and_raise ctx TKType WithType.no_value (CRToplevel None) (String.concat "." sl,p0) p0 - end; - raise e) - in - match path with - | [] -> assert false - | (name,_,p) :: pnext -> + let dot_path first pnext = + let name,_,p = first in + try + (* first, try to resolve the first ident in the chain and access its fields. + this doesn't support untyped identifiers yet, because we want to check fully-qualified + paths first (even in an untyped block) *) + field_chain ctx pnext (type_ident_raise ctx name p) + with Not_found -> + (* first ident couldn't be resolved, it's probably a fully qualified path - resolve it *) + let path = (first :: pnext) in try - (* - first, try to resolve the first ident in the chain and access its fields. - this doesn't support untyped identifiers yet, because we want to check - fully-qualified dot paths first even in an untyped block. - *) - fields pnext (fun _ -> type_ident_raise ctx name p MGet) + resolve_dot_path ctx path with Not_found -> - (* first ident couldn't be resolved, it's probably a fully qualified path - resolve it *) - loop [] path + (* dot-path resolution failed, it could be an untyped field access that happens to look like a dot-path, e.g. `untyped __global__.String` *) + try + (* TODO: we don't really want to do full type_ident again, just the second part of it *) + field_chain ctx pnext (type_ident ctx name p) + with Error (Unknown_ident _,p2) as e when p = p2 -> + try + (* try raising a more sensible error if there was an uppercase-first (module name) part *) + begin + (* TODO: we should pass the actual resolution error from resolve_dot_path instead of Not_found *) + let rec loop pack_acc first_uppercase path = + match path with + | (name,PLowercase,_) :: rest -> + (match first_uppercase with + | None -> loop (name :: pack_acc) None rest + | Some (n,p) -> List.rev pack_acc, n, None, p) + | (name,PUppercase,p) :: rest -> + (match first_uppercase with + | None -> loop pack_acc (Some (name,p)) rest + | Some (n,_) -> List.rev pack_acc, n, Some name, p) + | [] -> + (match first_uppercase with + | None -> raise Not_found + | Some (n,p) -> List.rev pack_acc, n, None, p) + in + let pack,name,sub,p = loop [] None path in + let mpath = (pack,name) in + if Hashtbl.mem ctx.g.modules mpath then + let tname = Option.default name sub in + raise (Error (Type_not_found (mpath,tname,Not_defined),p)) + else + raise (Error (Module_not_found mpath,p)) + end + with Not_found -> + (* if there was no module name part, last guess is that we're trying to get package completion *) + if ctx.in_display then begin + let sl = List.map (fun (n,_,_) -> n) path in + if is_legacy_completion ctx.com then + raise (Parser.TypePath (sl,None,false,p)) + else + DisplayToplevel.collect_and_raise ctx TKType WithType.no_value (CRToplevel None) (String.concat "." sl,p0) p0 + end; + raise e in - (* - loop through the given EField expression and behave differently depending on whether it's a simple dot-path - or a more complex expression, accumulating field access parts in form of (ident,starts_uppercase,pos) tuples. - - if it's a dot-path, then it might be either fully-qualified access (pack.Class.field) or normal field access of - a local/global/field identifier. we pass the accumulated path to `type_path` and let it figure out what it is. - - if it's NOT a dot-path (anything other than indentifiers appears in EField chain), then we can be sure it's - normal field access, not fully-qualified access, so we pass the non-ident expr along with the accumulated - fields chain to the `fields` function and let it type the field access. - *) - let rec loop acc (e,p) = + (* loop through the given EField expression to figure out whether it's a dot-path that we have to resolve, + or a simple field access chain *) + let rec loop dot_path_acc (e,p) = match e with | EField (e,s) -> - loop ((s,not (is_lower_ident s p),p) :: acc) e + (* field access - accumulate and check further *) + loop ((mk_dot_path_part s p) :: dot_path_acc) e | EConst (Ident i) -> - type_path ((i,not (is_lower_ident i p),p) :: acc) + (* it's a dot-path, so it might be either fully-qualified access (pack.Class.field) + or normal field access of a local/global/field identifier, proceed figuring this out *) + dot_path (mk_dot_path_part i p) dot_path_acc | _ -> - fields acc (type_access ctx e p) + (* non-ident expr occured: definitely NOT a fully-qualified access, + resolve the field chain against this expression *) + let e = type_access ctx e p in + field_chain ctx dot_path_acc e in - loop [] (e,p) mode + loop [] (e,p0) mode and type_access ctx e p mode = match e with @@ -1433,7 +1391,7 @@ and type_access ctx e p mode = let monos = List.map (fun _ -> mk_mono()) (match c.cl_kind with KAbstractImpl a -> a.a_params | _ -> c.cl_params) in let ct, cf = get_constructor ctx c monos p in check_constructor_access ctx c cf p; - let args = match follow ct with TFun(args,ret) -> args | _ -> assert false in + let args = match follow ct with TFun(args,ret) -> args | _ -> die "" __LOC__ in let vl = List.map (fun (n,_,t) -> alloc_var VGenerated n t c.cl_pos) args in let vexpr v = mk (TLocal v) v.v_type p in let el = List.map vexpr vl in @@ -1568,7 +1526,7 @@ and format_string ctx s p = let rec loop groups i = if i = len then match groups with - | [] -> assert false + | [] -> die "" __LOC__ | g :: _ -> error ("Unclosed " ^ gname) { p with pmin = !pmin + g + 1; pmax = !pmin + g + 2 } else let c = String.unsafe_get s i in @@ -1589,7 +1547,7 @@ and format_string ctx s p = let ep = { p with pmin = !pmin + pos + 2; pmax = !pmin + send + 1 } in try begin match ParserEntry.parse_expr_string ctx.com.defines scode ep error true with - | ParseSuccess data | ParseDisplayFile(data,_) -> data + | ParseSuccess(data,_,_) -> data | ParseError(_,(msg,p),_) -> error (Parser.error_msg msg) p end with Exit -> @@ -1602,7 +1560,7 @@ and format_string ctx s p = in parse 0 0; match !e with - | None -> assert false + | None -> die "" __LOC__ | Some e -> e and type_block ctx el with_type p = @@ -1689,7 +1647,7 @@ and type_object_decl ctx fl with_type p = end; ((n,pn,qs),e) ) fl in - let t = (TAnon { a_fields = !fields; a_status = ref Const }) in + let t = mk_anon ~fields:!fields (ref Const) in if not ctx.untyped then begin (match PMap.foldi (fun n cf acc -> if not (Meta.has Meta.Optional cf.cf_meta) && not (PMap.mem n !fields) then n :: acc else acc) field_map [] with | [] -> () @@ -1717,7 +1675,7 @@ and type_object_decl ctx fl with_type p = let fields , types = List.fold_left loop ([],PMap.empty) fl in let x = ref Const in ctx.opened <- x :: ctx.opened; - mk (TObjectDecl (List.rev fields)) (TAnon { a_fields = types; a_status = x }) p + mk (TObjectDecl (List.rev fields)) (mk_anon ~fields:types x) p in (match a with | ODKPlain -> type_plain_fields() @@ -1730,7 +1688,7 @@ and type_object_decl ctx fl with_type p = let t,ctor = get_constructor ctx c tl p in let args = match follow t with | TFun(args,_) -> args - | _ -> assert false + | _ -> die "" __LOC__ in let fields = List.fold_left (fun acc (n,opt,t) -> let f = mk_field n t ctor.cf_pos ctor.cf_name_pos in @@ -1754,13 +1712,45 @@ and type_object_decl ctx fl with_type p = ) ([],[],false) (List.rev fl) in let el = List.map (fun (n,_,t) -> try Expr.field_assoc n fl - with Not_found -> mk (TConst TNull) t p + with Not_found -> + try + match ctor.cf_expr with + | Some { eexpr = TFunction fn } -> + Option.get (snd (List.find (fun (v,e) -> n = v.v_name && Option.is_some e) fn.tf_args)) + | _ -> + raise Not_found + with Not_found | Option.No_value -> + let t = + if type_has_meta (Abstract.follow_with_abstracts_without_null t) Meta.NotNull then ctx.t.tnull t + else t + in + mk (TConst TNull) t p ) args in let e = mk (TNew(c,tl,el)) (TInst(c,tl)) p in mk (TBlock (List.rev (e :: (List.rev evars)))) e.etype e.epos ) and type_new ctx path el with_type force_inline p = + let path = + if snd path <> null_pos then + path + (* + Since macros don't have placed_type_path structure on Haxe side any ENew will have null_pos in `path`. + Try to calculate a better pos. + *) + else begin + match el with + | (_,p1) :: _ when p1.pfile = p.pfile && p.pmin < p1.pmin -> + let pmin = p.pmin + (String.length "new ") + and pmax = p1.pmin - 2 (* Additional "1" for an opening bracket *) + in + fst path, { p with + pmin = if pmin < pmax then pmin else p.pmin; + pmax = pmax; + } + | _ -> fst path, p + end + in let unify_constructor_call c params f ct = match follow ct with | TFun (args,r) -> (try @@ -1844,7 +1834,7 @@ and type_new ctx path el with_type force_inline p = end | TAbstract({a_impl = Some c} as a,tl) when not (Meta.has Meta.MultiType a.a_meta) -> let el,cf,ct = build_constructor_call c tl in - let ta = TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } in + let ta = mk_anon ~fields:c.cl_statics (ref (Statics c)) in let e = mk (TTypeExpr (TClassDecl c)) ta p in let e = mk (TField (e,(FStatic (c,cf)))) ct p in make_call ctx e el t ~force_inline p @@ -1864,11 +1854,14 @@ and type_try ctx e1 catches with_type p = let unreachable () = display_error ctx "This block is unreachable" p; let st = s_type (print_context()) in - display_error ctx (Printf.sprintf "%s can be assigned to %s, which is handled here" (st t) (st v.v_type)) e.epos + display_error ctx (Printf.sprintf "%s can be caught to %s, which is handled here" (st t) (st v.v_type)) e.epos in begin try begin match follow t,follow v.v_type with - | TDynamic _, TDynamic _ -> + | _, TDynamic _ + | _, TInst({ cl_path = ["haxe"],"Error"},_) -> + unreachable() + | _, TInst({ cl_path = path },_) when path = ctx.com.config.pf_exceptions.ec_wildcard_catch -> unreachable() | TDynamic _,_ -> () @@ -1891,7 +1884,8 @@ and type_try ctx e1 catches with_type p = | [] , name -> name) in let catches,el = List.fold_left (fun (acc1,acc2) ((v,pv),t,e_ast,pc) -> - let t = Typeload.load_complex_type ctx true t in + let th = Option.default (CTPath { tpackage = ["haxe"]; tname = "Exception"; tsub = None; tparams = [] },null_pos) t in + let t = Typeload.load_complex_type ctx true th in let rec loop t = match follow t with | TInst ({ cl_kind = KTypeParameter _} as c,_) when not (TypeloadCheck.is_generic_parameter ctx c) -> error "Cannot catch non-generic type parameter" p @@ -1959,6 +1953,9 @@ and type_map_declaration ctx e1 el with_type p = let el = e1 :: el in let el_kv = List.map (fun e -> match fst e with | EBinop(OpArrow,e1,e2) -> e1,e2 + | EDisplay _ -> + ignore(type_expr ctx e (WithType.with_type tkey)); + error "Expected a => b" (pos e) | _ -> error "Expected a => b" (pos e) ) el in let el_k,el_v,tkey,tval = if has_type then begin @@ -1990,7 +1987,7 @@ and type_map_declaration ctx e1 el with_type p = let m = TypeloadModule.load_module ctx (["haxe";"ds"],"Map") null_pos in let a,c = match m.m_types with | (TAbstractDecl ({a_impl = Some c} as a)) :: _ -> a,c - | _ -> assert false + | _ -> die "" __LOC__ in let tmap = TAbstract(a,[tkey;tval]) in let cf = PMap.find "set" c.cl_statics in @@ -2035,8 +2032,9 @@ and type_local_function ctx kind f with_type p = | _ -> () ) args args2; (* unify for top-down inference unless we are expecting Void *) - begin match follow tr,follow rt with - | TAbstract({a_path = [],"Void"},_),_ -> () + begin + match follow tr,follow rt with + | TAbstract({a_path = [],"Void"},_),_ when kind <> FKArrow -> () | _,TMono _ -> unify ctx rt tr p | _ -> () end @@ -2075,7 +2073,7 @@ and type_local_function ctx kind f with_type p = match v with | None -> e | Some v -> - Typeload.generate_value_meta ctx.com None (fun m -> v.v_meta <- m :: v.v_meta) f.f_args; + Typeload.generate_args_meta ctx.com None (fun m -> v.v_meta <- m :: v.v_meta) f.f_args; let open LocalUsage in if params <> [] || inline then v.v_extra <- Some (params,if inline then Some e else None); let rec loop = function @@ -2177,6 +2175,7 @@ and type_array_comprehension ctx e with_type p = | EFor(it,e2) -> (EFor (it, map_compr e2),p) | EWhile(cond,e2,flag) -> (EWhile (cond,map_compr e2,flag),p) | EIf (cond,e2,None) -> (EIf (cond,map_compr e2,None),p) + | EIf (cond,e2,Some e3) -> (EIf (cond,map_compr e2,Some (map_compr e3)),p) | EBlock [e] -> (EBlock [map_compr e],p) | EBlock el -> begin match List.rev el with | e :: el -> (EBlock ((List.rev el) @ [map_compr e]),p) @@ -2201,7 +2200,11 @@ and type_array_comprehension ctx e with_type p = ]) v.v_type p and type_return ?(implicit=false) ctx e with_type p = + let is_abstract_ctor = ctx.curfun = FunMemberAbstract && ctx.curfield.cf_name = "_new" in match e with + | None when is_abstract_ctor -> + let e_cast = mk (TCast(get_this ctx p,None)) ctx.ret p in + mk (TReturn (Some e_cast)) t_dynamic p | None -> let v = ctx.t.tvoid in unify ctx v ctx.ret p; @@ -2212,27 +2215,35 @@ and type_return ?(implicit=false) ctx e with_type p = in mk (TReturn None) (if expect_void then v else t_dynamic) p | Some e -> + if is_abstract_ctor then begin + match fst e with + | ECast((EConst(Ident "this"),_),None) -> () + | _ -> display_error ctx "Cannot return a value from constructor" p + end; try let with_expected_type = if implicit then WithType.of_implicit_return ctx.ret else WithType.with_type ctx.ret in let e = type_expr ctx e with_expected_type in - let e = AbstractCast.cast_or_unify ctx ctx.ret e p in - begin match follow e.etype with - | TAbstract({a_path=[],"Void"},_) -> - begin match (Texpr.skip e).eexpr with - | TConst TNull -> error "Cannot return `null` from Void-function" p - | _ -> () - end; - (* if we get a Void expression (e.g. from inlining) we don't want to return it (issue #4323) *) - mk (TBlock [ - e; - mk (TReturn None) t_dynamic p - ]) t_dynamic e.epos; + match follow ctx.ret with + | TAbstract({a_path=[],"Void"},_) when implicit -> + e | _ -> - mk (TReturn (Some e)) t_dynamic p - end + let e = AbstractCast.cast_or_unify ctx ctx.ret e p in + match follow e.etype with + | TAbstract({a_path=[],"Void"},_) -> + begin match (Texpr.skip e).eexpr with + | TConst TNull -> error "Cannot return `null` from Void-function" p + | _ -> () + end; + (* if we get a Void expression (e.g. from inlining) we don't want to return it (issue #4323) *) + mk (TBlock [ + e; + mk (TReturn None) t_dynamic p + ]) t_dynamic e.epos; + | _ -> + mk (TReturn (Some e)) t_dynamic p with Error(err,p) -> check_error ctx err p; (* If we have a bad return, let's generate a return null expression at least. This surpresses various @@ -2255,7 +2266,7 @@ and type_cast ctx e t p = (match c.cl_kind with KTypeParameter _ -> error "Can't cast to a type parameter" p | _ -> ()); TClassDecl c | TEnum (e,_) -> TEnumDecl e - | _ -> assert false); + | _ -> die "" __LOC__); | TAbstract (a,params) when Meta.has Meta.RuntimeValue a.a_meta -> List.iter check_param params; TAbstractDecl a @@ -2474,7 +2485,7 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) = let str = mk (TConst (TString r)) ctx.t.tstring p in let opt = mk (TConst (TString opt)) ctx.t.tstring p in let t = Typeload.load_core_type ctx "EReg" in - mk (TNew ((match t with TInst (c,[]) -> c | _ -> assert false),[],[str;opt])) t p + mk (TNew ((match t with TInst (c,[]) -> c | _ -> die "" __LOC__),[],[str;opt])) t p | EConst (String(s,_)) when s <> "" && Lexer.is_fmt_string p -> type_expr ctx (format_string ctx s p) with_type | EConst c -> @@ -2506,17 +2517,24 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) = | EArrayDecl ((EBinop(OpArrow,_,_),_) as e1 :: el) -> type_map_declaration ctx e1 el with_type p | EArrayDecl el -> - begin match el,with_type with - | [],WithType(t,_) -> - let rec loop t = match follow t with - | TAbstract({a_path = (["haxe";"ds"],"Map")},_) -> - type_expr ctx (ENew(({tpackage=["haxe";"ds"];tname="Map";tparams=[];tsub=None},null_pos),[]),p) with_type - | _ -> - type_array_decl ctx el with_type p - in - loop t + begin match with_type with + | WithType(t,_) -> + begin match follow t with + | TAbstract({a_path = (["haxe";"ds"],"Map")},[tk;tv]) -> + begin match el with + | [] -> + type_expr ctx (ENew(({tpackage=["haxe";"ds"];tname="Map";tparams=[];tsub=None},null_pos),[]),p) with_type + | [(EDisplay _,_) as e1] -> + (* This must mean we're just typing the first key of a map declaration (issue #9133). *) + type_expr ctx e1 (WithType.with_type tk) + | _ -> + type_array_decl ctx el with_type p + end | _ -> type_array_decl ctx el with_type p + end + | _ -> + type_array_decl ctx el with_type p end | EVars vl -> type_vars ctx vl p @@ -2588,7 +2606,7 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) = | EDisplay (e,dk) -> TyperDisplay.handle_edisplay ctx e dk with_type | EDisplayNew t -> - assert false + die "" __LOC__ | ECheckType (e,t) -> let t = Typeload.load_complex_type ctx true t in let e = type_expr ctx e (WithType.with_type t) in @@ -2623,6 +2641,7 @@ let rec create com = do_inherit = MagicTypes.on_inherit; do_create = create; do_macro = MacroContext.type_macro; + do_load_macro = MacroContext.load_macro'; do_load_module = TypeloadModule.load_module; do_load_type_def = Typeload.load_type_def; do_optimize = Optimizer.reduce_expression; @@ -2720,7 +2739,7 @@ let rec create com = raise Exit | _ -> () )) m.m_types; - assert false + die "" __LOC__ with Exit -> ()); let m = TypeloadModule.load_module ctx (["haxe"],"EnumTools") null_pos in (match m.m_types with @@ -2729,8 +2748,9 @@ let rec create com = let m = TypeloadModule.load_module ctx (["haxe"],"EnumWithType.valueTools") null_pos in (match m.m_types with | [TClassDecl c2 ] -> ctx.g.global_using <- (c1,c1.cl_pos) :: (c2,c2.cl_pos) :: ctx.g.global_using - | _ -> assert false); - | _ -> assert false); + | _ -> die "" __LOC__); + | _ -> die "" __LOC__); + ignore(TypeloadModule.load_module ctx (["haxe"],"Exception") null_pos); ctx.g.complete <- true; ctx diff --git a/src/typing/typerBase.ml b/src/typing/typerBase.ml index 9ab8bce2c337600f1dad6f67f46f0a1d0305cd7c..feccd86f20a918cda5d83d62446760f334b01688 100644 --- a/src/typing/typerBase.ml +++ b/src/typing/typerBase.ml @@ -19,8 +19,8 @@ type object_decl_kind = | ODKWithClass of tclass * tparams | ODKPlain -let build_call_ref : (typer -> access_kind -> expr list -> WithType.t -> pos -> texpr) ref = ref (fun _ _ _ _ _ -> assert false) -let type_call_target_ref : (typer -> expr -> WithType.t -> bool -> pos -> access_kind) ref = ref (fun _ _ _ _ _ -> assert false) +let build_call_ref : (typer -> access_kind -> expr list -> WithType.t -> pos -> texpr) ref = ref (fun _ _ _ _ _ -> die "" __LOC__) +let type_call_target_ref : (typer -> expr -> WithType.t -> bool -> pos -> access_kind) ref = ref (fun _ _ _ _ _ -> die "" __LOC__) let relative_path ctx file = let slashes path = String.concat "/" (ExtString.String.nsplit path "\\") in @@ -50,7 +50,7 @@ let mk_infos ctx p params = let rec is_pos_infos = function | TMono r -> - (match !r with + (match r.tm_type with | Some t -> is_pos_infos t | _ -> false) | TLazy f -> @@ -64,6 +64,10 @@ let rec is_pos_infos = function | _ -> false +let is_lower_ident s p = + try Ast.is_lower_ident s + with Invalid_argument msg -> error msg p + let get_this ctx p = match ctx.curfun with | FunStatic -> @@ -84,7 +88,7 @@ let get_this ctx p = in mk (TLocal v) ctx.tthis p | FunMemberAbstract -> - let v = (try PMap.find "this" ctx.locals with Not_found -> assert false) in + let v = (try PMap.find "this" ctx.locals with Not_found -> die "" __LOC__) in mk (TLocal v) v.v_type p | FunConstructor | FunMember -> mk (TConst TThis) ctx.tthis p @@ -107,7 +111,7 @@ let rec type_module_type ctx t tparams p = let mt = try module_type_of_type t with Exit -> - if follow t == t_dynamic then Typeload.load_type_def ctx p { tpackage = []; tname = "Dynamic"; tparams = []; tsub = None } + if follow t == t_dynamic then Typeload.load_type_def ctx p (mk_type_path ([],"Dynamic")) else error "Invalid module type" p in type_module_type ctx mt None p @@ -119,8 +123,7 @@ let rec type_module_type ctx t tparams p = mk (TTypeExpr (TEnumDecl e)) (TType (e.e_type,types)) p | TTypeDecl s -> let t = apply_params s.t_params (List.map (fun _ -> mk_mono()) s.t_params) s.t_type in - if not (Common.defined ctx.com Define.NoDeprecationWarnings) then - DeprecationCheck.check_typedef ctx.com s p; + DeprecationCheck.check_typedef ctx.com s p; (match follow t with | TEnum (e,params) -> type_module_type ctx (TEnumDecl e) (Some params) p @@ -138,7 +141,11 @@ let rec type_module_type ctx t tparams p = mk (TTypeExpr (TAbstractDecl a)) (TType (t_tmp,[])) p let type_type ctx tpath p = - type_module_type ctx (Typeload.load_type_def ctx p { tpackage = fst tpath; tname = snd tpath; tparams = []; tsub = None }) None p + type_module_type ctx (Typeload.load_type_def ctx p (mk_type_path tpath)) None p + +let mk_module_type_access ctx t p : access_mode -> access_kind = + let e = type_module_type ctx t None p in + (fun _ -> AKExpr e) let s_access_kind acc = let st = s_type (print_context()) in diff --git a/src/typing/typerDisplay.ml b/src/typing/typerDisplay.ml index 39674ed3bf718c6af6a316d31285f35ede3e0002..82e9071e21ca32382329a16c0308d6d699bab1d7 100644 --- a/src/typing/typerDisplay.ml +++ b/src/typing/typerDisplay.ml @@ -20,7 +20,7 @@ open Error let convert_function_signature ctx values (args,ret) = match CompletionType.from_type (get_import_status ctx) ~values (TFun(args,ret)) with | CompletionType.CTFunction ctf -> ((args,ret),ctf) - | _ -> assert false + | _ -> die "" __LOC__ let completion_item_of_expr ctx e = let retype e s t = @@ -49,6 +49,7 @@ let completion_item_of_expr ctx e = let rec loop e = match e.eexpr with | TLocal v | TVar(v,_) -> make_ci_local v (tpair ~values:(get_value_meta v.v_meta) v.v_type) | TField(e1,FStatic(c,cf)) -> + let te,c,cf = DisplayToplevel.maybe_resolve_macro_field ctx e.etype c cf in Display.merge_core_doc ctx (TClassDecl c); let decl = decl_of_class c in let origin = match c.cl_kind,e1.eexpr with @@ -60,8 +61,9 @@ let completion_item_of_expr ctx e = | KAbstractImpl a when Meta.has Meta.Enum cf.cf_meta -> make_ci_enum_abstract_field a | _ -> make_ci_class_field in - of_field e origin cf CFSStatic make_ci + of_field {e with etype = te} origin cf CFSStatic make_ci | TField(e1,(FInstance(c,_,cf) | FClosure(Some(c,_),cf))) -> + let te,c,cf = DisplayToplevel.maybe_resolve_macro_field ctx e.etype c cf in Display.merge_core_doc ctx (TClassDecl c); let origin = match follow e1.etype with | TInst(c',_) when c != c' -> @@ -69,7 +71,7 @@ let completion_item_of_expr ctx e = | _ -> Self (TClassDecl c) in - of_field e origin cf CFSMember make_ci_class_field + of_field {e with etype = te} origin cf CFSMember make_ci_class_field | TField(_,FEnum(en,ef)) -> of_enum_field e (Self (TEnumDecl en)) ef | TField(e1,(FAnon cf | FClosure(None,cf))) -> begin match follow e1.etype with @@ -109,7 +111,7 @@ let completion_item_of_expr ctx e = | 'm' -> doc c "multiline matching" | 's' -> doc c "dot also match newlines" | 'u' -> doc c "use UTF-8 matching" - | _ -> assert false + | _ -> die "" __LOC__ in let present = List.map f present in let present = match present with [] -> [] | _ -> "\n\nActive flags:\n\n" :: present in @@ -141,7 +143,7 @@ let get_expected_type ctx with_type = | None -> None | Some t -> let from_type = CompletionType.from_type (get_import_status ctx) in - Some (from_type t,from_type (follow t)) + Some (from_type t,from_type (Type.map follow (follow t))) let raise_toplevel ctx dk with_type (subject,psubject) = let expected_type = get_expected_type ctx with_type in @@ -149,7 +151,7 @@ let raise_toplevel ctx dk with_type (subject,psubject) = let display_dollar_type ctx p make_type = let mono = mk_mono() in - let doc = Some "Outputs type of argument as a warning and uses argument as value" in + let doc = doc_from_string "Outputs type of argument as a warning and uses argument as value" in let arg = ["expression",false,mono] in begin match ctx.com.display.dms_kind with | DMSignature -> @@ -244,10 +246,14 @@ let rec handle_signature_display ctx e_ast with_type = in let tl = match e1.eexpr with | TField(_,fa) -> - begin match extract_field fa with - | Some cf -> (e1.etype,cf.cf_doc,get_value_meta cf.cf_meta) :: List.rev_map (fun cf' -> cf'.cf_type,cf.cf_doc,get_value_meta cf'.cf_meta) cf.cf_overloads - | None -> [e1.etype,None,PMap.empty] - end + let f (t,_,cf) = + (t,cf.cf_doc,get_value_meta cf.cf_meta) :: List.rev_map (fun cf' -> cf'.cf_type,cf.cf_doc,get_value_meta cf'.cf_meta) cf.cf_overloads + in + begin match fa with + | FStatic(c,cf) | FInstance(c,_,cf) -> f (DisplayToplevel.maybe_resolve_macro_field ctx e1.etype c cf) + | FAnon cf | FClosure(_,cf) -> f (e1.etype,null_class,cf) + | _ -> [e1.etype,None,PMap.empty] + end; | TConst TSuper -> find_constructor_types e1.etype | TLocal v -> @@ -263,7 +269,7 @@ let rec handle_signature_display ctx e_ast with_type = begin match follow e1.etype with | TInst({cl_path=([],"Array")},[t]) -> let res = convert_function_signature ctx PMap.empty (["index",false,ctx.t.tint],t) in - raise_signatures [res,Some "The array index"] 0 0 SKCall + raise_signatures [res,doc_from_string "The array index"] 0 0 SKCall | TAbstract(a,tl) -> (match a.a_impl with Some c -> ignore(c.cl_build()) | _ -> ()); let sigs = ExtList.List.filter_map (fun cf -> match follow cf.cf_type with @@ -290,45 +296,47 @@ and display_expr ctx e_ast e dk with_type p = | None -> error "Current class does not have a super" p | Some (c,params) -> let _, f = get_constructor ctx c params p in - f + f,c in match ctx.com.display.dms_kind with | DMResolve _ | DMPackage -> - assert false + die "" __LOC__ | DMSignature -> handle_signature_display ctx e_ast with_type | DMHover -> let item = completion_item_of_expr ctx e in raise_hover item (Some with_type) e.epos - | DMUsage _ -> + | DMUsage _ | DMImplementation -> let rec loop e = match e.eexpr with | TField(_,FEnum(_,ef)) -> - Display.ReferencePosition.set (ef.ef_name,ef.ef_name_pos,KEnumField); - | TField(_,(FAnon cf | FInstance (_,_,cf) | FStatic (_,cf) | FClosure (_,cf))) -> - Display.ReferencePosition.set (cf.cf_name,cf.cf_name_pos,KClassField); + Display.ReferencePosition.set (ef.ef_name,ef.ef_name_pos,SKEnumField ef); + | TField(_,(FAnon cf | FClosure (None,cf))) -> + Display.ReferencePosition.set (cf.cf_name,cf.cf_name_pos,SKField (cf,None)); + | TField(_,(FInstance (c,_,cf) | FStatic (c,cf) | FClosure (Some (c,_),cf))) -> + Display.ReferencePosition.set (cf.cf_name,cf.cf_name_pos,SKField (cf,Some c.cl_path)); | TLocal v | TVar(v,_) -> - Display.ReferencePosition.set (v.v_name,v.v_pos,KVar); + Display.ReferencePosition.set (v.v_name,v.v_pos,SKVariable v); | TTypeExpr mt -> let ti = t_infos mt in - Display.ReferencePosition.set (snd ti.mt_path,ti.mt_name_pos,KModuleType); + Display.ReferencePosition.set (snd ti.mt_path,ti.mt_name_pos,symbol_of_module_type mt); | TNew(c,tl,_) -> begin try let _,cf = get_constructor ctx c tl p in - Display.ReferencePosition.set (snd c.cl_path,cf.cf_name_pos,KConstructor); + Display.ReferencePosition.set (snd c.cl_path,cf.cf_name_pos,SKConstructor cf); with Not_found -> () end | TCall({eexpr = TConst TSuper},_) -> begin try - let cf = get_super_constructor() in - Display.ReferencePosition.set (cf.cf_name,cf.cf_name_pos,KClassField); + let cf,c = get_super_constructor() in + Display.ReferencePosition.set (cf.cf_name,cf.cf_name_pos,SKField (cf,Some c.cl_path)); with Not_found -> () end | TConst TSuper -> begin match ctx.curclass.cl_super with | None -> () - | Some (c,_) -> Display.ReferencePosition.set (snd c.cl_path,c.cl_name_pos,KModuleType); + | Some (c,_) -> Display.ReferencePosition.set (snd c.cl_path,c.cl_name_pos,SKClass c); end | TCall(e1,_) -> loop e1 @@ -374,7 +382,7 @@ and display_expr ctx e_ast e dk with_type p = end | TCall({eexpr = TConst TSuper},_) -> begin try - let cf = get_super_constructor() in + let cf,_ = get_super_constructor() in [cf.cf_name_pos] with Not_found -> [] @@ -495,7 +503,7 @@ let handle_display ?resume_typing ctx e_ast dk with_type = | (EConst (Ident "$type"),p),_ -> display_dollar_type ctx p tpair | (EConst (Ident "trace"),_),_ -> - let doc = Some "Print given arguments" in + let doc = doc_from_string "Print given arguments" in let arg = ["value",false,t_dynamic] in let ret = ctx.com.basic.tvoid in let p = pos e_ast in @@ -519,7 +527,7 @@ let handle_display ?resume_typing ctx e_ast dk with_type = with Error (Unknown_ident n,_) when ctx.com.display.dms_kind = DMDefault -> if dk = DKDot && is_legacy_completion ctx.com then raise (Parser.TypePath ([n],None,false,p)) else raise_toplevel ctx dk with_type (n,p) - | Error ((Type_not_found (path,_) | Module_not_found path),_) as err when ctx.com.display.dms_kind = DMDefault -> + | Error ((Type_not_found (path,_,_) | Module_not_found path),_) as err when ctx.com.display.dms_kind = DMDefault -> if is_legacy_completion ctx.com then begin try raise_fields (DisplayFields.get_submodule_fields ctx path) (CRField((make_ci_module path),p,None,None)) (make_subject None (pos e_ast)) with Not_found -> @@ -541,16 +549,22 @@ let handle_display ?resume_typing ctx e_ast dk with_type = | Yes -> true | YesButPrivate -> if (Meta.has Meta.PrivateAccess ctx.meta) then true - else begin - let path = (mt.pack,mt.name) in - let rec loop c = - if c.cl_path = path then true - else match c.cl_super with - | Some(c,_) -> loop c - | None -> false - in - loop ctx.curclass - end + else + begin + match ctx.curclass.cl_kind with + | KAbstractImpl { a_path = (pack, name) } -> pack = mt.pack && name = mt.name + | _ -> false + end + || begin + let path = (mt.pack,mt.name) in + let rec loop c = + if c.cl_path = path then true + else match c.cl_super with + | Some(c,_) -> loop c + | None -> false + in + loop ctx.curclass + end | No -> false | Maybe -> begin try @@ -573,8 +587,9 @@ let handle_display ?resume_typing ctx e_ast dk with_type = timer(); raise_fields l CRNew r.fsubject in - let e = match e.eexpr with - | TField(e1,FDynamic "bind") when (match follow e1.etype with TFun _ -> true | _ -> false) -> e1 + let e = match e_ast, e.eexpr with + | _, TField(e1,FDynamic "bind") when (match follow e1.etype with TFun _ -> true | _ -> false) -> e1 + | (EField(_,"new"),_), TFunction { tf_expr = { eexpr = TReturn (Some ({ eexpr = TNew _ } as e1))} } -> e1 | _ -> e in let is_display_debug = Meta.has (Meta.Custom ":debug.display") ctx.curfield.cf_meta in @@ -617,7 +632,7 @@ let handle_edisplay ?resume_typing ctx e dk with_type = in handle_structure_display ctx e an.a_fields origin | TInst(c,tl) when Meta.has Meta.StructInit c.cl_meta -> - let fields = PMap.map (fun cf -> {cf with cf_type = apply_params c.cl_params tl cf.cf_type}) c.cl_fields in + let fields = get_struct_init_anon_fields c tl in handle_structure_display ctx e fields (Self (TClassDecl c)) | _ -> handle_display ctx e dk with_type end diff --git a/src/typing/typerDotPath.ml b/src/typing/typerDotPath.ml new file mode 100644 index 0000000000000000000000000000000000000000..0720ac64294fd62add3f8726fb7ab59163057c8f --- /dev/null +++ b/src/typing/typerDotPath.ml @@ -0,0 +1,119 @@ +(* + The Haxe Compiler + Copyright (C) 2005-2020 Haxe Foundation + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*) +open Globals +open Type +open Typecore +open TType +open TyperBase +open Calls +open Fields +open TFunctions +open Error + +type dot_path_part_case = + | PUppercase + | PLowercase + +type dot_path_part = (string * dot_path_part_case * pos) + +let mk_dot_path_part s p : dot_path_part = + let case = if is_lower_ident s p then PLowercase else PUppercase in + (s,case,p) + +let s_dot_path parts = + String.concat "." (List.map (fun (s,_,_) -> s) parts) + +let resolve_module_type ctx m name p = + let t = Typeload.find_type_in_module m name in (* raises Not_found *) + mk_module_type_access ctx t p + +let resolve_in_module ctx m path p = + let mname = snd m.m_path in + match path with + | (sname,PUppercase,sp) :: path_rest -> + begin + try + resolve_module_type ctx m sname sp, path_rest + with Not_found -> + resolve_module_type ctx m mname p, path + end + | _ -> + resolve_module_type ctx m mname p, path + +(** resolve given qualified module pack+name (and possibly next path part) or raise Not_found *) +let resolve_qualified ctx pack name next_path p = + try + let m = Typeload.load_module ctx (pack,name) p in + resolve_in_module ctx m next_path p + with Error (Module_not_found mpath,_) when mpath = (pack,name) -> + (* might be an instance of https://github.com/HaxeFoundation/haxe/issues/9150 + so let's also check (pack,name) of a TYPE in the current module context ¯\_(ツ)_/¯ *) + let t = Typeload.find_type_in_current_module_context ctx pack name in (* raises Not_found *) + mk_module_type_access ctx t p, next_path + +(** resolve the given unqualified name (and possibly next path part) or raise Not_found *) +let resolve_unqualified ctx name next_path p = + try + (* if there's a type with this name in current module context - try resolving against it *) + let t = Typeload.find_type_in_current_module_context ctx [] name in (* raises Not_found *) + + begin + (* + if there's further uppercase field access, it might be a this-package module access rather than static field access, + so we try resolving a field first and fall back to find_in_unqualified_modules + *) + match next_path with + | (field,PUppercase,pfield) :: next_path -> + let e = type_module_type ctx t None p in + let f = type_field (TypeFieldConfig.create true) ctx e field pfield in + ignore(f MCall); (* raises Not_found *) (* not necessarily a call, but prevent #2602 among others *) + f, next_path + | _ -> + mk_module_type_access ctx t p, next_path + end + with Not_found -> + (* otherwise run the unqualified module resolution mechanism and look into the modules *) + let f m ~resume = resolve_in_module ctx m next_path p in + Typeload.find_in_unqualified_modules ctx name p f ~resume:true (* raise Not_found *) + +(** given a list of dot path parts, resolve it into access getter or raise Not_found *) +let resolve_dot_path ctx (path_parts : dot_path_part list) = + let rec loop pack_acc path = + match path with + | (_,PLowercase,_) as x :: path -> + (* part starts with lowercase - it's a package part, add it the accumulator and proceed *) + loop (x :: pack_acc) path + + | (name,PUppercase,p) :: path -> + (* part starts with uppercase - it's a module name - try resolving *) + let accessor, path_rest = + if pack_acc <> [] then + let pack = List.rev_map (fun (x,_,_) -> x) pack_acc in + resolve_qualified ctx pack name path p + else + resolve_unqualified ctx name path p + in + (* if we get here (that is, Not_found is not raised) - we have something to resolve against *) + field_chain ctx path_rest accessor + + | [] -> + (* if we get to here, it means that there was no uppercase part, so it's not a qualified dot-path *) + raise Not_found + in + loop [] path_parts diff --git a/std/Array.hx b/std/Array.hx index 10c0a516cc097ad71ab5de7c209d2945bbe0718a..722c2a1303f8810d747f46111b0e7349181146a7 100644 --- a/std/Array.hx +++ b/std/Array.hx @@ -27,6 +27,9 @@ @see https://haxe.org/manual/std-Array.html @see https://haxe.org/manual/lf-array-comprehension.html **/ + +import haxe.iterators.ArrayKeyValueIterator; + extern class Array { /** The length of `this` Array. @@ -223,6 +226,15 @@ extern class Array { **/ function remove(x:T):Bool; + + /** + Returns whether `this` Array contains `x`. + + If `x` is found by checking standard equality, the function returns `true`, otherwise + the function returns `false`. + **/ + @:pure function contains( x : T ) : Bool; + /** Returns position of the first occurrence of `x` in `this` Array, searching front to back. @@ -265,7 +277,16 @@ extern class Array { /** Returns an iterator of the Array values. **/ - function iterator():Iterator; + @:runtime inline function iterator():haxe.iterators.ArrayIterator { + return new haxe.iterators.ArrayIterator(this); + } + + /** + Returns an iterator of the Array indices and values. + **/ + @:pure @:runtime public inline function keyValueIterator() : ArrayKeyValueIterator { + return new ArrayKeyValueIterator(this); + } /** Creates a new Array by applying function `f` to all elements of `this`. diff --git a/std/DateTools.hx b/std/DateTools.hx index c22afda95d8de4768135d7297edc99971c048bf1..b305659e08c31ef3d79df9611f449f88b96363bf 100644 --- a/std/DateTools.hx +++ b/std/DateTools.hx @@ -54,28 +54,28 @@ class DateTools { case "B": MONTH_NAMES[d.getMonth()]; case "C": - untyped StringTools.lpad(Std.string(Std.int(d.getFullYear() / 100)), "0", 2); + StringTools.lpad(Std.string(Std.int(d.getFullYear() / 100)), "0", 2); case "d": - untyped StringTools.lpad(Std.string(d.getDate()), "0", 2); + StringTools.lpad(Std.string(d.getDate()), "0", 2); case "D": __format(d, "%m/%d/%y"); case "e": - untyped Std.string(d.getDate()); + Std.string(d.getDate()); case "F": __format(d, "%Y-%m-%d"); case "H", "k": - untyped StringTools.lpad(Std.string(d.getHours()), if (e == "H") "0" else " ", 2); + StringTools.lpad(Std.string(d.getHours()), if (e == "H") "0" else " ", 2); case "I", "l": var hour = d.getHours() % 12; - untyped StringTools.lpad(Std.string(hour == 0 ? 12 : hour), if (e == "I") "0" else " ", 2); + StringTools.lpad(Std.string(hour == 0 ? 12 : hour), if (e == "I") "0" else " ", 2); case "m": - untyped StringTools.lpad(Std.string(d.getMonth() + 1), "0", 2); + StringTools.lpad(Std.string(d.getMonth() + 1), "0", 2); case "M": - untyped StringTools.lpad(Std.string(d.getMinutes()), "0", 2); + StringTools.lpad(Std.string(d.getMinutes()), "0", 2); case "n": "\n"; case "p": - untyped if (d.getHours() > 11) "PM"; else "AM"; + if (d.getHours() > 11) "PM"; else "AM"; case "r": __format(d, "%I:%M:%S %p"); case "R": @@ -83,25 +83,20 @@ class DateTools { case "s": Std.string(Std.int(d.getTime() / 1000)); case "S": - untyped StringTools.lpad(Std.string(d.getSeconds()), "0", 2); + StringTools.lpad(Std.string(d.getSeconds()), "0", 2); case "t": "\t"; case "T": __format(d, "%H:%M:%S"); case "u": - untyped { - var t = d.getDay(); - if (t == 0) - "7"; - else - Std.string(t); - } + var t = d.getDay(); + if (t == 0) "7" else Std.string(t); case "w": - untyped Std.string(d.getDay()); + Std.string(d.getDay()); case "y": - untyped StringTools.lpad(Std.string(d.getFullYear() % 100), "0", 2); + StringTools.lpad(Std.string(d.getFullYear() % 100), "0", 2); case "Y": - untyped Std.string(d.getFullYear()); + Std.string(d.getFullYear()); default: throw "Date.format %" + e + "- not implemented yet."; } @@ -194,7 +189,7 @@ class DateTools { /** Converts a number of minutes to a timestamp. **/ - #if as3 extern #end public static inline function minutes(n:Float):Float { + public static inline function minutes(n:Float):Float { return n * 60.0 * 1000.0; } diff --git a/std/Lambda.hx b/std/Lambda.hx index e3f95eb800ca441dadb227cc0401db50dd0e50bf..8b9f16f5231bd3e3c51543482738b5b86df90c06 100644 --- a/std/Lambda.hx +++ b/std/Lambda.hx @@ -186,6 +186,20 @@ class Lambda { return first; } + /** + Similar to fold, but also passes the index of each element to `f`. + + If `it` or `f` are null, the result is unspecified. + **/ + public static function foldi(it:Iterable, f:(item:A, result:B, index:Int) -> B, first:B):B { + var i = 0; + for (x in it) { + first = f(x, first, i); + ++i; + } + return first; + } + /** Returns the number of elements in `it` for which `pred` is true, or the total number of elements in `it` if `pred` is null. @@ -246,6 +260,26 @@ class Lambda { return null; } + /** + Returns the index of the first element of `it` for which `f` is true. + + This function returns as soon as an element is found for which a call to + `f` returns true. + + If no such element is found, the result is -1. + + If `f` is null, the result is unspecified. + **/ + public static function findIndex(it:Iterable, f:(item:T) -> Bool):Int { + var i = 0; + for (v in it) { + if (f(v)) + return i; + i++; + } + return -1; + } + /** Returns a new Array containing all elements of Iterable `a` followed by all elements of Iterable `b`. diff --git a/std/Math.hx b/std/Math.hx index 1fa4503afbdcb318862a4d2f59b0571bce7150ca..4dd349c09a250045f1ea3b6bcb013d77d4c39120 100644 --- a/std/Math.hx +++ b/std/Math.hx @@ -32,14 +32,14 @@ extern class Math { /** Represents the ratio of the circumference of a circle to its diameter, - specified by the constant, π. `PI` is approximately 3.141592653589793. + specified by the constant, π. `PI` is approximately `3.141592653589793`. **/ static var PI(default, null):Float; /** A special `Float` constant which denotes negative infinity. - For example, this is the result of -1.0 / 0.0. + For example, this is the result of `-1.0 / 0.0`. Operations with `NEGATIVE_INFINITY` as an operand may result in `NEGATIVE_INFINITY`, `POSITIVE_INFINITY` or `NaN`. @@ -52,7 +52,7 @@ extern class Math { /** A special `Float` constant which denotes positive infinity. - For example, this is the result of 1.0 / 0.0. + For example, this is the result of `1.0 / 0.0`. Operations with `POSITIVE_INFINITY` as an operand may result in `NEGATIVE_INFINITY`, `POSITIVE_INFINITY` or `NaN`. @@ -65,9 +65,9 @@ extern class Math { /** A special `Float` constant which denotes an invalid number. - NaN stands for "Not a Number". It occurs when a mathematically incorrect + `NaN` stands for "Not a Number". It occurs when a mathematically incorrect operation is executed, such as taking the square root of a negative - number: Math.sqrt(-1). + number: `Math.sqrt(-1)`. All further operations with `NaN` as an operand will result in `NaN`. @@ -81,31 +81,27 @@ extern class Math { /** Returns the absolute value of `v`. - If `v` is positive or 0, the result is unchanged. Otherwise the result - is -`v`. - - If `v` is `NEGATIVE_INFINITY` or `POSITIVE_INFINITY`, the result is - `POSITIVE_INFINITY`. - - If `v` is `NaN`, the result is `NaN`. + - If `v` is positive or `0`, the result is unchanged. Otherwise the result is `-v`. + - If `v` is `NEGATIVE_INFINITY` or `POSITIVE_INFINITY`, the result is `POSITIVE_INFINITY`. + - If `v` is `NaN`, the result is `NaN`. **/ static function abs(v:Float):Float; /** Returns the smaller of values `a` and `b`. - If `a` or `b` are `NaN`, the result is `NaN`. - If `a` or `b` are `NEGATIVE_INFINITY`, the result is `NEGATIVE_INFINITY`. - If `a` and `b` are `POSITIVE_INFINITY`, the result is `POSITIVE_INFINITY`. + - If `a` or `b` are `NaN`, the result is `NaN`. + - If `a` or `b` are `NEGATIVE_INFINITY`, the result is `NEGATIVE_INFINITY`. + - If `a` and `b` are `POSITIVE_INFINITY`, the result is `POSITIVE_INFINITY`. **/ static function min(a:Float, b:Float):Float; /** Returns the greater of values `a` and `b`. - If `a` or `b` are `NaN`, the result is `NaN`. - If `a` or `b` are `POSITIVE_INFINITY`, the result is `POSITIVE_INFINITY`. - If `a` and `b` are `NEGATIVE_INFINITY`, the result is `NEGATIVE_INFINITY`. + - If `a` or `b` are `NaN`, the result is `NaN`. + - If `a` or `b` are `POSITIVE_INFINITY`, the result is `POSITIVE_INFINITY`. + - If `a` and `b` are `NEGATIVE_INFINITY`, the result is `NEGATIVE_INFINITY`. **/ static function max(a:Float, b:Float):Float; @@ -165,11 +161,11 @@ extern class Math { /** Returns Euler's number, raised to the power of `v`. - exp(1.0) is approximately 2.718281828459. + `exp(1.0)` is approximately `2.718281828459`. - If `v` is `POSITIVE_INFINITY`, the result is `POSITIVE_INFINITY`. - If `v` is `NEGATIVE_INFINITY`, the result is `0.0`. - If `v` is `NaN`, the result is `NaN`. + - If `v` is `POSITIVE_INFINITY`, the result is `POSITIVE_INFINITY`. + - If `v` is `NEGATIVE_INFINITY`, the result is `0.0`. + - If `v` is `NaN`, the result is `NaN`. **/ static function exp(v:Float):Float; @@ -179,10 +175,9 @@ extern class Math { This is the mathematical inverse operation of exp, i.e. `log(exp(v)) == v` always holds. - If `v` is negative (including `NEGATIVE_INFINITY`) or `NaN`, the result - is `NaN`. - If `v` is `POSITIVE_INFINITY`, the result is `POSITIVE_INFINITY`. - If `v` is `0.0`, the result is `NEGATIVE_INFINITY`. + - If `v` is negative (including `NEGATIVE_INFINITY`) or `NaN`, the result is `NaN`. + - If `v` is `POSITIVE_INFINITY`, the result is `POSITIVE_INFINITY`. + - If `v` is `0.0`, the result is `NEGATIVE_INFINITY`. **/ static function log(v:Float):Float; @@ -194,10 +189,9 @@ extern class Math { /** Returns the square root of `v`. - If `v` is negative (including `NEGATIVE_INFINITY`) or `NaN`, the result - is `NaN`. - If `v` is `POSITIVE_INFINITY`, the result is `POSITIVE_INFINITY`. - If `v` is `0.0`, the result is `0.0`. + - If `v` is negative (including `NEGATIVE_INFINITY`) or `NaN`, the result is `NaN`. + - If `v` is `POSITIVE_INFINITY`, the result is `POSITIVE_INFINITY`. + - If `v` is `0.0`, the result is `0.0`. **/ static function sqrt(v:Float):Float; @@ -228,12 +222,12 @@ extern class Math { static function ceil(v:Float):Int; /** - Returns a pseudo-random number which is greater than or equal to 0.0, - and less than 1.0. + Returns a pseudo-random number which is greater than or equal to `0.0`, + and less than `1.0`. **/ static function random():Float; - #if ((flash && !as3) || cpp || eval) + #if (flash || cpp || eval) /** Returns the largest integer value that is not greater than `v`, as a `Float`. diff --git a/std/Reflect.hx b/std/Reflect.hx index e91dd8a6a340fc8e3e1e5b341a2d96924eb664d8..009e22384405f7aa2916686b37de39909fc218aa 100644 --- a/std/Reflect.hx +++ b/std/Reflect.hx @@ -35,7 +35,7 @@ extern class Reflect { If `o` or `field` are null, the result is unspecified. **/ - public static function hasField(o:Dynamic, field:String):Bool; + static function hasField(o:Dynamic, field:String):Bool; /** Returns the value of the field named `field` on object `o`. @@ -47,11 +47,8 @@ extern class Reflect { to `Reflect.getProperty` for a function supporting property accessors. If `field` is null, the result is unspecified. - - (As3) If used on a property field, the getter will be invoked. It is - not possible to obtain the value directly. **/ - public static function field(o:Dynamic, field:String):Dynamic; + static function field(o:Dynamic, field:String):Dynamic; /** Sets the field named `field` of object `o` to value `value`. @@ -60,11 +57,8 @@ extern class Reflect { work for anonymous structures. If `o` or `field` are null, the result is unspecified. - - (As3) If used on a property field, the setter will be invoked. It is - not possible to set the value directly. **/ - public static function setField(o:Dynamic, field:String, value:Dynamic):Void; + static function setField(o:Dynamic, field:String, value:Dynamic):Void; /** Returns the value of the field named `field` on object `o`, taking @@ -75,7 +69,7 @@ extern class Reflect { If `o` or `field` are null, the result is unspecified. **/ - public static function getProperty(o:Dynamic, field:String):Dynamic; + static function getProperty(o:Dynamic, field:String):Dynamic; /** Sets the field named `field` of object `o` to value `value`, taking @@ -86,7 +80,7 @@ extern class Reflect { If `field` is null, the result is unspecified. **/ - public static function setProperty(o:Dynamic, field:String, value:Dynamic):Void; + static function setProperty(o:Dynamic, field:String, value:Dynamic):Void; /** Call a method `func` with the given arguments `args`. @@ -101,7 +95,7 @@ extern class Reflect { or by using `(object : Dynamic).field`. However, if `func` has a context, `o` is ignored like on other targets. **/ - public static function callMethod(o:Dynamic, func:haxe.Constraints.Function, args:Array):Dynamic; + static function callMethod(o:Dynamic, func:haxe.Constraints.Function, args:Array):Dynamic; /** Returns the fields of structure `o`. @@ -111,14 +105,14 @@ extern class Reflect { If `o` is null, the result is unspecified. **/ - public static function fields(o:Dynamic):Array; + static function fields(o:Dynamic):Array; /** Returns true if `f` is a function, false otherwise. If `f` is null, the result is false. **/ - public static function isFunction(f:Dynamic):Bool; + static function isFunction(f:Dynamic):Bool; /** Compares `a` and `b`. @@ -141,7 +135,7 @@ extern class Reflect { If `a` and `b` are null, the result is 0. If only one of them is null, the result is unspecified. **/ - public static function compare(a:T, b:T):Int; + static function compare(a:T, b:T):Int; /** Compares the functions `f1` and `f2`. @@ -155,7 +149,7 @@ extern class Reflect { If `f1` or `f2` are member method closures, the result is true if they are closures of the same method on the same object value, false otherwise. **/ - public static function compareMethods(f1:Dynamic, f2:Dynamic):Bool; + static function compareMethods(f1:Dynamic, f2:Dynamic):Bool; /** Tells if `v` is an object. @@ -169,7 +163,7 @@ extern class Reflect { Otherwise, including if `v` is null, the result is false. **/ - public static function isObject(v:Dynamic):Bool; + static function isObject(v:Dynamic):Bool; /** Tells if `v` is an enum value. @@ -179,7 +173,7 @@ extern class Reflect { Otherwise, including if `v` is null, the result is false. **/ - public static function isEnumValue(v:Dynamic):Bool; + static function isEnumValue(v:Dynamic):Bool; /** Removes the field named `field` from structure `o`. @@ -188,7 +182,7 @@ extern class Reflect { If `o` or `field` are null, the result is unspecified. **/ - public static function deleteField(o:Dynamic, field:String):Bool; + static function deleteField(o:Dynamic, field:String):Bool; /** Copies the fields of structure `o`. @@ -197,12 +191,12 @@ extern class Reflect { If `o` is null, the result is `null`. **/ - public static function copy(o:Null):Null; + static function copy(o:Null):Null; /** Transform a function taking an array of arguments into a function that can be called with any number of arguments. **/ @:overload(function(f:Array->Void):Dynamic {}) - public static function makeVarArgs(f:Array->Dynamic):Dynamic; + static function makeVarArgs(f:Array->Dynamic):Dynamic; } diff --git a/std/Std.hx b/std/Std.hx index e919ae3164316dcd5fede0e224af4f988a02d8b2..03fe7a1633244639467740ad1461e258d088fa90 100644 --- a/std/Std.hx +++ b/std/Std.hx @@ -27,12 +27,21 @@ The Std class provides standard methods for manipulating basic types. **/ extern class Std { + /** + DEPRECATED. Use `Std.isOfType(v, t)` instead. + + Tells if a value `v` is of the type `t`. Returns `false` if `v` or `t` are null. + + If `t` is a class or interface with `@:generic` meta, the result is `false`. + **/ + static function is(v:Dynamic, t:Dynamic):Bool; + /** Tells if a value `v` is of the type `t`. Returns `false` if `v` or `t` are null. If `t` is a class or interface with `@:generic` meta, the result is `false`. **/ - public static function is(v:Dynamic, t:Dynamic):Bool; + static function isOfType(v:Dynamic, t:Dynamic):Bool; /** Checks if object `value` is an instance of class or interface `c`. @@ -50,10 +59,10 @@ extern class Std { If `value` is null, the result is null. If `c` is null, the result is unspecified. **/ - public static function downcast(value:T, c:Class):S; + static function downcast(value:T, c:Class):S; @:deprecated('Std.instance() is deprecated. Use Std.downcast() instead.') - public static function instance(value:T, c:Class):S; + static function instance(value:T, c:Class):S; /** Converts any value to a String. @@ -73,14 +82,14 @@ extern class Std { If s is null, "null" is returned. **/ - public static function string(s:Dynamic):String; + static function string(s:Dynamic):String; /** Converts a `Float` to an `Int`, rounded towards 0. If `x` is outside of the signed Int32 range, or is `NaN`, `NEGATIVE_INFINITY` or `POSITIVE_INFINITY`, the result is unspecified. **/ - public static function int(x:Float):Int; + static function int(x:Float):Int; /** Converts a `String` to an `Int`. @@ -103,7 +112,7 @@ extern class Std { If `x` is null, the result is unspecified. If `x` cannot be parsed as integer, the result is `null`. **/ - public static function parseInt(x:String):Null; + static function parseInt(x:String):Null; /** Converts a `String` to a `Float`. @@ -113,12 +122,12 @@ extern class Std { Additionally, decimal notation may contain a single `.` to denote the start of the fractions. **/ - public static function parseFloat(x:String):Float; + static function parseFloat(x:String):Float; /** Return a random integer between 0 included and `x` excluded. If `x <= 1`, the result is always 0. **/ - public static function random(x:Int):Int; + static function random(x:Int):Int; } diff --git a/std/String.hx b/std/String.hx index 5f48050bd5e58941ab101c7b306b7f277c9e1e69..837e39271ce285041143d7d4552f5219257a9bac 100644 --- a/std/String.hx +++ b/std/String.hx @@ -78,11 +78,12 @@ extern class String { String. If `startIndex` is given, the search is performed within the substring - of `this` String starting from `startIndex` (if `startIndex` is posivite - or 0) or `max(this.length + startIndex, 0)` (if `startIndex` is negative). + of `this` String starting from `startIndex`. If `startIndex` exceeds `this.length`, -1 is returned. + If `startIndex` is negative, the result is unspecifed. + Otherwise the search is performed within `this` String. In either case, the returned position is relative to the beginning of `this` String. @@ -99,6 +100,8 @@ extern class String { is performed within `this` String. In either case, the returned position is relative to the beginning of `this` String. + If `startIndex` is negative, the result is unspecifed. + If `str` cannot be found, -1 is returned. **/ function lastIndexOf(str:String, ?startIndex:Int):Int; diff --git a/std/StringBuf.hx b/std/StringBuf.hx index 1f84574b1c49868c014ae6fb64c619c8a85735d5..72a9aefa92a867f33a2f2b44ff22b70f28a4b700 100644 --- a/std/StringBuf.hx +++ b/std/StringBuf.hx @@ -24,12 +24,9 @@ A String buffer is an efficient way to build a big string by appending small elements together. - Its cross-platform implementation uses String concatenation internally, but - StringBuf may be optimized for different targets. - Unlike String, an instance of StringBuf is not immutable in the sense that it can be passed as argument to functions which modify it by appending more - values. However, the internal buffer cannot be modified. + values. **/ class StringBuf { var b:String; diff --git a/std/StringTools.hx b/std/StringTools.hx index c0dade39ba0b03c16c721cc4d32c8d1ca47a5548..26a10457f93b35cd6c9e410a898bdaf002b62210 100644 --- a/std/StringTools.hx +++ b/std/StringTools.hx @@ -157,7 +157,7 @@ class StringTools { **/ public static function htmlEscape(s:String, ?quotes:Bool):String { var buf = new StringBuf(); - for (code in new haxe.iterators.StringIteratorUnicode(s)) { + for (code in #if neko iterator(s) #else new haxe.iterators.StringIteratorUnicode(s) #end) { switch (code) { case '&'.code: buf.add("&"); diff --git a/std/Type.hx b/std/Type.hx index dab42fdda16189631f1bf52e2b96548c3ce3d79e..48e67b064ba69585de839f79df3891d58e8f2fbe 100644 --- a/std/Type.hx +++ b/std/Type.hx @@ -37,7 +37,7 @@ extern class Type { In general, type parameter information cannot be obtained at runtime. **/ - public static function getClass(o:T):Class; + static function getClass(o:T):Class; /** Returns the enum of enum instance `o`. @@ -49,7 +49,7 @@ extern class Type { In general, type parameter information cannot be obtained at runtime. **/ - public static function getEnum(o:EnumValue):Enum; + static function getEnum(o:EnumValue):Enum; /** Returns the super-class of class `c`. @@ -60,7 +60,7 @@ extern class Type { In general, type parameter information cannot be obtained at runtime. **/ - public static function getSuperClass(c:Class):Class; + static function getSuperClass(c:Class):Class; /** Returns the name of class `c`, including its path. @@ -77,7 +77,7 @@ extern class Type { The class name does not include any type parameters. **/ - public static function getClassName(c:Class):String; + static function getClassName(c:Class):String; /** Returns the name of enum `e`, including its path. @@ -94,7 +94,7 @@ extern class Type { The enum name does not include any type parameters. **/ - public static function getEnumName(e:Enum):String; + static function getEnumName(e:Enum):String; /** Resolves a class by name. @@ -108,7 +108,7 @@ extern class Type { The class name must not include any type parameters. **/ - public static function resolveClass(name:String):Class; + static function resolveClass(name:String):Class; /** Resolves an enum by name. @@ -123,7 +123,7 @@ extern class Type { The enum name must not include any type parameters. **/ - public static function resolveEnum(name:String):Enum; + static function resolveEnum(name:String):Enum; /** Creates an instance of class `cl`, using `args` as arguments to the @@ -142,7 +142,7 @@ extern class Type { In particular, default values of constructor arguments are not guaranteed to be taken into account. **/ - public static function createInstance(cl:Class, args:Array):T; + static function createInstance(cl:Class, args:Array):T; /** Creates an instance of class `cl`. @@ -151,7 +151,7 @@ extern class Type { If `cl` is null, the result is unspecified. **/ - public static function createEmptyInstance(cl:Class):T; + static function createEmptyInstance(cl:Class):T; /** Creates an instance of enum `e` by calling its constructor `constr` with @@ -162,7 +162,7 @@ extern class Type { expected number of constructor arguments, or if any argument has an invalid type, the result is unspecified. **/ - public static function createEnum(e:Enum, constr:String, ?params:Array):T; + static function createEnum(e:Enum, constr:String, ?params:Array):T; /** Creates an instance of enum `e` by calling its constructor number @@ -176,7 +176,7 @@ extern class Type { expected number of constructor arguments, or if any argument has an invalid type, the result is unspecified. **/ - public static function createEnumIndex(e:Enum, index:Int, ?params:Array):T; + static function createEnumIndex(e:Enum, index:Int, ?params:Array):T; /** Returns a list of the instance fields of class `c`, including @@ -189,10 +189,8 @@ extern class Type { The order of the fields in the returned Array is unspecified. If `c` is null, the result is unspecified. - - (As3) This method only returns instance fields that are public. **/ - public static function getInstanceFields(c:Class):Array; + static function getInstanceFields(c:Class):Array; /** Returns a list of static fields of class `c`. @@ -202,10 +200,8 @@ extern class Type { The order of the fields in the returned Array is unspecified. If `c` is null, the result is unspecified. - - (As3) This method only returns class fields that are public. **/ - public static function getClassFields(c:Class):Array; + static function getClassFields(c:Class):Array; /** Returns a list of the names of all constructors of enum `e`. @@ -215,7 +211,7 @@ extern class Type { If `e` is null, the result is unspecified. **/ - public static function getEnumConstructs(e:Enum):Array; + static function getEnumConstructs(e:Enum):Array; /** Returns the runtime type of value `v`. @@ -224,7 +220,7 @@ extern class Type { per platform. Assumptions regarding this should be minimized to avoid surprises. **/ - public static function typeof(v:Dynamic):ValueType; + static function typeof(v:Dynamic):ValueType; /** Recursively compares two enum instances `a` and `b` by value. @@ -234,7 +230,7 @@ extern class Type { If `a` or `b` are null, the result is unspecified. **/ - public static function enumEq(a:T, b:T):Bool; + static function enumEq(a:T, b:T):Bool; /** Returns the constructor name of enum instance `e`. @@ -243,7 +239,7 @@ extern class Type { If `e` is null, the result is unspecified. **/ - public static function enumConstructor(e:EnumValue):String; + static function enumConstructor(e:EnumValue):String; /** Returns a list of the constructor arguments of enum instance `e`. @@ -255,7 +251,7 @@ extern class Type { If `e` is null, the result is unspecified. **/ - public static function enumParameters(e:EnumValue):Array; + static function enumParameters(e:EnumValue):Array; /** Returns the index of enum instance `e`. @@ -265,7 +261,7 @@ extern class Type { If `e` is null, the result is unspecified. **/ - public static function enumIndex(e:EnumValue):Int; + static function enumIndex(e:EnumValue):Int; /** Returns a list of all constructors of enum `e` that require no @@ -280,7 +276,7 @@ extern class Type { If `e` is null, the result is unspecified. **/ - public static function allEnums(e:Enum):Array; + static function allEnums(e:Enum):Array; } /** diff --git a/std/UInt.hx b/std/UInt.hx index 44d7f1795a8df66b26403318c09b18f3ae285548..eca400e0a0bf1ae068af6347f3c0f8feb0d82073 100644 --- a/std/UInt.hx +++ b/std/UInt.hx @@ -299,11 +299,7 @@ abstract UInt(Int) from Int to Int { // TODO: radix is just defined to deal with doc_gen issues private inline function toString(?radix:Int):String { - #if static return Std.string(toFloat()); - #else - return Std.string(this == null ? null : toFloat()); - #end } private inline function toInt():Int { diff --git a/std/cpp/ArrayBase.hx b/std/cpp/ArrayBase.hx index a51154e323286382801feb64b7c9adf67e78b4ec..8f6e69cf9c0690b54fa1e050d0bc79ce148120be 100644 --- a/std/cpp/ArrayBase.hx +++ b/std/cpp/ArrayBase.hx @@ -24,8 +24,8 @@ package cpp; extern class ArrayBase { // Length is number of elements - public var length(default, null):Int; - public function getElementSize():Int; - public function getByteCount():Int; - public function getBase():RawPointer; + var length(default, null):Int; + function getElementSize():Int; + function getByteCount():Int; + function getBase():RawPointer; } diff --git a/std/cpp/ConstPointer.hx b/std/cpp/ConstPointer.hx index e4bc099517f6e16212bdaa691498f95ab0927b21..9342f309c7f17b8a607c3e58978cb84d64496cc1 100644 --- a/std/cpp/ConstPointer.hx +++ b/std/cpp/ConstPointer.hx @@ -26,46 +26,46 @@ package cpp; extern class ConstPointer { // ptr actually returns the pointer - not strictly a 'T' - for pointers to smart pointers // Use value or ref to get dereferenced value - public var ptr:Star; + var ptr:Star; - public var value(get, never):T; + var value(get, never):T; // Typecast to non-const - public var raw(get, never):RawPointer; + var raw(get, never):RawPointer; // const version - public var constRaw(get, never):RawConstPointer; + var constRaw(get, never):RawConstPointer; - public function get_value():Reference; + function get_value():Reference; - public function get_constRaw():RawConstPointer; - public function get_raw():RawPointer; + function get_constRaw():RawConstPointer; + function get_raw():RawPointer; - public function lt(inOther:ConstPointer):Bool; - public function leq(inOther:ConstPointer):Bool; - public function gt(inOther:ConstPointer):Bool; - public function geq(inOther:ConstPointer):Bool; + function lt(inOther:ConstPointer):Bool; + function leq(inOther:ConstPointer):Bool; + function gt(inOther:ConstPointer):Bool; + function geq(inOther:ConstPointer):Bool; - public function setRaw(ptr:RawPointer):Void; + function setRaw(ptr:RawPointer):Void; - public static function fromRaw(ptr:RawConstPointer):ConstPointer; + static function fromRaw(ptr:RawConstPointer):ConstPointer; @:native("::cpp::Pointer_obj::fromRaw") - public static function fromStar(star:Star):ConstPointer; + static function fromStar(star:Star):ConstPointer; - public static function fromPointer(inNativePointer:Dynamic):ConstPointer; + static function fromPointer(inNativePointer:Dynamic):ConstPointer; - public function reinterpret():Pointer; + function reinterpret():Pointer; - public function rawCast():RawPointer; + function rawCast():RawPointer; - public function at(inIndex:Int):Reference; + function at(inIndex:Int):Reference; - public function inc():ConstPointer; - public function dec():ConstPointer; - public function incBy(inT:Int):ConstPointer; - public function decBy(inT:Int):ConstPointer; - public function add(inT:Int):ConstPointer; - public function sub(inT:Int):ConstPointer; - public function postIncVal():Reference; + function inc():ConstPointer; + function dec():ConstPointer; + function incBy(inT:Int):ConstPointer; + function decBy(inT:Int):ConstPointer; + function add(inT:Int):ConstPointer; + function sub(inT:Int):ConstPointer; + function postIncVal():Reference; } diff --git a/std/cpp/EnumBase.hx b/std/cpp/EnumBase.hx index 507d12f14b7f47ea1e96380a499eb3b1fa328fba..dfd977aceeb4f90aa1c3066e0fb0e737c02f5253 100644 --- a/std/cpp/EnumBase.hx +++ b/std/cpp/EnumBase.hx @@ -25,36 +25,36 @@ package cpp; @:native("hx.EnumBase") extern class EnumBase { #if (hxcpp_api_level >= 330) - public function _hx_getIndex():Int; - public function _hx_getTag():String; - public function _hx_getParamCount():Int; - public function _hx_getParamI(inIndex:Int):Dynamic; - public function _hx_getParameters():Array; + function _hx_getIndex():Int; + function _hx_getTag():String; + function _hx_getParamCount():Int; + function _hx_getParamI(inIndex:Int):Dynamic; + function _hx_getParameters():Array; - inline public function getIndex():Int + inline function getIndex():Int return _hx_getIndex(); - inline public function getTag():String + inline function getTag():String return _hx_getTag(); - inline public function getParamCount():Int + inline function getParamCount():Int return _hx_getParamCount(); - inline public function getParamI(inIndex:Int):Dynamic + inline function getParamI(inIndex:Int):Dynamic return _hx_getParamI(inIndex); - inline public function getParameters():Array + inline function getParameters():Array return _hx_getParameters(); #else - public function __EnumParams():Array; - public function __Tag():String; - public function __Index():Int; + function __EnumParams():Array; + function __Tag():String; + function __Index():Int; - inline public function _hx_getIndex():Int + inline function _hx_getIndex():Int return untyped __Index(); - inline public function _hx_getTag():String + inline function _hx_getTag():String return untyped __Tag(); - inline public function _hx_getParamCount():Int + inline function _hx_getParamCount():Int return untyped __EnumParams() == null ? 0 : __EnumParams().length; - inline public function _hx_getParamI(inIndex:Int):Dynamic + inline function _hx_getParamI(inIndex:Int):Dynamic return untyped __EnumParams()[inIndex]; - inline public function _hx_getParameters():Array + inline function _hx_getParameters():Array return __EnumParams() == null ? [] : __EnumParams(); #end } diff --git a/std/cpp/ErrorConstants.hx b/std/cpp/ErrorConstants.hx index 837e605ddde8abd96da8c263a3802abd8fd9ffe6..0ea1fbabff7c9f21c043222b2dae366f32cd2ee0 100644 --- a/std/cpp/ErrorConstants.hx +++ b/std/cpp/ErrorConstants.hx @@ -24,17 +24,17 @@ package cpp; extern class ErrorConstants { @:native("HX_INVALID_CAST") - public static var invalidCast:Dynamic; + static var invalidCast:Dynamic; @:native("HX_INDEX_OUT_OF_BOUNDS") - public static var indexOutOfBounds:Dynamic; + static var indexOutOfBounds:Dynamic; @:native("HX_INVALID_OBJECT") - public static var invalidObject:Dynamic; + static var invalidObject:Dynamic; @:native("HX_INVALID_ARG_COUNT") - public static var invalidArgCount:Dynamic; + static var invalidArgCount:Dynamic; @:native("HX_NULL_FUNCTION_POINTER") - public static var nullFunctionPointer:Dynamic; + static var nullFunctionPointer:Dynamic; } diff --git a/std/cpp/FastIterator.hx b/std/cpp/FastIterator.hx index e5955e8d0417d9b374d82f2e391323ab662010b0..1a6b5dd1f307ff366282e876e6866808ee6eb30f 100644 --- a/std/cpp/FastIterator.hx +++ b/std/cpp/FastIterator.hx @@ -23,6 +23,6 @@ package cpp; extern class FastIterator { - public function hasNext():Bool; - public function next():T; + function hasNext():Bool; + function next():T; } diff --git a/std/cpp/Native.hx b/std/cpp/Native.hx index d900b089d9e1b10ca1d6f51a3d013d648ff23bfb..68b6c18cc4c4a29c3d3a72a0e4aca23a61671cc1 100644 --- a/std/cpp/Native.hx +++ b/std/cpp/Native.hx @@ -25,79 +25,79 @@ package cpp; @:include("stdlib.h") extern class Native { @:native("malloc") - public static function nativeMalloc(bytes:Int):cpp.Star; + static function nativeMalloc(bytes:Int):cpp.Star; @:native("calloc") - public static function nativeCalloc(bytes:Int):cpp.Star; + static function nativeCalloc(bytes:Int):cpp.Star; @:native("realloc") - public static function nativeRealloc(inPtr:cpp.Star, bytes:Int):cpp.RawPointer; + static function nativeRealloc(inPtr:cpp.Star, bytes:Int):cpp.RawPointer; @:native("free") - public static function nativeFree(ptr:cpp.Star):Void; + static function nativeFree(ptr:cpp.Star):Void; @:native("memcpy") - public static function nativeMemcpy(dest:cpp.Star, src:cpp.Star, bytes:Int):Void; + static function nativeMemcpy(dest:cpp.Star, src:cpp.Star, bytes:Int):Void; @:native("hx::ClassSizeOf") @:templatedCall - public static function sizeof(t:T):Int; + static function sizeof(t:T):Int; #if !cppia @:native("hx::Dereference") - public static function star(ptr:cpp.Star):cpp.Reference; + static function star(ptr:cpp.Star):cpp.Reference; @:generic - public static inline function set(ptr:cpp.Star, value:T):Void { + static inline function set(ptr:cpp.Star, value:T):Void { var ref:cpp.Reference = star(ptr); ref = value; } @:generic - public static inline function get(ptr:cpp.Star):T { + static inline function get(ptr:cpp.Star):T { var ref:cpp.Reference = star(ptr); return ref; } @:generic - public static inline function memcpy(dest:cpp.Star, src:cpp.Star, bytes:Int):Void + static inline function memcpy(dest:cpp.Star, src:cpp.Star, bytes:Int):Void nativeMemcpy(cast dest, cast src, bytes); @:generic - public static inline function malloc(bytes:Int):cpp.Star + static inline function malloc(bytes:Int):cpp.Star return cast nativeMalloc(bytes); @:generic - public static inline function calloc(bytes:Int):cpp.Star + static inline function calloc(bytes:Int):cpp.Star return cast nativeCalloc(bytes); @:generic - public static inline function realloc(ioPtr:cpp.Star, bytes:Int):cpp.Star + static inline function realloc(ioPtr:cpp.Star, bytes:Int):cpp.Star return cast nativeRealloc(cast ioPtr, bytes); @:generic - public static inline function free(ptr:cpp.Star):Void { + static inline function free(ptr:cpp.Star):Void { if (ptr != null) nativeFree(cast ptr); } @:native("hx::StarOf") - public static function addressOf(inVariable:Reference):Star; + static function addressOf(inVariable:Reference):Star; #else - public static inline function addressOf(inVariable:Reference):Star { + static inline function addressOf(inVariable:Reference):Star { throw "Native.addressOf not available in cppia"; } - public static inline function star(ptr:cpp.Star):cpp.Reference { + static inline function star(ptr:cpp.Star):cpp.Reference { throw "Native.star not available in cppia"; } - public static inline function set(ptr:cpp.Star, value:T):Void { + static inline function set(ptr:cpp.Star, value:T):Void { throw "Native.set not available in cppia"; } - public static inline function get(ptr:cpp.Star):T { + static inline function get(ptr:cpp.Star):T { throw "Native.get not available in cppia"; var d:Dynamic = null; return d; } - public static function memcpy(dest:cpp.Star, src:cpp.Star, bytes:Int):Void; - public static function malloc(bytes:Int):cpp.Star; - public static function calloc(bytes:Int):cpp.Star; - public static function realloc(ioPtr:cpp.Star, bytes:Int):cpp.Star; - public static function free(ptr:cpp.Star):Void; + static function memcpy(dest:cpp.Star, src:cpp.Star, bytes:Int):Void; + static function malloc(bytes:Int):cpp.Star; + static function calloc(bytes:Int):cpp.Star; + static function realloc(ioPtr:cpp.Star, bytes:Int):cpp.Star; + static function free(ptr:cpp.Star):Void; #end } diff --git a/std/cpp/NativeArc.hx b/std/cpp/NativeArc.hx index be889cc2a3c9e02aac295fe81531cf9f86b7887b..d0f98b6e8697da7dafe1c4f5be4a959a604cc197 100644 --- a/std/cpp/NativeArc.hx +++ b/std/cpp/NativeArc.hx @@ -24,8 +24,8 @@ package cpp; extern class NativeArc { @:native("(__bridge_transfer id)") - public static function _bridgeTransfer(ptr:cpp.RawPointer):cpp.RawPointer; + static function _bridgeTransfer(ptr:cpp.RawPointer):cpp.RawPointer; - public static inline function bridgeTransfer(ptr:cpp.RawPointer):T + static inline function bridgeTransfer(ptr:cpp.RawPointer):T return cast _bridgeTransfer(ptr); } diff --git a/std/cpp/NativeArray.hx b/std/cpp/NativeArray.hx index e065edd56ae06fa92d124334642787389bdf6eba..38c5c5bfd51aa44b680a84da7f6b9d40dc67d158 100644 --- a/std/cpp/NativeArray.hx +++ b/std/cpp/NativeArray.hx @@ -24,74 +24,74 @@ package cpp; extern class NativeArray { #if cppia - public static inline function create(length:Int):Array { + static inline function create(length:Int):Array { var result = new Array(); NativeArray.setSize(result, length); return result; } #else @:native("_hx_create_array_length") - public static function create(length:Int):Array; + static function create(length:Int):Array; #end - public static inline function blit(ioDestArray:Array, inDestElement:Int, inSourceArray:Array, inSourceElement:Int, inElementCount:Int):Void { + static inline function blit(ioDestArray:Array, inDestElement:Int, inSourceArray:Array, inSourceElement:Int, inElementCount:Int):Void { untyped ioDestArray.blit(inDestElement, inSourceArray, inSourceElement, inElementCount); }; - public static inline function getBase(inArray:Array):ArrayBase { + static inline function getBase(inArray:Array):ArrayBase { return untyped inArray; } @:nativeStaticExtension - public static function reserve(inArray:Array, inElements:Int):Void; + static function reserve(inArray:Array, inElements:Int):Void; @:nativeStaticExtension - public static function capacity(inArray:Array):Int; + static function capacity(inArray:Array):Int; @:nativeStaticExtension - public static function getElementSize(inArray:Array):Int; + static function getElementSize(inArray:Array):Int; - public static inline function address(inArray:Array, inIndex:Int):Pointer { + static inline function address(inArray:Array, inIndex:Int):Pointer { return Pointer.arrayElem(inArray, inIndex); } @:nativeStaticExtension - public static function setData(inArray:Array, inData:Pointer, inElementCount:Int):Void; + static function setData(inArray:Array, inData:Pointer, inElementCount:Int):Void; @:nativeStaticExtension - public static function setUnmanagedData(inArray:Array, inData:ConstPointer, inElementCount:Int):Void; + static function setUnmanagedData(inArray:Array, inData:ConstPointer, inElementCount:Int):Void; @:nativeStaticExtension - public static function zero(ioDestArray:Array, ?inFirst:Int, ?inElements:Int):Void; + static function zero(ioDestArray:Array, ?inFirst:Int, ?inElements:Int):Void; @:nativeStaticExtension - public static function memcmp(inArrayA:Array, inArrayB:Array):Int; + static function memcmp(inArrayA:Array, inArrayB:Array):Int; @:native("_hx_reslove_virtual_array") - public static function resolveVirtualArray(inArray:Array):Dynamic; + static function resolveVirtualArray(inArray:Array):Dynamic; #if cppia - public static inline function unsafeGet(inDestArray:Array, inIndex:Int):T { + static inline function unsafeGet(inDestArray:Array, inIndex:Int):T { return untyped inDestArray.__unsafe_get(inIndex); } - public static inline function unsafeSet(ioDestArray:Array, inIndex:Int, inValue:T):T { + static inline function unsafeSet(ioDestArray:Array, inIndex:Int, inValue:T):T { return untyped ioDestArray.__unsafe_set(inIndex, inValue); } - public static inline function setSize(ioArray:Array, inSize:Int):Array { + static inline function setSize(ioArray:Array, inSize:Int):Array { return untyped ioArray.__SetSizeExact(inSize); } #else @:native("_hx_array_unsafe_get") - public static function unsafeGet(inDestArray:Array, inIndex:Int):T; + static function unsafeGet(inDestArray:Array, inIndex:Int):T; @:native("_hx_array_unsafe_set") - public static inline function unsafeSet(ioDestArray:Array, inIndex:Int, inValue:T):T { + static inline function unsafeSet(ioDestArray:Array, inIndex:Int, inValue:T):T { return untyped ioDestArray.__unsafe_set(inIndex, inValue); } @:native("_hx_array_set_size_exact") - public static function setSize(ioArray:Array, inSize:Int):Array; + static function setSize(ioArray:Array, inSize:Int):Array; #end } diff --git a/std/cpp/NativeFile.hx b/std/cpp/NativeFile.hx index add849a8337c7bc7686dac41041f382522b7acb0..19b8078164ada645b26c7b2d918d4fed88272d1b 100644 --- a/std/cpp/NativeFile.hx +++ b/std/cpp/NativeFile.hx @@ -25,47 +25,47 @@ package cpp; @:buildXml('') extern class NativeFile { @:native("_hx_std_file_open") - extern public static function file_open(fname:String, r:String):Dynamic; + extern static function file_open(fname:String, r:String):Dynamic; @:native("_hx_std_file_close") - extern public static function file_close(handle:Dynamic):Void; + extern static function file_close(handle:Dynamic):Void; @:native("_hx_std_file_write") - extern public static function file_write(handle:Dynamic, s:haxe.io.BytesData, p:Int, n:Int):Int; + extern static function file_write(handle:Dynamic, s:haxe.io.BytesData, p:Int, n:Int):Int; @:native("_hx_std_file_write_char") - extern public static function file_write_char(handle:Dynamic, c:Int):Void; + extern static function file_write_char(handle:Dynamic, c:Int):Void; @:native("_hx_std_file_read") - extern public static function file_read(handle:Dynamic, s:haxe.io.BytesData, p:Int, n:Int):Int; + extern static function file_read(handle:Dynamic, s:haxe.io.BytesData, p:Int, n:Int):Int; @:native("_hx_std_file_read_char") - extern public static function file_read_char(handle:Dynamic):Int; + extern static function file_read_char(handle:Dynamic):Int; @:native("_hx_std_file_seek") - extern public static function file_seek(handle:Dynamic, pos:Int, kind:Int):Void; + extern static function file_seek(handle:Dynamic, pos:Int, kind:Int):Void; @:native("_hx_std_file_tell") - extern public static function file_tell(handle:Dynamic):Int; + extern static function file_tell(handle:Dynamic):Int; @:native("_hx_std_file_eof") - extern public static function file_eof(handle:Dynamic):Bool; + extern static function file_eof(handle:Dynamic):Bool; @:native("_hx_std_file_flush") - extern public static function file_flush(handle:Dynamic):Void; + extern static function file_flush(handle:Dynamic):Void; @:native("_hx_std_file_contents_string") - extern public static function file_contents_string(name:String):String; + extern static function file_contents_string(name:String):String; @:native("_hx_std_file_contents_bytes") - extern public static function file_contents_bytes(name:String):haxe.io.BytesData; + extern static function file_contents_bytes(name:String):haxe.io.BytesData; @:native("_hx_std_file_stdin") - extern public static function file_stdin():Dynamic; + extern static function file_stdin():Dynamic; @:native("_hx_std_file_stdout") - extern public static function file_stdout():Dynamic; + extern static function file_stdout():Dynamic; @:native("_hx_std_file_stderr") - extern public static function file_stderr():Dynamic; + extern static function file_stderr():Dynamic; } diff --git a/std/cpp/NativeGc.hx b/std/cpp/NativeGc.hx index ed0662e3f9d849791c142005ab1479779d50b92b..a6ad9d333499e8c49050ae6f876a01168caf810c 100644 --- a/std/cpp/NativeGc.hx +++ b/std/cpp/NativeGc.hx @@ -24,42 +24,42 @@ package cpp; extern class NativeGc { @:native("__hxcpp_gc_mem_info") - static public function memInfo(inWhatInfo:Int):Float; + static function memInfo(inWhatInfo:Int):Float; @:native("_hx_allocate_extended") @:templatedCall - static public function allocateExtended(cls:Class, size:Int):T; + static function allocateExtended(cls:Class, size:Int):T; @:native("_hx_add_finalizable") - public static function addFinalizable(instance:{function finalize():Void;}, inPin:Bool):Void; + static function addFinalizable(instance:{function finalize():Void;}, inPin:Bool):Void; @:native("hx::InternalNew") - public static function allocGcBytesRaw(inBytes:Int, isContainer:Bool):RawPointer; + static function allocGcBytesRaw(inBytes:Int, isContainer:Bool):RawPointer; - inline public static function allocGcBytes(inBytes:Int):Pointer { + inline static function allocGcBytes(inBytes:Int):Pointer { return Pointer.fromRaw(allocGcBytesRaw(inBytes, false)); } - @:native("__hxcpp_enable") extern static public function enable(inEnable:Bool):Void; + @:native("__hxcpp_enable") extern static function enable(inEnable:Bool):Void; - @:native("__hxcpp_collect") extern static public function run(major:Bool):Void; + @:native("__hxcpp_collect") extern static function run(major:Bool):Void; - @:native("__hxcpp_gc_compact") extern static public function compact():Void; + @:native("__hxcpp_gc_compact") extern static function compact():Void; - @:native("__hxcpp_gc_trace") extern static public function nativeTrace(sought:Class, printInstances:Bool):Int; + @:native("__hxcpp_gc_trace") extern static function nativeTrace(sought:Class, printInstances:Bool):Int; - @:native("__hxcpp_gc_do_not_kill") extern static public function doNotKill(inObject:Dynamic):Void; + @:native("__hxcpp_gc_do_not_kill") extern static function doNotKill(inObject:Dynamic):Void; - @:native("__hxcpp_get_next_zombie") extern static public function getNextZombie():Dynamic; + @:native("__hxcpp_get_next_zombie") extern static function getNextZombie():Dynamic; - @:native("__hxcpp_gc_safe_point") extern static public function safePoint():Void; + @:native("__hxcpp_gc_safe_point") extern static function safePoint():Void; - @:native("__hxcpp_enter_gc_free_zone") extern static public function enterGCFreeZone():Void; + @:native("__hxcpp_enter_gc_free_zone") extern static function enterGCFreeZone():Void; - @:native("__hxcpp_exit_gc_free_zone") extern static public function exitGCFreeZone():Void; + @:native("__hxcpp_exit_gc_free_zone") extern static function exitGCFreeZone():Void; - @:native("__hxcpp_set_minimum_free_space") extern static public function setMinimumFreeSpace(inBytes:Int):Void; + @:native("__hxcpp_set_minimum_free_space") extern static function setMinimumFreeSpace(inBytes:Int):Void; - @:native("__hxcpp_set_target_free_space_percentage") extern static public function setTargetFreeSpacePercentage(inPercentage:Int):Void; + @:native("__hxcpp_set_target_free_space_percentage") extern static function setTargetFreeSpacePercentage(inPercentage:Int):Void; - @:native("__hxcpp_set_minimum_working_memory") extern static public function setMinimumWorkingMemory(inBytes:Int):Void; + @:native("__hxcpp_set_minimum_working_memory") extern static function setMinimumWorkingMemory(inBytes:Int):Void; } diff --git a/std/cpp/NativeMath.hx b/std/cpp/NativeMath.hx index 75bbcf952838cf2fa13ace1e4a12b2621f28e88e..83dce90cdabfbf4e3f5ac4eb462e90f3fea7ef95 100644 --- a/std/cpp/NativeMath.hx +++ b/std/cpp/NativeMath.hx @@ -26,24 +26,24 @@ package cpp; extern class NativeMath { #if (cpp && !cppia) @:native("_hx_idiv") - public static function idiv(num:Int, denom:Int):Int; + static function idiv(num:Int, denom:Int):Int; @:native("_hx_imod") - public static function imod(num:Int, denom:Int):Int; + static function imod(num:Int, denom:Int):Int; @:native("_hx_cast_int") - public static function castInt(f:Float):Int; + static function castInt(f:Float):Int; @:native("_hx_fast_floor") - public static function fastInt(f:Float):Int; + static function fastInt(f:Float):Int; #else - public static inline function imod(num:Int, denom:Int):Int + static inline function imod(num:Int, denom:Int):Int return num % denom; - public static inline function idiv(num:Int, denom:Int):Int + static inline function idiv(num:Int, denom:Int):Int return Std.int(num / denom); - public static inline function castInt(f:Float):Int + static inline function castInt(f:Float):Int return Std.int(f); - public static inline function fastInt(f:Float):Int + static inline function fastInt(f:Float):Int return Std.int(f); #end } diff --git a/std/cpp/NativeProcess.hx b/std/cpp/NativeProcess.hx index e73ab9d5795cd22c6384edd23b13903336a3b09e..4ad465470d10cf3686b69f8f491c7cdf1cacdd63 100644 --- a/std/cpp/NativeProcess.hx +++ b/std/cpp/NativeProcess.hx @@ -25,32 +25,32 @@ package cpp; @:buildXml('') extern class NativeProcess { @:native("_hx_std_process_run") - public static function process_run(cmd:String, vargs:Array):Dynamic; + static function process_run(cmd:String, vargs:Array):Dynamic; @:native("_hx_std_process_run") - public static function process_run_with_show(cmd:String, vargs:Array, inShow:Int):Dynamic; + static function process_run_with_show(cmd:String, vargs:Array, inShow:Int):Dynamic; @:native("_hx_std_process_stdout_read") - public static function process_stdout_read(handle:Dynamic, buf:haxe.io.BytesData, pos:Int, len:Int):Int; + static function process_stdout_read(handle:Dynamic, buf:haxe.io.BytesData, pos:Int, len:Int):Int; @:native("_hx_std_process_stderr_read") - public static function process_stderr_read(handle:Dynamic, buf:haxe.io.BytesData, pos:Int, len:Int):Int; + static function process_stderr_read(handle:Dynamic, buf:haxe.io.BytesData, pos:Int, len:Int):Int; @:native("_hx_std_process_stdin_write") - public static function process_stdin_write(handle:Dynamic, buf:haxe.io.BytesData, pos:Int, len:Int):Int; + static function process_stdin_write(handle:Dynamic, buf:haxe.io.BytesData, pos:Int, len:Int):Int; @:native("_hx_std_process_stdin_close") - public static function process_stdin_close(handle:Dynamic):Void; + static function process_stdin_close(handle:Dynamic):Void; @:native("_hx_std_process_exit") - public static function process_exit(handle:Dynamic):Int; + static function process_exit(handle:Dynamic):Int; @:native("_hx_std_process_pid") - public static function process_pid(handle:Dynamic):Int; + static function process_pid(handle:Dynamic):Int; @:native("_hx_std_process_kill") - public static function process_kill(handle:Dynamic):Void; + static function process_kill(handle:Dynamic):Void; @:native("_hx_std_process_close") - public static function process_close(handle:Dynamic):Void; + static function process_close(handle:Dynamic):Void; } diff --git a/std/cpp/NativeRandom.hx b/std/cpp/NativeRandom.hx index a8ee8a0293795dadc469ac3b2978046c69e23cf7..f6536248292f009d80c805286b0a82174eac9f2c 100644 --- a/std/cpp/NativeRandom.hx +++ b/std/cpp/NativeRandom.hx @@ -25,14 +25,14 @@ package cpp; @:buildXml('') extern class NativeRandom { @:native("_hx_std_random_new") - public static function random_new():Dynamic; + static function random_new():Dynamic; @:native("_hx_std_random_set_seed") - public static function random_set_seed(handle:Dynamic, v:Int):Void; + static function random_set_seed(handle:Dynamic, v:Int):Void; @:native("_hx_std_random_int") - public static function random_int(handle:Dynamic, max:Int):Int; + static function random_int(handle:Dynamic, max:Int):Int; @:native("_hx_std_random_float") - public static function random_float(handle:Dynamic):Float; + static function random_float(handle:Dynamic):Float; } diff --git a/std/cpp/NativeSocket.hx b/std/cpp/NativeSocket.hx index d81944cc1d5ed8ab3387fd46845b7165ef1c8497..1475b168217d2dee1d9cf2aab640b1e675e735d6 100644 --- a/std/cpp/NativeSocket.hx +++ b/std/cpp/NativeSocket.hx @@ -27,119 +27,119 @@ import sys.net.Socket; @:buildXml('') extern class NativeSocket { @:native("_hx_std_socket_init") - public static function socket_init():Void; + static function socket_init():Void; @:native("_hx_std_socket_new") - public static function socket_new(udp:Bool):Dynamic; + static function socket_new(udp:Bool):Dynamic; @:native("_hx_std_socket_new") - public static function socket_new_ip(udp:Bool, ipv6:Bool):Dynamic; + static function socket_new_ip(udp:Bool, ipv6:Bool):Dynamic; @:native("_hx_std_socket_close") - public static function socket_close(handle:Dynamic):Void; + static function socket_close(handle:Dynamic):Void; @:native("_hx_std_socket_bind") - public static function socket_bind(o:Dynamic, host:Int, port:Int):Void; + static function socket_bind(o:Dynamic, host:Int, port:Int):Void; @:native("_hx_std_socket_bind_ipv6") - public static function socket_bind_ipv6(o:Dynamic, host:haxe.io.BytesData, port:Int):Void; + static function socket_bind_ipv6(o:Dynamic, host:haxe.io.BytesData, port:Int):Void; @:native("_hx_std_socket_send_char") - public static function socket_send_char(o:Dynamic, c:Int):Void; + static function socket_send_char(o:Dynamic, c:Int):Void; @:native("_hx_std_socket_send") - public static function socket_send(o:Dynamic, buf:haxe.io.BytesData, p:Int, l:Int):Int; + static function socket_send(o:Dynamic, buf:haxe.io.BytesData, p:Int, l:Int):Int; @:native("_hx_std_socket_recv") - public static function socket_recv(o:Dynamic, buf:haxe.io.BytesData, p:Int, l:Int):Int; + static function socket_recv(o:Dynamic, buf:haxe.io.BytesData, p:Int, l:Int):Int; @:native("_hx_std_socket_recv_char") - public static function socket_recv_char(o:Dynamic):Int; + static function socket_recv_char(o:Dynamic):Int; @:native("_hx_std_socket_write") - public static function socket_write(o:Dynamic, buf:haxe.io.BytesData):Void; + static function socket_write(o:Dynamic, buf:haxe.io.BytesData):Void; @:native("_hx_std_socket_read") - public static function socket_read(o:Dynamic):haxe.io.BytesData; + static function socket_read(o:Dynamic):haxe.io.BytesData; @:native("_hx_std_host_resolve_ipv6") - public static function host_resolve_ipv6(host:String):haxe.io.BytesData; + static function host_resolve_ipv6(host:String):haxe.io.BytesData; @:native("_hx_std_host_resolve") - public static function host_resolve(host:String):Int; + static function host_resolve(host:String):Int; @:native("_hx_std_host_to_string") - public static function host_to_string(ip:Int):String; + static function host_to_string(ip:Int):String; @:native("_hx_std_host_to_string_ipv6") - public static function host_to_string_ipv6(ipv6:haxe.io.BytesData):String; + static function host_to_string_ipv6(ipv6:haxe.io.BytesData):String; @:native("_hx_std_host_reverse") - public static function host_reverse(host:Int):String; + static function host_reverse(host:Int):String; @:native("_hx_std_host_reverse_ipv6") - public static function host_reverse_ipv6(ipv6:haxe.io.BytesData):String; + static function host_reverse_ipv6(ipv6:haxe.io.BytesData):String; @:native("_hx_std_host_local") - public static function host_local():String; + static function host_local():String; - inline public static function host_local_ipv6():String + inline static function host_local_ipv6():String return "::1"; @:native("_hx_std_socket_connect") - public static function socket_connect(o:Dynamic, host:Int, port:Int):Void; + static function socket_connect(o:Dynamic, host:Int, port:Int):Void; @:native("_hx_std_socket_connect_ipv6") - public static function socket_connect_ipv6(o:Dynamic, host:haxe.io.BytesData, port:Int):Void; + static function socket_connect_ipv6(o:Dynamic, host:haxe.io.BytesData, port:Int):Void; @:native("_hx_std_socket_listen") - public static function socket_listen(o:Dynamic, n:Int):Void; + static function socket_listen(o:Dynamic, n:Int):Void; @:native("_hx_std_socket_select") - public static function socket_select(rs:Array, ws:Array, es:Array, timeout:Dynamic):Array; + static function socket_select(rs:Array, ws:Array, es:Array, timeout:Dynamic):Array; @:native("_hx_std_socket_fast_select") - public static function socket_fast_select(rs:Array, ws:Array, es:Array, timeout:Dynamic):Void; + static function socket_fast_select(rs:Array, ws:Array, es:Array, timeout:Dynamic):Void; @:native("_hx_std_socket_accept") - public static function socket_accept(o:Dynamic):Dynamic; + static function socket_accept(o:Dynamic):Dynamic; @:native("_hx_std_socket_peer") - public static function socket_peer(o:Dynamic):Array; + static function socket_peer(o:Dynamic):Array; @:native("_hx_std_socket_host") - public static function socket_host(o:Dynamic):Array; + static function socket_host(o:Dynamic):Array; @:native("_hx_std_socket_set_timeout") - public static function socket_set_timeout(o:Dynamic, t:Dynamic):Void; + static function socket_set_timeout(o:Dynamic, t:Dynamic):Void; @:native("_hx_std_socket_shutdown") - public static function socket_shutdown(o:Dynamic, r:Bool, w:Bool):Void; + static function socket_shutdown(o:Dynamic, r:Bool, w:Bool):Void; @:native("_hx_std_socket_set_blocking") - public static function socket_set_blocking(o:Dynamic, b:Bool):Void; + static function socket_set_blocking(o:Dynamic, b:Bool):Void; @:native("_hx_std_socket_set_fast_send") - public static function socket_set_fast_send(o:Dynamic, b:Bool):Void; + static function socket_set_fast_send(o:Dynamic, b:Bool):Void; @:native("_hx_std_socket_set_broadcast") - public static function socket_set_broadcast(o:Dynamic, b:Bool):Void; + static function socket_set_broadcast(o:Dynamic, b:Bool):Void; @:native("_hx_std_socket_poll_alloc") - public static function socket_poll_alloc(nsocks:Int):Dynamic; + static function socket_poll_alloc(nsocks:Int):Dynamic; @:native("_hx_std_socket_poll_prepare") - public static function socket_poll_prepare(pdata:Dynamic, rsocks:Array, wsocks:Array):Array>; + static function socket_poll_prepare(pdata:Dynamic, rsocks:Array, wsocks:Array):Array>; @:native("_hx_std_socket_poll_events") - public static function socket_poll_events(pdata:Dynamic, timeout:Float):Void; + static function socket_poll_events(pdata:Dynamic, timeout:Float):Void; @:native("_hx_std_socket_poll") - public static function socket_poll(socks:Array, pdata:Dynamic, timeout:Float):Array; + static function socket_poll(socks:Array, pdata:Dynamic, timeout:Float):Array; @:native("_hx_std_socket_send_to") - public static function socket_send_to(o:Dynamic, buf:haxe.io.BytesData, p:Int, l:Int, inAddr:Dynamic):Int; + static function socket_send_to(o:Dynamic, buf:haxe.io.BytesData, p:Int, l:Int, inAddr:Dynamic):Int; @:native("_hx_std_socket_recv_from") - public static function socket_recv_from(o:Dynamic, buf:haxe.io.BytesData, p:Int, l:Int, outAddr:Dynamic):Int; + static function socket_recv_from(o:Dynamic, buf:haxe.io.BytesData, p:Int, l:Int, outAddr:Dynamic):Int; } diff --git a/std/cpp/NativeSsl.hx b/std/cpp/NativeSsl.hx index 4ec353fbf5b2cc612ad354cb30d158f4df4c6158..587345ed9866e212264995766d5ea66d3bebb6f5 100644 --- a/std/cpp/NativeSsl.hx +++ b/std/cpp/NativeSsl.hx @@ -24,111 +24,114 @@ package cpp; @:buildXml('') extern class NativeSsl { + @:native("_hx_ssl_debug_set") + static function ssl_debug_set(int:Int):Void; + @:native("_hx_ssl_new") - public static function ssl_new(conf:Dynamic):Dynamic; + static function ssl_new(conf:Dynamic):Dynamic; @:native("_hx_ssl_close") - public static function ssl_close(ctx:Dynamic):Void; + static function ssl_close(ctx:Dynamic):Void; @:native("_hx_ssl_handshake") - public static function ssl_handshake(ctx:Dynamic):Void; + static function ssl_handshake(ctx:Dynamic):Void; @:native("_hx_ssl_set_socket") - public static function ssl_set_socket(ctx:Dynamic, socket:Dynamic):Void; + static function ssl_set_socket(ctx:Dynamic, socket:Dynamic):Void; @:native("_hx_ssl_set_hostname") - public static function ssl_set_hostname(ctx:Dynamic, hostname:String):Void; + static function ssl_set_hostname(ctx:Dynamic, hostname:String):Void; @:native("_hx_ssl_get_peer_certificate") - public static function ssl_get_peer_certificate(ctx:Dynamic):Dynamic; + static function ssl_get_peer_certificate(ctx:Dynamic):Dynamic; @:native("_hx_ssl_get_verify_result") - public static function ssl_get_verify_result(ctx:Dynamic):Bool; + static function ssl_get_verify_result(ctx:Dynamic):Bool; @:native("_hx_ssl_send_char") - public static function ssl_send_char(ctx:Dynamic, char:Int):Void; + static function ssl_send_char(ctx:Dynamic, char:Int):Void; @:native("_hx_ssl_send") - public static function ssl_send(ctx:Dynamic, buf:haxe.io.BytesData, p:Int, l:Int):Int; + static function ssl_send(ctx:Dynamic, buf:haxe.io.BytesData, p:Int, l:Int):Int; @:native("_hx_ssl_write") - public static function ssl_write(ctx:Dynamic, data:haxe.io.BytesData):Void; + static function ssl_write(ctx:Dynamic, data:haxe.io.BytesData):Void; @:native("_hx_ssl_recv_char") - public static function ssl_recv_char(ctx:Dynamic):Int; + static function ssl_recv_char(ctx:Dynamic):Int; @:native("_hx_ssl_recv") - public static function ssl_recv(ctx:Dynamic, buf:haxe.io.BytesData, p:Int, l:Int):Int; + static function ssl_recv(ctx:Dynamic, buf:haxe.io.BytesData, p:Int, l:Int):Int; @:native("_hx_ssl_read") - public static function ssl_read(ctx:Dynamic):haxe.io.BytesData; + static function ssl_read(ctx:Dynamic):haxe.io.BytesData; @:native("_hx_ssl_conf_new") - public static function conf_new(server:Bool):Dynamic; + static function conf_new(server:Bool):Dynamic; @:native("_hx_ssl_conf_close") - public static function conf_close(conf:Dynamic):Void; + static function conf_close(conf:Dynamic):Void; @:native("_hx_ssl_conf_set_ca") - public static function conf_set_ca(conf:Dynamic, cert:Dynamic):Void; + static function conf_set_ca(conf:Dynamic, cert:Dynamic):Void; @:native("_hx_ssl_conf_set_verify") - public static function conf_set_verify(conf:Dynamic, mode:Int):Void; + static function conf_set_verify(conf:Dynamic, mode:Int):Void; @:native("_hx_ssl_conf_set_cert") - public static function conf_set_cert(conf:Dynamic, cert:Dynamic, pkey:Dynamic):Void; + static function conf_set_cert(conf:Dynamic, cert:Dynamic, pkey:Dynamic):Void; @:native("_hx_ssl_conf_set_servername_callback") - public static function conf_set_servername_callback(conf:Dynamic, cb:Dynamic):Void; + static function conf_set_servername_callback(conf:Dynamic, cb:Dynamic):Void; @:native("_hx_ssl_cert_load_defaults") - public static function cert_load_defaults():Dynamic; + static function cert_load_defaults():Dynamic; @:native("_hx_ssl_cert_load_file") - public static function cert_load_file(file:String):Dynamic; + static function cert_load_file(file:String):Dynamic; @:native("_hx_ssl_cert_load_path") - public static function cert_load_path(path:String):Dynamic; + static function cert_load_path(path:String):Dynamic; @:native("_hx_ssl_cert_get_subject") - public static function cert_get_subject(cert:Dynamic, field:String):String; + static function cert_get_subject(cert:Dynamic, field:String):String; @:native("_hx_ssl_cert_get_issuer") - public static function cert_get_issuer(cert:Dynamic, field:String):String; + static function cert_get_issuer(cert:Dynamic, field:String):String; @:native("_hx_ssl_cert_get_altnames") - public static function cert_get_altnames(cert:Dynamic):Array; + static function cert_get_altnames(cert:Dynamic):Array; @:native("_hx_ssl_cert_get_notbefore") - public static function cert_get_notbefore(cert:Dynamic):Array; + static function cert_get_notbefore(cert:Dynamic):Array; @:native("_hx_ssl_cert_get_notafter") - public static function cert_get_notafter(cert:Dynamic):Array; + static function cert_get_notafter(cert:Dynamic):Array; @:native("_hx_ssl_cert_get_next") - public static function cert_get_next(cert:Dynamic):Dynamic; + static function cert_get_next(cert:Dynamic):Dynamic; @:native("_hx_ssl_cert_add_pem") - public static function cert_add_pem(cert:Dynamic, data:String):Dynamic; + static function cert_add_pem(cert:Dynamic, data:String):Dynamic; @:native("_hx_ssl_cert_add_der") - public static function cert_add_der(cert:Dynamic, data:haxe.io.BytesData):Dynamic; + static function cert_add_der(cert:Dynamic, data:haxe.io.BytesData):Dynamic; @:native("_hx_ssl_key_from_der") - public static function key_from_der(data:haxe.io.BytesData, pub:Bool):Dynamic; + static function key_from_der(data:haxe.io.BytesData, pub:Bool):Dynamic; @:native("_hx_ssl_key_from_pem") - public static function key_from_pem(data:String, pub:Bool, pass:String):Dynamic; + static function key_from_pem(data:String, pub:Bool, pass:String):Dynamic; @:native("_hx_ssl_dgst_make") - public static function dgst_make(data:haxe.io.BytesData, alg:String):haxe.io.BytesData; + static function dgst_make(data:haxe.io.BytesData, alg:String):haxe.io.BytesData; @:native("_hx_ssl_dgst_sign") - public static function dgst_sign(data:haxe.io.BytesData, key:Dynamic, alg:String):haxe.io.BytesData; + static function dgst_sign(data:haxe.io.BytesData, key:Dynamic, alg:String):haxe.io.BytesData; @:native("_hx_ssl_dgst_verify") - public static function dgst_verify(data:haxe.io.BytesData, sign:haxe.io.BytesData, key:Dynamic, alg:String):Bool; + static function dgst_verify(data:haxe.io.BytesData, sign:haxe.io.BytesData, key:Dynamic, alg:String):Bool; @:native("_hx_ssl_init") - public static function init():Void; + static function init():Void; } diff --git a/std/cpp/NativeString.hx b/std/cpp/NativeString.hx index 6d90fc300d2b7790af9970e92987fd79f7ad51be..7b91e7b6aa98fad3bda4e9a0b7ba5fb92d55361c 100644 --- a/std/cpp/NativeString.hx +++ b/std/cpp/NativeString.hx @@ -23,37 +23,37 @@ package cpp; extern class NativeString { - public static inline function raw(inString:String):RawConstPointer { + static inline function raw(inString:String):RawConstPointer { return untyped inString.raw_ptr(); } - public static inline function c_str(inString:String):ConstPointer { + static inline function c_str(inString:String):ConstPointer { return cpp.ConstPointer.fromPointer(untyped inString.c_str()); } - public static inline function fromPointer(inPtr:ConstPointer):String { + static inline function fromPointer(inPtr:ConstPointer):String { return untyped __global__.String(inPtr.ptr); } - public static inline function fromGcPointer(inPtr:ConstPointer, inLen:Int):String { + static inline function fromGcPointer(inPtr:ConstPointer, inLen:Int):String { return untyped __global__.String(inPtr.ptr, inLen); } @:native("_hx_string_compare") - public static function compare(inString0:String, inString1:String):Int; + static function compare(inString0:String, inString1:String):Int; @:native("_hx_utf8_char_code_at") - public static function utf8CharCodeAt(inString:String, inIndex:Int):Int; + static function utf8CharCodeAt(inString:String, inIndex:Int):Int; @:native("_hx_utf8_length") - public static function utf8Length(inString:String):Int; + static function utf8Length(inString:String):Int; @:native("_hx_utf8_is_valid") - public static function utf8IsValid(inString:String):Bool; + static function utf8IsValid(inString:String):Bool; @:native("_hx_utf8_sub") - public static function utf8Sub(inString:String, charStart:Int, inLen:Int):String; + static function utf8Sub(inString:String, charStart:Int, inLen:Int):String; @:native("_hx_string_create") - public static function fromPointerLen(inPtr:ConstPointer, len:Int):String; + static function fromPointerLen(inPtr:ConstPointer, len:Int):String; @:native("_hx_utf8_decode_advance") - public static function utf8DecodeAdvance(reference:Char):Int; + static function utf8DecodeAdvance(reference:Char):Int; } diff --git a/std/cpp/NativeSys.hx b/std/cpp/NativeSys.hx index d2656a28a4f3676bb9f8bc8b145631c098ce21fd..cd5851ec062b5dc048d6d3fd78be23dfef7a4c42 100644 --- a/std/cpp/NativeSys.hx +++ b/std/cpp/NativeSys.hx @@ -25,83 +25,83 @@ package cpp; @:buildXml('') extern class NativeSys { @:native("__hxcpp_print") - public static function print(v:Dynamic):Void; + static function print(v:Dynamic):Void; @:native("__hxcpp_println") - public static function println(v:Dynamic):Void; + static function println(v:Dynamic):Void; @:native("_hx_std_get_env") - extern public static function get_env(v:String):String; + extern static function get_env(v:String):String; @:native("_hx_std_put_env") - extern public static function put_env(e:String, v:String):Void; + extern static function put_env(e:String, v:String):Void; @:native("_hx_std_sys_sleep") - extern public static function sys_sleep(f:Float):Void; + extern static function sys_sleep(f:Float):Void; @:native("_hx_std_set_time_locale") - extern public static function set_time_locale(l:String):Bool; + extern static function set_time_locale(l:String):Bool; @:native("_hx_std_get_cwd") - extern public static function get_cwd():String; + extern static function get_cwd():String; @:native("_hx_std_set_cwd") - extern public static function set_cwd(d:String):Void; + extern static function set_cwd(d:String):Void; @:native("_hx_std_sys_string") - extern public static function sys_string():String; + extern static function sys_string():String; @:native("_hx_std_sys_is64") - extern public static function sys_is64():Bool; + extern static function sys_is64():Bool; @:native("_hx_std_sys_command") - extern public static function sys_command(cmd:String):Int; + extern static function sys_command(cmd:String):Int; @:native("_hx_std_sys_exit") - extern public static function sys_exit(code:Int):Void; + extern static function sys_exit(code:Int):Void; @:native("_hx_std_sys_exists") - extern public static function sys_exists(path:String):Bool; + extern static function sys_exists(path:String):Bool; @:native("_hx_std_file_delete") - extern public static function file_delete(path:String):Void; + extern static function file_delete(path:String):Void; @:native("_hx_std_sys_rename") - extern public static function sys_rename(path:String, newname:String):Bool; + extern static function sys_rename(path:String, newname:String):Bool; @:native("_hx_std_sys_stat") - extern public static function sys_stat(path:String):Dynamic; + extern static function sys_stat(path:String):Dynamic; @:native("_hx_std_sys_file_type") - extern public static function sys_file_type(path:String):String; + extern static function sys_file_type(path:String):String; @:native("_hx_std_sys_create_dir") - extern public static function sys_create_dir(path:String, mode:Int):Bool; + extern static function sys_create_dir(path:String, mode:Int):Bool; @:native("_hx_std_sys_remove_dir") - extern public static function sys_remove_dir(path:String):Void; + extern static function sys_remove_dir(path:String):Void; @:native("_hx_std_sys_time") - extern public static function sys_time():Float; + extern static function sys_time():Float; @:native("_hx_std_sys_cpu_time") - extern public static function sys_cpu_time():Float; + extern static function sys_cpu_time():Float; @:native("_hx_std_sys_read_dir") - extern public static function sys_read_dir(p:String):Array; + extern static function sys_read_dir(p:String):Array; @:native("_hx_std_file_full_path") - extern public static function file_full_path(path:String):String; + extern static function file_full_path(path:String):String; @:native("_hx_std_sys_exe_path") - extern public static function sys_exe_path():String; + extern static function sys_exe_path():String; @:native("_hx_std_sys_env") - extern public static function sys_env():Array; + extern static function sys_env():Array; @:native("_hx_std_sys_getch") - extern public static function sys_getch(b:Bool):Int; + extern static function sys_getch(b:Bool):Int; @:native("_hx_std_sys_get_pid") - extern public static function sys_get_pid():Int; + extern static function sys_get_pid():Int; } diff --git a/std/cpp/ObjectType.hx b/std/cpp/ObjectType.hx index 8b25ed754d2b6f55eb15b1426d89b9da3d93ff7e..a403984adda3f5051456bdbf3addab034b019f3a 100644 --- a/std/cpp/ObjectType.hx +++ b/std/cpp/ObjectType.hx @@ -23,17 +23,17 @@ package cpp; extern class ObjectType { - public inline static var vtUnknown = -1; - public inline static var vtInt = 0xff; - public inline static var vtNull = 0; - public inline static var vtFloat = 1; - public inline static var vtBool = 2; - public inline static var vtString = 3; - public inline static var vtObject = 4; - public inline static var vtArray = 5; - public inline static var vtFunction = 6; - public inline static var vtEnum = 7; - public inline static var vtClass = 8; - public inline static var vtInt64 = 9; - public inline static var vtAbstractBase = 0x100; + inline static var vtUnknown = -1; + inline static var vtInt = 0xff; + inline static var vtNull = 0; + inline static var vtFloat = 1; + inline static var vtBool = 2; + inline static var vtString = 3; + inline static var vtObject = 4; + inline static var vtArray = 5; + inline static var vtFunction = 6; + inline static var vtEnum = 7; + inline static var vtClass = 8; + inline static var vtInt64 = 9; + inline static var vtAbstractBase = 0x100; } diff --git a/std/cpp/Pointer.hx b/std/cpp/Pointer.hx index 2762155e69c3fce9ecf0314bba66763181e01c55..5b6e370ea963744bf400b786dfb6239b912ee67f 100644 --- a/std/cpp/Pointer.hx +++ b/std/cpp/Pointer.hx @@ -27,29 +27,29 @@ import haxe.extern.AsVar; @:coreType @:semantics(variable) extern class Pointer extends ConstPointer implements ArrayAccess { - public var ref(get, set):Reference; + var ref(get, set):Reference; - public function get_ref():Reference; - public function set_ref(t:T):Reference; + function get_ref():Reference; + function set_ref(t:T):Reference; - public function setAt(inIndex:Int, value:T):Void; + function setAt(inIndex:Int, value:T):Void; - public static function fromRaw(ptr:RawPointer):Pointer; + static function fromRaw(ptr:RawPointer):Pointer; @:native("::cpp::Pointer_obj::fromRaw") - public static function fromStar(star:Star):Pointer; + static function fromStar(star:Star):Pointer; @:native("::cpp::Pointer_obj::fromHandle") static function nativeFromHandle(inHandle:Dynamic, ?inKind:String):AutoCast; - inline public static function fromHandle(inHandle:Dynamic, ?inKind:String):Pointer { + inline static function fromHandle(inHandle:Dynamic, ?inKind:String):Pointer { return cast nativeFromHandle(inHandle, inKind); } - public static function fromPointer(inNativePointer:Dynamic):Pointer; + static function fromPointer(inNativePointer:Dynamic):Pointer; - public static function addressOf(inVariable:cpp.Reference):Pointer; + static function addressOf(inVariable:cpp.Reference):Pointer; - public static function endOf(inVariable:T):Pointer; + static function endOf(inVariable:T):Pointer; @:native("::cpp::Pointer_obj::arrayElem") static function nativeArrayElem(array:Array, inElem:Int):AutoCast; @@ -59,28 +59,28 @@ extern class Pointer extends ConstPointer implements ArrayAccess { @:native("::cpp::Pointer_obj::ofArray") static function nativeOfArray(array:Array):AutoCast; - inline public static function ofArray(array:Array):Pointer { + inline static function ofArray(array:Array):Pointer { return cast nativeOfArray(array); } - inline public function toUnmanagedArray(elementCount:Int):Array { + inline function toUnmanagedArray(elementCount:Int):Array { var result = new Array(); NativeArray.setUnmanagedData(result, this, elementCount); return result; } - inline public function toUnmanagedVector(elementCount:Int):haxe.ds.Vector + inline function toUnmanagedVector(elementCount:Int):haxe.ds.Vector return cast toUnmanagedArray(elementCount); - override public function inc():Pointer; - override public function dec():Pointer; - override public function incBy(inT:Int):Pointer; - override public function decBy(inT:Int):Pointer; - override public function add(inT:Int):Pointer; - override public function sub(inT:Int):Pointer; + override function inc():Pointer; + override function dec():Pointer; + override function incBy(inT:Int):Pointer; + override function decBy(inT:Int):Pointer; + override function add(inT:Int):Pointer; + override function sub(inT:Int):Pointer; - public function postIncRef():Reference; + function postIncRef():Reference; - public function destroy():Void; - public function destroyArray():Void; + function destroy():Void; + function destroyArray():Void; } diff --git a/std/cpp/RawConstPointer.hx b/std/cpp/RawConstPointer.hx index adaf122c7e5274851e9cdedbaa5c40d5428ba27b..5edda998b87e9eace275a2d40ddd77f650d23833 100644 --- a/std/cpp/RawConstPointer.hx +++ b/std/cpp/RawConstPointer.hx @@ -25,5 +25,5 @@ package cpp; @:unreflective extern class RawConstPointer implements ArrayAccess { @:native("hx::AddressOf") - public static function addressOf(t:T):RawConstPointer; + static function addressOf(t:T):RawConstPointer; } diff --git a/std/cpp/RawPointer.hx b/std/cpp/RawPointer.hx index c52bbd57da74739eec79f40d72d022d5ed28e5da..475470cf27f78b680274dd4b7f45268ab8e3ea83 100644 --- a/std/cpp/RawPointer.hx +++ b/std/cpp/RawPointer.hx @@ -25,5 +25,5 @@ package cpp; @:unreflective extern class RawPointer extends RawConstPointer { @:native("hx::AddressOf") - public static function addressOf(t:T):RawPointer; + static function addressOf(t:T):RawPointer; } diff --git a/std/cpp/StdString.hx b/std/cpp/StdString.hx index 41b4e6144f7942b390270c1329f174479b5b35b7..239b44631c2191c3b4297072004da8fbdc83aee2 100644 --- a/std/cpp/StdString.hx +++ b/std/cpp/StdString.hx @@ -31,19 +31,19 @@ using cpp.NativeString; @:unreflective extern class StdString { @:native("std::string::npos") - public static var npos(default, null):Int; + static var npos(default, null):Int; - // public function new(inData:StdStringData); + // function new(inData:StdStringData); @:native("hx::StdString") - static public function ofString(s:String):StdString; + static function ofString(s:String):StdString; - // public function toString():String; - // public function find(s:String):Int; - // public function substr(pos:Int, len:Int):StdString; - public function c_str():ConstPointer; - public function size():Int; - public function find(s:String):Int; - public function substr(pos:Int, len:Int):StdString; - public function toString():String; - public function toStdString():StdString; + // function toString():String; + // function find(s:String):Int; + // function substr(pos:Int, len:Int):StdString; + function c_str():ConstPointer; + function size():Int; + function find(s:String):Int; + function substr(pos:Int, len:Int):StdString; + function toString():String; + function toStdString():StdString; } diff --git a/std/cpp/StdStringRef.hx b/std/cpp/StdStringRef.hx index a55472ad3295851acb787e4235bf0d500f3a5f22..44108bb7ba31fff066a414b608c735386c29928e 100644 --- a/std/cpp/StdStringRef.hx +++ b/std/cpp/StdStringRef.hx @@ -28,10 +28,10 @@ using cpp.NativeString; @:include("hx/StdString.h") @:structAccess extern class StdStringRef { - public function c_str():ConstPointer; - public function size():Int; - public function find(s:String):Int; - public function substr(pos:Int, len:Int):StdString; - public function toString():String; - public function toStdString():StdString; + function c_str():ConstPointer; + function size():Int; + function find(s:String):Int; + function substr(pos:Int, len:Int):StdString; + function toString():String; + function toStdString():StdString; } diff --git a/std/cpp/Stdio.hx b/std/cpp/Stdio.hx index 6c30aeb62eccc217c06d4586f7e396fef744a119..13e77a842911671c586d39470d97b033eb381801 100644 --- a/std/cpp/Stdio.hx +++ b/std/cpp/Stdio.hx @@ -27,17 +27,17 @@ import haxe.extern.Rest; @:include("stdio.h") extern class Stdio { @:native("printf") - public static function printf(format:ConstCharStar, rest:Rest):Void; + static function printf(format:ConstCharStar, rest:Rest):Void; @:native("fopen") - public static function fopen(filename:ConstCharStar, mode:ConstCharStar):FILE; + static function fopen(filename:ConstCharStar, mode:ConstCharStar):FILE; @:native("fwrite") - public static function fwrite(data:RawPointer, elemSize:SizeT, elemCount:SizeT, file:FILE):SizeT; + static function fwrite(data:RawPointer, elemSize:SizeT, elemCount:SizeT, file:FILE):SizeT; @:native("fclose") - public static function fclose(file:FILE):Int; + static function fclose(file:FILE):Int; @:native("fprintf") - public static function fprintf(file:FILE, format:ConstCharStar, rest:Rest):Void; + static function fprintf(file:FILE, format:ConstCharStar, rest:Rest):Void; } diff --git a/std/cpp/Stdlib.hx b/std/cpp/Stdlib.hx index 2b299e58a5c5fcbe07faea0471d6452044bae245..8bd9ab8986d8f42850236f58862976de5c94b689 100644 --- a/std/cpp/Stdlib.hx +++ b/std/cpp/Stdlib.hx @@ -25,32 +25,32 @@ package cpp; @:include("stdlib.h") extern class Stdlib { @:native("malloc") - public static function nativeMalloc(bytes:Int):cpp.RawPointer; + static function nativeMalloc(bytes:Int):cpp.RawPointer; @:native("calloc") - public static function nativeCalloc(bytes:Int):cpp.RawPointer; + static function nativeCalloc(bytes:Int):cpp.RawPointer; @:native("realloc") - public static function nativeRealloc(inPtr:cpp.RawPointer, bytes:Int):cpp.RawPointer; + static function nativeRealloc(inPtr:cpp.RawPointer, bytes:Int):cpp.RawPointer; @:native("free") - public static function nativeFree(ptr:cpp.RawPointer):Void; + static function nativeFree(ptr:cpp.RawPointer):Void; @:native("memcpy") - public static function nativeMemcpy(dest:cpp.RawPointer, src:cpp.RawConstPointer, bytes:Int):Void; + static function nativeMemcpy(dest:cpp.RawPointer, src:cpp.RawConstPointer, bytes:Int):Void; @:native("hx::ClassSizeOf") @:templatedCall - public static function sizeof(t:T):Int; + static function sizeof(t:T):Int; - inline public static function memcpy(dest:cpp.Pointer, src:cpp.ConstPointer, bytes:Int):Void + inline static function memcpy(dest:cpp.Pointer, src:cpp.ConstPointer, bytes:Int):Void nativeMemcpy(cast dest.ptr, cast src.ptr, bytes); - inline public static function malloc(bytes:Int):cpp.Pointer + inline static function malloc(bytes:Int):cpp.Pointer return cast nativeMalloc(bytes); - inline public static function calloc(bytes:Int):cpp.Pointer + inline static function calloc(bytes:Int):cpp.Pointer return cast nativeCalloc(bytes); - inline public static function realloc(ioPtr:cpp.Pointer, bytes:Int):Void + inline static function realloc(ioPtr:cpp.Pointer, bytes:Int):Void ioPtr.setRaw(nativeRealloc(cast ioPtr.ptr, bytes)); - inline public static function free(ptr:cpp.Pointer):Void { + inline static function free(ptr:cpp.Pointer):Void { if (ptr != null) { nativeFree(cast ptr.ptr); ptr.ptr = null; diff --git a/std/cpp/VirtualArray.hx b/std/cpp/VirtualArray.hx index 9af2d7faf57f8cea424d9e049675d373305e745e..3f66162e54a36a805f622783176c486e99d83ba4 100644 --- a/std/cpp/VirtualArray.hx +++ b/std/cpp/VirtualArray.hx @@ -24,29 +24,30 @@ package cpp; @:native("cpp::VirtualArray") @:coreType extern class NativeVirtualArray implements ArrayAccess { - public function new():Void; - public var length(get, null):Int; + function new():Void; + var length(get, null):Int; // concat( a:Array ) : Array ? - public function concat(a:VirtualArray):VirtualArray; - public function join(sep:String):String; - public function pop():Dynamic; - public function push(x:Dynamic):Int; - public function reverse():Void; - public function shift():Dynamic; - public function slice(pos:Int, ?end:Int):VirtualArray; - public function sort(f:Dynamic->Dynamic->Int):Void; - public function splice(pos:Int, len:Int):VirtualArray; - public function toString():String; - public function unshift(x:Dynamic):Void; - public function insert(pos:Int, x:Dynamic):Void; - public function remove(x:Dynamic):Bool; - public function indexOf(x:Dynamic, ?fromIndex:Int):Int; - public function lastIndexOf(x:Dynamic, ?fromIndex:Int):Int; - public function copy():VirtualArray; - public function iterator():Iterator; - public function map(f:Dynamic->S):VirtualArray; - public function filter(f:Dynamic->Bool):VirtualArray; - public function resize(len:Int):Void; + function concat(a:VirtualArray):VirtualArray; + function join(sep:String):String; + function pop():Dynamic; + function push(x:Dynamic):Int; + function reverse():Void; + function shift():Dynamic; + function slice(pos:Int, ?end:Int):VirtualArray; + function sort(f:Dynamic->Dynamic->Int):Void; + function splice(pos:Int, len:Int):VirtualArray; + function toString():String; + function unshift(x:Dynamic):Void; + function insert(pos:Int, x:Dynamic):Void; + function remove(x:Dynamic):Bool; + function indexOf(x:Dynamic, ?fromIndex:Int):Int; + function lastIndexOf(x:Dynamic, ?fromIndex:Int):Int; + function copy():VirtualArray; + function iterator():Iterator; + function keyValueIterator():KeyValueIterator; + function map(f:Dynamic->S):VirtualArray; + function filter(f:Dynamic->Bool):VirtualArray; + function resize(len:Int):Void; } abstract VirtualArray(NativeVirtualArray) { @@ -121,6 +122,9 @@ abstract VirtualArray(NativeVirtualArray) { extern inline public function iterator():Iterator return this.iterator(); + extern inline public function keyValueIterator():KeyValueIterator + return this.keyValueIterator(); + extern inline public function map(f:Dynamic->S):VirtualArray return this.map(f); diff --git a/std/cpp/_std/Std.hx b/std/cpp/_std/Std.hx index 95be55dce55e2a38ba8c7ae758daa646e5b4da2d..a0bdb73d918974eae3b8079fd7ac0f3c317b850c 100644 --- a/std/cpp/_std/Std.hx +++ b/std/cpp/_std/Std.hx @@ -21,12 +21,16 @@ */ @:headerClassCode("\t\tstatic inline String string(String &s) { return s; }") @:coreApi class Std { - @:keep public static function is(v:Dynamic, t:Dynamic):Bool { + @:keep public static inline function is(v:Dynamic, t:Dynamic):Bool { + return isOfType(v, t); + } + + public static function isOfType(v:Dynamic, t:Dynamic):Bool { return untyped __global__.__instanceof(v, t); } @:keep public static function downcast(value:T, c:Class):S { - return Std.is(value, c) ? cast value : null; + return Std.isOfType(value, c) ? cast value : null; } @:deprecated('Std.instance() is deprecated. Use Std.downcast() instead.') diff --git a/std/cpp/_std/haxe/Exception.hx b/std/cpp/_std/haxe/Exception.hx new file mode 100644 index 0000000000000000000000000000000000000000..355d7e527b183768038f0058e9fa90e434e0c36a --- /dev/null +++ b/std/cpp/_std/haxe/Exception.hx @@ -0,0 +1,85 @@ +package haxe; + +//TODO: extend ::std::exception +@:coreApi +class Exception { + public var message(get,never):String; + public var stack(get,never):CallStack; + public var previous(get,never):Null; + public var native(get,never):Any; + + @:noCompletion var __exceptionMessage:String; + @:noCompletion var __exceptionStack:Null; + @:noCompletion var __nativeStack:Array; + @:noCompletion @:ifFeature("haxe.Exception.get_stack") var __skipStack:Int = 0; + @:noCompletion var __nativeException:Any; + @:noCompletion var __previousException:Null; + + static function caught(value:Any):Exception { + if(Std.is(value, Exception)) { + return value; + } else { + return new ValueException(value, null, value); + } + } + + static function thrown(value:Any):Any { + if(Std.isOfType(value, Exception)) { + return (value:Exception).native; + } else { + var e = new ValueException(value); + e.__shiftStack(); + return e; + } + } + + public function new(message:String, ?previous:Exception, ?native:Any) { + __exceptionMessage = message; + __previousException = previous; + if(native != null) { + __nativeStack = NativeStackTrace.exceptionStack(); + __nativeException = native; + } else { + __nativeStack = NativeStackTrace.callStack(); + __nativeException = this; + } + } + + function unwrap():Any { + return __nativeException; + } + + public function toString():String { + return message; + } + + public function details():String { + return inline CallStack.exceptionToString(this); + } + + @:noCompletion + @:ifFeature("haxe.Exception.get_stack") + inline function __shiftStack():Void { + __skipStack++; + } + + function get_message():String { + return __exceptionMessage; + } + + function get_previous():Null { + return __previousException; + } + + final function get_native():Any { + return __nativeException; + } + + function get_stack():CallStack { + return switch __exceptionStack { + case null: __exceptionStack = NativeStackTrace.toHaxe(__nativeStack, __skipStack); + case s: s; + } + } +} + diff --git a/std/cpp/_std/haxe/Int64.hx b/std/cpp/_std/haxe/Int64.hx index 37f3da93081c1d27e21ff5b9330857981a8f7353..1ed9d3d78fabebc07a1d71cdd7caa7708509f756 100644 --- a/std/cpp/_std/haxe/Int64.hx +++ b/std/cpp/_std/haxe/Int64.hx @@ -28,109 +28,109 @@ import haxe.Int64Helper; @:include("cpp/Int64.h") @:native("cpp::Int64Struct") private extern class ___Int64 { - public function get():cpp.Int64; + function get():cpp.Int64; @:native("_hx_int64_make") - public static function make(high:Int32, low:Int32):__Int64; + static function make(high:Int32, low:Int32):__Int64; @:native(" ::cpp::Int64Struct") - public static function ofInt(value:Int):__Int64; + static function ofInt(value:Int):__Int64; @:native(" ::cpp::Int64Struct::is") - public static function is(d:Dynamic):Bool; + static function isInt64(d:Dynamic):Bool; @:native("_hx_int64_is_neg") - public static function isNeg(a:__Int64):Bool; + static function isNeg(a:__Int64):Bool; @:native("_hx_int64_is_zero") - public static function isZero(a:__Int64):Bool; + static function isZero(a:__Int64):Bool; @:native("_hx_int64_compare") - public static function compare(a:__Int64, b:__Int64):Int; + static function compare(a:__Int64, b:__Int64):Int; @:native("_hx_int64_ucompare") - public static function ucompare(a:__Int64, b:__Int64):Int; + static function ucompare(a:__Int64, b:__Int64):Int; @:native("_hx_int64_to_string") - public static function toString(a:__Int64):String; + static function toString(a:__Int64):String; @:native("_hx_int64_neg") - public static function neg(a:__Int64):__Int64; + static function neg(a:__Int64):__Int64; @:native("_hx_int64_pre_increment") - public static function preIncrement(a:__Int64):__Int64; + static function preIncrement(a:__Int64):__Int64; @:native("_hx_int64_post_increment") - public static function postIncrement(a:__Int64):__Int64; + static function postIncrement(a:__Int64):__Int64; @:native("_hx_int64_pre_decrement") - public static function preDecrement(a:__Int64):__Int64; + static function preDecrement(a:__Int64):__Int64; @:native("_hx_int64_post_decrement") - public static function postDecrement(a:__Int64):__Int64; + static function postDecrement(a:__Int64):__Int64; @:native("_hx_int64_add") - public static function add(a:__Int64, b:__Int64):__Int64; + static function add(a:__Int64, b:__Int64):__Int64; @:native("_hx_int64_add") - public static function addInt(a:__Int64, b:Int):__Int64; + static function addInt(a:__Int64, b:Int):__Int64; @:native("_hx_int64_sub") - public static function sub(a:__Int64, b:__Int64):__Int64; + static function sub(a:__Int64, b:__Int64):__Int64; @:native("_hx_int64_sub") - public static function subInt(a:__Int64, b:Int):__Int64; + static function subInt(a:__Int64, b:Int):__Int64; @:native("_hx_int64_sub") - public static function intSub(a:Int, b:__Int64):__Int64; + static function intSub(a:Int, b:__Int64):__Int64; @:native("_hx_int64_mul") - public static function mul(a:__Int64, b:__Int64):__Int64; + static function mul(a:__Int64, b:__Int64):__Int64; @:native("_hx_int64_div") - public static function div(a:__Int64, b:__Int64):__Int64; + static function div(a:__Int64, b:__Int64):__Int64; @:native("_hx_int64_mod") - public static function mod(a:__Int64, b:__Int64):__Int64; + static function mod(a:__Int64, b:__Int64):__Int64; @:native("_hx_int64_eq") - public static function eq(a:__Int64, b:__Int64):Bool; + static function eq(a:__Int64, b:__Int64):Bool; @:native("_hx_int64_eq") - public static function eqInt(a:__Int64, b:Int):Bool; + static function eqInt(a:__Int64, b:Int):Bool; @:native("_hx_int64_neq") - public static function neq(a:__Int64, b:__Int64):Bool; + static function neq(a:__Int64, b:__Int64):Bool; @:native("_hx_int64_neq") - public static function neqInt(a:__Int64, b:Int):Bool; + static function neqInt(a:__Int64, b:Int):Bool; @:native("_hx_int64_complement") - public static function complement(a:__Int64):__Int64; + static function complement(a:__Int64):__Int64; @:native("_hx_int64_and") - public static function bitAnd(a:__Int64, b:__Int64):__Int64; + static function bitAnd(a:__Int64, b:__Int64):__Int64; @:native("_hx_int64_or") - public static function bitOr(a:__Int64, b:__Int64):__Int64; + static function bitOr(a:__Int64, b:__Int64):__Int64; @:native("_hx_int64_xor") - public static function bitXor(a:__Int64, b:__Int64):__Int64; + static function bitXor(a:__Int64, b:__Int64):__Int64; @:native("_hx_int64_shl") - public static function shl(a:__Int64, b:Int):__Int64; + static function shl(a:__Int64, b:Int):__Int64; @:native("_hx_int64_shr") - public static function shr(a:__Int64, b:Int):__Int64; + static function shr(a:__Int64, b:Int):__Int64; @:native("_hx_int64_ushr") - public static function ushr(a:__Int64, b:Int):__Int64; + static function ushr(a:__Int64, b:Int):__Int64; @:native("_hx_int64_high") - public static function high(a:__Int64):Int32; + static function high(a:__Int64):Int32; @:native("_hx_int64_low") - public static function low(a:__Int64):Int32; + static function low(a:__Int64):Int32; } private typedef __Int64 = ___Int64; @@ -156,8 +156,13 @@ abstract Int64(__Int64) from __Int64 to __Int64 { return x.low; } - public static #if !cppia inline #end function is(val:Dynamic):Bool - return __Int64.is(val); + @:deprecated('haxe.Int64.is() is deprecated. Use haxe.Int64.isInt64() instead') + inline public static function is(val:Dynamic):Bool { + return isInt64(val); + } + + public static #if !cppia inline #end function isInt64(val:Dynamic):Bool + return __Int64.isInt64(val); @:deprecated("Use high instead") public static #if !cppia inline #end function getHigh(x:Int64):Int32 diff --git a/std/cpp/_std/haxe/NativeStackTrace.hx b/std/cpp/_std/haxe/NativeStackTrace.hx new file mode 100644 index 0000000000000000000000000000000000000000..1d0760dcc8a6049f3abb8e02dcbba1e18110ce1f --- /dev/null +++ b/std/cpp/_std/haxe/NativeStackTrace.hx @@ -0,0 +1,42 @@ +package haxe; + +import haxe.CallStack.StackItem; + +/** + Do not use manually. +**/ +@:dox(hide) +@:noCompletion +class NativeStackTrace { + @:ifFeature('haxe.NativeStackTrace.exceptionStack') + static public inline function saveStack(exception:Any):Void { + } + + @:noDebug //Do not mess up the exception stack + static public function callStack():Array { + return untyped __global__.__hxcpp_get_call_stack(true); + } + + @:noDebug //Do not mess up the exception stack/ + static public function exceptionStack():Array { + return untyped __global__.__hxcpp_get_exception_stack(); + } + + static public function toHaxe(native:Array, skip:Int = 0):Array { + var stack:Array = native; + var m = new Array(); + for (i in 0...stack.length) { + if(skip > i) { + continue; + } + var words = stack[i].split("::"); + if (words.length == 0) + m.push(CFunction) + else if (words.length == 2) + m.push(Method(words[0], words[1])); + else if (words.length == 4) + m.push(FilePos(Method(words[0], words[1]), words[2], Std.parseInt(words[3]))); + } + return m; + } +} \ No newline at end of file diff --git a/std/cpp/_std/sys/db/Mysql.hx b/std/cpp/_std/sys/db/Mysql.hx index 9ecdbecb90a2c353cc4e76a7b185afc9283b1fe7..86fb0febeb2fbd351c757e18312d657bd49cff19 100644 --- a/std/cpp/_std/sys/db/Mysql.hx +++ b/std/cpp/_std/sys/db/Mysql.hx @@ -158,7 +158,7 @@ private class MysqlConnection implements sys.db.Connection { public function addValue(s:StringBuf, v:Dynamic) { if (v == null) { s.add(v); - } else if (Std.is(v, Bool)) { + } else if (Std.isOfType(v, Bool)) { s.add(v ? 1 : 0); } else { var t:Int = untyped v.__GetType(); diff --git a/std/cpp/_std/sys/db/Sqlite.hx b/std/cpp/_std/sys/db/Sqlite.hx index d8f3b2756806555264e1f0fde36ee6b951029438..abc4fd626cd64206c5e73aa16893867d2d56820c 100644 --- a/std/cpp/_std/sys/db/Sqlite.hx +++ b/std/cpp/_std/sys/db/Sqlite.hx @@ -58,7 +58,7 @@ private class SqliteConnection implements Connection { public function addValue(s:StringBuf, v:Dynamic) { if (v == null) { s.add(v); - } else if (Std.is(v, Bool)) { + } else if (Std.isOfType(v, Bool)) { s.add(v ? 1 : 0); } else { var t:Int = untyped v.__GetType(); diff --git a/std/cpp/cppia/HostClasses.hx b/std/cpp/cppia/HostClasses.hx index f8ebbc25e971dba7fbc36607f61048128c417c43..d395145fa34d6866f2a67c678a823e7b0c307f43 100644 --- a/std/cpp/cppia/HostClasses.hx +++ b/std/cpp/cppia/HostClasses.hx @@ -85,7 +85,7 @@ class HostClasses { "haxe.ds.ObjectMap", "haxe.ds.StringMap", "haxe.ds.BalancedTree", - "haxe.CallStack", + "haxe.NativeStackTrace", "haxe.Serializer", "haxe.Unserializer", "haxe.Resource", @@ -117,7 +117,7 @@ class HostClasses { "haxe.io.StringInput", "haxe.xml.Parser", "haxe.Json", - "haxe.CallStack", + "haxe.NativeStackTrace", "haxe.Resource", "haxe.Utf8", "haxe.Int64", diff --git a/std/cpp/cppia/Module.hx b/std/cpp/cppia/Module.hx index 10e2abf642f4f95e78b4e3f74b83bfa43a192a53..1a98bd9ef635dfd39374ccc4a2e4bec182dc91bc 100644 --- a/std/cpp/cppia/Module.hx +++ b/std/cpp/cppia/Module.hx @@ -26,11 +26,11 @@ package cpp.cppia; @:build(cpp.cppia.HostClasses.include()) extern class Module { @:native("__scriptable_cppia_from_string") - public static function fromString(sourceCode:String):Module; + static function fromString(sourceCode:String):Module; @:native("__scriptable_cppia_from_data") - public static function fromData(data:haxe.io.BytesData):Module; + static function fromData(data:haxe.io.BytesData):Module; - public function boot():Void; - public function run():Void; - public function resolveClass(inName:String):Class; + function boot():Void; + function run():Void; + function resolveClass(inName:String):Class; } diff --git a/std/cpp/net/ThreadServer.hx b/std/cpp/net/ThreadServer.hx index cecdb5f3aa66a38eede6e8d696ac4714782ab833..a3f7a7455bce7b951023ec9399cadd22c48245be 100644 --- a/std/cpp/net/ThreadServer.hx +++ b/std/cpp/net/ThreadServer.hx @@ -160,7 +160,7 @@ class ThreadServer { readClientData(infos); } catch (e:Dynamic) { t.socks.remove(s); - if (!Std.is(e, haxe.io.Eof) && !Std.is(e, haxe.io.Error)) + if (!Std.isOfType(e, haxe.io.Eof) && !Std.isOfType(e, haxe.io.Error)) logError(e); work(doClientDisconnected.bind(s, infos.client)); } diff --git a/std/cpp/objc/NSError.hx b/std/cpp/objc/NSError.hx index 0cea993a36858090dad1ee88dfda7c84a8ba92ea..06c8b7d8a3000b95d9cce61549cd10535e39dce0 100644 --- a/std/cpp/objc/NSError.hx +++ b/std/cpp/objc/NSError.hx @@ -25,5 +25,5 @@ package cpp.objc; @:objc @:native("NSError") extern class NSError { - public var localizedDescription(default, null):NSString; + var localizedDescription(default, null):NSString; } diff --git a/std/cpp/objc/NSLog.hx b/std/cpp/objc/NSLog.hx index 19b792dfa3e0c4a856a5f1662f39327e9080e7e6..cba71e88397dd30b0358cca2392e148fd48ec201 100644 --- a/std/cpp/objc/NSLog.hx +++ b/std/cpp/objc/NSLog.hx @@ -26,5 +26,5 @@ extern class NSLog { @:native("NSLog") @:overload(function(format:NSString, a0:NSObject):Void {}) @:overload(function(format:NSString, a0:NSObject, a1:NSObject):Void {}) - public static function log(format:NSString):Void; + static function log(format:NSString):Void; } diff --git a/std/cs/Boot.hx b/std/cs/Boot.hx index 921fe4939af012593d827696c6646691a17ad5fd..2b3639e623fa844d742f0292afdbce5c278a7a19 100644 --- a/std/cs/Boot.hx +++ b/std/cs/Boot.hx @@ -22,7 +22,6 @@ package cs; -import cs.internal.Exceptions; import cs.internal.FieldLookup; import cs.internal.Function; import cs.internal.HxObject; diff --git a/std/cs/NativeArray.hx b/std/cs/NativeArray.hx index 7f92f1ad70b64832b5dac7ab94b004e176fdf4da..bfa756bc9e5557b106e8cddf9c8a8fa19901eab2 100644 --- a/std/cs/NativeArray.hx +++ b/std/cs/NativeArray.hx @@ -36,17 +36,17 @@ extern class NativeArray extends cs.system.Array implements ArrayAccess { var elements = NativeArray.make(1,2,3,4,5,6); ``` **/ - public static function make(elements:Rest):NativeArray; + static function make(elements:Rest):NativeArray; /** Allocates a new array with size `len` **/ - public function new(len:Int):Void; + function new(len:Int):Void; /** Alias to array's `Length` property. Returns the size of the array **/ - public var length(get, never):Int; + var length(get, never):Int; extern inline private function get_length():Int return this.Length; @@ -56,7 +56,7 @@ extern class NativeArray extends cs.system.Array implements ArrayAccess { /** Returns an iterator so it's possible to use `for` with C#'s `NativeArray` **/ - extern inline public function iterator():NativeArrayIterator + extern inline function iterator():NativeArrayIterator return new NativeArrayIterator(this); } diff --git a/std/cs/_std/Array.hx b/std/cs/_std/Array.hx index 929b65373c66f45a6f9ee6774d7828ff94912915..e17ab87fe94d9db9f82515b073a9677d23662c74 100644 --- a/std/cs/_std/Array.hx +++ b/std/cs/_std/Array.hx @@ -21,6 +21,7 @@ */ import cs.NativeArray; +import haxe.iterators.ArrayKeyValueIterator; #if core_api_serialize @:meta(System.Serializable) @@ -397,6 +398,17 @@ final class Array implements ArrayAccess { return ret; } + public function contains(x:T):Bool { + var __a = __a; + var i = -1; + var length = length; + while (++i < length) { + if (__a[i] == x) + return true; + } + return false; + } + public inline function filter(f:T->Bool):Array { var ret = []; for (i in 0...length) { @@ -415,8 +427,13 @@ final class Array implements ArrayAccess { return ofNative(newarr); } - public inline function iterator():Iterator { - return new ArrayIterator(this); + public inline function iterator():haxe.iterators.ArrayIterator { + return new haxe.iterators.ArrayIterator(this); + } + + public inline function keyValueIterator() : ArrayKeyValueIterator + { + return new ArrayKeyValueIterator(this); } public function resize(len:Int):Void { @@ -460,21 +477,3 @@ final class Array implements ArrayAccess { return __a[idx] = val; } } - -private final class ArrayIterator { - var arr:Array; - var len:Int; - var i:Int; - - public inline function new(a:Array) { - arr = a; - len = a.length; - i = 0; - } - - public inline function hasNext():Bool - return i < len; - - public inline function next():T - return arr[i++]; -} diff --git a/std/cs/_std/Reflect.hx b/std/cs/_std/Reflect.hx index c02c7e46646d44c7a07a6afece5a003806962669..4f8f03f1de33ba7a3ccc7413ffdbfa405dd7d376 100644 --- a/std/cs/_std/Reflect.hx +++ b/std/cs/_std/Reflect.hx @@ -90,7 +90,7 @@ import cs.system.reflection.*; var ret = []; untyped ihx.__hx_getFields(ret); return ret; - } else if (Std.is(o, cs.system.Type)) { + } else if (Std.isOfType(o, cs.system.Type)) { return Type.getClassFields(o); } else { return instanceFields(untyped o.GetType()); @@ -109,7 +109,7 @@ import cs.system.reflection.*; } inline public static function isFunction(f:Dynamic):Bool { - return Std.is(f, Function); + return Std.isOfType(f, Function); } public static function compare(a:T, b:T):Int { @@ -121,7 +121,7 @@ import cs.system.reflection.*; if (f1 == f2) return true; - if (Std.is(f1, Closure) && Std.is(f2, Closure)) { + if (Std.isOfType(f1, Closure) && Std.isOfType(f2, Closure)) { var f1c:Closure = cast f1; var f2c:Closure = cast f2; @@ -132,11 +132,11 @@ import cs.system.reflection.*; } public static function isObject(v:Dynamic):Bool { - return v != null && !(Std.is(v, HxEnum) || Std.is(v, Function) || Std.is(v, cs.system.ValueType)); + return v != null && !(Std.isOfType(v, HxEnum) || Std.isOfType(v, Function) || Std.isOfType(v, cs.system.ValueType)); } public static function isEnumValue(v:Dynamic):Bool { - return v != null && (Std.is(v, HxEnum) || Std.is(v, cs.system.Enum)); + return v != null && (Std.isOfType(v, HxEnum) || Std.isOfType(v, cs.system.Enum)); } public static function deleteField(o:Dynamic, field:String):Bool { diff --git a/std/cs/_std/Std.hx b/std/cs/_std/Std.hx index fb2134ef7183196806b218b76625159ade2b2326..540d5578ca9f849fc285a586863643da2fdc7d54 100644 --- a/std/cs/_std/Std.hx +++ b/std/cs/_std/Std.hx @@ -22,10 +22,13 @@ import cs.Boot; import cs.Lib; -import cs.internal.Exceptions; @:coreApi @:nativeGen class Std { - public static function is(v:Dynamic, t:Dynamic):Bool { + public static inline function is(v:Dynamic, t:Dynamic):Bool { + return isOfType(v, t); + } + + public static function isOfType(v:Dynamic, t:Dynamic):Bool { if (v == null) return false; if (t == null) @@ -65,7 +68,7 @@ import cs.internal.Exceptions; public static function string(s:Dynamic):String { if (s == null) return "null"; - if (Std.is(s, Bool)) + if (Std.isOfType(s, Bool)) return cast(s, Bool) ? "true" : "false"; return s.ToString(); diff --git a/std/cs/_std/Type.hx b/std/cs/_std/Type.hx index e47dea4110a92744522cf0fe894c5ca132cf339d..a55387da4a25b37f9290f2559ccffa66d658b589 100644 --- a/std/cs/_std/Type.hx +++ b/std/cs/_std/Type.hx @@ -44,16 +44,16 @@ enum ValueType { @:coreApi class Type { public static function getClass(o:T):Class { - if (Object.ReferenceEquals(o, null) || Std.is(o, DynamicObject) || Std.is(o, cs.system.Type)) + if (Object.ReferenceEquals(o, null) || Std.isOfType(o, DynamicObject) || Std.isOfType(o, cs.system.Type)) return null; return cast cs.Lib.getNativeType(o); } public static function getEnum(o:EnumValue):Enum { - if (Std.is(o, HxEnum)) + if (Std.isOfType(o, HxEnum)) return cast cs.Lib.getNativeType(o).BaseType; // enum constructors are subclasses of an enum type - else if (Std.is(o, cs.system.Enum)) + else if (Std.isOfType(o, cs.system.Enum)) return cast cs.Lib.getNativeType(o); return null; } @@ -211,7 +211,7 @@ enum ValueType { var mis = c.GetMembers(new cs.Flags(BindingFlags.Public) | BindingFlags.Instance | BindingFlags.FlattenHierarchy); for (i in 0...mis.Length) { var i = mis[i]; - if (Std.is(i, PropertyInfo)) + if (Std.isOfType(i, PropertyInfo)) continue; var n = i.Name; if (!n.startsWith('__hx_') && n.fastCodeAt(0) != '.'.code) { @@ -266,7 +266,7 @@ enum ValueType { t = v.GetType(); if (t.IsEnum) return ValueType.TEnum(cast t); - if (Std.is(v, HxEnum)) + if (Std.isOfType(v, HxEnum)) return ValueType.TEnum(cast t.BaseType); // enum constructors are subclasses of an enum type if (t.IsValueType) { var vc = Std.downcast(v, cs.system.IConvertible); @@ -290,11 +290,11 @@ enum ValueType { } } - if (Std.is(v, IHxObject)) { - if (Std.is(v, DynamicObject)) + if (Std.isOfType(v, IHxObject)) { + if (Std.isOfType(v, DynamicObject)) return ValueType.TObject; return ValueType.TClass(cast t); - } else if (Std.is(v, Function)) { + } else if (Std.isOfType(v, Function)) { return ValueType.TFunction; } else { return ValueType.TClass(cast t); @@ -312,17 +312,17 @@ enum ValueType { } public static function enumConstructor(e:EnumValue):String { - return Std.is(e, cs.system.Enum) ? cast(e, cs.system.Enum).ToString() : cast(e, HxEnum).getTag(); + return Std.isOfType(e, cs.system.Enum) ? cast(e, cs.system.Enum).ToString() : cast(e, HxEnum).getTag(); } public static function enumParameters(e:EnumValue):Array { - return Std.is(e, cs.system.Enum) ? [] : cast(e, HxEnum).getParams(); + return Std.isOfType(e, cs.system.Enum) ? [] : cast(e, HxEnum).getParams(); } @:ifFeature("has_enum") @:pure public static function enumIndex(e:EnumValue):Int { - if (Std.is(e, cs.system.Enum)) { + if (Std.isOfType(e, cs.system.Enum)) { var values = cs.system.Enum.GetValues(Lib.getNativeType(e)); return cs.system.Array.IndexOf(values, e); } else { @@ -335,7 +335,7 @@ enum ValueType { var ret = []; for (ctor in ctors) { var v = Reflect.field(e, ctor); - if (Std.is(v, e)) + if (Std.isOfType(v, e)) ret.push(v); } diff --git a/std/cs/_std/haxe/Exception.hx b/std/cs/_std/haxe/Exception.hx new file mode 100644 index 0000000000000000000000000000000000000000..f801f5c450eda19503316ed3c68db65ee8098303 --- /dev/null +++ b/std/cs/_std/haxe/Exception.hx @@ -0,0 +1,118 @@ +package haxe; + +import cs.system.Exception as CsException; +import cs.system.diagnostics.StackTrace; + +@:coreApi +class Exception extends NativeException { + public var message(get,never):String; + public var stack(get,never):CallStack; + public var previous(get,never):Null; + public var native(get,never):Any; + + @:noCompletion var __exceptionStack:Null; + @:noCompletion var __nativeStack:StackTrace; + @:noCompletion var __ownStack:Bool; + @:noCompletion @:ifFeature("haxe.Exception.get_stack") var __skipStack:Int = 0; + @:noCompletion var __nativeException:CsException; + @:noCompletion var __previousException:Null; + + static public function caught(value:Any):Exception { + if(Std.is(value, Exception)) { + return value; + } else if(Std.isOfType(value, CsException)) { + return new Exception((value:CsException).Message, null, value); + } else { + return new ValueException(value, null, value); + } + } + + static public function thrown(value:Any):Any { + if(Std.isOfType(value, Exception)) { + return (value:Exception).native; + } else if(Std.isOfType(value, CsException)) { + return value; + } else { + var e = new ValueException(value); + e.__shiftStack(); + return e; + } + } + + public function new(message:String, ?previous:Exception, ?native:Any) { + super(message, previous); + this.__previousException = previous; + + if(native != null && Std.isOfType(native, CsException)) { + __nativeException = native; + if(__nativeException.StackTrace == null) { + __nativeStack = new StackTrace(1, true); + __ownStack = true; + } else { + __nativeStack = new StackTrace(__nativeException, true); + __ownStack = false; + } + } else { + __nativeException = cast this; + __nativeStack = new StackTrace(1, true); + __ownStack = true; + } + } + + public function unwrap():Any { + return __nativeException; + } + + public function toString():String { + return message; + } + + public function details():String { + return inline CallStack.exceptionToString(this); + } + + @:noCompletion + @:ifFeature("haxe.Exception.get_stack") + inline function __shiftStack():Void { + if(__ownStack) __skipStack++; + } + + function get_message():String { + return this.Message; + } + + function get_previous():Null { + return __previousException; + } + + final function get_native():Any { + return __nativeException; + } + + function get_stack():CallStack { + return switch __exceptionStack { + case null: + __exceptionStack = NativeStackTrace.toHaxe(__nativeStack, __skipStack); + case s: s; + } + } +} + +@:dox(hide) +@:nativeGen +@:noCompletion +@:native('System.Exception') +private extern class NativeException { + @:noCompletion private function new(message:String, innerException:NativeException):Void; + @:noCompletion @:skipReflection private final Data:cs.system.collections.IDictionary; + @:noCompletion @:skipReflection private var HelpLink:String; + @:noCompletion @:skipReflection private final InnerException:cs.system.Exception; + @:noCompletion @:skipReflection private final Message:String; + @:noCompletion @:skipReflection private var Source:String; + @:noCompletion @:skipReflection private final StackTrace:String; + @:noCompletion @:skipReflection private final TargetSite:cs.system.reflection.MethodBase; + @:overload @:noCompletion @:skipReflection private function GetBaseException():cs.system.Exception; + @:overload @:noCompletion @:skipReflection private function GetObjectData(info:cs.system.runtime.serialization.SerializationInfo, context:cs.system.runtime.serialization.StreamingContext):Void; + @:overload @:noCompletion @:skipReflection private function GetType():cs.system.Type; + @:overload @:noCompletion @:skipReflection private function ToString():cs.system.String; +} \ No newline at end of file diff --git a/std/cs/_std/haxe/Int64.hx b/std/cs/_std/haxe/Int64.hx index 7121df24126378cfbbb7d87c0c887ac456d3bb4f..fd4d21f2865185933dd4f249d123ef5340a7d4bd 100644 --- a/std/cs/_std/haxe/Int64.hx +++ b/std/cs/_std/haxe/Int64.hx @@ -46,12 +46,12 @@ abstract Int64(__Int64) from __Int64 to __Int64 { public var high(get, never):Int32; - public inline function get_high():Int32 + inline function get_high():Int32 return cast(this >> 32); public var low(get, never):Int32; - public inline function get_low():Int32 + inline function get_low():Int32 return cast this; public inline function copy():Int64 @@ -66,8 +66,12 @@ abstract Int64(__Int64) from __Int64 to __Int64 { return cast x.val; } + @:deprecated('haxe.Int64.is() is deprecated. Use haxe.Int64.isInt64() instead') inline public static function is(val:Dynamic):Bool - return Std.is(val, cs.system.Int64); + return Std.isOfType(val, cs.system.Int64); + + inline public static function isInt64(val:Dynamic):Bool + return Std.isOfType(val, cs.system.Int64); public static inline function getHigh(x:Int64):Int32 return cast(x.val >> 32); diff --git a/std/cs/_std/haxe/NativeStackTrace.hx b/std/cs/_std/haxe/NativeStackTrace.hx new file mode 100644 index 0000000000000000000000000000000000000000..e3e7d0f49654e920ded7988f3df56cbfdbab10cf --- /dev/null +++ b/std/cs/_std/haxe/NativeStackTrace.hx @@ -0,0 +1,60 @@ +package haxe; + +import haxe.CallStack.StackItem; +import cs.system.diagnostics.StackTrace; + +/** + Do not use manually. +**/ +@:dox(hide) +@:noCompletion +class NativeStackTrace { + @:meta(System.ThreadStaticAttribute) + static var exception:Null; + + @:ifFeature('haxe.NativeStackTrace.exceptionStack') + static public inline function saveStack(e:Any):Void { + exception = e; + } + + static public inline function callStack():StackTrace { + return new StackTrace(1, true); + } + + static public function exceptionStack():Null { + return switch exception { + case null: null; + case e: new StackTrace(e, true); + } + } + + static public function toHaxe(native:Null, skip:Int = 0):Array { + var stack = []; + if(native == null) { + return stack; + } + var cnt = 0; + for (i in 0...native.FrameCount) { + var frame = native.GetFrame(i); + var m = frame.GetMethod(); + + if (m == null) { + continue; + } + if(skip > cnt++) { + continue; + } + + var method = StackItem.Method(m.ReflectedType.ToString(), m.Name); + + var fileName = frame.GetFileName(); + var lineNumber = frame.GetFileLineNumber(); + + if (fileName != null || lineNumber >= 0) + stack.push(FilePos(method, fileName, lineNumber)); + else + stack.push(method); + } + return stack; + } +} \ No newline at end of file diff --git a/std/cs/_std/sys/io/File.hx b/std/cs/_std/sys/io/File.hx index 6736085bd65b7d0be1bf982943d3684b2594f1ca..680feae33474134401a77b8ca83839a40e55a6f8 100644 --- a/std/cs/_std/sys/io/File.hx +++ b/std/cs/_std/sys/io/File.hx @@ -56,7 +56,7 @@ class File { #else var stream = new cs.system.io.FileStream(path, Open, Read, ReadWrite); #end - return new FileInput(stream); + return @:privateAccess new FileInput(stream); } public static function write(path:String, binary:Bool = true):FileOutput { @@ -65,7 +65,7 @@ class File { #else var stream = new cs.system.io.FileStream(path, Create, Write, ReadWrite); #end - return new FileOutput(stream); + return @:privateAccess new FileOutput(stream); } public static function append(path:String, binary:Bool = true):FileOutput { @@ -74,7 +74,7 @@ class File { #else var stream = new cs.system.io.FileStream(path, Append, Write, ReadWrite); #end - return new FileOutput(stream); + return @:privateAccess new FileOutput(stream); } public static function update(path:String, binary:Bool = true):FileOutput { @@ -86,7 +86,7 @@ class File { #else var stream = new cs.system.io.FileStream(path, OpenOrCreate, Write, ReadWrite); #end - return new FileOutput(stream); + return @:privateAccess new FileOutput(stream); } public static function copy(srcPath:String, dstPath:String):Void { diff --git a/std/cs/_std/sys/io/FileInput.hx b/std/cs/_std/sys/io/FileInput.hx index 1d87218a08ac7ab554f5b080ae72deb3b84982cc..5c67f3e1f1ec0b087501c09fdbb2ddb04200a9e3 100644 --- a/std/cs/_std/sys/io/FileInput.hx +++ b/std/cs/_std/sys/io/FileInput.hx @@ -23,7 +23,7 @@ package sys.io; class FileInput extends cs.io.NativeInput { - public function new(stream:cs.system.io.FileStream) { + function new(stream:cs.system.io.FileStream) { super(stream); } } diff --git a/std/cs/_std/sys/io/FileOutput.hx b/std/cs/_std/sys/io/FileOutput.hx index 400e749a973a89baa195cad54b28bfb782b542d8..fdffd51e44a6299df22bc1bc5ca90ab43c672ed6 100644 --- a/std/cs/_std/sys/io/FileOutput.hx +++ b/std/cs/_std/sys/io/FileOutput.hx @@ -23,7 +23,7 @@ package sys.io; class FileOutput extends cs.io.NativeOutput { - public function new(stream:cs.system.io.FileStream) { + function new(stream:cs.system.io.FileStream) { super(stream); } } diff --git a/std/cs/db/AdoNet.hx b/std/cs/db/AdoNet.hx index 98fbdb3bdb2eb685abd67d68ccc8c58fedd6a9df..2c724c0c062d66c31abe0b106fca13832127d710 100644 --- a/std/cs/db/AdoNet.hx +++ b/std/cs/db/AdoNet.hx @@ -74,9 +74,9 @@ private class AdoConnection implements Connection { } public function addValue(s:StringBuf, v:Dynamic) { - if (Std.is(v, Date)) { + if (Std.isOfType(v, Date)) { v = Std.string(v); - } else if (Std.is(v, haxe.io.Bytes)) { + } else if (Std.isOfType(v, haxe.io.Bytes)) { var bt:haxe.io.Bytes = v; v = bt.getData(); } @@ -284,7 +284,7 @@ private class AdoResultSet implements ResultSet { } else { val = reader.GetValue(i); } - if (Std.is(val, cs.system.DBNull)) + if (Std.isOfType(val, cs.system.DBNull)) val = null; Reflect.setField(ret, name, val); } diff --git a/std/cs/internal/HxObject.hx b/std/cs/internal/HxObject.hx index f1197e4046c528a3176c486a457b74e7e4084bb7..e1cca96edf378b1b2ed7847a41962e338078cfab 100644 --- a/std/cs/internal/HxObject.hx +++ b/std/cs/internal/HxObject.hx @@ -127,7 +127,7 @@ class DynamicObject extends HxObject { } else { var res = FieldLookup.findHash(hash, this.__hx_hashes_f, this.__hx_length_f); if (res >= 0) { - if (Std.is(value, Float)) { + if (Std.isOfType(value, Float)) { return this.__hx_dynamics_f[res] = value; } diff --git a/std/cs/internal/Runtime.hx b/std/cs/internal/Runtime.hx index a5b2855dcf0adc5541a7c81585ab0ea49c5944a2..3538b9ecdce9bbb085e8d7645c19ffd21f080d60 100644 --- a/std/cs/internal/Runtime.hx +++ b/std/cs/internal/Runtime.hx @@ -132,23 +132,23 @@ import cs.system.Object; public static function refEq(v1:{}, v2:{}):Bool { #if !erase_generics - if (Std.is(v1, Type)) + if (Std.isOfType(v1, Type)) return typeEq(Lib.as(v1, Type), Lib.as(v2, Type)); #end return Object.ReferenceEquals(v1, v2); } public static function toDouble(obj:Dynamic):Float { - return (obj == null) ? .0 : Std.is(obj, Float) ? cast obj : Lib.as(obj, IConvertible).ToDouble(null); + return (obj == null) ? .0 : Std.isOfType(obj, Float) ? cast obj : Lib.as(obj, IConvertible).ToDouble(null); } public static function toInt(obj:Dynamic):Int { - return (obj == null) ? 0 : Std.is(obj, Int) ? cast obj : Lib.as(obj, IConvertible).ToInt32(null); + return (obj == null) ? 0 : Std.isOfType(obj, Int) ? cast obj : Lib.as(obj, IConvertible).ToInt32(null); } #if erase_generics public static function toLong(obj:Dynamic):Int64 { - return (obj == null) ? 0 : Std.is(obj, Int64) ? cast obj : Lib.as(obj, IConvertible).ToInt64(null); + return (obj == null) ? 0 : Std.isOfType(obj, Int64) ? cast obj : Lib.as(obj, IConvertible).ToInt64(null); } #end @@ -228,7 +228,7 @@ import cs.system.Object; } public static function plus(v1:Dynamic, v2:Dynamic):Dynamic { - if (Std.is(v1, String) || Std.is(v2, String)) + if (Std.isOfType(v1, String) || Std.isOfType(v2, String)) return Std.string(v1) + Std.string(v2); if (v1 == null) { @@ -370,9 +370,9 @@ import cs.system.Object; value = mkNullable(value, prop.PropertyType); } if (Object.ReferenceEquals(Lib.toNativeType(cs.system.Double), Lib.getNativeType(value)) - && !Object.ReferenceEquals(t, f.FieldType)) { + && !Object.ReferenceEquals(t, prop.PropertyType)) { var ic = Lib.as(value, IConvertible); - value = ic.ToType(f.FieldType, null); + value = ic.ToType(prop.PropertyType, null); } prop.SetValue(obj, value, null); @@ -411,7 +411,7 @@ import cs.system.Object; // if it is directly assignable, we'll give it top rate continue; } else if (untyped strParam.StartsWith("haxe.lang.Null") - || ((oargs[i] == null || Std.is(oargs[i], IConvertible)) + || ((oargs[i] == null || Std.isOfType(oargs[i], IConvertible)) && cast(untyped __typeof__(IConvertible), Type).IsAssignableFrom(param))) { // if it needs conversion, give a penalty. TODO rate penalty crate++; @@ -468,7 +468,7 @@ import cs.system.Object; } } - if (methods[0].ContainsGenericParameters && Std.is(methods[0], cs.system.reflection.MethodInfo)) { + if (methods[0].ContainsGenericParameters && Std.isOfType(methods[0], cs.system.reflection.MethodInfo)) { var m:MethodInfo = cast methods[0]; var tgs = m.GetGenericArguments(); for (i in 0...tgs.Length) { @@ -480,7 +480,7 @@ import cs.system.Object; } var m = methods[0]; - if (obj == null && Std.is(m, cs.system.reflection.ConstructorInfo)) { + if (obj == null && Std.isOfType(m, cs.system.reflection.ConstructorInfo)) { var ret = cast(m, cs.system.reflection.ConstructorInfo).Invoke(oargs); return unbox(ret); } @@ -604,7 +604,7 @@ import cs.system.Object; public static function toString(obj:Dynamic):String { if (obj == null) return null; - if (Std.is(obj, Bool)) + if (Std.isOfType(obj, Bool)) if (obj) return "true"; else @@ -643,7 +643,7 @@ import cs.system.Object; #if !erase_generics public static function getGenericAttr(t:cs.system.Type):cs.internal.HxObject.GenericInterface { for (attr in t.GetCustomAttributes(true)) - if (Std.is(attr, cs.internal.HxObject.GenericInterface)) + if (Std.isOfType(attr, cs.internal.HxObject.GenericInterface)) return cast attr; return null; } diff --git a/std/cs/internal/StringExt.hx b/std/cs/internal/StringExt.hx index f742198fb8d55a04759b1dc7910cb3177dcfac0d..204dff87e8e4a39c01e60ebc4b2c68d9f9810127 100644 --- a/std/cs/internal/StringExt.hx +++ b/std/cs/internal/StringExt.hx @@ -45,6 +45,13 @@ private typedef NativeString = cs.system.String; public static function indexOf(me:NativeString, str:String, ?startIndex:Int):Int { var sIndex:Int = startIndex != null ? startIndex : 0; + if(str == '') { + if(sIndex < 0) { + sIndex = me.Length + sIndex; + if(sIndex < 0) sIndex = 0; + } + return sIndex > me.Length ? me.Length : sIndex; + } if (sIndex >= me.Length) return -1; return @:privateAccess me.IndexOf(str, sIndex, cs.system.StringComparison.Ordinal); @@ -57,6 +64,10 @@ private typedef NativeString = cs.system.String; else if (sIndex < 0) return -1; + if (str.Length == 0) { + return startIndex == null || startIndex > me.Length ? me.Length : startIndex; + } + // TestBaseTypes.hx@133 fix if (startIndex != null) { // if the number of letters between start index and the length of the string diff --git a/std/cs/io/NativeInput.hx b/std/cs/io/NativeInput.hx index c0e6eae7eaefc4ad829b6572dccbe436404e745e..743e2a3e336a227a3232d5699e3dd85e563b4906 100644 --- a/std/cs/io/NativeInput.hx +++ b/std/cs/io/NativeInput.hx @@ -53,7 +53,11 @@ class NativeInput extends Input { override public function readBytes(s:Bytes, pos:Int, len:Int):Int { if (pos < 0 || len < 0 || pos + len > s.length) throw Error.OutsideBounds; - var ret = stream.Read(s.getData(), pos, len); + var ret = 0; + var data = s.getData(); + try { + ret = stream.Read(data, pos, len); + } catch (e: Dynamic) {} if (ret == 0) { _eof = true; throw new Eof(); diff --git a/std/eval/Vector.hx b/std/eval/Vector.hx index b5dc38666a6a112cce6d13106c997b5c54826d58..94ae2c4e5db2398d9a78e765f497214eca090823 100644 --- a/std/eval/Vector.hx +++ b/std/eval/Vector.hx @@ -23,12 +23,12 @@ package eval; extern class Vector implements ArrayAccess { - public function new(size:Int):Void; - public var length(default, null):Int; - public function blit(srcPos:Int, dest:Vector, destPos:Int, len:Int):Void; - public function toArray():Array; - static public function fromArrayCopy(array:Array):Vector; - public function copy():Vector; - public function join(sep:String):String; - public function map(f:T->S):Vector; + function new(size:Int):Void; + var length(default, null):Int; + function blit(srcPos:Int, dest:Vector, destPos:Int, len:Int):Void; + function toArray():Array; + static function fromArrayCopy(array:Array):Vector; + function copy():Vector; + function join(sep:String):String; + function map(f:T->S):Vector; } diff --git a/std/eval/_std/EReg.hx b/std/eval/_std/EReg.hx index d542debf9ad739e9149bd867e204aa6b6e7da955..917520602a41f4d5d48935833dbd04e963846d06 100644 --- a/std/eval/_std/EReg.hx +++ b/std/eval/_std/EReg.hx @@ -23,15 +23,15 @@ // don't get optimized away. @:coreApi extern class EReg { - public function new(r:String, opt:String):Void; - public function match(s:String):Bool; - public function matched(n:Int):String; - public function matchedLeft():String; - public function matchedRight():String; - public function matchedPos():{pos:Int, len:Int}; - public function matchSub(s:String, pos:Int, len:Int = -1):Bool; - public function split(s:String):Array; - public function replace(s:String, by:String):String; - public function map(s:String, f:EReg->String):String; - public static function escape(s:String):String; + function new(r:String, opt:String):Void; + function match(s:String):Bool; + function matched(n:Int):String; + function matchedLeft():String; + function matchedRight():String; + function matchedPos():{pos:Int, len:Int}; + function matchSub(s:String, pos:Int, len:Int = -1):Bool; + function split(s:String):Array; + function replace(s:String, by:String):String; + function map(s:String, f:EReg->String):String; + static function escape(s:String):String; } diff --git a/std/eval/_std/StringBuf.hx b/std/eval/_std/StringBuf.hx index 66f4f3999d3d3985c8d63a0b0f742f9929968e6d..4d4fdf23dd34814d260d93bb90c9af2f6e006540 100644 --- a/std/eval/_std/StringBuf.hx +++ b/std/eval/_std/StringBuf.hx @@ -21,11 +21,11 @@ */ @:coreApi extern class StringBuf { - public var length(get, never):Int; - public function new():Void; + var length(get, never):Int; + function new():Void; private function get_length():Int; - public function add(x:T):Void; - public function addChar(c:Int):Void; - public function addSub(s:String, pos:Int, ?len:Int):Void; - public function toString():String; + function add(x:T):Void; + function addChar(c:Int):Void; + function addSub(s:String, pos:Int, ?len:Int):Void; + function toString():String; } diff --git a/std/eval/_std/haxe/Exception.hx b/std/eval/_std/haxe/Exception.hx new file mode 100644 index 0000000000000000000000000000000000000000..da76a442cf86e386f59a57c3c7651e0388822392 --- /dev/null +++ b/std/eval/_std/haxe/Exception.hx @@ -0,0 +1,89 @@ +package haxe; + +@:coreApi +class Exception { + public var message(get,never):String; + public var stack(get,never):CallStack; + public var previous(get,never):Null; + public var native(get,never):Any; + + @:noCompletion var __exceptionMessage:String; + @:noCompletion var __exceptionStack:Null; + @:noCompletion var __nativeStack:CallStack; + @:noCompletion @:ifFeature("haxe.Exception.get_stack") var __skipStack:Int = 0; + @:noCompletion var __nativeException:Any; + @:noCompletion var __previousException:Null; + + static function caught(value:Any):Exception { + if(Std.is(value, Exception)) { + return value; + } else { + return new ValueException(value, null, value); + } + } + + static function thrown(value:Any):Any { + if(Std.isOfType(value, Exception)) { + return (value:Exception).native; + } else { + var e = new ValueException(value); + e.__shiftStack(); + return e; + } + } + + public function new(message:String, ?previous:Exception, ?native:Any) { + __exceptionMessage = message; + __previousException = previous; + if(native != null) { + __nativeStack = NativeStackTrace.exceptionStack(); + __nativeException = native; + } else { + __nativeStack = NativeStackTrace.callStack(); + __nativeException = this; + } + } + + function unwrap():Any { + return __nativeException; + } + + @:ifFeature("haxe.Exception.thrown") + public function toString():String { + return message; + } + + public function details():String { + return inline CallStack.exceptionToString(this); + } + + @:noCompletion + @:ifFeature("haxe.Exception.get_stack") + inline function __shiftStack():Void { + __skipStack++; + } + + function get_message():String { + return __exceptionMessage; + } + + function get_previous():Null { + return __previousException; + } + + final function get_native():Any { + return __nativeException; + } + + function get_stack():CallStack { + return switch __exceptionStack { + case null: + __exceptionStack = if(__skipStack > 0) { + __nativeStack.asArray().slice(__skipStack); + } else { + __nativeStack; + } + case s: s; + } + } +} \ No newline at end of file diff --git a/std/eval/_std/haxe/NativeStackTrace.hx b/std/eval/_std/haxe/NativeStackTrace.hx new file mode 100644 index 0000000000000000000000000000000000000000..0443d907d42b105c9342d90c164ccc29de8a9d1d --- /dev/null +++ b/std/eval/_std/haxe/NativeStackTrace.hx @@ -0,0 +1,32 @@ +package haxe; + +import haxe.CallStack.StackItem; + +/** + Do not use manually. +**/ +@:dox(hide) +@:noCompletion +class NativeStackTrace { + @:ifFeature('haxe.NativeStackTrace.exceptionStack') + static public inline function saveStack(exception:Any):Void { + } + + static public function callStack():Array { + return _callStack(); + } + + //implemented in the compiler + static function _callStack():Array { + return null; + } + + //implemented in the compiler + static public function exceptionStack():Array { + return null; + } + + static public inline function toHaxe(stack:Array, skip:Int = 0):Array { + return skip > 0 ? stack.slice(skip) : stack; + } +} \ No newline at end of file diff --git a/std/eval/_std/haxe/Resource.hx b/std/eval/_std/haxe/Resource.hx index 314699673f9ee78aa00e41b611c993057b6fe168..101ed64be4614d377962ac0994e71f174eca91eb 100644 --- a/std/eval/_std/haxe/Resource.hx +++ b/std/eval/_std/haxe/Resource.hx @@ -24,7 +24,7 @@ package haxe; @:coreApi extern class Resource { - public static function listNames():Array; - public static function getString(name:String):String; - public static function getBytes(name:String):haxe.io.Bytes; + static function listNames():Array; + static function getString(name:String):String; + static function getBytes(name:String):haxe.io.Bytes; } diff --git a/std/eval/_std/haxe/Utf8.hx b/std/eval/_std/haxe/Utf8.hx index b5e26c6d29675029c14b136d3cc4e0c35450e5ac..023138ea99a17b0fb0bc7d1802575b42052aae4d 100644 --- a/std/eval/_std/haxe/Utf8.hx +++ b/std/eval/_std/haxe/Utf8.hx @@ -25,15 +25,15 @@ package haxe; @:coreApi @:deprecated('haxe.Utf8 is deprecated. Use UnicodeString instead.') extern class Utf8 { - public function new(?size:Int):Void; - public function addChar(c:Int):Void; - public function toString():String; - public static function iter(s:String, chars:Int->Void):Void; - public static function encode(s:String):String; - public static function decode(s:String):String; - public static function charCodeAt(s:String, index:Int):Int; - public static function validate(s:String):Bool; - public static function length(s:String):Int; - public static function compare(a:String, b:String):Int; - public static function sub(s:String, pos:Int, len:Int):String; + function new(?size:Int):Void; + function addChar(c:Int):Void; + function toString():String; + static function iter(s:String, chars:Int->Void):Void; + static function encode(s:String):String; + static function decode(s:String):String; + static function charCodeAt(s:String, index:Int):Int; + static function validate(s:String):Bool; + static function length(s:String):Int; + static function compare(a:String, b:String):Int; + static function sub(s:String, pos:Int, len:Int):String; } diff --git a/std/eval/_std/haxe/io/Bytes.hx b/std/eval/_std/haxe/io/Bytes.hx index 75489c6ab048814679afbeaf473dbb66a19657bb..03758d861b3e8909bf9dea5c076b2c189cde9a57 100644 --- a/std/eval/_std/haxe/io/Bytes.hx +++ b/std/eval/_std/haxe/io/Bytes.hx @@ -25,33 +25,33 @@ package haxe.io; // @:coreApi extern class Bytes { function new(length:Int, b:BytesData):Void; - public var length(default, null):Int; - public function get(pos:Int):Int; - public function set(pos:Int, v:Int):Void; - public function blit(pos:Int, src:Bytes, srcpos:Int, len:Int):Void; - public function fill(pos:Int, len:Int, value:Int):Void; - public function sub(pos:Int, len:Int):Bytes; - public function compare(other:Bytes):Int; - public function getDouble(pos:Int):Float; - public function getFloat(pos:Int):Float; - public function setDouble(pos:Int, v:Float):Void; - public function setFloat(pos:Int, v:Float):Void; - public function getUInt16(pos:Int):Int; - public function setUInt16(pos:Int, v:Int):Void; - public function getInt32(pos:Int):Int; - public function getInt64(pos:Int):haxe.Int64; - public function setInt32(pos:Int, v:Int):Void; - public function setInt64(pos:Int, v:haxe.Int64):Void; - public function getString(pos:Int, len:Int, ?encoding:Encoding):String; - public function toString():String; - public function toHex():String; - public function getData():BytesData; - public static function alloc(length:Int):Bytes; + var length(default, null):Int; + function get(pos:Int):Int; + function set(pos:Int, v:Int):Void; + function blit(pos:Int, src:Bytes, srcpos:Int, len:Int):Void; + function fill(pos:Int, len:Int, value:Int):Void; + function sub(pos:Int, len:Int):Bytes; + function compare(other:Bytes):Int; + function getDouble(pos:Int):Float; + function getFloat(pos:Int):Float; + function setDouble(pos:Int, v:Float):Void; + function setFloat(pos:Int, v:Float):Void; + function getUInt16(pos:Int):Int; + function setUInt16(pos:Int, v:Int):Void; + function getInt32(pos:Int):Int; + function getInt64(pos:Int):haxe.Int64; + function setInt32(pos:Int, v:Int):Void; + function setInt64(pos:Int, v:haxe.Int64):Void; + function getString(pos:Int, len:Int, ?encoding:Encoding):String; + function toString():String; + function toHex():String; + function getData():BytesData; + static function alloc(length:Int):Bytes; @:pure - public static function ofString(s:String, ?encoding:Encoding):Bytes; - public static function ofData(b:BytesData):Bytes; - public static function ofHex(s:String):Bytes; - public static function fastGet(b:BytesData, pos:Int):Int; + static function ofString(s:String, ?encoding:Encoding):Bytes; + static function ofData(b:BytesData):Bytes; + static function ofHex(s:String):Bytes; + static function fastGet(b:BytesData, pos:Int):Int; static function __init__():Void { haxe.io.Error; } diff --git a/std/eval/_std/haxe/io/BytesBuffer.hx b/std/eval/_std/haxe/io/BytesBuffer.hx index 328784fa68ea9d81d5c739cb1679e567f966f50a..b70b5e6cb92313028f8c8f201d01f99ccfd26065 100644 --- a/std/eval/_std/haxe/io/BytesBuffer.hx +++ b/std/eval/_std/haxe/io/BytesBuffer.hx @@ -24,16 +24,16 @@ package haxe.io; @:coreApi extern class BytesBuffer { - public var length(get, never):Int; - public function new():Void; + var length(get, never):Int; + function new():Void; private function get_length():Int; - public function addByte(byte:Int):Void; - public function add(src:Bytes):Void; - public function addString(v:String, ?encoding:Encoding):Void; - public function addInt32(v:Int):Void; - public function addInt64(v:haxe.Int64):Void; - public function addFloat(v:Float):Void; - public function addDouble(v:Float):Void; - public function addBytes(src:Bytes, pos:Int, len:Int):Void; - public function getBytes():Bytes; + function addByte(byte:Int):Void; + function add(src:Bytes):Void; + function addString(v:String, ?encoding:Encoding):Void; + function addInt32(v:Int):Void; + function addInt64(v:haxe.Int64):Void; + function addFloat(v:Float):Void; + function addDouble(v:Float):Void; + function addBytes(src:Bytes, pos:Int, len:Int):Void; + function getBytes():Bytes; } diff --git a/std/eval/_std/haxe/zip/Compress.hx b/std/eval/_std/haxe/zip/Compress.hx index 6e0f793de988029d7fd6975de28eb1745b5468b2..49088b84581b9f9860536f286f48b16dea242ad3 100644 --- a/std/eval/_std/haxe/zip/Compress.hx +++ b/std/eval/_std/haxe/zip/Compress.hx @@ -23,9 +23,9 @@ package haxe.zip; extern class Compress { - public function new(level:Int):Void; - public function execute(src:haxe.io.Bytes, srcPos:Int, dst:haxe.io.Bytes, dstPos:Int):{done:Bool, read:Int, wriet:Int}; - public function setFlushMode(f:FlushMode):Void; - public function close():Void; - public static function run(s:haxe.io.Bytes, level:Int):haxe.io.Bytes; + function new(level:Int):Void; + function execute(src:haxe.io.Bytes, srcPos:Int, dst:haxe.io.Bytes, dstPos:Int):{done:Bool, read:Int, wriet:Int}; + function setFlushMode(f:FlushMode):Void; + function close():Void; + static function run(s:haxe.io.Bytes, level:Int):haxe.io.Bytes; } diff --git a/std/eval/_std/haxe/zip/Uncompress.hx b/std/eval/_std/haxe/zip/Uncompress.hx index 73adbec46b34998a43cb11d2783849e8c22e3189..7bb31af65866604b4710a8b8e3404ec366f76edb 100644 --- a/std/eval/_std/haxe/zip/Uncompress.hx +++ b/std/eval/_std/haxe/zip/Uncompress.hx @@ -23,9 +23,9 @@ package haxe.zip; extern class Uncompress { - public function new(?windowBits:Int):Void; - public function execute(src:haxe.io.Bytes, srcPos:Int, dst:haxe.io.Bytes, dstPos:Int):{done:Bool, read:Int, write:Int}; - public function setFlushMode(f:FlushMode):Void; - public function close():Void; - public static function run(src:haxe.io.Bytes, ?bufsize:Int):haxe.io.Bytes; + function new(?windowBits:Int):Void; + function execute(src:haxe.io.Bytes, srcPos:Int, dst:haxe.io.Bytes, dstPos:Int):{done:Bool, read:Int, write:Int}; + function setFlushMode(f:FlushMode):Void; + function close():Void; + static function run(src:haxe.io.Bytes, ?bufsize:Int):haxe.io.Bytes; } diff --git a/std/eval/_std/mbedtls/Config.hx b/std/eval/_std/mbedtls/Config.hx new file mode 100644 index 0000000000000000000000000000000000000000..132a7f0118f3900a8df407239751e53ffb370a1f --- /dev/null +++ b/std/eval/_std/mbedtls/Config.hx @@ -0,0 +1,10 @@ +package mbedtls; + +extern class Config { + function new():Void; + + function authmode(authmode:SslAuthmode):Void; + function ca_chain(ca_chain:X509Crt):Void; + function defaults(endpoint:SslEndpoint, transport:SslTransport, preset:SslPreset):Int; + function rng(p_rng:T):Void; +} diff --git a/std/eval/_std/mbedtls/CtrDrbg.hx b/std/eval/_std/mbedtls/CtrDrbg.hx new file mode 100644 index 0000000000000000000000000000000000000000..42a67bbeb20f3933e0ebbd180c36628055095ad0 --- /dev/null +++ b/std/eval/_std/mbedtls/CtrDrbg.hx @@ -0,0 +1,10 @@ +package mbedtls; + +import haxe.io.Bytes; + +extern class CtrDrbg { + function new():Void; + + function random(output:Bytes, output_len:Int):Int; + function seed(entropy:Entropy, ?custom:String):Int; +} diff --git a/std/eval/_std/mbedtls/Entropy.hx b/std/eval/_std/mbedtls/Entropy.hx new file mode 100644 index 0000000000000000000000000000000000000000..fb5a09d72f741db4c29542a7fc7e50073bdc4385 --- /dev/null +++ b/std/eval/_std/mbedtls/Entropy.hx @@ -0,0 +1,5 @@ +package mbedtls; + +extern class Entropy { + function new():Void; +} diff --git a/std/eval/_std/mbedtls/Error.hx b/std/eval/_std/mbedtls/Error.hx new file mode 100644 index 0000000000000000000000000000000000000000..343fb0365f13219203e28a5baddd7eec18b26755 --- /dev/null +++ b/std/eval/_std/mbedtls/Error.hx @@ -0,0 +1,5 @@ +package mbedtls; + +class Error { + extern static public function strerror(code:Int):String; +} diff --git a/std/eval/_std/mbedtls/PkContext.hx b/std/eval/_std/mbedtls/PkContext.hx new file mode 100644 index 0000000000000000000000000000000000000000..0c83a4a47f40a0cd23426b3ec6df80e238b3e627 --- /dev/null +++ b/std/eval/_std/mbedtls/PkContext.hx @@ -0,0 +1,12 @@ +package mbedtls; + +import haxe.io.Bytes; + +extern class PkContext { + function new():Void; + + function parse_key(key:Bytes, ?pwd:String):Int; + function parse_keyfile(path:String, ?password:String):Int; + function parse_public_key(key:Bytes):Int; + function parse_public_keyfile(path:String):Int; +} diff --git a/std/eval/_std/mbedtls/Ssl.hx b/std/eval/_std/mbedtls/Ssl.hx new file mode 100644 index 0000000000000000000000000000000000000000..42fc6843aa67a5a538049cbe1ed3e756741d87f7 --- /dev/null +++ b/std/eval/_std/mbedtls/Ssl.hx @@ -0,0 +1,15 @@ +package mbedtls; + +import mbedtls.X509Crt; +import haxe.io.Bytes; + +extern class Ssl { + function new():Void; + + function get_peer_cert():Null; + function handshake():Int; + function read(buf:Bytes, pos:Int, len:Int):Int; + function set_hostname(hostname:String):Int; + function setup(conf:Config):Int; + function write(buf:Bytes, pos:Int, len:Int):Int; +} diff --git a/std/eval/_std/mbedtls/SslAuthmode.hx b/std/eval/_std/mbedtls/SslAuthmode.hx new file mode 100644 index 0000000000000000000000000000000000000000..f00c0126859476fbb38396bc086028726a04509e --- /dev/null +++ b/std/eval/_std/mbedtls/SslAuthmode.hx @@ -0,0 +1,8 @@ +package mbedtls; + +@:native("mbedtls.SslAuthmode") +extern enum abstract SslAuthmode(Int) { + var SSL_VERIFY_NONE; + var SSL_VERIFY_OPTIONAL; + var SSL_VERIFY_REQUIRED; +} diff --git a/std/eval/_std/mbedtls/SslEndpoint.hx b/std/eval/_std/mbedtls/SslEndpoint.hx new file mode 100644 index 0000000000000000000000000000000000000000..1b5278a68443e482b00ebfdef0a1ca32ee6e1a16 --- /dev/null +++ b/std/eval/_std/mbedtls/SslEndpoint.hx @@ -0,0 +1,7 @@ +package mbedtls; + +@:native("mbedtls.SslEndpoint") +extern enum abstract SslEndpoint(Int) { + var SSL_IS_CLIENT; + var SSL_IS_SERVER; +} diff --git a/std/eval/_std/mbedtls/SslPreset.hx b/std/eval/_std/mbedtls/SslPreset.hx new file mode 100644 index 0000000000000000000000000000000000000000..5316452f592695d3b26f5e3fa5c947f1004fa2b1 --- /dev/null +++ b/std/eval/_std/mbedtls/SslPreset.hx @@ -0,0 +1,7 @@ +package mbedtls; + +@:native("mbedtls.SslPreset") +extern enum abstract SslPreset(Int) { + var SSL_PRESET_DEFAULT; + var SSL_PRESET_SUITEB; +} diff --git a/std/eval/_std/mbedtls/SslTransport.hx b/std/eval/_std/mbedtls/SslTransport.hx new file mode 100644 index 0000000000000000000000000000000000000000..a0a03c7af3b4ae3ceebababd2e8f9a739d5bdeab --- /dev/null +++ b/std/eval/_std/mbedtls/SslTransport.hx @@ -0,0 +1,7 @@ +package mbedtls; + +@:native("mbedtls.SslTransport") +extern enum abstract SslTransport(Int) { + var SSL_TRANSPORT_STREAM; + var SSL_TRANSPORT_DATAGRAM; +} diff --git a/std/eval/_std/mbedtls/X509Crt.hx b/std/eval/_std/mbedtls/X509Crt.hx new file mode 100644 index 0000000000000000000000000000000000000000..04b64a303ee76c446070181be542c58e25d40b76 --- /dev/null +++ b/std/eval/_std/mbedtls/X509Crt.hx @@ -0,0 +1,12 @@ +package mbedtls; + +import haxe.io.Bytes; + +extern class X509Crt { + function new():Void; + + function next():Null; + function parse(buf:Bytes):Int; + function parse_file(path:String):Int; + function parse_path(path:String):Int; +} diff --git a/std/eval/_std/sys/net/Socket.hx b/std/eval/_std/sys/net/Socket.hx index 629943ff94060ad2a50726af82cfa9aaa3535980..9833a2172c31df5cfa849f5d23bba6da11a8031d 100644 --- a/std/eval/_std/sys/net/Socket.hx +++ b/std/eval/_std/sys/net/Socket.hx @@ -23,27 +23,7 @@ package sys.net; import haxe.io.Error; - -extern private class NativeSocket { - function new():Void; - function accept():NativeSocket; - function bind(host:Int, port:Int):Void; - function close():Void; - function connect(host:Int, port:Int):Void; - function host():{ip:Int, port:Int}; - function listen(connections:Int):Void; - function peer():{ip:Int, port:Int}; - function receive(buf:haxe.io.Bytes, pos:Int, len:Int):Int; - function receiveChar():Int; - function send(buf:haxe.io.Bytes, pos:Int, len:Int):Int; - function sendChar(char:Int):Void; - function setFastSend(b:Bool):Void; - function setTimeout(timeout:Float):Void; - function shutdown(read:Bool, write:Bool):Void; - - public static function select(read:Array, write:Array, others:Array, - ?timeout:Float):{read:Array, write:Array, others:Array}; -} +import eval.vm.NativeSocket; private class SocketOutput extends haxe.io.Output { var socket:NativeSocket; diff --git a/std/eval/_std/sys/ssl/Certificate.hx b/std/eval/_std/sys/ssl/Certificate.hx new file mode 100644 index 0000000000000000000000000000000000000000..6fc30795cdbee099819efe6407b4e69e81c8d918 --- /dev/null +++ b/std/eval/_std/sys/ssl/Certificate.hx @@ -0,0 +1,102 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package sys.ssl; + +import haxe.io.Bytes; +import sys.ssl.Mbedtls; +import mbedtls.X509Crt; + +@:coreApi +class Certificate { + var native:X509Crt; + + function new(native:X509Crt) { + this.native = native; + } + + public static function loadFile(file:String):Certificate { + var cert = new X509Crt(); + cert.parse_file(file); + return new Certificate(cert); + } + + public static function loadPath(path:String):Certificate { + var cert = new X509Crt(); + cert.parse_path(path); + return new Certificate(cert); + } + + public static function fromString(str:String):Certificate { + var cert = new X509Crt(); + trace(mbedtls.Error.strerror(cert.parse(Bytes.ofString(str)))); + return new Certificate(cert); + } + + public static function loadDefaults():Certificate { + var cert = new X509Crt(); + Mbedtls.loadDefaultCertificates(cert); + return new Certificate(cert); + } + + public var commonName(get, null):Null; + + public var altNames(get, null):Array; + + public var notBefore(get, null):Date; + + public var notAfter(get, null):Date; + + extern public function subject(field:String):Null; + + extern public function issuer(field:String):Null; + + public function next():Null { + var cert = native.next(); + if (cert == null) { + return null; + } + return new Certificate(cert); + } + + public function add(pem:String):Void { + native.parse(Bytes.ofString(pem)); + } + + public function addDER(der:Bytes):Void { + native.parse(der); + } + + private function get_commonName():Null { + return subject("CN"); + } + + extern private function get_altNames():Array; + + extern private function get_notBefore():Date; + + extern private function get_notAfter():Date; + + private inline function getNative():X509Crt { + return native; + } +} diff --git a/std/eval/_std/sys/ssl/Key.hx b/std/eval/_std/sys/ssl/Key.hx new file mode 100644 index 0000000000000000000000000000000000000000..67ea51a5cf87bf8dd35720888630b9eb4e797b3e --- /dev/null +++ b/std/eval/_std/sys/ssl/Key.hx @@ -0,0 +1,69 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package sys.ssl; + +import haxe.io.Bytes; +import mbedtls.PkContext; + +@:coreApi +class Key { + var native:PkContext; + + function new() { + native = new PkContext(); + } + + static public function loadFile(file:String, ?isPublic:Bool, ?pass:String):Key { + var key = new Key(); + var code = if (isPublic) { + key.native.parse_public_keyfile(file); + } else { + key.native.parse_keyfile(file, pass); + } + if (code != 0) { + throw(mbedtls.Error.strerror(code)); + } + return key; + } + + static function parse(data:Bytes, isPublic:Bool, ?pass:String):Key { + var key = new Key(); + var code = if (isPublic) { + key.native.parse_public_key(data); + } else { + key.native.parse_key(data); + } + if (code != 0) { + throw(mbedtls.Error.strerror(code)); + } + return key; + } + + static public function readPEM(data:String, isPublic:Bool, ?pass:String):Key { + return parse(Bytes.ofString(data), isPublic, pass); + } + + static public function readDER(data:haxe.io.Bytes, isPublic:Bool):Key { + return parse(data, isPublic); + } +} diff --git a/std/eval/_std/sys/ssl/Mbedtls.hx b/std/eval/_std/sys/ssl/Mbedtls.hx new file mode 100644 index 0000000000000000000000000000000000000000..e5ef79db591def20634f19247e849aaeffcc2bdb --- /dev/null +++ b/std/eval/_std/sys/ssl/Mbedtls.hx @@ -0,0 +1,66 @@ +package sys.ssl; + +import eval.vm.NativeSocket; +import mbedtls.Ssl; +import mbedtls.Entropy; +import mbedtls.CtrDrbg; +import mbedtls.X509Crt; + +class Mbedtls { + static var entropy:Null; + static var ctr:Null; + + static public function getDefaultEntropy() { + if (entropy == null) { + entropy = new Entropy(); + } + return entropy; + } + + static public function getDefaultCtrDrbg() { + if (ctr == null) { + ctr = new CtrDrbg(); + ctr.seed(getDefaultEntropy()); + } + return ctr; + } + + static public function loadDefaultCertificates(certificate:X509Crt) { + if (loadDefaults(certificate) == 0) { + return; + } + var defPaths = switch (Sys.systemName()) { + case "Linux": + [ + "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc. + "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL + "/etc/ssl/ca-bundle.pem", // OpenSUSE + "/etc/pki/tls/cacert.pem", // OpenELEC + "/etc/ssl/certs", // SLES10/SLES11 + "/system/etc/security/cacerts" // Android + ]; + case "BSD": + [ + "/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly + "/etc/ssl/cert.pem", // OpenBSD + "/etc/openssl/certs/ca-certificates.crt", // NetBSD + ]; + case "Android": + ["/system/etc/security/cacerts"]; + default: + []; + } + for (path in defPaths) { + if (sys.FileSystem.exists(path)) { + if (sys.FileSystem.isDirectory(path)) + certificate.parse_path(path); + else + certificate.parse_file(path); + } + } + } + + extern static public function setSocket(ssl:Ssl, socket:NativeSocket):Int; + + extern static function loadDefaults(certificate:X509Crt):Int; +} diff --git a/std/eval/_std/sys/ssl/Socket.hx b/std/eval/_std/sys/ssl/Socket.hx new file mode 100644 index 0000000000000000000000000000000000000000..451cc6e52f627510bb98bc19ee33d8b62a157497 --- /dev/null +++ b/std/eval/_std/sys/ssl/Socket.hx @@ -0,0 +1,206 @@ +package sys.ssl; + +import haxe.io.Bytes; +import eval.vm.NativeSocket; +import mbedtls.Config; +import mbedtls.Ssl; + +private class SocketInput extends haxe.io.Input { + @:allow(sys.ssl.Socket) private var socket:Socket; + var readBuf:Bytes; + + public function new(s:Socket) { + this.socket = s; + readBuf = Bytes.alloc(1); + } + + public override function readByte() { + socket.handshake(); + var r = @:privateAccess socket.ssl.read(readBuf, 0, 1); + if (r == -1) + throw haxe.io.Error.Blocked; + else if (r < 0) + throw new haxe.io.Eof(); + return readBuf.get(0); + } + + public override function readBytes(buf:haxe.io.Bytes, pos:Int, len:Int):Int { + if (pos < 0 || len < 0 || ((pos + len) : UInt) > (buf.length : UInt)) + throw haxe.io.Error.OutsideBounds; + socket.handshake(); + var r = @:privateAccess socket.ssl.read(buf, pos, len); + if (r == -1) + throw haxe.io.Error.Blocked; + else if (r <= 0) + throw new haxe.io.Eof(); + return r; + } + + public override function close() { + super.close(); + if (socket != null) + socket.close(); + } +} + +private class SocketOutput extends haxe.io.Output { + @:allow(sys.ssl.Socket) private var socket:Socket; + var writeBuf:Bytes; + + public function new(s:Socket) { + this.socket = s; + writeBuf = Bytes.alloc(1); + } + + public override function writeByte(c:Int) { + socket.handshake(); + writeBuf.set(0, c); + var r = @:privateAccess socket.ssl.write(writeBuf, 0, 1); + if (r == -1) + throw haxe.io.Error.Blocked; + else if (r < 0) + throw new haxe.io.Eof(); + } + + public override function writeBytes(buf:haxe.io.Bytes, pos:Int, len:Int):Int { + if (pos < 0 || len < 0 || ((pos + len) : UInt) > (buf.length : UInt)) + throw haxe.io.Error.OutsideBounds; + socket.handshake(); + var r = @:privateAccess socket.ssl.write(buf, pos, len); + if (r == -1) + throw haxe.io.Error.Blocked; + else if (r < 0) + throw new haxe.io.Eof(); + return r; + } + + public override function close() { + super.close(); + if (socket != null) + socket.close(); + } +} + +@:coreApi +class Socket extends sys.net.Socket { + public static var DEFAULT_VERIFY_CERT:Null = true; + + public static var DEFAULT_CA:Null; + + private var conf:Config; + private var ssl:Ssl; + + public var verifyCert:Null; + + private var caCert:Null; + private var hostname:String; + + private var handshakeDone:Bool; + private var isBlocking:Bool = true; + + override function init(socket:NativeSocket):Void { + this.socket = socket; + input = new SocketInput(this); + output = new SocketOutput(this); + if (DEFAULT_VERIFY_CERT && DEFAULT_CA == null) { + DEFAULT_CA = Certificate.loadDefaults(); + } + verifyCert = DEFAULT_VERIFY_CERT; + caCert = DEFAULT_CA; + } + + public override function connect(host:sys.net.Host, port:Int):Void { + conf = buildConfig(false); + ssl = new Ssl(); + ssl.setup(conf); + Mbedtls.setSocket(ssl, socket); + handshakeDone = false; + if (hostname == null) + hostname = host.host; + if (hostname != null) + ssl.set_hostname(hostname); + socket.connect(host.ip, port); + if (isBlocking) + handshake(); + } + + public function handshake():Void { + if (!handshakeDone) { + var r = ssl.handshake(); + if (r == 0) + handshakeDone = true; + else if (r == -1) + throw haxe.io.Error.Blocked; + else + throw mbedtls.Error.strerror(r); + } + } + + override function setBlocking(b:Bool):Void { + super.setBlocking(b); + isBlocking = b; + } + + public function setCA(cert:Certificate):Void { + caCert = cert; + } + + public function setHostname(name:String):Void { + hostname = name; + } + + public override function close():Void { + super.close(); + var input:SocketInput = cast input; + var output:SocketOutput = cast output; + @:privateAccess input.socket = output.socket = null; + input.close(); + output.close(); + } + + public override function bind(host:sys.net.Host, port:Int):Void { + conf = buildConfig(true); + + socket.bind(host.ip, port); + } + + public override function accept():Socket { + var c = socket.accept(); + var cssl = new Ssl(); + cssl.setup(conf); + Mbedtls.setSocket(cssl, c); + + var s = Type.createEmptyInstance(sys.ssl.Socket); + s.socket = c; + s.ssl = cssl; + s.input = new SocketInput(s); + s.output = new SocketOutput(s); + s.handshakeDone = false; + + return s; + } + + public function addSNICertificate(cbServernameMatch:String->Bool, cert:Certificate, key:Key):Void { + throw "Not implemented"; + } + + public function peerCertificate():Certificate { + return @:privateAccess new Certificate(ssl.get_peer_cert()); + } + + public function setCertificate(cert:Certificate, key:Key):Void { + throw "Not implemented"; + } + + private function buildConfig(server:Bool):Config { + var conf = new Config(); + conf.defaults(server ? SSL_IS_SERVER : SSL_IS_CLIENT, SSL_TRANSPORT_STREAM, SSL_PRESET_DEFAULT); + conf.rng(Mbedtls.getDefaultCtrDrbg()); + + if (caCert != null) { + conf.ca_chain(@:privateAccess caCert.getNative()); + } + conf.authmode(if (verifyCert) SSL_VERIFY_REQUIRED else if (verifyCert == null) SSL_VERIFY_OPTIONAL else SSL_VERIFY_NONE); + return conf; + } +} diff --git a/std/eval/vm/NativeSocket.hx b/std/eval/vm/NativeSocket.hx new file mode 100644 index 0000000000000000000000000000000000000000..1943030f975e5cfce7317a6e28f8b4849ddaebde --- /dev/null +++ b/std/eval/vm/NativeSocket.hx @@ -0,0 +1,46 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package eval.vm; + +import sys.net.Socket; + +extern class NativeSocket { + function new():Void; + function accept():NativeSocket; + function bind(host:Int, port:Int):Void; + function close():Void; + function connect(host:Int, port:Int):Void; + function host():{ip:Int, port:Int}; + function listen(connections:Int):Void; + function peer():{ip:Int, port:Int}; + function receive(buf:haxe.io.Bytes, pos:Int, len:Int):Int; + function receiveChar():Int; + function send(buf:haxe.io.Bytes, pos:Int, len:Int):Int; + function sendChar(char:Int):Void; + function setFastSend(b:Bool):Void; + function setTimeout(timeout:Float):Void; + function shutdown(read:Bool, write:Bool):Void; + + static function select(read:Array, write:Array, others:Array, + ?timeout:Float):{read:Array, write:Array, others:Array}; +} diff --git a/std/flash/Boot.hx b/std/flash/Boot.hx index 95ed3b9d3e2bad537ef62771110f8c7f46206f15..076ca85ae6fb66222b4292153d861fcede30caf5 100644 --- a/std/flash/Boot.hx +++ b/std/flash/Boot.hx @@ -22,7 +22,6 @@ package flash; -#if !as3 @:keep private class RealBoot extends Boot { #if swc public function new() { @@ -42,7 +41,6 @@ package flash; } #end } -#end @:dox(hide) @:keep @@ -234,7 +232,7 @@ class Boot extends flash.display.MovieClip { } static public function mapDynamic(d:Dynamic, f:Dynamic) { - if (Std.is(d, Array)) { + if (Std.isOfType(d, Array)) { return untyped d["mapHX"](f); } else { return untyped d["map"](f); @@ -242,7 +240,7 @@ class Boot extends flash.display.MovieClip { } static public function filterDynamic(d:Dynamic, f:Dynamic) { - if (Std.is(d, Array)) { + if (Std.isOfType(d, Array)) { return untyped d["filterHX"](f); } else { return untyped d["filter"](f); @@ -282,7 +280,7 @@ class Boot extends flash.display.MovieClip { throw "Invalid date format : " + s; } }; - d.prototype[#if (as3 || no_flash_override) "toStringHX" #else "toString" #end] = function() { + d.prototype[#if no_flash_override "toStringHX" #else "toString" #end] = function() { var date:Date = __this__; var m = date.getMonth() + 1; var d = date.getDate(); @@ -299,6 +297,9 @@ class Boot extends flash.display.MovieClip { aproto.insert = function(i, x) { __this__.splice(i, 0, x); }; + aproto.contains = function(obj) { + return __this__.indexOf(obj) != -1; + } aproto.remove = function(obj) { var idx = __this__.indexOf(obj); if (idx == -1) @@ -313,26 +314,22 @@ class Boot extends flash.display.MovieClip { return true; } aproto.iterator = function() { - var cur = 0; - var arr:Array = __this__; - return { - hasNext: function() { - return cur < arr.length; - }, - next: function() { - return arr[cur++]; - } - } + return new haxe.iterators.ArrayIterator(cast __this__); + }; + aproto.keyValueIterator = function() { + return new haxe.iterators.ArrayKeyValueIterator(untyped __this__); }; aproto.resize = function(len) { __this__.length = len; }; aproto.setPropertyIsEnumerable("copy", false); aproto.setPropertyIsEnumerable("insert", false); + aproto.setPropertyIsEnumerable("contains", false); aproto.setPropertyIsEnumerable("remove", false); aproto.setPropertyIsEnumerable("iterator", false); + aproto.setPropertyIsEnumerable("keyValueIterator", false); aproto.setPropertyIsEnumerable("resize", false); - #if (as3 || no_flash_override) + #if no_flash_override aproto.filterHX = function(f) { var ret = []; var i = 0; diff --git a/std/flash/Memory.hx b/std/flash/Memory.hx index 88a27cf4b85417e70f2effb12d846742ed53cabb..6dc6e82ec5f6df8736541e0f0bce246f621b2b72 100644 --- a/std/flash/Memory.hx +++ b/std/flash/Memory.hx @@ -23,59 +23,59 @@ package flash; extern class Memory { - public static inline function select(b:flash.utils.ByteArray):Void { + static inline function select(b:flash.utils.ByteArray):Void { flash.system.ApplicationDomain.currentDomain.domainMemory = b; } - public static inline function setByte(addr:Int, v:Int):Void { + static inline function setByte(addr:Int, v:Int):Void { untyped __vmem_set__(0, addr, v); } - public static inline function setI16(addr:Int, v:Int):Void { + static inline function setI16(addr:Int, v:Int):Void { untyped __vmem_set__(1, addr, v); } - public static inline function setI32(addr:Int, v:Int):Void { + static inline function setI32(addr:Int, v:Int):Void { untyped __vmem_set__(2, addr, v); } - public static inline function setFloat(addr:Int, v:Float):Void { + static inline function setFloat(addr:Int, v:Float):Void { untyped __vmem_set__(3, addr, v); } - public static inline function setDouble(addr:Int, v:Float):Void { + static inline function setDouble(addr:Int, v:Float):Void { untyped __vmem_set__(4, addr, v); } - public static inline function getByte(addr:Int):Int { + static inline function getByte(addr:Int):Int { return untyped __vmem_get__(0, addr); } - public static inline function getUI16(addr:Int):Int { + static inline function getUI16(addr:Int):Int { return untyped __vmem_get__(1, addr); } - public static inline function getI32(addr:Int):Int { + static inline function getI32(addr:Int):Int { return untyped __vmem_get__(2, addr); } - public static inline function getFloat(addr:Int):Float { + static inline function getFloat(addr:Int):Float { return untyped __vmem_get__(3, addr); } - public static inline function getDouble(addr:Int):Float { + static inline function getDouble(addr:Int):Float { return untyped __vmem_get__(4, addr); } - public static inline function signExtend1(v:Int):Int { + static inline function signExtend1(v:Int):Int { return untyped __vmem_sign__(0, v); } - public static inline function signExtend8(v:Int):Int { + static inline function signExtend8(v:Int):Int { return untyped __vmem_sign__(1, v); } - public static inline function signExtend16(v:Int):Int { + static inline function signExtend16(v:Int):Int { return untyped __vmem_sign__(2, v); } } diff --git a/std/flash/NativeXml.hx b/std/flash/NativeXml.hx index 309e224826944488e6891e044afd5f2af76aeab7..68b1d705a255b112196828154e3d54884e353cd1 100644 --- a/std/flash/NativeXml.hx +++ b/std/flash/NativeXml.hx @@ -66,8 +66,7 @@ class Xml { return wrap(root, Xml.Document); } - @:keep #if as3 @:hack - public #end static function compare(a:Xml, b:Xml):Bool { + @:keep static function compare(a:Xml, b:Xml):Bool { return a == null ? b == null : (b == null ? false : a._node == b._node); } diff --git a/std/flash/Vector.hx b/std/flash/Vector.hx index 3892edf3b6f101cc008cadfc5c5d454d05047715..a4a96a5a2482b339b0e1c06dc2abf6aac1f050dd 100644 --- a/std/flash/Vector.hx +++ b/std/flash/Vector.hx @@ -53,11 +53,11 @@ package flash; #end @:require(flash19) function removeAt(index:Int):T; - public inline static function ofArray(v:Array):Vector { + inline static function ofArray(v:Array):Vector { return untyped __vector__(v); } - public inline static function convert(v:Vector):Vector { + inline static function convert(v:Vector):Vector { return untyped __vector__(v); } @@ -68,7 +68,7 @@ package flash; so there is no way to check if a value is of a type with specific type parameters. However, on the Flash target, the `flash.Vector` values carry type parameter - information at run-time all the type-checks (such as `Std.is` and `Std.downcast`) on them + information at run-time all the type-checks (such as `Std.isOfType` and `Std.downcast`) on them must be done using a `Class` value that also carries the type parameters. However, Haxe syntax does not allow creating such values and this function exists to mitigate this limitation. @@ -76,11 +76,11 @@ package flash; It should be used as such: ```haxe var specificVectorType:Class> = Vector.typeReference(); - trace(Std.is(vec, specificVectorType)); + trace(Std.isOfType(vec, specificVectorType)); ``` or using the type-check syntax: ```haxe - trace(Std.is(vec, (Vector.typeReference() : Class>))); + trace(Std.isOfType(vec, (Vector.typeReference() : Class>))); ``` It's also helpful when working with native Flash libraries, that receive Class instances: @@ -88,7 +88,7 @@ package flash; new Signal((Vector.typeReference() : Class>)); ``` **/ - public inline static function typeReference():Class> { + inline static function typeReference():Class> { return untyped __vector__(); } } diff --git a/std/flash/_std/Reflect.hx b/std/flash/_std/Reflect.hx index 88b7c2789c6ced7aab662db49a263a91fa85e209..b4a9b8b4a0680f1d544e5614844ed38b8093f6db 100644 --- a/std/flash/_std/Reflect.hx +++ b/std/flash/_std/Reflect.hx @@ -65,16 +65,6 @@ untyped { if (o == null) return new Array(); - #if as3 - var a:Array = __keys__(o); - var i = 0; - while (i < a.length) { - if (!o.hasOwnProperty(a[i])) - a.splice(i, 1); - else - ++i; - } - #else var i = 0; var a = []; while (untyped __has_next__(o, i)) { @@ -82,7 +72,6 @@ if (o.hasOwnProperty(prop)) a.push(prop); } - #end return a; } @@ -113,11 +102,7 @@ } public static function isEnumValue(v:Dynamic):Bool { - #if as3 - return try Type.getEnum(v) != null catch (e:Dynamic) false; - #else return try v.__enum__ == true catch (e:Dynamic) false; - #end } public static function deleteField(o:Dynamic, field:String):Bool diff --git a/std/flash/_std/Std.hx b/std/flash/_std/Std.hx index ca34930d8be07bb769dc2939ef77fa00c6c60b11..9609b7fe1c3434449863ecba1647a7806265152a 100644 --- a/std/flash/_std/Std.hx +++ b/std/flash/_std/Std.hx @@ -23,7 +23,11 @@ import flash.Boot; @:coreApi class Std { - public static function is(v:Dynamic, t:Dynamic):Bool { + public static inline function is(v:Dynamic, t:Dynamic):Bool { + return isOfType(v, t); + } + + public static function isOfType(v:Dynamic, t:Dynamic):Bool { return flash.Boot.__instanceof(v, t); } diff --git a/std/flash/_std/Type.hx b/std/flash/_std/Type.hx index 4585e97d4d4595e24b285e1a6734622ce49b0b7f..c1e6e79fd680f59cedec023ca156b6ee9fef52d9 100644 --- a/std/flash/_std/Type.hx +++ b/std/flash/_std/Type.hx @@ -78,19 +78,14 @@ enum ValueType { return "Float"; case "Boolean": return "Bool"; - #if as3 - case "Object": - return "Dynamic"; - #end - default: - } - var parts = str.split("::"); - #if as3 - if (parts[parts.length - 1] == "_Object") { - parts[parts.length - 1] = "Object"; + case _: + var idx = str.lastIndexOf("::"); + if (idx == -1) { + return str; + } else { + return str.substring(0, idx) + "." + str.substring(idx + 2); + } } - #end - return parts.join("."); } public static function getEnumName(e:Enum):String { @@ -111,10 +106,6 @@ enum ValueType { return Int; case "Float": return Float; - #if as3 - case "Dynamic": - return Dynamic; - #end } return null; } diff --git a/std/flash/_std/haxe/Exception.hx b/std/flash/_std/haxe/Exception.hx new file mode 100644 index 0000000000000000000000000000000000000000..597b78826629d5cce18482a9fba68b0add953a4c --- /dev/null +++ b/std/flash/_std/haxe/Exception.hx @@ -0,0 +1,100 @@ +package haxe; + +import flash.errors.Error; + +@:coreApi +class Exception extends NativeException { + public var message(get,never):String; + public var stack(get,never):CallStack; + public var previous(get,never):Null; + public var native(get,never):Any; + + @:noCompletion var __exceptionStack:Null; + @:noCompletion var __nativeStack:String; + @:noCompletion @:ifFeature("haxe.Exception.get_stack") var __skipStack:Int; + @:noCompletion var __nativeException:Error; + @:noCompletion var __previousException:Null; + + static function caught(value:Any):Exception { + if(Std.is(value, Exception)) { + return value; + } else if(Std.isOfType(value, Error)) { + return new Exception((value:Error).message, null, value); + } else { + return new ValueException(value, null, value); + } + } + + static function thrown(value:Any):Any { + if(Std.isOfType(value, Exception)) { + return (value:Exception).native; + } else if(Std.isOfType(value, Error)) { + return value; + } else { + var e = new ValueException(value); + e.__shiftStack(); + return e; + } + } + + public function new(message:String, ?previous:Exception, ?native:Any) { + super(message); + __previousException = previous; + if(native != null && Std.isOfType(native, Error)) { + __nativeException = native; + __nativeStack = NativeStackTrace.normalize((native:Error).getStackTrace()); + } else { + __nativeException = cast this; + __nativeStack = NativeStackTrace.callStack(); + } + } + + function unwrap():Any { + return __nativeException; + } + + public function toString():String { + return message; + } + + public function details():String { + return inline CallStack.exceptionToString(this); + } + + @:noCompletion + @:ifFeature("haxe.Exception.get_stack") + inline function __shiftStack():Void { + __skipStack++; + } + + function get_message():String { + return (cast this:Error).message; + } + + function get_previous():Null { + return __previousException; + } + + final function get_native():Any { + return __nativeException; + } + + function get_stack():CallStack { + return switch __exceptionStack { + case null: + __exceptionStack = NativeStackTrace.toHaxe(__nativeStack, __skipStack); + case s: s; + } + } +} + +@:dox(hide) +@:native('flash.errors.Error') +extern class NativeException { + @:noCompletion @:flash.property private var errorID(get,never):Int; + // @:noCompletion private var message:Dynamic; + @:noCompletion private var name:Dynamic; + @:noCompletion private function new(?message:Dynamic, id:Dynamic = 0):Void; + @:noCompletion private function getStackTrace():String; + @:noCompletion private function get_errorID():Int; +} \ No newline at end of file diff --git a/std/flash/_std/haxe/NativeStackTrace.hx b/std/flash/_std/haxe/NativeStackTrace.hx new file mode 100644 index 0000000000000000000000000000000000000000..e7508875ae526d80b1e855baa985d7896b46ba36 --- /dev/null +++ b/std/flash/_std/haxe/NativeStackTrace.hx @@ -0,0 +1,69 @@ +package haxe; + +import flash.errors.Error; +import haxe.CallStack.StackItem; + +/** + Do not use manually. +**/ +@:dox(hide) +@:noCompletion +@:allow(haxe.Exception) +class NativeStackTrace { + @:ifFeature('haxe.NativeStackTrace.exceptionStack') + static public inline function saveStack(e:Any):Void { + } + + static public inline function callStack():String { + return normalize(new Error().getStackTrace(), 1); + } + + static public function exceptionStack():String { + var err:Null = untyped flash.Boot.lastError; + return err == null ? '' : normalize(err.getStackTrace()); + } + + static public function toHaxe(native:String, skip:Int = 0):Array { + var a = new Array(); + var r = ~/at ([^\/]+?)\$?(\/[^\(]+)?\(\)(\[(.*?):([0-9]+)\])?/; + var rlambda = ~/^MethodInfo-([0-9]+)$/g; + var cnt = 0; + while (r.match(native)) { + native = r.matchedRight(); + if(skip > cnt++) { + continue; + } + var cl = r.matched(1).split("::").join("."); + var meth = r.matched(2); + var item; + if (meth == null) { + if (rlambda.match(cl)) + item = LocalFunction(Std.parseInt(rlambda.matched(1))); + else + item = Method(cl, "new"); + } else + item = Method(cl, meth.substring(1)); + if (r.matched(3) != null) + item = FilePos(item, r.matched(4), Std.parseInt(r.matched(5))); + a.push(item); + } + return a; + } + + static function normalize(stack:String, skipItems:Int = 0):String { + switch (stack:String).substring(0, 6) { + case 'Error:' | 'Error\n': skipItems += 1; + case _: + } + return skipLines(stack, skipItems); + } + + static function skipLines(stack:String, skip:Int, pos:Int = 0):String { + return if(skip > 0) { + pos = stack.indexOf('\n', pos); + return pos < 0 ? '' : skipLines(stack, --skip, pos + 1); + } else { + return stack.substring(pos); + } + } +} \ No newline at end of file diff --git a/std/flash/_std/haxe/Resource.hx b/std/flash/_std/haxe/Resource.hx index 263aaad6f82c47ae4c364417e1693101f2f109e7..60217376ab7058481a5cf61e97cb07fefb25704a 100644 --- a/std/flash/_std/haxe/Resource.hx +++ b/std/flash/_std/haxe/Resource.hx @@ -22,37 +22,6 @@ package haxe; -#if as3 -@:coreApi -class Resource { - public static function listNames():Array - untyped { - return __keys__(__resources__.list); - } - - public static function getString(name:String):String { - var b = resolve(name); - return b == null ? null : b.readUTFBytes(b.length); - } - - public static function getBytes(name:String):haxe.io.Bytes { - var b = resolve(name); - return b == null ? null : haxe.io.Bytes.ofData(b); - } - - static function resolve(name:String):flash.utils.ByteArray - untyped { - var n = __resources__.list[name]; - if (n == null) - return null; - return untyped __new__(n); - } - - static function __init__():Void { - untyped __resources__.__init__(); - } -} -#else @:coreApi class Resource { static var content:Array<{name:String}>; @@ -88,4 +57,3 @@ class Resource { content = untyped __resources__(); } } -#end diff --git a/std/flash/_std/haxe/ds/IntMap.hx b/std/flash/_std/haxe/ds/IntMap.hx index 18a2d84a296a11b01f6faffb644ea788b685a4cf..54738c1f87ae6b74f219a77e566b78cf1b355ca8 100644 --- a/std/flash/_std/haxe/ds/IntMap.hx +++ b/std/flash/_std/haxe/ds/IntMap.hx @@ -48,27 +48,6 @@ package haxe.ds; return true; } - #if as3 - // unoptimized version - - public function keys():Iterator { - return untyped (__keys__(h)).iterator(); - } - - @:analyzer(ignore) public function iterator():Iterator { - return untyped { - ref: h, - it: keys(), - hasNext: function() { - return __this__.it.hasNext(); - }, - next: function() { - var i = __this__.it.next(); - return __this__.ref[i]; - } - }; - } - #else public inline function keys():Iterator { return new IntMapKeysIterator(h); } @@ -76,7 +55,6 @@ package haxe.ds; public inline function iterator():Iterator { return new IntMapValuesIterator(h); } - #end @:runtime public inline function keyValueIterator():KeyValueIterator { return new haxe.iterators.MapKeyValueIterator(this); @@ -109,7 +87,6 @@ package haxe.ds; } } -#if !as3 // this version uses __has_next__/__forin__ special SWF opcodes for iteration with no allocation @:allow(haxe.ds.IntMap) @@ -163,4 +140,3 @@ private class IntMapValuesIterator { return r; } } -#end diff --git a/std/flash/_std/haxe/ds/ObjectMap.hx b/std/flash/_std/haxe/ds/ObjectMap.hx index 64f06c7171fcef3845fe5a702fd4236d4f4041ac..288cb6f9197234dabe19f7081b4e044918c8472b 100644 --- a/std/flash/_std/haxe/ds/ObjectMap.hx +++ b/std/flash/_std/haxe/ds/ObjectMap.hx @@ -46,18 +46,6 @@ class ObjectMap extends flash.utils.Dictionary implements haxe.Constrai return has; } - #if as3 - public function keys():Iterator { - return untyped __keys__(this).iterator(); - } - - public function iterator():Iterator { - var ret = []; - for (i in keys()) - ret.push(get(i)); - return ret.iterator(); - } - #else public function keys():Iterator { return NativePropertyIterator.iterator(this); } @@ -65,7 +53,6 @@ class ObjectMap extends flash.utils.Dictionary implements haxe.Constrai public function iterator():Iterator { return NativeValueIterator.iterator(this); } - #end @:runtime public inline function keyValueIterator():KeyValueIterator { return new haxe.iterators.MapKeyValueIterator(this); @@ -95,7 +82,6 @@ class ObjectMap extends flash.utils.Dictionary implements haxe.Constrai } } -#if !as3 private class NativePropertyIterator { var collection:Dynamic; var index:Int = 0; @@ -153,4 +139,3 @@ private class NativeValueIterator { return result; } } -#end diff --git a/std/flash/_std/haxe/ds/StringMap.hx b/std/flash/_std/haxe/ds/StringMap.hx index 144973ba89484942141facaa1a3ea0b587f19c24..a6fd0a060f87884bd33f99a833fb9d620585d7d5 100644 --- a/std/flash/_std/haxe/ds/StringMap.hx +++ b/std/flash/_std/haxe/ds/StringMap.hx @@ -86,28 +86,6 @@ package haxe.ds; } } - #if as3 - // unoptimized version - - public function keys():Iterator { - var out:Array = untyped __keys__(h); - if (rh != null) - out = out.concat(untyped __hkeys__(rh)); - return out.iterator(); - } - - public function iterator():Iterator { - return untyped { - it: keys(), - hasNext: function() { - return __this__.it.hasNext(); - }, - next: function() { - return get(__this__.it.next()); - } - }; - } - #else public inline function keys():Iterator { return new StringMapKeysIterator(h, rh); } @@ -115,7 +93,6 @@ package haxe.ds; public inline function iterator():Iterator { return new StringMapValuesIterator(h, rh); } - #end @:runtime public inline function keyValueIterator():KeyValueIterator { return new haxe.iterators.MapKeyValueIterator(this); @@ -149,7 +126,6 @@ package haxe.ds; } } -#if !as3 // this version uses __has_next__/__forin__ special SWF opcodes for iteration with no allocation @:allow(haxe.ds.StringMap) @@ -224,4 +200,3 @@ private class StringMapValuesIterator { return r; } } -#end diff --git a/std/flash/_std/haxe/ds/UnsafeStringMap.hx b/std/flash/_std/haxe/ds/UnsafeStringMap.hx index 73946229911b47d2e33ab579e0fee04ae832c361..3d2969f254ee0eb3be37581538aa988061b54c11 100644 --- a/std/flash/_std/haxe/ds/UnsafeStringMap.hx +++ b/std/flash/_std/haxe/ds/UnsafeStringMap.hx @@ -53,27 +53,6 @@ class UnsafeStringMap implements haxe.Constraints.IMap { return true; } - #if as3 - // unoptimized version - - public function keys():Iterator { - return untyped (__keys__(h)).iterator(); - } - - public function iterator():Iterator { - return untyped { - ref: h, - it: __keys__(h).iterator(), - hasNext: function() { - return __this__.it.hasNext(); - }, - next: function() { - var i:Dynamic = __this__.it.next(); - return __this__.ref[i]; - } - }; - } - #else public inline function keys():Iterator { return new UnsafeStringMapKeysIterator(h); } @@ -81,7 +60,6 @@ class UnsafeStringMap implements haxe.Constraints.IMap { public inline function iterator():Iterator { return new UnsafeStringMapValuesIterator(h); } - #end public inline function keyValueIterator():KeyValueIterator { return new haxe.iterators.MapKeyValueIterator(this); @@ -114,7 +92,6 @@ class UnsafeStringMap implements haxe.Constraints.IMap { } } -#if !as3 // this version uses __has_next__/__forin__ special SWF opcodes for iteration with no allocation @:allow(haxe.ds.UnsafeStringMap) @@ -168,4 +145,3 @@ private class UnsafeStringMapValuesIterator { return r; } } -#end diff --git a/std/flash/_std/haxe/ds/WeakMap.hx b/std/flash/_std/haxe/ds/WeakMap.hx index 7b52ecda7ac0f5570bccecda5a3c2f4b0e4a8b53..fee582cd26c397ac1276af0eb44befc7df555ccc 100644 --- a/std/flash/_std/haxe/ds/WeakMap.hx +++ b/std/flash/_std/haxe/ds/WeakMap.hx @@ -46,18 +46,6 @@ class WeakMap extends flash.utils.Dictionary implements haxe.Constraint return has; } - #if as3 - public function keys():Iterator { - return untyped __keys__(this).iterator(); - } - - public function iterator():Iterator { - var ret = []; - for (i in keys()) - ret.push(get(i)); - return ret.iterator(); - } - #else public function keys():Iterator { return NativePropertyIterator.iterator(this); } @@ -65,7 +53,6 @@ class WeakMap extends flash.utils.Dictionary implements haxe.Constraint public function iterator():Iterator { return NativeValueIterator.iterator(this); } - #end public inline function keyValueIterator():KeyValueIterator { return new haxe.iterators.MapKeyValueIterator(this); @@ -95,7 +82,6 @@ class WeakMap extends flash.utils.Dictionary implements haxe.Constraint } } -#if !as3 private class NativePropertyIterator { var collection:Dynamic; var index:Int = 0; @@ -153,4 +139,3 @@ private class NativeValueIterator { return result; } } -#end diff --git a/std/flash/ui/Mouse.hx b/std/flash/ui/Mouse.hx index 18aac659f4a3cb95bb08be502f4e1b2ad5f57b41..93cd0e8a3cb46d7334683ec15aa5c46ca568af61 100644 --- a/std/flash/ui/Mouse.hx +++ b/std/flash/ui/Mouse.hx @@ -3,7 +3,7 @@ package flash.ui; extern class Mouse { @:flash.property @:require(flash10) static var cursor(get,set) : Dynamic; @:flash.property @:require(flash10_1) static var supportsCursor(get,never) : Bool; - @:flash.property @:require(flash11) static var supportsNativeCursor(get,never) : Bool; + @:flash.property @:require(flash10_2) static var supportsNativeCursor(get,never) : Bool; private static function get_cursor() : Dynamic; private static function get_supportsCursor() : Bool; private static function get_supportsNativeCursor() : Bool; @@ -11,5 +11,5 @@ extern class Mouse { @:require(flash10_2) static function registerCursor(name : String, cursor : MouseCursorData) : Void; private static function set_cursor(value : Dynamic) : Dynamic; static function show() : Void; - @:require(flash11) static function unregisterCursor(name : String) : Void; + @:require(flash10_2) static function unregisterCursor(name : String) : Void; } diff --git a/std/haxe/CallStack.hx b/std/haxe/CallStack.hx index 8e98b8c7a936a04391c4d3b2d6f331b5b0ffd501..815f0938969679529ba96ff6aca884ce2e01e142 100644 --- a/std/haxe/CallStack.hx +++ b/std/haxe/CallStack.hx @@ -36,236 +36,122 @@ enum StackItem { /** Get information about the call stack. **/ -class CallStack { - #if js - static var lastException:js.lib.Error; - - static function getStack(e:js.lib.Error):Array { - if (e == null) - return []; - // https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi - var oldValue = (untyped Error).prepareStackTrace; - (untyped Error).prepareStackTrace = function(error, callsites:Array) { - var stack = []; - for (site in callsites) { - if (wrapCallSite != null) - site = wrapCallSite(site); - var method = null; - var fullName:String = site.getFunctionName(); - if (fullName != null) { - var idx = fullName.lastIndexOf("."); - if (idx >= 0) { - var className = fullName.substr(0, idx); - var methodName = fullName.substr(idx + 1); - method = Method(className, methodName); - } - } - var fileName:String = site.getFileName(); - var fileAddr = fileName == null ? -1 : fileName.indexOf("file:"); - if (wrapCallSite != null && fileAddr > 0) - fileName = fileName.substr(fileAddr + 6); - stack.push(FilePos(method, fileName, site.getLineNumber(), site.getColumnNumber())); - } - return stack; - } - var a = makeStack(e.stack); - (untyped Error).prepareStackTrace = oldValue; - return a; - } - - // support for source-map-support module - @:noCompletion - public static var wrapCallSite:Dynamic->Dynamic; - #end - - #if eval - static function getCallStack() { - return []; - } - - static function getExceptionStack() { - return []; - } - #end +@:allow(haxe.Exception) +@:using(haxe.CallStack) +abstract CallStack(Array) from Array { + /** + The length of this stack. + **/ + public var length(get,never):Int; + inline function get_length():Int return this.length; /** Return the call stack elements, or an empty array if not available. **/ public static function callStack():Array { - #if neko - var a = makeStack(untyped __dollar__callstack()); - a.shift(); // remove Stack.callStack() - return a; - #elseif flash - var a = makeStack(new flash.errors.Error().getStackTrace()); - a.shift(); // remove Stack.callStack() - return a; - #elseif cpp - var s:Array = untyped __global__.__hxcpp_get_call_stack(true); - return makeStack(s); - #elseif js - try { - throw new js.lib.Error(); - } catch (e:Dynamic) { - var a = getStack(js.Lib.getOriginalException()); - a.shift(); // remove Stack.callStack() - return a; - } - #elseif java - var stack = []; - for (el in java.lang.Thread.currentThread().getStackTrace()) { - var className = el.getClassName(); - var methodName = el.getMethodName(); - var fileName = el.getFileName(); - var lineNumber = el.getLineNumber(); - var method = Method(className, methodName); - if (fileName != null || lineNumber >= 0) { - stack.push(FilePos(method, fileName, lineNumber)); - } else { - stack.push(method); - } - } - stack.shift(); - stack.shift(); - stack.pop(); - return stack; - #elseif cs - return makeStack(new cs.system.diagnostics.StackTrace(1, true)); - #elseif python - var stack = []; - var infos = python.lib.Traceback.extract_stack(); - infos.pop(); - infos.reverse(); - for (elem in infos) - stack.push(FilePos(Method(null, elem._3), elem._1, elem._2)); - return stack; - #elseif lua - var stack = []; - var infos = lua.Debug.traceback(); - var luastack = infos.split("\n").slice(2, -1); - for (s in luastack) { - var parts = s.split(":"); - var file = parts[0]; - var line = parts[1]; - var method = if(parts.length <= 2) { - null; - } else { - var methodPos = parts[2].indexOf("'"); - if(methodPos < 0) { - null; - } else { - Method(null, parts[2].substring(methodPos + 1, parts[2].length - 1)); - } - } - stack.push(FilePos(method, file, Std.parseInt(line))); - } - return stack; - #elseif hl - try { - throw null; - } catch (e:Dynamic) { - var st = _getExceptionStack(); - return makeStack(st.length > 2 ? st.sub(2, st.length - 2) : st); - } - #elseif eval - return getCallStack(); - #else - return []; // Unsupported - #end + return NativeStackTrace.toHaxe(NativeStackTrace.callStack()); } - #if hl - @:hlNative("std", "exception_stack") static function _getExceptionStack():hl.NativeArray { - return null; - } - #end - /** Return the exception stack : this is the stack elements between the place the last exception was thrown and the place it was caught, or an empty array if not available. + + May not work if catch type was a derivative from `haxe.Exception`. **/ - #if cpp - @:noDebug /* Do not mess up the exception stack */ - #end public static function exceptionStack():Array { - #if neko - return makeStack(untyped __dollar__excstack()); - #elseif as3 - return new Array(); - #elseif hl - return makeStack(_getExceptionStack()); - #elseif flash - var err:flash.errors.Error = untyped flash.Boot.lastError; - if (err == null) - return new Array(); - var a = makeStack(err.getStackTrace()); - var c = callStack(); - var i = c.length - 1; - while (i > 0) { - if (Std.string(a[a.length - 1]) == Std.string(c[i])) - a.pop(); - else - break; - i--; - } - return a; - #elseif cpp - var s:Array = untyped __global__.__hxcpp_get_exception_stack(); - return makeStack(s); - #elseif java - var stack = []; - switch (#if jvm jvm.Exception #else java.internal.Exceptions #end.currentException()) { - case null: - case current: - for (el in current.getStackTrace()) { - var className = el.getClassName(); - var methodName = el.getMethodName(); - var fileName = el.getFileName(); - var lineNumber = el.getLineNumber(); - var method = Method(className, methodName); - if (fileName != null || lineNumber >= 0) { - stack.push(FilePos(method, fileName, lineNumber)); - } else { - stack.push(method); - } - } - } - return stack; - #elseif cs - return cs.internal.Exceptions.exception == null ? [] : makeStack(new cs.system.diagnostics.StackTrace(cs.internal.Exceptions.exception, true)); - #elseif python - var stack = []; - var exc = python.lib.Sys.exc_info(); - if (exc._3 != null) { - var infos = python.lib.Traceback.extract_tb(exc._3); - infos.reverse(); - for (elem in infos) - stack.push(FilePos(Method(null, elem._3), elem._1, elem._2)); - } - return stack; - #elseif js - return getStack(lastException); - #elseif eval - return getExceptionStack(); - #else - return []; // Unsupported - #end + var eStack:CallStack = NativeStackTrace.toHaxe(NativeStackTrace.exceptionStack()); + return eStack.subtract(callStack()).asArray(); } /** Returns a representation of the stack as a printable string. **/ - public static function toString(stack:Array) { + static public function toString(stack:CallStack):String { var b = new StringBuf(); - for (s in stack) { - b.add("\nCalled from "); + for (s in stack.asArray()) { + b.add('\nCalled from '); itemToString(b, s); } return b.toString(); } - private static function itemToString(b:StringBuf, s) { + /** + Returns a range of entries of current stack from the beginning to the the + common part of this and `stack`. + **/ + public function subtract(stack:CallStack):CallStack { + var startIndex = -1; + var i = -1; + while(++i < this.length) { + for(j in 0...stack.length) { + if(equalItems(this[i], stack[j])) { + if(startIndex < 0) { + startIndex = i; + } + ++i; + if(i >= this.length) break; + } else { + startIndex = -1; + } + } + if(startIndex >= 0) break; + } + return startIndex >= 0 ? this.slice(0, startIndex) : this; + } + + /** + Make a copy of the stack. + **/ + public inline function copy():CallStack { + return this.copy(); + } + + @:arrayAccess public inline function get(index:Int):StackItem { + return this[index]; + } + + inline function asArray():Array { + return this; + } + + static function equalItems(item1:Null, item2:Null):Bool { + return switch([item1, item2]) { + case [null, null]: true; + case [CFunction, CFunction]: true; + case [Module(m1), Module(m2)]: + m1 == m2; + case [FilePos(item1, file1, line1, col1), FilePos(item2, file2, line2, col2)]: + file1 == file2 && line1 == line2 && col1 == col2 && equalItems(item1, item2); + case [Method(class1, method1), Method(class2, method2)]: + class1 == class2 && method1 == method2; + case [LocalFunction(v1), LocalFunction(v2)]: + v1 == v2; + case _: false; + } + } + + static function exceptionToString(e:Exception):String { + if(e.previous == null) { + return 'Exception: ${e.message}${e.stack}'; + } + var result = ''; + var e:Null = e; + var prev:Null = null; + while(e != null) { + if(prev == null) { + result = 'Exception: ${e.message}${e.stack}' + result; + } else { + var prevStack = @:privateAccess e.stack.subtract(prev.stack); + result = 'Exception: ${e.message}${prevStack}\n\nNext ' + result; + } + prev = e; + e = e.previous; + } + return result; + } + + static function itemToString(b:StringBuf, s) { switch (s) { case CFunction: b.add("a C function"); @@ -295,121 +181,4 @@ class CallStack { b.add(n); } } - - #if cpp - @:noDebug /* Do not mess up the exception stack */ - #end - private static function makeStack(s #if cs:cs.system.diagnostics.StackTrace #elseif hl:hl.NativeArray #else:Dynamic #end) { - #if neko - var a = new Array(); - var l = untyped __dollar__asize(s); - var i = 0; - while (i < l) { - var x = s[i++]; - if (x == null) - a.unshift(CFunction); - else if (untyped __dollar__typeof(x) == __dollar__tstring) - a.unshift(Module(new String(x))); - else - a.unshift(FilePos(null, new String(untyped x[0]), untyped x[1])); - } - return a; - #elseif flash - var a = new Array(); - var r = ~/at ([^\/]+?)\$?(\/[^\(]+)?\(\)(\[(.*?):([0-9]+)\])?/; - var rlambda = ~/^MethodInfo-([0-9]+)$/g; - while (r.match(s)) { - var cl = r.matched(1).split("::").join("."); - var meth = r.matched(2); - var item; - if (meth == null) { - if (rlambda.match(cl)) - item = LocalFunction(Std.parseInt(rlambda.matched(1))); - else - item = Method(cl, "new"); - } else - item = Method(cl, meth.substr(1)); - if (r.matched(3) != null) - item = FilePos(item, r.matched(4), Std.parseInt(r.matched(5))); - a.push(item); - s = r.matchedRight(); - } - return a; - #elseif cpp - var stack:Array = s; - var m = new Array(); - for (func in stack) { - var words = func.split("::"); - if (words.length == 0) - m.push(CFunction) - else if (words.length == 2) - m.push(Method(words[0], words[1])); - else if (words.length == 4) - m.push(FilePos(Method(words[0], words[1]), words[2], Std.parseInt(words[3]))); - } - return m; - #elseif js - if (s == null) { - return []; - } else if (js.Syntax.typeof(s) == "string") { - // Return the raw lines in browsers that don't support prepareStackTrace - var stack:Array = s.split("\n"); - if (stack[0] == "Error") - stack.shift(); - var m = []; - var rie10 = ~/^ at ([A-Za-z0-9_. ]+) \(([^)]+):([0-9]+):([0-9]+)\)$/; - for (line in stack) { - if (rie10.match(line)) { - var path = rie10.matched(1).split("."); - var meth = path.pop(); - var file = rie10.matched(2); - var line = Std.parseInt(rie10.matched(3)); - var column = Std.parseInt(rie10.matched(4)); - m.push(FilePos(meth == "Anonymous function" ? LocalFunction() : meth == "Global code" ? null : Method(path.join("."), meth), file, line, - column)); - } else - m.push(Module(StringTools.trim(line))); // A little weird, but better than nothing - } - return m; - } else { - return cast s; - } - #elseif cs - var stack = []; - for (i in 0...s.FrameCount) { - var frame = s.GetFrame(i); - var m = frame.GetMethod(); - - if (m == null) { - continue; - } - var method = StackItem.Method(m.ReflectedType.ToString(), m.Name); - - var fileName = frame.GetFileName(); - var lineNumber = frame.GetFileLineNumber(); - - if (fileName != null || lineNumber >= 0) - stack.push(FilePos(method, fileName, lineNumber)); - else - stack.push(method); - } - return stack; - #elseif hl - var stack = []; - var r = ~/^([A-Za-z0-9.$_]+)\.([~A-Za-z0-9_]+(\.[0-9]+)?)\((.+):([0-9]+)\)$/; - var r_fun = ~/^fun\$([0-9]+)\((.+):([0-9]+)\)$/; - for (i in 0...s.length - 1) { - var str = @:privateAccess String.fromUCS2(s[i]); - if (r.match(str)) - stack.push(FilePos(Method(r.matched(1), r.matched(2)), r.matched(4), Std.parseInt(r.matched(5)))); - else if (r_fun.match(str)) - stack.push(FilePos(LocalFunction(Std.parseInt(r_fun.matched(1))), r_fun.matched(2), Std.parseInt(r_fun.matched(3)))); - else - stack.push(Module(str)); - } - return stack; - #else - return null; - #end - } -} +} \ No newline at end of file diff --git a/std/haxe/Constraints.hx b/std/haxe/Constraints.hx index 18f6402b4db107d1a0673df2c6385f61c3217f52..e0138e53f99ca0e88f37c1c17a6f5b341d6b14b5 100644 --- a/std/haxe/Constraints.hx +++ b/std/haxe/Constraints.hx @@ -40,6 +40,14 @@ abstract Function(Dynamic) {} **/ abstract FlatEnum(Dynamic) {} +/** + This type unifies with anything but `Void`. + + It is intended to be used as a type parameter constraint. If used as a real + type, the underlying type will be `Dynamic`. +**/ +abstract NotVoid(Dynamic) { } + /** This type unifies with any instance of classes that have a constructor which diff --git a/std/haxe/EntryPoint.hx b/std/haxe/EntryPoint.hx index a35bd855732c34e08483d3a03f986a8ea36eca77..9399a3d2a699212d507a5a3098b54cb2b779f9a9 100644 --- a/std/haxe/EntryPoint.hx +++ b/std/haxe/EntryPoint.hx @@ -108,15 +108,25 @@ class EntryPoint { @:keep public static function run() @:privateAccess { #if js var nextTick = processEvents(); - + inline function setTimeoutNextTick() { + if (nextTick >= 0) { + (untyped setTimeout)(run, nextTick * 1000); + } + } #if nodejs - if (nextTick < 0) - return; - (untyped setTimeout)(run, nextTick); + setTimeoutNextTick(); #else - var window:Dynamic = js.Browser.window; - var rqf:Dynamic = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame; - rqf(run); + if(js.Lib.typeof(js.Browser.window) != 'undefined') { + var window:Dynamic = js.Browser.window; + var rqf:Dynamic = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame; + if(rqf != null) { + rqf(run); + } else { + setTimeoutNextTick(); + } + } else { + setTimeoutNextTick(); + } #end #elseif flash flash.Lib.current.stage.addEventListener(flash.events.Event.ENTER_FRAME, function(_) processEvents()); diff --git a/std/haxe/EnumTools.hx b/std/haxe/EnumTools.hx index 583f9f2c5943785a462774d526d3d3b0cccafd0d..6a69a2c02e0f425dcaeee5a9068cc25c165106a9 100644 --- a/std/haxe/EnumTools.hx +++ b/std/haxe/EnumTools.hx @@ -49,7 +49,7 @@ extern class EnumTools { The enum name does not include any type parameters. **/ - static public inline function getName(e:Enum):String { + static inline function getName(e:Enum):String { return Type.getEnumName(e); } @@ -62,7 +62,7 @@ extern class EnumTools { expected number of constructor arguments, or if any argument has an invalid type, the result is unspecified. **/ - static public inline function createByName(e:Enum, constr:String, ?params:Array):T { + static inline function createByName(e:Enum, constr:String, ?params:Array):T { return Type.createEnum(e, constr, params); } @@ -78,7 +78,7 @@ extern class EnumTools { does not match the expected number of constructor arguments, or if any argument has an invalid type, the result is unspecified. **/ - static public inline function createByIndex(e:Enum, index:Int, ?params:Array):T { + static inline function createByIndex(e:Enum, index:Int, ?params:Array):T { return Type.createEnumIndex(e, index, params); } @@ -95,7 +95,7 @@ extern class EnumTools { If `e` is `null`, the result is unspecified. **/ - static public inline function createAll(e:Enum):Array { + static inline function createAll(e:Enum):Array { return Type.allEnums(e); } @@ -107,7 +107,7 @@ extern class EnumTools { If `c` is `null`, the result is unspecified. **/ - static public inline function getConstructors(e:Enum):Array { + static inline function getConstructors(e:Enum):Array { return Type.getEnumConstructs(e); } } @@ -130,7 +130,7 @@ extern class EnumValueTools { If `a` or `b` are `null`, the result is unspecified. **/ - static public inline function equals(a:T, b:T):Bool { + static inline function equals(a:T, b:T):Bool { return Type.enumEq(a, b); } @@ -141,7 +141,7 @@ extern class EnumValueTools { If `e` is `null`, the result is unspecified. **/ - static public inline function getName(e:EnumValue):String { + static inline function getName(e:EnumValue):String { return Type.enumConstructor(e); } @@ -155,7 +155,7 @@ extern class EnumValueTools { If `e` is `null`, the result is unspecified. **/ - static public inline function getParameters(e:EnumValue):Array { + static inline function getParameters(e:EnumValue):Array { return Type.enumParameters(e); } @@ -167,7 +167,7 @@ extern class EnumValueTools { If `e` is `null`, the result is unspecified. **/ - static public inline function getIndex(e:EnumValue):Int { + static inline function getIndex(e:EnumValue):Int { return Type.enumIndex(e); } } diff --git a/std/haxe/Exception.hx b/std/haxe/Exception.hx new file mode 100644 index 0000000000000000000000000000000000000000..256515a96f73525e3145441015a44c42e6d69b41 --- /dev/null +++ b/std/haxe/Exception.hx @@ -0,0 +1,117 @@ +package haxe; + +/** + Base class for exceptions. + + If this class (or derivatives) is used to catch an exception, then + `haxe.CallStack.exceptionStack()` will not return a stack for the exception + caught. Use `haxe.Exception.stack` property instead: + ```haxe + try { + throwSomething(); + } catch(e:Exception) { + trace(e.stack); + } + ``` + + Custom exceptions should extend this class: + ```haxe + class MyException extends haxe.Exception {} + //... + throw new MyException('terrible exception'); + ``` + + `haxe.Exception` is also a wildcard type to catch any exception: + ```haxe + try { + throw 'Catch me!'; + } catch(e:haxe.Exception) { + trace(e.message); // Output: Catch me! + } + ``` + + To rethrow an exception just throw it again. + Haxe will try to rethrow an original native exception whenever possible. + ```haxe + try { + var a:Array = null; + a.push(1); // generates target-specific null-pointer exception + } catch(e:haxe.Exception) { + throw e; // rethrows native exception instead of haxe.Exception + } + ``` +**/ +extern class Exception { + /** + Exception message. + **/ + public var message(get,never):String; + private function get_message():String; + + /** + The call stack at the moment of the exception creation. + **/ + public var stack(get,never):CallStack; + private function get_stack():CallStack; + + /** + Contains an exception, which was passed to `previous` constructor argument. + **/ + public var previous(get,never):Null; + private function get_previous():Null; + + /** + Native exception, which caused this exception. + **/ + public var native(get,never):Any; + final private function get_native():Any; + + /** + Used internally for wildcard catches like `catch(e:Exception)`. + **/ + static private function caught(value:Any):Exception; + + /** + Used internally for wrapping non-throwable values for `throw` expressions. + **/ + static private function thrown(value:Any):Any; + + /** + Create a new Exception instance. + + The `previous` argument could be used for exception chaining. + + The `native` argument is for internal usage only. + There is no need to provide `native` argument manually and no need to keep it + upon extending `haxe.Exception` unless you know what you're doing. + **/ + public function new(message:String, ?previous:Exception, ?native:Any):Void; + + /** + Extract an originally thrown value. + + Used internally for catching non-native exceptions. + Do _not_ override unless you know what you are doing. + **/ + private function unwrap():Any; + + /** + Returns exception message. + **/ + public function toString():String; + + /** + Detailed exception description. + + Includes message, stack and the chain of previous exceptions (if set). + **/ + public function details():String; + + /** + If this field is defined in a target implementation, then a call to this + field will be generated automatically in every constructor of derived classes + to make exception stacks point to derived constructor invocations instead of + `super` calls. + **/ + // @:noCompletion @:ifFeature("haxe.Exception.stack") private function __shiftStack():Void; +} diff --git a/std/haxe/Int32.hx b/std/haxe/Int32.hx index 5c1210049ec88466fd85f7dca969e4e7119392a5..da01ff1d79c765d8463bde7b83cc06088bcdfb59 100644 --- a/std/haxe/Int32.hx +++ b/std/haxe/Int32.hx @@ -69,7 +69,7 @@ abstract Int32(Int) from Int to Int { @:op(A - B) public static function floatSub(a:Float, b:Int32):Float; - #if (as3 || js || php || python || lua) + #if (js || php || python || lua) #if js // on JS we want to try using Math.imul, but we have to assign that function to Int32.mul only once, // or else V8 will deoptimize it, so we need to be a bit funky with this. @@ -265,7 +265,7 @@ abstract Int32(Int) from Int to Int { #end static function clamp(x:Int):Int { // force to-int conversion on platforms that require it - #if (as3 || js) + #if js return x | 0; #elseif php // we might be on 64-bit php, so sign extend from 32-bit diff --git a/std/haxe/Int64.hx b/std/haxe/Int64.hx index a4c7d202f72081f7a74cb443e3c57b877a430170..2560ec8ef1132afe8116e003e9a10bdd164d7f63 100644 --- a/std/haxe/Int64.hx +++ b/std/haxe/Int64.hx @@ -65,11 +65,16 @@ abstract Int64(__Int64) from __Int64 to __Int64 { return x.low; } + @:deprecated('haxe.Int64.is() is deprecated. Use haxe.Int64.isInt64() instead') + inline public static function is(val:Dynamic):Bool { + return isInt64(val); + } + /** Returns whether the value `val` is of type `haxe.Int64` **/ - inline public static function is(val:Dynamic):Bool - return Std.is(val, __Int64); + inline public static function isInt64(val:Dynamic):Bool + return Std.isOfType(val, __Int64); /** Returns the high 32-bit word of `x`. @@ -124,7 +129,7 @@ abstract Int64(__Int64) from __Int64 to __Int64 { public static inline function toStr(x:Int64):String return x.toString(); - #if as3 public #else private #end function toString():String { + function toString():String { var i:Int64 = cast this; if (i == 0) return "0"; diff --git a/std/haxe/NativeStackTrace.hx b/std/haxe/NativeStackTrace.hx new file mode 100644 index 0000000000000000000000000000000000000000..d2ca55227d4d3eec744f3e4a5fd4a589326349a0 --- /dev/null +++ b/std/haxe/NativeStackTrace.hx @@ -0,0 +1,15 @@ +package haxe; + +import haxe.CallStack.StackItem; + +/** + Do not use manually. +**/ +@:dox(hide) +@:noCompletion +extern class NativeStackTrace { + static public function saveStack(exception:Any):Void; + static public function callStack():Any; + static public function exceptionStack():Any; + static public function toHaxe(nativeStackTrace:Any, skip:Int = 0):Array; +} \ No newline at end of file diff --git a/std/haxe/Resource.hx b/std/haxe/Resource.hx index 1769ffa1166df8acbf59115401b220b511b357e5..ed92050529fdb4e9a6a25db5fc31a242b8046dd7 100644 --- a/std/haxe/Resource.hx +++ b/std/haxe/Resource.hx @@ -50,14 +50,10 @@ class Resource { public static function getString(name:String):String { for (x in content) if (x.name == name) { - #if neko - return new String(x.data); - #else if (x.str != null) return x.str; var b:haxe.io.Bytes = haxe.crypto.Base64.decode(x.data); return b.toString(); - #end } return null; } @@ -71,25 +67,14 @@ class Resource { public static function getBytes(name:String):haxe.io.Bytes { for (x in content) if (x.name == name) { - #if neko - return haxe.io.Bytes.ofData(cast x.data); - #else if (x.str != null) return haxe.io.Bytes.ofString(x.str); return haxe.crypto.Base64.decode(x.data); - #end } return null; } static function __init__() { - #if neko - var tmp = untyped __resources__(); - content = untyped Array.new1(tmp, __dollar__asize(tmp)); - #elseif as3 - null; - #else content = untyped __resources__(); - #end } } diff --git a/std/haxe/Serializer.hx b/std/haxe/Serializer.hx index be4b24a7d9e9362d0bb26b0146179782936828da..f1ab2d06132dde068ebcb84fd610ba4c5f088a01 100644 --- a/std/haxe/Serializer.hx +++ b/std/haxe/Serializer.hx @@ -410,7 +410,7 @@ class Serializer { } } case TObject: - if (Std.is(v, Class)) { + if (Std.isOfType(v, Class)) { var className = Type.getClassName(v); #if (flash || cpp) // Currently, Enum and Class are the same for flash and cpp. @@ -421,7 +421,7 @@ class Serializer { #end buf.add("A"); serializeString(className); - } else if (Std.is(v, Enum)) { + } else if (Std.isOfType(v, Enum)) { buf.add("B"); serializeString(Type.getEnumName(v)); } else { diff --git a/std/haxe/Timer.hx b/std/haxe/Timer.hx index 17e984f514e1bdbb54cd695481ddb67dfccd9c25..a2cbf0532589b8c9d16345388196721af02b9618 100644 --- a/std/haxe/Timer.hx +++ b/std/haxe/Timer.hx @@ -39,7 +39,7 @@ package haxe; class Timer { #if (flash || js) private var id:Null; - #elseif java + #elseif (java && !jvm) private var timer:java.util.Timer; private var task:java.util.TimerTask; #else @@ -66,7 +66,7 @@ class Timer { #elseif js var me = this; id = untyped setInterval(function() me.run(), time_ms); - #elseif java + #elseif (java && !jvm) timer = new java.util.Timer(); timer.scheduleAtFixedRate(task = new TimerTask(this), haxe.Int64.ofInt(time_ms), haxe.Int64.ofInt(time_ms)); #else @@ -97,7 +97,7 @@ class Timer { untyped clearInterval(id); #end id = null; - #elseif java + #elseif (java && !jvm) if (timer != null) { timer.cancel(); timer = null; @@ -121,7 +121,7 @@ class Timer { var timer = new haxe.Timer(1000); // 1000ms delay timer.run = function() { ... } ``` - + Once bound, it can still be rebound to different functions until `this` Timer is stopped through a call to `this.stop`. **/ @@ -172,10 +172,13 @@ class Timer { public static inline function stamp():Float { #if flash return flash.Lib.getTimer() / 1000; - #elseif (neko || php) - return Sys.time(); #elseif js - return js.lib.Date.now() / 1000; + #if nodejs + var hrtime = js.Syntax.code('process.hrtime()'); // [seconds, remaining nanoseconds] + return hrtime[0] + hrtime[1] / 1e9; + #else + return @:privateAccess HxOverrides.now() / 1000; + #end #elseif cpp return untyped __global__.__time_stamp(); #elseif python @@ -188,7 +191,7 @@ class Timer { } } -#if java +#if (java && !jvm) @:nativeGen private class TimerTask extends java.util.TimerTask { var timer:Timer; diff --git a/std/haxe/Unserializer.hx b/std/haxe/Unserializer.hx index 2e62a5956a4fe6d4bfeed196890eac5753d54dec..8b983c9b4e310ffb95b93cd4f15d8b3848a5560f 100644 --- a/std/haxe/Unserializer.hx +++ b/std/haxe/Unserializer.hx @@ -188,7 +188,7 @@ class Unserializer { if (get(pos) == "g".code) break; var k:Dynamic = unserialize(); - if (!Std.is(k, String)) + if (!Std.isOfType(k, String)) throw "Invalid object key"; var v = unserialize(); Reflect.setField(o, k, v); diff --git a/std/haxe/ValueException.hx b/std/haxe/ValueException.hx new file mode 100644 index 0000000000000000000000000000000000000000..7cabec1b455d38bc19a5073bfc436730fd7aab3e --- /dev/null +++ b/std/haxe/ValueException.hx @@ -0,0 +1,38 @@ +package haxe; + +/** + An exception containing arbitrary value. + + This class is automatically used for throwing values, which don't extend `haxe.Exception` + or native exception type. + For example: + ```haxe + throw "Terrible error"; + ``` + will be compiled to + ```haxe + throw new ValueException("Terrible error"); + ``` +**/ +class ValueException extends Exception { + /** + Thrown value. + **/ + public var value(default,null):Any; + + public function new(value:Any, ?previous:Exception, ?native:Any):Void { + super(#if js js.Syntax.code('String({0})', value) #else Std.string(value) #end, previous, native); + this.value = value; + } + + /** + Extract an originally thrown value. + + This method must return the same value on subsequent calls. + Used internally for catching non-native exceptions. + Do _not_ override unless you know what you are doing. + **/ + override function unwrap():Any { + return value; + } +} \ No newline at end of file diff --git a/std/haxe/crypto/Md5.hx b/std/haxe/crypto/Md5.hx index 057c048a167463679b7c4ceba44da05fb194be1e..303913884b53d4e785924e8d0fa2a88f9d5e5ad9 100644 --- a/std/haxe/crypto/Md5.hx +++ b/std/haxe/crypto/Md5.hx @@ -27,19 +27,12 @@ package haxe.crypto; **/ class Md5 { public static function encode(s:String):String { - #if neko - return untyped new String(base_encode(make_md5(s.__s), "0123456789abcdef".__s)); - #else var m = new Md5(); var h = m.doEncode(str2blks(s)); return m.hex(h); - #end } public static function make(b:haxe.io.Bytes):haxe.io.Bytes { - #if neko - return haxe.io.Bytes.ofData(make_md5(b.getData())); - #else var h = new Md5().doEncode(bytes2blks(b)); var out = haxe.io.Bytes.alloc(16); var p = 0; @@ -50,13 +43,8 @@ class Md5 { out.set(p++, h[i] >>> 24); } return out; - #end } - #if neko - static var base_encode = neko.Lib.load("std", "base_encode", 2); - static var make_md5 = neko.Lib.load("std", "make_md5", 1); - #else /* * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message * Digest Algorithm, as defined in RFC 1321. @@ -277,5 +265,4 @@ class Md5 { } return [a, b, c, d]; } - #end } diff --git a/std/haxe/crypto/Sha256.hx b/std/haxe/crypto/Sha256.hx index cc144525e6b87fa2590aaebbd5dce4ddc46cd701..0fbf1a4f57f038220a9c421aef0ce67c6bdd1bd0 100644 --- a/std/haxe/crypto/Sha256.hx +++ b/std/haxe/crypto/Sha256.hx @@ -45,7 +45,7 @@ class Sha256 { return out; } - public function new() {} + function new() {} function doEncode(m:Array, l:Int):Array { var K:Array = [ diff --git a/std/haxe/display/Display.hx b/std/haxe/display/Display.hx index 5b4bf6f7b744ff17a21e6dea5efbe68135e18ae1..4ae6aa40ffbcab75727ba3fb5f3e53f921e9597a 100644 --- a/std/haxe/display/Display.hx +++ b/std/haxe/display/Display.hx @@ -23,8 +23,8 @@ package haxe.display; import haxe.display.JsonModuleTypes; -import haxe.display.Protocol; import haxe.display.Position; +import haxe.display.Protocol; /** Methods of the JSON-RPC-based `--display` protocol in Haxe 4. @@ -46,13 +46,18 @@ class DisplayMethods { /** The find references request is sent from the client to Haxe to find locations that reference the symbol at a given text document position. **/ - static inline var FindReferences = new HaxeRequestMethod("display/references"); + static inline var FindReferences = new HaxeRequestMethod("display/references"); /** The goto definition request is sent from the client to Haxe to resolve the definition location(s) of a symbol at a given text document position. **/ static inline var GotoDefinition = new HaxeRequestMethod("display/definition"); + /** + The goto implementation request is sent from the client to Haxe to resolve the implementation location(s) of a symbol at a given text document position. + **/ + static inline var GotoImplementation = new HaxeRequestMethod("display/implementation"); + /** The goto type definition request is sent from the client to Haxe to resolve the type definition location(s) of a symbol at a given text document position. **/ @@ -459,6 +464,28 @@ typedef CompletionItemResolveResult = Response<{ var item:DisplayItem; }>; +/** FindReferences **/ +typedef FindReferencesParams = PositionParams & { + var ?kind:FindReferencesKind; +} + +enum abstract FindReferencesKind(String) to String { + /** + Find only direct references to the requested symbol. + Does not look for references to parent or overriding methods. + **/ + var Direct = "direct"; + /** + Find references to the base field and all the overidding fields in the inheritance chain. + **/ + var WithBaseAndDescendants = "withBaseAndDescendants"; + /** + Find references to the requested field and references to all + descendants of the requested field. + **/ + var WithDescendants = "withDescendants"; +} + /** GotoDefinition **/ typedef GotoDefinitionResult = Response>; diff --git a/std/haxe/display/JsonModuleTypes.hx b/std/haxe/display/JsonModuleTypes.hx index 88ba7d88b63cfe368f04ab083f56cb9ab076ca8c..e55087bfc22fb97bcc35ac8e4778b81d12ebda90 100644 --- a/std/haxe/display/JsonModuleTypes.hx +++ b/std/haxe/display/JsonModuleTypes.hx @@ -299,6 +299,7 @@ typedef JsonClass = { var kind:JsonClassKind; var isInterface:Bool; var isExtern:Bool; + var isFinal:Bool; var superClass:Null; var interfaces:Array; var fields:JsonClassFields; diff --git a/std/haxe/display/Protocol.hx b/std/haxe/display/Protocol.hx index 99a27b57ba3ecdb97b822cff0883ab8e3af38f0f..44fd54593756848c995542fa09aa5a1201491cb1 100644 --- a/std/haxe/display/Protocol.hx +++ b/std/haxe/display/Protocol.hx @@ -50,8 +50,8 @@ typedef Version = { final major:Int; final minor:Int; final patch:Int; - final pre:String; - final build:String; + final ?pre:String; + final ?build:String; } typedef InitializeResult = Response<{ diff --git a/std/haxe/ds/BalancedTree.hx b/std/haxe/ds/BalancedTree.hx index 71350a22d479f5de8e356be6e52f81634afb14cc..315b176ae28f3566079fece40eb9641389ee0cdf 100644 --- a/std/haxe/ds/BalancedTree.hx +++ b/std/haxe/ds/BalancedTree.hx @@ -169,7 +169,7 @@ class BalancedTree implements haxe.Constraints.IMap { node.right); else balance(node.left, node.key, node.value, removeLoop(k, node.right)); } - function iteratorLoop(node:TreeNode, acc:Array) { + static function iteratorLoop(node:TreeNode, acc:Array) { if (node != null) { iteratorLoop(node.left, acc); acc.push(node.value); @@ -247,9 +247,6 @@ class TreeNode { public var key:K; public var value:V; - #if as3 - public - #end var _height:Int; public function new(l, k, v, r, h = -1) { diff --git a/std/haxe/ds/EnumValueMap.hx b/std/haxe/ds/EnumValueMap.hx index 742e3c1228f57778702fa079d5a3847eb45e93d1..ef231864cd090805d0a132d539017b12425fe4f8 100644 --- a/std/haxe/ds/EnumValueMap.hx +++ b/std/haxe/ds/EnumValueMap.hx @@ -55,7 +55,7 @@ class EnumValueMap extends haxe.ds.BalancedTree implements function compareArg(v1:Dynamic, v2:Dynamic):Int { return if (Reflect.isEnumValue(v1) && Reflect.isEnumValue(v2)) { compare(v1, v2); - } else if (Std.is(v1, Array) && Std.is(v2, Array)) { + } else if (Std.isOfType(v1, Array) && Std.isOfType(v2, Array)) { compareArgs(v1, v2); } else { Reflect.compare(v1, v2); diff --git a/std/haxe/ds/HashMap.hx b/std/haxe/ds/HashMap.hx index 0f6a346b09981bba782606ec19c7a3ea115117a6..4ca5e6f8f1531602bb4398dc0c17ebd651486d64 100644 --- a/std/haxe/ds/HashMap.hx +++ b/std/haxe/ds/HashMap.hx @@ -22,6 +22,8 @@ package haxe.ds; +import haxe.iterators.HashMapKeyValueIterator; + /** HashMap allows mapping of hashable objects to arbitrary values. @@ -40,7 +42,7 @@ abstract HashMap(HashMapData) { /** See `Map.set` **/ - public inline function set(k:K, v:V) { + @:arrayAccess public inline function set(k:K, v:V) { this.keys.set(k.hashCode(), k); this.values.set(k.hashCode(), v); } @@ -48,7 +50,7 @@ abstract HashMap(HashMapData) { /** See `Map.get` **/ - public inline function get(k:K) { + @:arrayAccess public inline function get(k:K) { return this.values.get(k.hashCode()); } @@ -91,6 +93,13 @@ abstract HashMap(HashMapData) { return this.values.iterator(); } + /** + See `Map.keyValueIterator` + **/ + public inline function keyValueIterator():HashMapKeyValueIterator { + return new HashMapKeyValueIterator(cast this); + } + /** See `Map.clear` **/ diff --git a/std/haxe/ds/IntMap.hx b/std/haxe/ds/IntMap.hx index 713eabca11c885294b2bea65da8959807faa3249..8197e098ee74a03e8204e9cba2eac67b35b98c07 100644 --- a/std/haxe/ds/IntMap.hx +++ b/std/haxe/ds/IntMap.hx @@ -33,27 +33,27 @@ extern class IntMap implements haxe.Constraints.IMap { /** Creates a new IntMap. **/ - public function new():Void; + function new():Void; /** See `Map.set` **/ - public function set(key:Int, value:T):Void; + function set(key:Int, value:T):Void; /** See `Map.get` **/ - public function get(key:Int):Null; + function get(key:Int):Null; /** See `Map.exists` **/ - public function exists(key:Int):Bool; + function exists(key:Int):Bool; /** See `Map.remove` **/ - public function remove(key:Int):Bool; + function remove(key:Int):Bool; /** See `Map.keys` @@ -61,7 +61,7 @@ extern class IntMap implements haxe.Constraints.IMap { (cs, java) Implementation detail: Do not `set()` any new value while iterating, as it may cause a resize, which will break iteration. **/ - public function keys():Iterator; + function keys():Iterator; /** See `Map.iterator` @@ -69,31 +69,31 @@ extern class IntMap implements haxe.Constraints.IMap { (cs, java) Implementation detail: Do not `set()` any new value while iterating, as it may cause a resize, which will break iteration. **/ - public function iterator():Iterator; + function iterator():Iterator; /** See `Map.keyValueIterator` **/ #if eval - @:runtime public inline function keyValueIterator():KeyValueIterator { + @:runtime inline function keyValueIterator():KeyValueIterator { return new haxe.iterators.MapKeyValueIterator(this); } #else - public function keyValueIterator():KeyValueIterator; + function keyValueIterator():KeyValueIterator; #end /** See `Map.copy` **/ - public function copy():IntMap; + function copy():IntMap; /** See `Map.toString` **/ - public function toString():String; + function toString():String; /** See `Map.clear` **/ - public function clear():Void; + function clear():Void; } diff --git a/std/haxe/ds/ObjectMap.hx b/std/haxe/ds/ObjectMap.hx index ae613db8ce38140e620f72867010e36303e3b7a7..ebae1d4950fda7737ebf72fcbae7b0397c7e5956 100644 --- a/std/haxe/ds/ObjectMap.hx +++ b/std/haxe/ds/ObjectMap.hx @@ -36,27 +36,27 @@ extern class ObjectMap implements haxe.Constraints.IMap { /** Creates a new ObjectMap. **/ - public function new():Void; + function new():Void; /** See `Map.set` **/ - public function set(key:K, value:V):Void; + function set(key:K, value:V):Void; /** See `Map.get` **/ - public function get(key:K):Null; + function get(key:K):Null; /** See `Map.exists` **/ - public function exists(key:K):Bool; + function exists(key:K):Bool; /** See `Map.remove` **/ - public function remove(key:K):Bool; + function remove(key:K):Bool; /** See `Map.keys` @@ -64,7 +64,7 @@ extern class ObjectMap implements haxe.Constraints.IMap { (cs, java) Implementation detail: Do not `set()` any new value while iterating, as it may cause a resize, which will break iteration. **/ - public function keys():Iterator; + function keys():Iterator; /** See `Map.iterator` @@ -72,31 +72,31 @@ extern class ObjectMap implements haxe.Constraints.IMap { (cs, java) Implementation detail: Do not `set()` any new value while iterating, as it may cause a resize, which will break iteration. **/ - public function iterator():Iterator; + function iterator():Iterator; /** See `Map.keyValueIterator` **/ #if eval - @:runtime public inline function keyValueIterator():KeyValueIterator { + @:runtime inline function keyValueIterator():KeyValueIterator { return new haxe.iterators.MapKeyValueIterator(this); } #else - public function keyValueIterator():KeyValueIterator; + function keyValueIterator():KeyValueIterator; #end /** See `Map.copy` **/ - public function copy():ObjectMap; + function copy():ObjectMap; /** See `Map.toString` **/ - public function toString():String; + function toString():String; /** See `Map.clear` **/ - public function clear():Void; + function clear():Void; } diff --git a/std/haxe/ds/ReadOnlyArray.hx b/std/haxe/ds/ReadOnlyArray.hx index 86197bc6e033b9b7e3852e1d038a5793496ac036..1ed85ae0cc1c2388a4b55c0b3c4eae0936892d9c 100644 --- a/std/haxe/ds/ReadOnlyArray.hx +++ b/std/haxe/ds/ReadOnlyArray.hx @@ -31,7 +31,7 @@ package haxe.ds; and the reference can be obtained with a `cast`. **/ @:forward(concat, copy, filter, indexOf, iterator, join, lastIndexOf, map, slice, toString) -abstract ReadOnlyArray(Array) from Array { +abstract ReadOnlyArray(Array) from Array to Iterable { /** The length of `this` Array. **/ diff --git a/std/haxe/ds/StringMap.hx b/std/haxe/ds/StringMap.hx index 708fb619abb5f02d29e27f4f26e236839efcd110..11fb14a5c538f45929be9508183a26f474434200 100644 --- a/std/haxe/ds/StringMap.hx +++ b/std/haxe/ds/StringMap.hx @@ -33,27 +33,27 @@ extern class StringMap implements haxe.Constraints.IMap { /** Creates a new StringMap. **/ - public function new():Void; + function new():Void; /** See `Map.set` **/ - public function set(key:String, value:T):Void; + function set(key:String, value:T):Void; /** See `Map.get` **/ - public function get(key:String):Null; + function get(key:String):Null; /** See `Map.exists` **/ - public function exists(key:String):Bool; + function exists(key:String):Bool; /** See `Map.remove` **/ - public function remove(key:String):Bool; + function remove(key:String):Bool; /** See `Map.keys` @@ -61,7 +61,7 @@ extern class StringMap implements haxe.Constraints.IMap { (cs, java) Implementation detail: Do not `set()` any new value while iterating, as it may cause a resize, which will break iteration. **/ - public function keys():Iterator; + function keys():Iterator; /** See `Map.iterator` @@ -69,31 +69,31 @@ extern class StringMap implements haxe.Constraints.IMap { (cs, java) Implementation detail: Do not `set()` any new value while iterating, as it may cause a resize, which will break iteration. **/ - public function iterator():Iterator; + function iterator():Iterator; /** See `Map.keyValueIterator` **/ #if eval - @:runtime public inline function keyValueIterator():KeyValueIterator { + @:runtime inline function keyValueIterator():KeyValueIterator { return new haxe.iterators.MapKeyValueIterator(this); } #else - public function keyValueIterator():KeyValueIterator; + function keyValueIterator():KeyValueIterator; #end /** See `Map.copy` **/ - public function copy():StringMap; + function copy():StringMap; /** See `Map.toString` **/ - public function toString():String; + function toString():String; /** See `Map.clear` **/ - public function clear():Void; + function clear():Void; } diff --git a/std/haxe/ds/Vector.hx b/std/haxe/ds/Vector.hx index 50eff3a974b412bc41266e192198e487d4c38b96..05a4e615673466ea7de85f127c35983ec0b39824 100644 --- a/std/haxe/ds/Vector.hx +++ b/std/haxe/ds/Vector.hx @@ -241,9 +241,6 @@ abstract Vector(VectorData) { If `array` is null, the result is unspecified. **/ - #if as3 - extern - #end static public inline function fromArrayCopy(array:Array):Vector { #if python return cast array.copy(); diff --git a/std/haxe/format/JsonPrinter.hx b/std/haxe/format/JsonPrinter.hx index 093b037754daf212ae736978ba71b382cd3f2cde..f0471164e9f1e6e70e807b7919fcd3500e2a7be0 100644 --- a/std/haxe/format/JsonPrinter.hx +++ b/std/haxe/format/JsonPrinter.hx @@ -87,7 +87,7 @@ class JsonPrinter { case TObject: objString(v); case TInt: - add(#if (as3 || jvm) Std.string(v) #else v #end); + add(#if (jvm || hl) Std.string(v) #else v #end); case TFloat: add(Math.isFinite(v) ? Std.string(v) : 'null'); case TFunction: @@ -131,7 +131,7 @@ class JsonPrinter { var i:Dynamic = Type.enumIndex(v); add(i); case TBool: - add(#if (php || as3 || jvm) (v ? 'true' : 'false') #else v #end); + add(#if (php || jvm || hl) (v ? 'true' : 'false') #else v #end); case TNull: add('null'); } diff --git a/std/haxe/http/HttpJs.hx b/std/haxe/http/HttpJs.hx index e768932329e39fe90857f4e0021e5279e06314b4..316a5e259e9c12d1675676e93cf6c943e00444cd 100644 --- a/std/haxe/http/HttpJs.hx +++ b/std/haxe/http/HttpJs.hx @@ -58,7 +58,7 @@ class HttpJs extends haxe.http.HttpBase { if (r.readyState != 4) return; var s = try r.status catch (e:Dynamic) null; - if (s == 0 && js.Browser.supported) { + if (s == 0 && js.Browser.supported && js.Browser.location != null) { // If the request is local and we have data: assume a success (jQuery approach): var protocol = js.Browser.location.protocol.toLowerCase(); var rlocalProtocol = ~/^(?:about|app|app-storage|.+-extension|file|res|widget):$/; @@ -74,7 +74,7 @@ class HttpJs extends haxe.http.HttpBase { if (s != null && s >= 200 && s < 400) { req = null; success(Bytes.ofData(r.response)); - } else if (s == null) { + } else if (s == null || (s == 0 && r.response == null)) { req = null; onError("Failed to connect or resolve host"); } else @@ -87,7 +87,7 @@ class HttpJs extends haxe.http.HttpBase { onError("Unknown host"); default: req = null; - responseBytes = Bytes.ofData(r.response); + responseBytes = r.response != null ? Bytes.ofData(r.response) : null; onError("Http Error #" + r.status); } }; diff --git a/std/haxe/io/Error.hx b/std/haxe/io/Error.hx index 7dece351d33a1fb81d1344c07e1a0a11ad62c84e..beb00995a317293d08c75c756094b09c12401f89 100644 --- a/std/haxe/io/Error.hx +++ b/std/haxe/io/Error.hx @@ -25,6 +25,9 @@ package haxe.io; /** The possible IO errors that can occur **/ +#if eval +@:keep +#end enum Error { /** The IO is set into nonblocking mode and some data cannot be read or written **/ Blocked; diff --git a/std/haxe/io/StringInput.hx b/std/haxe/io/StringInput.hx index 7d058a4497a7ad383145022a674cfa3d9b9077c6..c2beb566b1e00d665e39fe851e7c88b54744cdb2 100644 --- a/std/haxe/io/StringInput.hx +++ b/std/haxe/io/StringInput.hx @@ -24,11 +24,6 @@ package haxe.io; class StringInput extends BytesInput { public function new(s:String) { - #if neko - // don't copy the string - super(neko.Lib.bytesReference(s)); - #else super(haxe.io.Bytes.ofString(s)); - #end } } diff --git a/std/haxe/iterators/ArrayIterator.hx b/std/haxe/iterators/ArrayIterator.hx new file mode 100644 index 0000000000000000000000000000000000000000..a02059b634d848ddff8f953218107cf7d2982b38 --- /dev/null +++ b/std/haxe/iterators/ArrayIterator.hx @@ -0,0 +1,55 @@ +/* + * Copyright (C)2005-2018 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package haxe.iterators; + +/** + This iterator is used only when `Array` is passed to `Iterable` +**/ +class ArrayIterator { + final array:Array; + var current:Int = 0; + + /** + Create a new `ArrayIterator`. + **/ + #if !hl inline #end + public function new(array:Array) { + this.array = array; + } + + /** + See `Iterator.hasNext` + **/ + #if !hl inline #end + public function hasNext() { + return current < array.length; + } + + /** + See `Iterator.next` + **/ + #if !hl inline #end + public function next() { + return array[current++]; + } +} diff --git a/std/haxe/iterators/ArrayKeyValueIterator.hx b/std/haxe/iterators/ArrayKeyValueIterator.hx new file mode 100644 index 0000000000000000000000000000000000000000..5261b7d32101f7360ea66e63b62ab674a765126e --- /dev/null +++ b/std/haxe/iterators/ArrayKeyValueIterator.hx @@ -0,0 +1,44 @@ +/* + * Copyright (C)2005-2018 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package haxe.iterators; + +@:ifFeature("anon_read.keyValueIterator", "dynamic_read.keyValueIterator") +class ArrayKeyValueIterator { + var current:Int = 0; + var array:Array; + + #if !hl inline #end + public function new(array:Array) { + this.array = array; + } + + #if !hl inline #end + public function hasNext():Bool { + return current < array.length; + } + + #if !hl inline #end + public function next():{key:Int,value:T} { + return {value:array[current], key:current++}; + } +} diff --git a/std/haxe/iterators/HashMapKeyValueIterator.hx b/std/haxe/iterators/HashMapKeyValueIterator.hx new file mode 100644 index 0000000000000000000000000000000000000000..da6e70696d68620be3a552434f5cc41f73d91515 --- /dev/null +++ b/std/haxe/iterators/HashMapKeyValueIterator.hx @@ -0,0 +1,28 @@ +package haxe.iterators; + +import haxe.ds.HashMap; + +class HashMapKeyValueIterator { + final map:HashMap; + final keys:Iterator; + + public inline function new(map:HashMap) { + this.map = map; + this.keys = map.keys(); + } + + /** + See `Iterator.hasNext` + **/ + public inline function hasNext():Bool { + return keys.hasNext(); + } + + /** + See `Iterator.next` + **/ + public inline function next():{key:K, value:V} { + var key = keys.next(); + return {value: map.get(key), key: key}; + } +} diff --git a/std/haxe/iterators/StringIterator.hx b/std/haxe/iterators/StringIterator.hx index 7d7005db22adb49bed6e765441b4195cd11a0baf..46d3a421857e30c84bb8940094f4158e1948a24e 100644 --- a/std/haxe/iterators/StringIterator.hx +++ b/std/haxe/iterators/StringIterator.hx @@ -23,33 +23,33 @@ package haxe.iterators; /** - This iterator can be used to iterate over char codes in a string. + This iterator can be used to iterate over char codes in a string. - Note that char codes may differ across platforms because of different - internal encoding of strings in different of runtimes. -**/ + Note that char codes may differ across platforms because of different + internal encoding of strings in different of runtimes. + **/ class StringIterator { - var offset = 0; - var s:String; + var offset = 0; + var s:String; - /** - Create a new `StringIterator` over String `s`. - **/ - public inline function new(s:String) { - this.s = s; - } + /** + Create a new `StringIterator` over String `s`. + **/ + public inline function new(s:String) { + this.s = s; + } - /** - See `Iterator.hasNext` - **/ - public inline function hasNext() { - return offset < s.length; - } + /** + See `Iterator.hasNext` + **/ + public inline function hasNext() { + return offset < s.length; + } - /** - See `Iterator.next` - **/ - public inline function next() { - return StringTools.fastCodeAt(s, offset++); - } + /** + See `Iterator.next` + **/ + public inline function next() { + return StringTools.fastCodeAt(s, offset++); + } } diff --git a/std/haxe/macro/Compiler.hx b/std/haxe/macro/Compiler.hx index a4a9e6e9bebca4c1aeb1932398acca7ca85d3d5c..52b6a14ad94bb316556d55a5eb4f51982911731e 100644 --- a/std/haxe/macro/Compiler.hx +++ b/std/haxe/macro/Compiler.hx @@ -419,7 +419,7 @@ class Compiler { /** Enables null safety for a type or a package. - @param path A package, module or sub-type dot path to keep. + @param path A package, module or sub-type dot path to enable null safety for. @param recursive If true, recurses into sub-packages for package paths. **/ public static function nullSafety(path:String, mode:NullSafetyMode = Loose, recursive:Bool = true) { @@ -486,8 +486,11 @@ class Compiler { var f = try sys.io.File.getContent(Context.resolvePath(file)) catch (e:Dynamic) Context.error(Std.string(e), Context.currentPos()); var p = Context.currentPos(); - var magic = if (Context.defined("js")) "__js__" else "__lua__"; - {expr: EUntyped({expr: ECall({expr: EConst(CIdent(magic)), pos: p}, [{expr: EConst(CString(f)), pos: p}]), pos: p}), pos: p}; + if(Context.defined("js")) { + macro @:pos(p) js.Syntax.plainCode($v{f}); + } else { + macro @:pos(p) untyped __lua__($v{f}); + } case Top | Closure: @:privateAccess Context.includeFile(file, position); macro {}; @@ -523,14 +526,9 @@ enum abstract NullSafetyMode(String) to String { **/ var Off; - /** - Full scale null safety. - **/ - var Strict; - /** Loose safety. - If an expression is checked ` != null`, then it's considered safe even if it could be modified after the check. + If an expression is checked `!= null`, then it's considered safe even if it could be modified after the check. E.g. ```haxe function example(o:{field:Null}) { @@ -546,4 +544,34 @@ enum abstract NullSafetyMode(String) to String { ``` **/ var Loose; + + /** + Full scale null safety. + If a field is checked `!= null` it stays safe until a call is made or any field of any object is reassigned, + because that could potentially alter an object of the checked field. + E.g. + ```haxe + function example(o:{field:Null}, b:{o:{field:Null}}) { + if(o.field != null) { + var notNullable:String = o.field; //no error + someCall(); + var notNullable:String = o.field; // Error! + } + if(o.field != null) { + var notNullable:String = o.field; //no error + b.o = {field:null}; + var notNullable:String = o.field; // Error! + } + } + ``` + **/ + var Strict; + + /** + Full scale null safety for a multi-threaded environment. + With this mode checking a field `!= null` does not make it safe, because it could be changed from another thread + at the same time or immediately after the check. + The only nullable thing could be safe are local variables. + **/ + var StrictThreaded; } diff --git a/std/haxe/macro/Context.hx b/std/haxe/macro/Context.hx index c97d8aae6004880556054bbd40908519c1a55c8e..7df7072b219fe62176e2a4d2744fdf3bb18b5c8f 100644 --- a/std/haxe/macro/Context.hx +++ b/std/haxe/macro/Context.hx @@ -112,6 +112,13 @@ class Context { return load("class_path", 0)(); } + /** + Check if current display position is within `pos`. + **/ + public static function containsDisplayPosition(pos:Position):Bool { + return load("contains_display_position", 1)(pos); + } + /** Returns the position at which the macro was called. **/ @@ -284,7 +291,7 @@ class Context { The resolution follows the usual class path rules where the last declared class path has priority. - If no module can be found, `null` is returned. + If no module can be found, an exception of type `String` is thrown. **/ public static function getModule(name:String):Array { return load("get_module", 1)(name); @@ -585,6 +592,24 @@ class Context { load("register_module_dependency", 2)(modulePath, externFile); } + /** + Creates a timer which will be printed in the compilation report + if `--times` compilation argument is set. + + Note that a timer may be omitted from the report if the amount of time + measured is too small. + + This method immediately starts a timer and returns a function to stop it: + ``` + var stopTimer = haxe.macro.Context.timer("my heavy task"); + runTask(); + stopTimer(); + ``` + **/ + public static function timer(id:String):()->Void { + return load("timer", 1)(id); + } + @:deprecated public static function registerModuleReuseCall(modulePath:String, macroCall:String) { throw "This method is no longer supported. See https://github.com/HaxeFoundation/haxe/issues/5746"; diff --git a/std/haxe/macro/Expr.hx b/std/haxe/macro/Expr.hx index 98212bd4926034a7de3f005972d207e768bf6ada..bb15ac30982fff0a8da87b112df65b438b340e7b 100644 --- a/std/haxe/macro/Expr.hx +++ b/std/haxe/macro/Expr.hx @@ -81,8 +81,9 @@ enum Constant { Represents a regular expression literal. Example: `~/haxe/i` - * The first argument _haxe_ is a string with regular expression pattern. - * The second argument _i_ is a string with regular expression flags. + + - The first argument `haxe` is a string with regular expression pattern. + - The second argument `i` is a string with regular expression flags. @see https://haxe.org/manual/std-regex.html **/ @@ -195,17 +196,7 @@ enum Binop { OpMod; /** - `+=` - `-=` - `/=` - `*=` - `<<=` - `>>=` - `>>>=` - `|=` - `&=` - `^=` - `%=` + `+=` `-=` `/=` `*=` `<<=` `>>=` `>>>=` `|=` `&=` `^=` `%=` **/ OpAssignOp(op:Binop); @@ -328,7 +319,7 @@ typedef Var = { /** Represents a catch in the AST. - @https://haxe.org/manual/expression-try-catch.html + @see https://haxe.org/manual/expression-try-catch.html **/ typedef Catch = { /** @@ -339,7 +330,7 @@ typedef Catch = { /** The type of the catch. **/ - var type:ComplexType; + var ?type:ComplexType; /** The expression of the catch. @@ -390,10 +381,12 @@ enum FunctionKind { Anonymous function **/ FAnonymous; + /** Named function **/ FNamed(name:String, ?inlined:Bool); + /** Arrow function **/ @@ -452,13 +445,13 @@ enum ExprDef { /** An unary operator `op` on `e`: - * e++ (op = OpIncrement, postFix = true) - * e-- (op = OpDecrement, postFix = true) - * ++e (op = OpIncrement, postFix = false) - * --e (op = OpDecrement, postFix = false) - * -e (op = OpNeg, postFix = false) - * !e (op = OpNot, postFix = false) - * ~e (op = OpNegBits, postFix = false) + - `e++` (`op = OpIncrement, postFix = true`) + - `e--` (`op = OpDecrement, postFix = true`) + - `++e` (`op = OpIncrement, postFix = false`) + - `--e` (`op = OpDecrement, postFix = false`) + - `-e` (`op = OpNeg, postFix = false`) + - `!e` (`op = OpNot, postFix = false`) + - `~e` (`op = OpNegBits, postFix = false`) **/ EUnop(op:Unop, postFix:Bool, e:Expr); @@ -483,20 +476,22 @@ enum ExprDef { EFor(it:Expr, expr:Expr); /** - An `if(econd) eif` or `if(econd) eif else eelse` expression. + An `if (econd) eif` or `if (econd) eif else eelse` expression. **/ EIf(econd:Expr, eif:Expr, eelse:Null); /** Represents a `while` expression. + When `normalWhile` is `true` it is `while (...)`. + When `normalWhile` is `false` it is `do {...} while (...)`. **/ EWhile(econd:Expr, e:Expr, normalWhile:Bool); /** Represents a `switch` expression with related cases and an optional. - `default` case if edef != null. + `default` case if `edef != null`. **/ ESwitch(e:Expr, cases:Array, edef:Null); @@ -536,12 +531,12 @@ enum ExprDef { ECast(e:Expr, t:Null); /** - Internally used to provide completion. + Used internally to provide completion. **/ EDisplay(e:Expr, displayKind:DisplayKind); /** - Internally used to provide completion. + Used internally to provide completion. **/ EDisplayNew(t:TypePath); @@ -640,7 +635,7 @@ typedef TypePath = { /** Sub is set on module sub-type access: - `pack.Module.Type` has name = Module, sub = Type, if available. + `pack.Module.Type` has `name = "Module"`, `sub = "Type"`, if available. **/ var ?sub:Null; } @@ -653,14 +648,7 @@ typedef TypePath = { in the normal case it's `TPType`. **/ enum TypeParam { - /** - - **/ TPType(t:ComplexType); - - /** - - **/ TPExpr(e:Expr); } @@ -849,7 +837,7 @@ enum Access { AInline; /** - Macros access modifier. Allows expression macro functions. These are + Macro access modifier. Allows expression macro functions. These are normal functions which are executed as soon as they are typed. **/ AMacro; @@ -970,30 +958,18 @@ enum TypeDefKind { /** This error can be used to handle or produce compilation errors in macros. **/ -class Error { - /** - The error message. - **/ - public var message:String; - +class Error extends Exception { /** The position of the error. **/ - public var pos:Expr.Position; + public var pos:Position; /** Instantiates an error with given message and position. **/ - public function new(m, p) { - this.message = m; - this.pos = p; - } - - /** - Returns the string representation of the error. - **/ - function toString() { - return message; + public function new(message:String, pos:Position, ?previous:Exception) { + super(message, previous); + this.pos = pos; } } diff --git a/std/haxe/macro/Printer.hx b/std/haxe/macro/Printer.hx index 4c73ed9c0cd5dab4a3b6df8125e6fc3bcb63b77a..382a37cec7237a7883729780434b99512375e395 100644 --- a/std/haxe/macro/Printer.hx +++ b/std/haxe/macro/Printer.hx @@ -120,14 +120,19 @@ class Printer { return switch (ct) { case TPath(tp): printTypePath(tp); case TFunction(args, ret): - if (args.length == 1 && !(args[0].match(TNamed(_, _)) || args[0].match(TFunction(_, _)))) { - // This special case handles an ambigity between the old function syntax and the new - // (T) -> T parses as `TFunction([TParent(TPath)], ...`, rather than `TFunction([TPath], ...` - // We forgo patenthesis in this case so that (T) -> T doesn't get round-tripped to ((T)) -> T - printComplexType(args[0]) + " -> " + printComplexType(ret); - } else { - '(${args.map(printComplexType).join(", ")})' + " -> " + printComplexType(ret); + var wrapArgumentsInParentheses = switch args { + // type `:(a:X) -> Y` has args as [TParent(TNamed(...))], i.e `a:X` gets wrapped in `TParent()`. We don't add parentheses to avoid printing `:((a:X)) -> Y` + case [TParent(t)]: false; + // this case catches a single argument that's a type-path, so that `X -> Y` prints `X -> Y` not `(X) -> Y` + case [TPath(_) | TOptional(TPath(_))]: false; + default: true; } + var argStr = args.map(printComplexType).join(", "); + (wrapArgumentsInParentheses ? '($argStr)' : argStr) + " -> " + (switch ret { + // wrap return type in parentheses if it's also a function + case TFunction(_): '(${printComplexType(ret)})'; + default: (printComplexType(ret): String); + }); case TAnonymous(fields): "{ " + [for (f in fields) printField(f) + "; "].join("") + "}"; case TParent(ct): "(" + printComplexType(ct) + ")"; case TOptional(ct): "?" + printComplexType(ct); @@ -152,7 +157,12 @@ class Printer { case AExtern: "extern"; } - public function printField(field:Field) + public function printField(field:Field) { + inline function orderAccess(access: Array) { + // final should always be printed last + // (does not modify input array) + return access.has(AFinal) ? access.filter(a -> !a.match(AFinal)).concat([AFinal]) : access; + } return (field.doc != null && field.doc != "" ? "/**\n" + tabs @@ -163,12 +173,13 @@ class Printer { + "**/\n" + tabs : "") + (field.meta != null && field.meta.length > 0 ? field.meta.map(printMetadata).join('\n$tabs') + '\n$tabs' : "") - + (field.access != null && field.access.length > 0 ? field.access.map(printAccess).join(" ") + " " : "") + + (field.access != null && field.access.length > 0 ? orderAccess(field.access).map(printAccess).join(" ") + " " : "") + switch (field.kind) { case FVar(t, eo): ((field.access != null && field.access.has(AFinal)) ? '' : 'var ') + '${field.name}' + opt(t, printComplexType, " : ") + opt(eo, printExpr, " = "); case FProp(get, set, t, eo): 'var ${field.name}($get, $set)' + opt(t, printComplexType, " : ") + opt(eo, printExpr, " = "); case FFun(func): 'function ${field.name}' + printFunction(func); } + } public function printTypeParamDecl(tpd:TypeParamDecl) return tpd.name @@ -178,13 +189,19 @@ class Printer { public function printFunctionArg(arg:FunctionArg) return (arg.opt ? "?" : "") + arg.name + opt(arg.type, printComplexType, ":") + opt(arg.value, printExpr, " = "); - public function printFunction(func:Function) + public function printFunction(func:Function, ?kind:FunctionKind) { + var skipParentheses = switch func.args { + case [{ type:null }]: kind == FArrow; + case _: false; + } return (func.params == null ? "" : func.params.length > 0 ? "<" + func.params.map(printTypeParamDecl).join(", ") + ">" : "") - + "(" + + (skipParentheses ? "" : "(") + func.args.map(printFunctionArg).join(", ") - + ")" + + (skipParentheses ? "" : ")") + + (kind == FArrow ? " ->" : "") + opt(func.ret, printComplexType, ":") + opt(func.expr, printExpr, " "); + } public function printVar(v:Var) return v.name + opt(v.type, printComplexType, ":") + opt(v.expr, printExpr, " = "); @@ -218,7 +235,7 @@ class Printer { case EUnop(op, true, e1): printExpr(e1) + printUnop(op); case EUnop(op, false, e1): printUnop(op) + printExpr(e1); case EFunction(FNamed(no,inlined), func): (inlined ? 'inline ' : '') + 'function $no' + printFunction(func); - case EFunction(_, func): "function" + printFunction(func); + case EFunction(kind, func): (kind != FArrow ? "function" : "") + printFunction(func, kind); case EVars(vl): "var " + vl.map(printVar).join(", "); case EBlock([]): '{ }'; case EBlock(el): @@ -244,7 +261,7 @@ class Printer { tabs = old; s + '\n$tabs}'; case ETry(e1, cl): - 'try ${printExpr(e1)}' + cl.map(function(c) return ' catch(${c.name}:${printComplexType(c.type)}) ${printExpr(c.expr)}').join(""); + 'try ${printExpr(e1)}' + cl.map(function(c) return ' catch(${c.name}${c.type == null ? '' : (':' + printComplexType(c.type))}) ${printExpr(c.expr)}').join(""); case EReturn(eo): "return" + opt(eo, printExpr, " "); case EBreak: "break"; case EContinue: "continue"; @@ -256,6 +273,7 @@ class Printer { case EDisplayNew(tp): '#DISPLAY(${printTypePath(tp)})'; case ETernary(econd, eif, eelse): '${printExpr(econd)} ? ${printExpr(eif)} : ${printExpr(eelse)}'; case ECheckType(e1, ct): '(${printExpr(e1)} : ${printComplexType(ct)})'; + case EMeta({ name:":implicitReturn" }, { expr:EReturn(e1) }): printExpr(e1); case EMeta(meta, e1): printMetadata(meta) + " " + printExpr(e1); } diff --git a/std/haxe/macro/TypeTools.hx b/std/haxe/macro/TypeTools.hx index eadf70149416a7685939632d994e9853770562f1..f75ac52940b42fc332abe9a2f56900137efed9ad 100644 --- a/std/haxe/macro/TypeTools.hx +++ b/std/haxe/macro/TypeTools.hx @@ -307,7 +307,7 @@ class TypeTools { t: f(arg.t) }), f(ret)); case TAnonymous(an): - t; // TODO: Ref? + TAnonymous(Context.load("map_anon_ref", 2)(an, f)); case TDynamic(t2): t == t2 ? t : TDynamic(f(t2)); case TLazy(ft): diff --git a/std/haxe/rtti/CType.hx b/std/haxe/rtti/CType.hx index e2e4ecbd4eb22aa696b3828bf9c091c5ab40ee44..9ff975b9a800546b9d8535fddb32d19b250bdb08 100644 --- a/std/haxe/rtti/CType.hx +++ b/std/haxe/rtti/CType.hx @@ -22,8 +22,6 @@ package haxe.rtti; -import haxe.ds.List; - /** The (dot-)path of the runtime type. **/ @@ -108,12 +106,12 @@ typedef ClassField = { var type:CType; /** - Whether or not the field is public. + Whether or not the field is `public`. **/ var isPublic:Bool; /** - Whether or not the field is final. + Whether or not the field is `final`. **/ var isFinal:Bool; @@ -130,13 +128,13 @@ typedef ClassField = { var doc:Null; /** - The [read access](https://haxe.org/manual/dictionary.html#define-read-access) + The [read access](https://haxe.org/manual/class-field-property.html#define-read-access) behavior of the field. **/ var get:Rights; /** - The [write access](https://haxe.org/manual/dictionary.html#define-write-access) + The [write access](https://haxe.org/manual/class-field-property.html#define-write-access) behavior of the field. **/ var set:Rights; @@ -211,7 +209,7 @@ typedef TypeInfos = { var doc:Null; /** - Whether or not the type is [private](https://haxe.org/manual/dictionary.html#define-private-type). + Whether or not the type is [`private`](https://haxe.org/manual/type-system-module-sub-types.html#define-private-type). **/ var isPrivate:Bool; @@ -236,6 +234,11 @@ typedef Classdef = TypeInfos & { **/ var isExtern:Bool; + /** + Whether or not the class is `final`. + **/ + var isFinal:Bool; + /** Whether or not the class is actually an [interface](https://haxe.org/manual/types-interfaces.html). **/ @@ -542,7 +545,7 @@ class TypeApi { } /** - The CTypeTools class contains some extra functionalities for handling + The `CTypeTools` class contains some extra functionalities for handling `CType` instances. **/ class CTypeTools { diff --git a/std/haxe/rtti/Meta.hx b/std/haxe/rtti/Meta.hx index adca8dc0c239ad62686bcba877c600f28f2271f3..89c046d2be59cfdc001b82649c89bbeaa9cf53c4 100644 --- a/std/haxe/rtti/Meta.hx +++ b/std/haxe/rtti/Meta.hx @@ -48,8 +48,6 @@ class Meta { return java.Lib.toNativeType(t).isInterface(); #elseif cs return cs.Lib.toNativeType(t).IsInterface; - #elseif (flash && as3) - return untyped flash.Lib.describeType(t).factory.extendsClass.length() == 0; #else throw "Something went wrong"; #end @@ -58,9 +56,9 @@ class Meta { private static function getMeta(t:Dynamic):MetaObject { #if php return php.Boot.getMeta(t.phpClassName); - #elseif (java || cs || (flash && as3)) + #elseif (java || cs) var ret = Reflect.field(t, "__meta__"); - if (ret == null && Std.is(t, Class)) { + if (ret == null && Std.isOfType(t, Class)) { if (isInterface(t)) { var name = Type.getClassName(t), cls = Type.resolveClass(name + '_HxMeta'); diff --git a/std/haxe/rtti/XmlParser.hx b/std/haxe/rtti/XmlParser.hx index 7773fbef7f0bc718b0a567747303ea4708c5f44b..8f7ac5a9bf4c42c1ba999a9506317452d0d4f106 100644 --- a/std/haxe/rtti/XmlParser.hx +++ b/std/haxe/rtti/XmlParser.hx @@ -168,8 +168,8 @@ class XmlParser { break; } if (found == null) - return false; // don't allow by-platform constructor ? - if (curplatform != null) + e.constructors.push(c2); + else if (curplatform != null) found.platforms.push(curplatform); } return true; @@ -371,12 +371,17 @@ class XmlParser { var fields = new Array(); var statics = new Array(); var meta = []; + var isInterface = x.x.exists("interface"); for (c in x.elements) switch (c.name) { case "haxe_doc": doc = c.innerData; case "extends": - csuper = xpath(c); + if (isInterface) { + interfaces.push(xpath(c)); + } else { + csuper = xpath(c); + } case "implements": interfaces.push(xpath(c)); case "haxe_dynamic": @@ -396,7 +401,8 @@ class XmlParser { doc: doc, isPrivate: x.x.exists("private"), isExtern: x.x.exists("extern"), - isInterface: x.x.exists("interface"), + isFinal: x.x.exists("final"), + isInterface: isInterface, params: mkTypeParams(x.att.params), superClass: csuper, interfaces: interfaces, diff --git a/std/haxe/zip/Tools.hx b/std/haxe/zip/Tools.hx index 373f3ade8b663e119bf578905d0ca302a10224cc..bf6860609b7da0291a53ca28b50cda022a6f08db 100644 --- a/std/haxe/zip/Tools.hx +++ b/std/haxe/zip/Tools.hx @@ -34,4 +34,19 @@ class Tools { f.data = data.sub(2, data.length - 6); f.dataSize = f.data.length; } + + public static function uncompress(f:Entry) { + if( !f.compressed ) + return; + + var c = new Uncompress(-15); + var s = haxe.io.Bytes.alloc(f.fileSize); + var r = c.execute(f.data,0,s,0); + c.close(); + if( !r.done || r.read != f.data.length || r.write != f.fileSize ) + throw "Invalid compressed data for "+f.fileName; + f.compressed = false; + f.dataSize = f.fileSize; + f.data = s; + } } diff --git a/std/hl/Api.hx b/std/hl/Api.hx index 9949ec656aaa77cb33514d541a5cea431785b905..cab198b4c3a91c7de2e7d6fdf0697376e4ddbb5e 100644 --- a/std/hl/Api.hx +++ b/std/hl/Api.hx @@ -41,4 +41,7 @@ extern class Api { @:hlNative("std", "breakpoint") static function breakPoint():Void; @:hlNative("std", "sys_is64") static function is64():Bool; @:hlNative("std", "ptr_compare") static function comparePointer(a:Dynamic, b:Dynamic):Int; + #if (hl_ver >= version("1.12.0")) + @:hlNative("std", "is_prim_loaded") static function isPrimLoaded(f:haxe.Constraints.Function):Bool; + #end } diff --git a/std/hl/NativeArray.hx b/std/hl/NativeArray.hx index 18d3173f552425f86642482d338f2661e1e2be00..8cf6b66c3c2c103320ed823afdde435e065e32df 100644 --- a/std/hl/NativeArray.hx +++ b/std/hl/NativeArray.hx @@ -42,6 +42,24 @@ package hl; } } +@:generic class NativeArrayKeyValueIterator { + var arr : NativeArray; + var pos : Int; + var length : Int; + public inline function new(arr:NativeArray) { + this.arr = arr; + pos = 0; + length = arr.length; + } + public inline function hasNext() { + return pos < length; + } + public inline function next() { + var v = arr[pos]; + return {key:pos++, value:v}; + } +} + @:coreType abstract NativeArray { public var length(get, never):Int; diff --git a/std/hl/_std/Reflect.hx b/std/hl/_std/Reflect.hx index 7768660fa915885980d64fcc50c80d63fbf77485..3865b53a85b1ed2fbccab3ed3b73e25864d3296d 100644 --- a/std/hl/_std/Reflect.hx +++ b/std/hl/_std/Reflect.hx @@ -131,11 +131,9 @@ class Reflect { } @:overload(function(f:Array->Void):Dynamic {}) - extern public inline static function makeVarArgs(f:Array->Dynamic):Dynamic { - return _makeVarArgs(f); - } + extern public static function makeVarArgs(f:Array->Dynamic):Dynamic; - static function _makeVarArgs(f:Array->Dynamic):Dynamic { + @:ifFeature("Reflect.makeVarArgs") static function _makeVarArgs(f:Array->Dynamic):Dynamic { return hl.Api.makeVarArgs(function(args:hl.NativeArray) { var arr = hl.types.ArrayDyn.alloc(hl.types.ArrayObj.alloc(args), true); return f(cast arr); diff --git a/std/hl/_std/Std.hx b/std/hl/_std/Std.hx index ff9a70272375d7bd51ac5511063ecb9875f967d1..bc1369f3c148b37fb6459cedeb5edb9f1aa27f8c 100644 --- a/std/hl/_std/Std.hx +++ b/std/hl/_std/Std.hx @@ -49,7 +49,11 @@ class Std { return x <= 0 ? 0 : (rnd_int(rnd) & 0x3FFFFFFF) % x; } - public static function is(v:Dynamic, t:Dynamic):Bool { + public static inline function is(v:Dynamic, t:Dynamic):Bool { + return isOfType(v, t); + } + + public static function isOfType(v:Dynamic, t:Dynamic):Bool { var t:hl.BaseType = t; if (t == null) return false; diff --git a/std/hl/_std/String.hx b/std/hl/_std/String.hx index 20a33423251269225f29ebe0c8fa73627f02292d..5d3163cebb9eb4def02fd66a16e97d0a4c835d4f 100644 --- a/std/hl/_std/String.hx +++ b/std/hl/_std/String.hx @@ -69,7 +69,7 @@ class String { var startByte = 0; if (startIndex != null && startIndex > 0) { if (startIndex >= length) - return -1; + return str == '' ? length : -1; startByte = startIndex << 1; } var p = findChar(startByte, length << 1, str.bytes, str.length << 1); diff --git a/std/hl/_std/StringBuf.hx b/std/hl/_std/StringBuf.hx index 794237cd945fc854e75ef8583f125f8323cb8f7f..ab5dcdb0450e7ccb9805316f4ee7843465482e83 100644 --- a/std/hl/_std/StringBuf.hx +++ b/std/hl/_std/StringBuf.hx @@ -55,6 +55,11 @@ public function add(x:T):Void { var slen = 0; + var str = Std.downcast((x:Dynamic),String); + if( str != null ) { + __add(@:privateAccess str.bytes, 0, str.length<<1); + return; + } var sbytes = hl.Bytes.fromValue(x, new hl.Ref(slen)); __add(sbytes, 0, slen << 1); } diff --git a/std/hl/_std/Type.hx b/std/hl/_std/Type.hx index 10196f87c1c3d5e32892a173dba5dce22fb021b2..7326242ce23b44b5d0149a42ecaff64b59d8b7a3 100644 --- a/std/hl/_std/Type.hx +++ b/std/hl/_std/Type.hx @@ -109,14 +109,14 @@ class Type { public static function resolveClass(name:String):Class { var t:hl.BaseType = allTypes.get(@:privateAccess name.bytes); - if (t == null || !Std.is(t, hl.BaseType.Class)) + if (t == null || !Std.isOfType(t, hl.BaseType.Class)) return null; return cast t; } public static function resolveEnum(name:String):Enum { var t:hl.BaseType = allTypes.get(@:privateAccess name.bytes); - if (t == null || !Std.is(t, hl.BaseType.Enum)) + if (t == null || !Std.isOfType(t, hl.BaseType.Enum)) return null; return cast t; } diff --git a/std/hl/_std/haxe/Exception.hx b/std/hl/_std/haxe/Exception.hx new file mode 100644 index 0000000000000000000000000000000000000000..3c036a9e1ff0b401c4425bbc4cd43831687263a6 --- /dev/null +++ b/std/hl/_std/haxe/Exception.hx @@ -0,0 +1,83 @@ +package haxe; + +@:coreApi +class Exception { + public var message(get,never):String; + public var stack(get,never):CallStack; + public var previous(get,never):Null; + public var native(get,never):Any; + + @:noCompletion var __exceptionMessage:String; + @:noCompletion var __exceptionStack:Null; + @:noCompletion var __nativeStack:hl.NativeArray; + @:noCompletion @:ifFeature("haxe.Exception.get_stack") var __skipStack:Int = 0; + @:noCompletion var __nativeException:Any; + @:noCompletion var __previousException:Null; + + static function caught(value:Any):Exception { + if(Std.is(value, Exception)) { + return value; + } else { + return new ValueException(value, null, value); + } + } + + static function thrown(value:Any):Any { + if(Std.isOfType(value, Exception)) { + return (value:Exception).native; + } else { + var e = new ValueException(value); + e.__shiftStack(); + return e; + } + } + + public function new(message:String, ?previous:Exception, ?native:Any) { + __exceptionMessage = message; + __previousException = previous; + if(native != null) { + __nativeStack = NativeStackTrace.exceptionStack(); + __nativeException = native; + } else { + __nativeStack = NativeStackTrace.callStack(); + __nativeException = this; + } + } + + function unwrap():Any { + return __nativeException; + } + + public function toString():String { + return message; + } + + public function details():String { + return inline CallStack.exceptionToString(this); + } + + @:noCompletion + @:ifFeature("haxe.Exception.get_stack") + inline function __shiftStack():Void { + __skipStack++; + } + + function get_message():String { + return __exceptionMessage; + } + + function get_previous():Null { + return __previousException; + } + + final function get_native():Any { + return __nativeException; + } + + function get_stack():CallStack { + return switch __exceptionStack { + case null: __exceptionStack = NativeStackTrace.toHaxe(__nativeStack, __skipStack); + case s: s; + } + } +} \ No newline at end of file diff --git a/std/hl/_std/haxe/NativeStackTrace.hx b/std/hl/_std/haxe/NativeStackTrace.hx new file mode 100644 index 0000000000000000000000000000000000000000..31e55e715613bdad454601ee2b4dbffdb588f680 --- /dev/null +++ b/std/hl/_std/haxe/NativeStackTrace.hx @@ -0,0 +1,58 @@ +package haxe; + +import hl.NativeArray; +import hl.Bytes; +import haxe.CallStack.StackItem; + +/** + Do not use manually. +**/ +@:dox(hide) +@:noCompletion +class NativeStackTrace { + @:ifFeature('haxe.NativeStackTrace.exceptionStack') + static public inline function saveStack(exception:Any):Void { + } + + @:hlNative("std", "exception_stack") + static public function exceptionStack():NativeArray { + return null; + } + + //TODO: implement in hashlink like `exceptionStack` + static public function callStack():NativeArray { + var stack:NativeArray = try { + throw new Exception('', null, 'stack'); + } catch (e:Exception) { + exceptionStack(); + } + var skip = 1; + for(i in 0...stack.length - 1) { + var s = @:privateAccess String.fromUCS2(stack[i]); + if(s.indexOf('NativeStackTrace.callStack') < 0) { + break; + } + skip++; + } + return skip < stack.length ? stack.sub(skip, stack.length - skip) : stack; + } + + static public function toHaxe(native:NativeArray, skip:Int = 0):Array { + var stack = []; + var r = ~/^([A-Za-z0-9.$_]+)\.([~A-Za-z0-9_]+(\.[0-9]+)?)\((.+):([0-9]+)\)$/; + var r_fun = ~/^fun\$([0-9]+)\((.+):([0-9]+)\)$/; + for (i in 0...native.length - 1) { + if(skip > i) { + continue; + } + var str = @:privateAccess String.fromUCS2(native[i]); + if (r.match(str)) + stack.push(FilePos(Method(r.matched(1), r.matched(2)), r.matched(4), Std.parseInt(r.matched(5)))); + else if (r_fun.match(str)) + stack.push(FilePos(LocalFunction(Std.parseInt(r_fun.matched(1))), r_fun.matched(2), Std.parseInt(r_fun.matched(3)))); + else + stack.push(Module(str)); + } + return stack; + } +} \ No newline at end of file diff --git a/std/hl/_std/sys/db/Sqlite.hx b/std/hl/_std/sys/db/Sqlite.hx index 57df2197d0f26cc3f8da36fde5d7df81792729c6..f54a65b3736700960108fd995d12e47657f3baae 100644 --- a/std/hl/_std/sys/db/Sqlite.hx +++ b/std/hl/_std/sys/db/Sqlite.hx @@ -114,6 +114,10 @@ private class SqliteConnection implements Connection { s.add(v); case TBool: s.add(v ? 1 : 0); + case TClass(haxe.io.Bytes): + s.add("x'"); + s.add((v : haxe.io.Bytes).toHex()); + s.add("'"); case _: s.add(quote(Std.string(v))); } @@ -208,10 +212,20 @@ private class SqliteResultSet implements ResultSet { while (i < l) { var n:String = names[i]; var v:Dynamic = a[i]; - if (hl.Type.getDynamic(v).kind == hl.Type.TypeKind.HBytes) - Reflect.setField(o, n, String.fromUCS2(v)); - else - Reflect.setField(o, n, v); + switch (hl.Type.getDynamic(v).kind) { + case hl.Type.TypeKind.HArray: + var pair:hl.NativeArray = v; + var bytes:hl.Bytes = pair[0]; + var len:Int = pair[1]; + var data = new haxe.io.BytesData(bytes, len); + Reflect.setField(o, n, haxe.io.Bytes.ofData(data)); + + case hl.Type.TypeKind.HBytes: + Reflect.setField(o, n, String.fromUCS2(v)); + + default: + Reflect.setField(o, n, v); + } i++; } return o; diff --git a/std/hl/_std/sys/thread/Deque.hx b/std/hl/_std/sys/thread/Deque.hx index eb71312e91df6f3c7a5b30b263f0e7dbe3dce6de..11d2bb79f1cad840856220b8fb6519e8728cec92 100644 --- a/std/hl/_std/sys/thread/Deque.hx +++ b/std/hl/_std/sys/thread/Deque.hx @@ -24,10 +24,10 @@ package sys.thread; #if doc_gen @:coreApi extern class Deque { - public function new():Void; - public function add(i:T):Void; - public function push(i:T):Void; - public function pop(block:Bool):Null; + function new():Void; + function add(i:T):Void; + function push(i:T):Void; + function pop(block:Bool):Null; } #else diff --git a/std/hl/_std/sys/thread/Mutex.hx b/std/hl/_std/sys/thread/Mutex.hx index cc37e1aca7188ebcb4a79b88dcb0dfae924af63a..fc3aa6fb5f7720d03bee3564538b6bba3e61701f 100644 --- a/std/hl/_std/sys/thread/Mutex.hx +++ b/std/hl/_std/sys/thread/Mutex.hx @@ -25,10 +25,10 @@ package sys.thread; #if doc_gen @:coreApi extern class Mutex { - public function new():Void; - public function acquire():Void; - public function tryAcquire():Bool; - public function release():Void; + function new():Void; + function acquire():Void; + function tryAcquire():Bool; + function release():Void; } #else diff --git a/std/hl/_std/sys/thread/Tls.hx b/std/hl/_std/sys/thread/Tls.hx index bfc894ce2cd08279b70df507db76f3ed8a1b0af2..472bdef4866c89052ebd9501eab9b16e7fbeb4e4 100644 --- a/std/hl/_std/sys/thread/Tls.hx +++ b/std/hl/_std/sys/thread/Tls.hx @@ -25,8 +25,8 @@ package sys.thread; #if doc_gen @:coreApi extern class Tls { - public var value(get, set):T; - public function new():Void; + var value(get, set):T; + function new():Void; } #else diff --git a/std/hl/types/ArrayBase.hx b/std/hl/types/ArrayBase.hx index 5b89e2954a70a4f6958586d370c7aa4997834ad4..a54b685af07dc13a3e915b2e7d3b9445f61abff4 100644 --- a/std/hl/types/ArrayBase.hx +++ b/std/hl/types/ArrayBase.hx @@ -65,6 +65,11 @@ class ArrayBase extends ArrayAccess { throw "Not implemented"; } + public function containsDyn(v:Dynamic):Bool { + throw "Not implemented"; + return false; + } + public function removeDyn(v:Dynamic):Bool { throw "Not implemented"; return false; diff --git a/std/hl/types/ArrayBytes.hx b/std/hl/types/ArrayBytes.hx index 20cf96c0068132c223ab61418cd74a46b5506375..8edff5adbd1231604c2a070d78d6d32446221053 100644 --- a/std/hl/types/ArrayBytes.hx +++ b/std/hl/types/ArrayBytes.hx @@ -22,22 +22,45 @@ package hl.types; +import haxe.iterators.ArrayIterator; +import haxe.iterators.ArrayKeyValueIterator; + @:keep @:generic -class BytesIterator { - var pos:Int; +class BytesIterator extends ArrayIterator { var a:ArrayBytes; public function new(a) { + super((null:Dynamic)); + this.a = a; + } + + override public function hasNext() { + return current < a.length; + } + + override public function next():T { + return @:privateAccess a.bytes.get(current++); + } +} + +@:keep +@:generic +class BytesKeyValueIterator extends ArrayKeyValueIterator { + var a : ArrayBytes; + + public function new(a) { + super((null:Dynamic)); this.a = a; } - public function hasNext() { - return pos < a.length; + override public function hasNext():Bool { + return current < a.length; } - public function next():T { - return @:privateAccess a.bytes.get(pos++); + override public function next():{key:Int, value:T} { + var v = @:privateAccess a.bytes.get(current); + return {key:current++, value:v}; } } @@ -208,6 +231,10 @@ class BytesIterator { bytes[pos] = x; } + public function contains(x:T):Bool { + return indexOf(x) != -1; + } + public function remove(x:T):Bool { var idx = indexOf(x); if (idx < 0) @@ -253,10 +280,14 @@ class BytesIterator { return a; } - public function iterator():Iterator { + public function iterator():ArrayIterator { return new BytesIterator(this); } + public function keyValueIterator() : ArrayKeyValueIterator { + return new BytesKeyValueIterator(this); + } + public function map(f:T->S):ArrayDyn@:privateAccess { var a = new ArrayObj(); if (length > 0) @@ -314,6 +345,9 @@ class BytesIterator { override function insertDyn(pos:Int, v:Dynamic) insert(pos, v); + override function containsDyn(v:Dynamic) + return contains(v); + override function removeDyn(v:Dynamic) return remove(v); diff --git a/std/hl/types/ArrayDyn.hx b/std/hl/types/ArrayDyn.hx index 0244574b12ccd892e1ecf6f0986c90274de53d72..603e4d9cccc4735dda0ccc190d6b42896472fcc0 100644 --- a/std/hl/types/ArrayDyn.hx +++ b/std/hl/types/ArrayDyn.hx @@ -23,24 +23,41 @@ package hl.types; import hl.types.ArrayBase; +import haxe.iterators.ArrayIterator; +import haxe.iterators.ArrayKeyValueIterator; -class ArrayDynIterator { +class ArrayDynIterator extends ArrayIterator { var a:ArrayBase; - var len:Int; - var pos:Int; public function new(a) { + super((null:Dynamic)); this.a = a; - this.len = a.length; - this.pos = 0; } - public function hasNext() { - return pos < len; + override public function hasNext() { + return current < a.length; } - public function next() { - return a.getDyn(pos++); + override public function next() { + return a.getDyn(current++); + } +} + +class ArrayDynKeyValueIterator extends ArrayKeyValueIterator { + var a : ArrayBase; + + public function new(a) { + super((null:Dynamic)); + this.a = a; + } + + override public function hasNext() { + return current < a.length; + } + + override public function next() { + var v = a.getDyn(current); + return {key:current++, value:v}; } } @@ -131,6 +148,10 @@ class ArrayDyn extends ArrayAccess { array.insertDyn(pos, x); } + public function contains(x:Dynamic):Bool { + return array.containsDyn(x); + } + public function remove(x:Dynamic):Bool { return array.removeDyn(x); } @@ -169,10 +190,14 @@ class ArrayDyn extends ArrayAccess { return alloc(ArrayObj.alloc(a), true); } - public function iterator():Iterator { + public function iterator():ArrayIterator { return new ArrayDynIterator(array); } + public function keyValueIterator() : ArrayKeyValueIterator { + return new ArrayDynKeyValueIterator(array); + } + public function map(f:Dynamic->Dynamic):ArrayDyn { var a = new NativeArray(length); for (i in 0...length) diff --git a/std/hl/types/ArrayObj.hx b/std/hl/types/ArrayObj.hx index ce36921741d54f70b4e4b77258fbd5cd03e8b6bd..3431f89895b18f725b2be5321f0a11f397052dfe 100644 --- a/std/hl/types/ArrayObj.hx +++ b/std/hl/types/ArrayObj.hx @@ -22,6 +22,44 @@ package hl.types; +import haxe.iterators.ArrayIterator; +import haxe.iterators.ArrayKeyValueIterator; + +class ArrayObjIterator extends ArrayIterator { + var arr:ArrayObj; + + public inline function new(arr:ArrayObj) { + super((null:Dynamic)); + this.arr = arr; + } + + override public function hasNext():Bool { + return current < arr.length; + } + + override public function next():T { + return @:privateAccess arr.array[current++]; + } +} + +class ArrayObjKeyValueIterator extends ArrayKeyValueIterator { + var arr:ArrayObj; + + public inline function new(arr:ArrayObj) { + super((null:Dynamic)); + this.arr = arr; + } + + override public function hasNext():Bool { + return current < arr.length; + } + + override public function next():{key:Int, value:T} { + var v = @:privateAccess arr.array[current]; + return {key:current++, value:v}; + } +} + @:keep class ArrayObj extends ArrayBase { var array:hl.NativeArray; @@ -189,6 +227,10 @@ class ArrayObj extends ArrayBase { array[pos] = x; } + public function contains(x:T):Bool { + return indexOf(x) != -1; + } + public function remove(x:T):Bool { var i = indexOf(x); if (i < 0) @@ -244,10 +286,12 @@ class ArrayObj extends ArrayBase { return alloc(n); } - public function iterator():Iterator { - var n = new NativeArray.NativeArrayIterator(cast array); - @:privateAccess n.length = length; - return n; + public function iterator():ArrayIterator { + return new ArrayObjIterator(this); + } + + public function keyValueIterator():ArrayKeyValueIterator { + return new ArrayObjKeyValueIterator(this); } public function map(f:T->S):ArrayDyn { @@ -326,6 +370,9 @@ class ArrayObj extends ArrayBase { override function insertDyn(pos:Int, v:Dynamic) insert(pos, v); + override function containsDyn(v:Dynamic) + return contains(v); + override function removeDyn(v:Dynamic) return remove(v); diff --git a/std/java/Boot.hx b/std/java/Boot.hx index 6e641eb52125920d073a3a6eeb4778c6ceb2b357..8d75e7d7b47663a7ae4724afb727164d0a5448ea 100644 --- a/std/java/Boot.hx +++ b/std/java/Boot.hx @@ -22,7 +22,6 @@ package java; -import java.internal.Exceptions; import java.internal.Function; import java.internal.HxObject; import java.internal.Runtime; diff --git a/std/java/NativeArray.hx b/std/java/NativeArray.hx index 6c9054db5f9fa85b87eeedd37f922ed2d25d6952..685da74773984d6d1100c032e28ca975d672971c 100644 --- a/std/java/NativeArray.hx +++ b/std/java/NativeArray.hx @@ -36,15 +36,15 @@ import haxe.extern.Rest; var elements = NativeArray.make(1,2,3,4,5,6); ``` **/ - public static function make(elements:Rest):NativeArray; + static function make(elements:Rest):NativeArray; /** The length of the array **/ - public var length(default, null):Int; + var length(default, null):Int; /** Allocates a new array with size `len` **/ - public function new(len:Int):Void; + function new(len:Int):Void; } diff --git a/std/java/_std/Array.hx b/std/java/_std/Array.hx index 12ed28a18b68af2347e10397dfebe96bd86d9171..463d55d63849c15e182f8263d5b0af1478cce5a8 100644 --- a/std/java/_std/Array.hx +++ b/std/java/_std/Array.hx @@ -22,6 +22,7 @@ import java.lang.System; import java.NativeArray; +import haxe.iterators.ArrayKeyValueIterator; @:classCode(' public Array(T[] _native) @@ -375,6 +376,17 @@ import java.NativeArray; return false; } + public function contains(x:T):Bool { + var __a = __a; + var i = -1; + var length = length; + while (++i < length) { + if (__a[i] == x) + return true; + } + return false; + } + public function indexOf(x:T, ?fromIndex:Int):Int { var len = length, a = __a, i:Int = (fromIndex == null) ? 0 : fromIndex; if (i < 0) { @@ -414,8 +426,12 @@ import java.NativeArray; return ofNative(newarr); } - public inline function iterator():Iterator { - return new ArrayIterator(this); + public inline function iterator():haxe.iterators.ArrayIterator { + return new haxe.iterators.ArrayIterator(this); + } + + public inline function keyValueIterator() : ArrayKeyValueIterator { + return new ArrayKeyValueIterator(this); } public function resize(len:Int):Void { @@ -483,22 +499,4 @@ import java.NativeArray; private inline function __unsafe_set(idx:Int, val:T):T { return __a[idx] = val; } -} - -private final class ArrayIterator { - var arr:Array; - var len:Int; - var i:Int; - - public inline function new(a:Array) { - arr = a; - len = a.length; - i = 0; - } - - public inline function hasNext():Bool - return i < len; - - public inline function next():T - return arr[i++]; -} +} \ No newline at end of file diff --git a/std/java/_std/Reflect.hx b/std/java/_std/Reflect.hx index 6389300387f664dcbc92d23fe50bc828f084eae2..00f8002a4a1e48722568a201d30c0d0fa73b7cae 100644 --- a/std/java/_std/Reflect.hx +++ b/std/java/_std/Reflect.hx @@ -27,7 +27,7 @@ import java.Boot; @:coreApi class Reflect { public static function hasField(o:Dynamic, field:String):Bool { - if (Std.is(o, IHxObject)) { + if (Std.isOfType(o, IHxObject)) { return untyped (o : IHxObject).__hx_getField(field, false, true, false) != Runtime.undefined; } return Runtime.slowHasField(o, field); @@ -35,7 +35,7 @@ import java.Boot; @:keep public static function field(o:Dynamic, field:String):Dynamic { - if (Std.is(o, IHxObject)) { + if (Std.isOfType(o, IHxObject)) { return untyped (o : IHxObject).__hx_getField(field, false, false, false); } return Runtime.slowGetField(o, field, false); @@ -43,7 +43,7 @@ import java.Boot; @:keep public static function setField(o:Dynamic, field:String, value:Dynamic):Void { - if (Std.is(o, IHxObject)) { + if (Std.isOfType(o, IHxObject)) { untyped (o : IHxObject).__hx_setField(field, value, false); } else { Runtime.slowSetField(o, field, value); @@ -54,7 +54,7 @@ import java.Boot; if (o == null || field == null) { return null; } - if (Std.is(o, IHxObject)) { + if (Std.isOfType(o, IHxObject)) { return untyped (o : IHxObject).__hx_getField(field, false, false, true); } if (Runtime.slowHasField(o, "get_" + field)) { @@ -64,7 +64,7 @@ import java.Boot; } public static function setProperty(o:Dynamic, field:String, value:Dynamic):Void { - if (Std.is(o, IHxObject)) { + if (Std.isOfType(o, IHxObject)) { untyped (o : IHxObject).__hx_setField(field, value, true); } else if (Runtime.slowHasField(o, "set_" + field)) { Runtime.slowCallField(o, "set_" + field, java.NativeArray.make(value)); @@ -80,11 +80,11 @@ import java.Boot; @:keep public static function fields(o:Dynamic):Array { - if (Std.is(o, IHxObject)) { + if (Std.isOfType(o, IHxObject)) { var ret:Array = []; untyped (o : IHxObject).__hx_getFields(ret); return ret; - } else if (Std.is(o, java.lang.Class)) { + } else if (Std.isOfType(o, java.lang.Class)) { return Type.getClassFields(cast o); } else { return []; @@ -92,7 +92,7 @@ import java.Boot; } public static function isFunction(f:Dynamic):Bool { - return Std.is(f, Function); + return Std.isOfType(f, Function); } public static function compare(a:T, b:T):Int { @@ -104,7 +104,7 @@ import java.Boot; if (f1 == f2) { return true; } - if (Std.is(f1, Closure) && Std.is(f2, Closure)) { + if (Std.isOfType(f1, Closure) && Std.isOfType(f2, Closure)) { var f1c:Closure = cast f1; var f2c:Closure = cast f2; return Runtime.refEq(f1c.obj, f2c.obj) && f1c.field == f2c.field; @@ -114,19 +114,19 @@ import java.Boot; public static function isObject(v:Dynamic):Bool { return v != null - && !(Std.is(v, HxEnum) - || Std.is(v, Function) - || Std.is(v, java.lang.Enum) - || Std.is(v, java.lang.Number) - || Std.is(v, java.lang.Boolean.BooleanClass)); + && !(Std.isOfType(v, HxEnum) + || Std.isOfType(v, Function) + || Std.isOfType(v, java.lang.Enum) + || Std.isOfType(v, java.lang.Number) + || Std.isOfType(v, java.lang.Boolean.BooleanClass)); } public static function isEnumValue(v:Dynamic):Bool { - return v != null && (Std.is(v, HxEnum) || Std.is(v, java.lang.Enum)); + return v != null && (Std.isOfType(v, HxEnum) || Std.isOfType(v, java.lang.Enum)); } public static function deleteField(o:Dynamic, field:String):Bool { - return (Std.is(o, DynamicObject) && (o : DynamicObject).__hx_deleteField(field)); + return (Std.isOfType(o, DynamicObject) && (o : DynamicObject).__hx_deleteField(field)); } public static function copy(o:Null):Null { diff --git a/std/java/_std/Std.hx b/std/java/_std/Std.hx index 186e1a6095cf63aba50950ddf76d1ed9705bd23e..33a6dca7c2db3aacf1516276f29b7659b5795aad 100644 --- a/std/java/_std/Std.hx +++ b/std/java/_std/Std.hx @@ -22,10 +22,13 @@ import java.Boot; import java.Lib; -import java.internal.Exceptions; @:coreApi @:nativeGen class Std { - public static function is(v:Dynamic, t:Dynamic):Bool { + public static inline function is(v:Dynamic, t:Dynamic):Bool { + return isOfType(v, t); + } + + public static function isOfType(v:Dynamic, t:Dynamic):Bool { if (v == null) return false; if (t == null) @@ -157,7 +160,7 @@ import java.internal.Exceptions; } inline public static function downcast(value:T, c:Class):S { - return Std.is(value, c) ? cast value : null; + return Std.isOfType(value, c) ? cast value : null; } @:deprecated('Std.instance() is deprecated. Use Std.downcast() instead.') diff --git a/std/java/_std/StringBuf.hx b/std/java/_std/StringBuf.hx index d695dfe996ec3ebafaf8c06942e39375a2a12af3..731fbb74ac0b2da9608cb2a190e104d6800979a0 100644 --- a/std/java/_std/StringBuf.hx +++ b/std/java/_std/StringBuf.hx @@ -33,17 +33,8 @@ class StringBuf { return b.length(); } - #if jvm public function add(x:T):Void { - if (jvm.Jvm.instanceof(x, java.lang.Double.DoubleClass)) { - b.append(jvm.Jvm.toString(cast x)); - } else { - b.append(x); - } - } - #else - public function add(x:T):Void { - if (Std.is(x, Int)) { + if (Std.isOfType(x, Int)) { var x:Int = cast x; var xd:Dynamic = x; b.append(xd); @@ -51,7 +42,6 @@ class StringBuf { b.append(x); } } - #end public function addSub(s:String, pos:Int, ?len:Int):Void { var l:Int = (len == null) ? s.length - pos : len; diff --git a/std/java/_std/Type.hx b/std/java/_std/Type.hx index 828aead09c2d7726e0bca14f7e6a63a44439de09..63a06fbcd339af46f324fd097dbb3355db7169eb 100644 --- a/std/java/_std/Type.hx +++ b/std/java/_std/Type.hx @@ -38,14 +38,14 @@ enum ValueType { @:coreApi class Type { public static function getClass(o:T):Class { - if (o == null || Std.is(o, DynamicObject) || Std.is(o, java.lang.Class)) { + if (o == null || Std.isOfType(o, DynamicObject) || Std.isOfType(o, java.lang.Class)) { return null; } return cast java.Lib.getNativeType(o); } public static function getEnum(o:EnumValue):Enum { - if (Std.is(o, java.lang.Enum) || Std.is(o, HxEnum)) { + if (Std.isOfType(o, java.lang.Enum) || Std.isOfType(o, HxEnum)) { return untyped o.getClass(); } return null; @@ -137,14 +137,14 @@ enum ValueType { for (arg in args) { argNum++; var expectedType = argNum < ptypes.length ? ptypes[argNum] : ptypes[ptypes.length - 1]; // varags - var isDynamic = Std.is(arg, DynamicObject) && expectedType.isAssignableFrom(java.Lib.getNativeType(arg)); + var isDynamic = Std.isOfType(arg, DynamicObject) && expectedType.isAssignableFrom(java.Lib.getNativeType(arg)); var argType = Type.getClass(arg); if (arg == null || isDynamic || (argType != null && expectedType.isAssignableFrom(java.Lib.toNativeType(argType)))) { callArguments[argNum] = arg; } else if(expectedType.getName() == 'boolean' && (cast argType:java.lang.Class).getName() == 'java.lang.Boolean') { callArguments[argNum] = (cast arg : java.lang.Boolean).booleanValue(); - } else if (Std.is(arg, java.lang.Number)) { + } else if (Std.isOfType(arg, java.lang.Number)) { var name = expectedType.getName(); switch (name) { case 'double' | 'java.lang.Double': @@ -195,7 +195,7 @@ enum ValueType { public static function createEnum(e:Enum, constr:String, ?params:Array):T { if (params == null || params.length == 0) { var ret:Dynamic = java.internal.Runtime.slowGetField(e, constr, true); - if (Std.is(ret, java.internal.Function)) { + if (Std.isOfType(ret, java.internal.Function)) { throw "Constructor " + constr + " needs parameters"; } return ret; @@ -361,7 +361,7 @@ enum ValueType { var ret = []; for (ctor in ctors) { var v = Reflect.field(e, ctor); - if (Std.is(v, e)) + if (Std.isOfType(v, e)) ret.push(v); } diff --git a/std/java/_std/haxe/Exception.hx b/std/java/_std/haxe/Exception.hx new file mode 100644 index 0000000000000000000000000000000000000000..2f2ce0ac917f004c9d23fb28722b161ac0a565a3 --- /dev/null +++ b/std/java/_std/haxe/Exception.hx @@ -0,0 +1,112 @@ +package haxe; + +import java.NativeArray; +import java.lang.Throwable; +import java.lang.RuntimeException; +import java.lang.StackTraceElement; +import java.io.PrintStream; +import java.io.PrintWriter; + +@:coreApi +class Exception extends NativeException { + public var message(get,never):String; + public var stack(get,never):CallStack; + public var previous(get,never):Null; + public var native(get,never):Any; + + @:noCompletion var __exceptionStack:Null; + @:noCompletion var __nativeException:Throwable; + @:noCompletion var __previousException:Null; + + static function caught(value:Any):Exception { + if(Std.is(value, Exception)) { + return value; + } else if(Std.isOfType(value, Throwable)) { + return new Exception((value:Throwable).getMessage(), null, value); + } else { + return new ValueException(value, null, value); + } + } + + static function thrown(value:Any):Any { + if(Std.isOfType(value, Exception)) { + var native = (value:Exception).__nativeException; + return Std.isOfType(native, RuntimeException) ? native : value; + } else if(Std.isOfType(value, RuntimeException)) { + return value; + } else if(Std.isOfType(value, Throwable)) { + return new Exception((value:Throwable).getMessage(), null, value); + } else { + var e = new ValueException(value); + var stack = e.getStackTrace(); + if(stack.length > 1) { + e.setStackTrace(java.util.Arrays.copyOfRange(stack, 1, stack.length)); + } + return e; + } + } + + public function new(message:String, ?previous:Exception, ?native:Any) { + super(message, cast previous); + __previousException = previous; + if(native != null && Std.isOfType(native, Throwable)) { + __nativeException = native; + setStackTrace(__nativeException.getStackTrace()); + } else { + __nativeException = cast this; + } + } + + function unwrap():Any { + return __nativeException; + } + + override public function toString():String { + return message; + } + + public function details():String { + return inline CallStack.exceptionToString(this); + } + + function get_message():String { + return this.getMessage(); + } + + function get_previous():Null { + return __previousException; + } + + final function get_native():Any { + return __nativeException; + } + + function get_stack():CallStack { + return switch __exceptionStack { + case null: + __exceptionStack = NativeStackTrace.toHaxe(__nativeException.getStackTrace()); + case s: s; + } + } +} + +@:dox(hide) +@:noCompletion +@:native('java.lang.RuntimeException') +private extern class NativeException { + @:noCompletion private function new(?message:String, ?cause:Throwable):Void; + + @:noCompletion @:skipReflection private function addSuppressed (param1:Throwable):Void; + @:noCompletion @:skipReflection private function fillInStackTrace ():Throwable; + @:noCompletion @:skipReflection private function getCause ():Throwable; + @:noCompletion @:skipReflection private function getLocalizedMessage ():String; + @:noCompletion @:skipReflection private function getMessage ():String; + @:noCompletion @:skipReflection private function getStackTrace ():NativeArray; + @:noCompletion @:skipReflection private function getSuppressed ():NativeArray; + @:noCompletion @:skipReflection private function initCause (param1:Throwable):Throwable; + @:noCompletion @:skipReflection @:overload private function printStackTrace (param1:PrintWriter):Void; + @:noCompletion @:skipReflection @:overload private function printStackTrace ():Void; + @:noCompletion @:skipReflection @:overload private function printStackTrace (param1:PrintStream):Void; + @:noCompletion @:skipReflection private function setStackTrace (param1:NativeArray):Void; + @:noCompletion @:skipReflection private function toString ():String; +} \ No newline at end of file diff --git a/std/java/_std/haxe/Int64.hx b/std/java/_std/haxe/Int64.hx index 5f6ac934f6521e91cab44097d9cd71e194fddfc9..e63cf3a2694332fbb98f57a2446ec1a794c3cb38 100644 --- a/std/java/_std/haxe/Int64.hx +++ b/std/java/_std/haxe/Int64.hx @@ -50,12 +50,12 @@ abstract Int64(__Int64) from __Int64 to __Int64 { public var high(get, never):Int32; - public inline function get_high():Int32 + inline function get_high():Int32 return cast(this >> 32); public var low(get, never):Int32; - public inline function get_low():Int32 + inline function get_low():Int32 return cast this; public inline function copy():Int64 @@ -64,8 +64,12 @@ abstract Int64(__Int64) from __Int64 to __Int64 { @:from public static inline function ofInt(x:Int):Int64 return cast x; + @:deprecated('haxe.Int64.is() is deprecated. Use haxe.Int64.isInt64() instead') inline public static function is(val:Dynamic):Bool - return Std.is(val, java.lang.Long.LongClass); + return Std.isOfType(val, java.lang.Long.LongClass); + + inline public static function isInt64(val:Dynamic):Bool + return Std.isOfType(val, java.lang.Long.LongClass); public static inline function toInt(x:Int64):Int { if (x.val < 0x80000000 || x.val > 0x7FFFFFFF) diff --git a/std/java/_std/haxe/NativeStackTrace.hx b/std/java/_std/haxe/NativeStackTrace.hx new file mode 100644 index 0000000000000000000000000000000000000000..048f25dcc6e52935678d9450c4ba49c7927d67f3 --- /dev/null +++ b/std/java/_std/haxe/NativeStackTrace.hx @@ -0,0 +1,55 @@ +package haxe; + +import java.NativeArray; +import java.lang.ThreadLocal; +import java.lang.Throwable; +import java.lang.Thread; +import java.lang.StackTraceElement; +import haxe.CallStack.StackItem; + +/** + Do not use manually. +**/ +@:dox(hide) +@:noCompletion +class NativeStackTrace { + static var exception = new ThreadLocal(); + + @:ifFeature('haxe.NativeStackTrace.exceptionStack') + static public inline function saveStack(e:Throwable):Void { + exception.set(e); + } + + static public function callStack():NativeArray { + var stack = Thread.currentThread().getStackTrace(); + return stack.length <= 3 ? stack : java.util.Arrays.copyOfRange(stack, 3, stack.length); + } + + static public function exceptionStack():NativeArray { + return switch exception.get() { + case null: new NativeArray(0); + case e: e.getStackTrace(); + } + } + + static public function toHaxe(native:NativeArray, skip:Int = 0):Array { + var stack = []; + for (i in 0...native.length) { + if(skip > i) { + continue; + } + var el = native[i]; + var className = el.getClassName(); + var methodName = el.getMethodName(); + var fileName = el.getFileName(); + var lineNumber = el.getLineNumber(); + var method = Method(className, methodName); + if (fileName != null || lineNumber >= 0) { + stack.push(FilePos(method, fileName, lineNumber)); + } else { + stack.push(method); + } + } + return stack; + } +} \ No newline at end of file diff --git a/std/java/_std/haxe/crypto/Md5.hx b/std/java/_std/haxe/crypto/Md5.hx new file mode 100644 index 0000000000000000000000000000000000000000..51c4f656bd77382e7c0d9ec934559506df6b66e9 --- /dev/null +++ b/std/java/_std/haxe/crypto/Md5.hx @@ -0,0 +1,42 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +package haxe.crypto; + +import haxe.io.Bytes; +import haxe.io.BytesData; +import java.security.MessageDigest; +import java.nio.charset.StandardCharsets; + +@:coreApi +class Md5 { + public static function encode(s:String):String { + return Bytes.ofData(digest((cast s : java.NativeString).getBytes(StandardCharsets.UTF_8))).toHex(); + } + + public static function make(b:haxe.io.Bytes):haxe.io.Bytes { + return Bytes.ofData(digest(b.getData())); + } + + inline static function digest(b:BytesData):BytesData { + return MessageDigest.getInstance("MD5").digest(b); + } +} diff --git a/std/java/_std/haxe/crypto/Sha1.hx b/std/java/_std/haxe/crypto/Sha1.hx new file mode 100644 index 0000000000000000000000000000000000000000..075228b51ce1928f7f566b1711340e118b9ae74b --- /dev/null +++ b/std/java/_std/haxe/crypto/Sha1.hx @@ -0,0 +1,42 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +package haxe.crypto; + +import haxe.io.Bytes; +import haxe.io.BytesData; +import java.security.MessageDigest; +import java.nio.charset.StandardCharsets; + +@:coreApi +class Sha1 { + public static function encode(s:String):String { + return Bytes.ofData(digest((cast s : java.NativeString).getBytes(StandardCharsets.UTF_8))).toHex(); + } + + public static function make(b:haxe.io.Bytes):haxe.io.Bytes { + return Bytes.ofData(digest(b.getData())); + } + + inline static function digest(b:BytesData):BytesData { + return MessageDigest.getInstance("SHA-1").digest(b); + } +} diff --git a/std/java/_std/haxe/crypto/Sha256.hx b/std/java/_std/haxe/crypto/Sha256.hx new file mode 100644 index 0000000000000000000000000000000000000000..0ad4d3ce7aaf022e90bc32bc0a01361cf9d6b2dd --- /dev/null +++ b/std/java/_std/haxe/crypto/Sha256.hx @@ -0,0 +1,42 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +package haxe.crypto; + +import haxe.io.Bytes; +import haxe.io.BytesData; +import java.security.MessageDigest; +import java.nio.charset.StandardCharsets; + +@:coreApi +class Sha256 { + public static function encode(s:String):String { + return Bytes.ofData(digest((cast s : java.NativeString).getBytes(StandardCharsets.UTF_8))).toHex(); + } + + public static function make(b:haxe.io.Bytes):haxe.io.Bytes { + return Bytes.ofData(digest(b.getData())); + } + + inline static function digest(b:BytesData):BytesData { + return MessageDigest.getInstance("SHA-256").digest(b); + } +} diff --git a/std/java/_std/sys/io/File.hx b/std/java/_std/sys/io/File.hx index 3ce9a33cd71a8a9d40857c713449b395f07682a1..3c7b909b4e960024341c92601d81ca5a86b2e55c 100644 --- a/std/java/_std/sys/io/File.hx +++ b/std/java/_std/sys/io/File.hx @@ -52,9 +52,9 @@ class File { public static function read(path:String, binary:Bool = true):FileInput { try { - return new FileInput(new java.io.RandomAccessFile(new java.io.File(path), "r")); - } catch (e:Dynamic) // swallow checked exceptions - { + return @:privateAccess new FileInput(new java.io.RandomAccessFile(new java.io.File(path), "r")); + } catch (e:Dynamic) { + // swallow checked exceptions throw e; } } @@ -66,9 +66,9 @@ class File { } try { - return new FileOutput(new java.io.RandomAccessFile(f, "rw")); - } catch (e:Dynamic) // swallow checked exceptions - { + return @:privateAccess new FileOutput(new java.io.RandomAccessFile(f, "rw")); + } catch (e:Dynamic) { + // swallow checked exceptions throw e; } } @@ -81,9 +81,9 @@ class File { if (f.exists()) { ra.seek(f.length()); } - return new FileOutput(ra); - } catch (e:Dynamic) // swallow checked exceptions - { + return @:privateAccess new FileOutput(ra); + } catch (e:Dynamic) { + // swallow checked exceptions throw e; } } @@ -93,9 +93,9 @@ class File { try { var ra = new java.io.RandomAccessFile(f, "rw"); - return new FileOutput(ra); - } catch (e:Dynamic) // swallow checked exceptions - { + return @:privateAccess new FileOutput(ra); + } catch (e:Dynamic) { + // swallow checked exceptions throw e; } } diff --git a/std/java/_std/sys/io/FileInput.hx b/std/java/_std/sys/io/FileInput.hx index 3905cad459b2e41f9f4373bdaae20f03f6c65c4a..6e4a080c95ac2c4648c4a0a67fa5fbf455f5fc03 100644 --- a/std/java/_std/sys/io/FileInput.hx +++ b/std/java/_std/sys/io/FileInput.hx @@ -33,7 +33,7 @@ class FileInput extends Input { var f:java.io.RandomAccessFile; var _eof:Bool; - public function new(f) { + function new(f) { this.f = f; this._eof = false; } diff --git a/std/java/_std/sys/io/FileOutput.hx b/std/java/_std/sys/io/FileOutput.hx index ae75449117f3b4af74267db1d891414d1831a16e..193353b84e9eb13af2640e056f9cb43de74b4c20 100644 --- a/std/java/_std/sys/io/FileOutput.hx +++ b/std/java/_std/sys/io/FileOutput.hx @@ -31,7 +31,7 @@ import java.io.IOException; class FileOutput extends Output { var f:java.io.RandomAccessFile; - public function new(f) { + function new(f) { this.f = f; } diff --git a/std/java/_std/sys/thread/Thread.hx b/std/java/_std/sys/thread/Thread.hx index 47c0641ef77a8bc7b034e4836f65cbf81b476437..39098610da9a872fe84940787332af14ad1c0742 100644 --- a/std/java/_std/sys/thread/Thread.hx +++ b/std/java/_std/sys/thread/Thread.hx @@ -63,7 +63,7 @@ abstract Thread(NativeThread) { }; public static function getThread(jt:java.lang.Thread):NativeThread { - if (Std.is(jt, HaxeThread)) { + if (Std.isOfType(jt, HaxeThread)) { var t:HaxeThread = cast jt; return t.threadObject; } else if (jt == mainJavaThread) { diff --git a/std/java/db/Jdbc.hx b/std/java/db/Jdbc.hx index 1c9811e1cc66fa3ddc981583b0a9603af0d1f97a..23e07407c07d4c94ec189f498d43c4edd0d05006 100644 --- a/std/java/db/Jdbc.hx +++ b/std/java/db/Jdbc.hx @@ -68,9 +68,9 @@ private class JdbcConnection implements sys.db.Connection { } public function addValue(s:StringBuf, v:Dynamic) { - if (Std.is(v, Date)) { + if (Std.isOfType(v, Date)) { v = Std.string(v); - } else if (Std.is(v, Bytes)) { + } else if (Std.isOfType(v, Bytes)) { var bt:Bytes = v; v = bt.getData(); } diff --git a/std/java/internal/Exceptions.hx b/std/java/internal/Exceptions.hx deleted file mode 100644 index 7e54fbcdef3098c904613cf93be00590b2358877..0000000000000000000000000000000000000000 --- a/std/java/internal/Exceptions.hx +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package java.internal; - -import java.lang.Throwable; -import java.lang.RuntimeException; -import java.lang.Exception; - -@:native("haxe.lang.Exceptions") -class Exceptions { - private static var exception = new java.lang.ThreadLocal(); - - @:keep private static function setException(exc:Throwable) { - exception.set(exc); - } - - public static function currentException() { - return exception.get(); - } -} - -@:classCode("public static final long serialVersionUID = 5956463319488556322L;") -@:nativeGen @:keep @:native("haxe.lang.HaxeException") private class HaxeException extends RuntimeException { - private var obj:Dynamic; - - public function new(obj:Dynamic, msg:String, cause:Throwable) { - super(msg, cause); - - if (Std.is(obj, HaxeException)) { - var _obj:HaxeException = cast obj; - obj = _obj.getObject(); - } - - this.obj = obj; - } - - public function getObject():Dynamic { - return obj; - } - - #if !debug - @:overload override public function fillInStackTrace():Throwable { - return this; - } - #end - - @:overload override public function toString():String { - return "Haxe Exception: " + obj; - } - - @:overload override public function getMessage():String { - return switch (super.getMessage()) { - case null: Std.string(obj); - case var message: message; - } - } - - public static function wrap(obj:Dynamic):RuntimeException { - var ret:RuntimeException = null; - if (Std.is(obj, RuntimeException)) - ret = obj; - else if (Std.is(obj, String)) - ret = new HaxeException(obj, obj, null); - else if (Std.is(obj, Throwable)) - ret = new HaxeException(obj, Std.string(obj), obj); - else - ret = new HaxeException(obj, Std.string(obj), null); - return ret; - } -} diff --git a/std/java/internal/HxObject.hx b/std/java/internal/HxObject.hx index d8f4d795c4c97e6a84afd18cf664ee06923c7330..990d1879fc6ddd75d08379bb8a9fa1c2102e71dc 100644 --- a/std/java/internal/HxObject.hx +++ b/std/java/internal/HxObject.hx @@ -103,7 +103,7 @@ class DynamicObject extends HxObject { } else { var res = FieldLookup.findHash(field, this.__hx_fields_f, this.__hx_length_f); if (res >= 0) { - if (Std.is(value, Float)) { + if (Std.isOfType(value, Float)) { return this.__hx_dynamics_f[res] = value; } @@ -267,8 +267,8 @@ private class ParamEnum extends HxEnum { public function equals(obj:Dynamic) { if (obj == this) // we cannot use == as .Equals ! return true; - var obj:ParamEnum = Std.is(obj, ParamEnum) ? cast obj : null; - var ret = obj != null && Std.is(obj, StdType.getEnum(cast this)) && obj.index == this.index; + var obj:ParamEnum = Std.isOfType(obj, ParamEnum) ? cast obj : null; + var ret = obj != null && Std.isOfType(obj, StdType.getEnum(cast this)) && obj.index == this.index; if (!ret) return false; if (obj.params == this.params) diff --git a/std/java/internal/Runtime.hx b/std/java/internal/Runtime.hx index 104ef34923c6e6690f34fcf792e11867eb990616..689d0eda8476233a46b013aab092aa73b1b22c40 100644 --- a/std/java/internal/Runtime.hx +++ b/std/java/internal/Runtime.hx @@ -149,7 +149,7 @@ package java.internal; } @:overload public static function isInt(obj:Dynamic):Bool { - if (Std.is(obj, java.lang.Number)) { + if (Std.isOfType(obj, java.lang.Number)) { var n:java.lang.Number = obj; return n.doubleValue() == n.intValue(); } else { @@ -294,7 +294,7 @@ package java.internal; } if (throwErrors) - throw HaxeException.wrap(t); + throw (java.lang.RuntimeException)haxe.Exception.thrown(t); return null; } @@ -331,7 +331,7 @@ package java.internal; } catch (Throwable t) { - throw HaxeException.wrap(t); + throw (java.lang.RuntimeException)haxe.Exception.thrown(t); } ') public static function slowSetField(obj:Dynamic, field:String, value:Dynamic):Dynamic { @@ -421,7 +421,7 @@ package java.internal; java.lang.reflect.Method found; if (ms.length == 0 || (found = ms[0]) == null) - throw haxe.lang.HaxeException.wrap("No compatible method found for: " + field); + throw (java.lang.RuntimeException)haxe.Exception.thrown("No compatible method found for: " + field); if (hasNumber) { @@ -471,12 +471,12 @@ package java.internal; catch (java.lang.reflect.InvocationTargetException e) { - throw haxe.lang.HaxeException.wrap(e.getCause()); + throw (java.lang.RuntimeException)haxe.Exception.thrown(e.getCause()); } catch (Throwable t) { - throw haxe.lang.HaxeException.wrap(t); + throw (java.lang.RuntimeException)haxe.Exception.thrown(t); } ') public static function slowCallField(obj:Dynamic, field:String, args:java.NativeArray):Dynamic { @@ -547,7 +547,7 @@ package java.internal; if (obj == null) return null; - if (Std.is(obj, java.lang.Number) && !Std.is(obj, java.lang.Integer.IntegerClass) && isInt((obj : java.lang.Number))) + if (Std.isOfType(obj, java.lang.Number) && !Std.isOfType(obj, java.lang.Integer.IntegerClass) && isInt((obj : java.lang.Number))) return java.lang.Integer._toString(toInt(obj)); return untyped obj.toString(); } @@ -569,27 +569,27 @@ package java.internal; } public static function numToInteger(num:java.lang.Number):java.lang.Integer { - return num == null ? null : (Std.is(num, java.lang.Integer.IntegerClass) ? cast num : java.lang.Integer.valueOf(num.intValue())); + return num == null ? null : (Std.isOfType(num, java.lang.Integer.IntegerClass) ? cast num : java.lang.Integer.valueOf(num.intValue())); } public static function numToDouble(num:java.lang.Number):java.lang.Double { - return num == null ? null : (Std.is(num, java.lang.Double.DoubleClass) ? cast num : java.lang.Double.valueOf(num.doubleValue())); + return num == null ? null : (Std.isOfType(num, java.lang.Double.DoubleClass) ? cast num : java.lang.Double.valueOf(num.doubleValue())); } public static function numToFloat(num:java.lang.Number):java.lang.Float { - return num == null ? null : (Std.is(num, java.lang.Float.FloatClass) ? cast num : java.lang.Float.valueOf(num.floatValue())); + return num == null ? null : (Std.isOfType(num, java.lang.Float.FloatClass) ? cast num : java.lang.Float.valueOf(num.floatValue())); } public static function numToByte(num:java.lang.Number):java.lang.Byte { - return num == null ? null : (Std.is(num, java.lang.Byte.ByteClass) ? cast num : java.lang.Byte.valueOf(num.byteValue())); + return num == null ? null : (Std.isOfType(num, java.lang.Byte.ByteClass) ? cast num : java.lang.Byte.valueOf(num.byteValue())); } public static function numToLong(num:java.lang.Number):java.lang.Long { - return num == null ? null : (Std.is(num, java.lang.Long.LongClass) ? cast num : java.lang.Long.valueOf(num.longValue())); + return num == null ? null : (Std.isOfType(num, java.lang.Long.LongClass) ? cast num : java.lang.Long.valueOf(num.longValue())); } public static function numToShort(num:java.lang.Number):java.lang.Short { - return num == null ? null : (Std.is(num, java.lang.Short.ShortClass) ? cast num : java.lang.Short.valueOf(num.shortValue())); + return num == null ? null : (Std.isOfType(num, java.lang.Short.ShortClass) ? cast num : java.lang.Short.valueOf(num.shortValue())); } } diff --git a/std/java/internal/StringExt.hx b/std/java/internal/StringExt.hx index 95cc03a5f1614de8b05ce350aac25bd1cae4c6d7..886eba58742af2c7c2c5f9155a417ae684d4010e 100644 --- a/std/java/internal/StringExt.hx +++ b/std/java/internal/StringExt.hx @@ -49,6 +49,14 @@ private typedef NativeString = String; @:functionCode(' int sIndex = (startIndex != null ) ? (haxe.lang.Runtime.toInt(startIndex)) : 0; + if(str == "") { + int length = me.length(); + if(sIndex < 0) { + sIndex = length + sIndex; + if(sIndex < 0) sIndex = 0; + } + return sIndex > length ? length : sIndex; + } if (sIndex >= me.length() || sIndex < 0) return -1; return me.indexOf(str, sIndex); @@ -63,6 +71,9 @@ private typedef NativeString = String; sIndex = me.length() - 1; else if (sIndex < 0) return -1; + if (str.length() == 0) { + return startIndex == null || haxe.lang.Runtime.toInt(startIndex) > me.length() ? me.length() : haxe.lang.Runtime.toInt(startIndex); + } return me.lastIndexOf(str, sIndex); ') public static function lastIndexOf(me:NativeString, str:NativeString, ?startIndex:Int):Int { diff --git a/std/js/Boot.hx b/std/js/Boot.hx index e27b52f07524843ae898ad8546176d000127e103..8f36b233052d8632d2d70b27e26f4105fe4d9e96 100644 --- a/std/js/Boot.hx +++ b/std/js/Boot.hx @@ -24,26 +24,6 @@ package js; import js.Syntax; // import it here so it's always available in the compiler -private class HaxeError extends js.lib.Error { - var val:Dynamic; - - @:pure - public function new(val:Dynamic) { - super(); - this.val = val; - if ((cast js.lib.Error).captureStackTrace) - (cast js.lib.Error).captureStackTrace(this, HaxeError); - } - - public static function wrap(val:Dynamic):js.lib.Error { - return if (js.Syntax.instanceof(val, js.lib.Error)) val else new HaxeError(val); - } - - static function __init__() { - js.lib.Object.defineProperty((cast HaxeError).prototype, "message", {get: () -> (cast String)(js.Lib.nativeThis.val)}); - } -} - @:dox(hide) class Boot { static inline function isClass(o:Dynamic):Bool { @@ -61,7 +41,7 @@ class Boot { @:pure static function getClass(o:Null):Null { if (o == null) { return null; - } else if (Std.is(o, Array)) { + } else if (Std.isOfType(o, Array)) { return Array; } else { var cl = untyped __define_feature__("js.Boot.getClass", o.__class__); @@ -129,7 +109,7 @@ class Boot { // strange error on IE return "???"; } - if (tostr != null && tostr != __js__("Object.toString") && js.Syntax.typeof(tostr) == "function") { + if (tostr != null && tostr != js.Syntax.code("Object.toString") && js.Syntax.typeof(tostr) == "function") { var s2 = o.toString(); if (s2 != "[object Object]") return s2; @@ -138,15 +118,15 @@ class Boot { s += "\t"; var hasp = (o.hasOwnProperty != null); var k:String = null; - __js__("for( {0} in {1} ) {", k, o); + js.Syntax.code("for( {0} in {1} ) {", k, o); if (hasp && !o.hasOwnProperty(k)) - __js__("continue"); + js.Syntax.code("continue"); if (k == "prototype" || k == "__class__" || k == "__super__" || k == "__interfaces__" || k == "__properties__") - __js__("continue"); + js.Syntax.code("continue"); if (str.length != 2) str += ", \n"; str += s + k + " : " + __string_rec(o[k], s); - __js__("}"); + js.Syntax.code("}"); s = s.substring(1); str += "\n" + s + "}"; return str; @@ -165,8 +145,11 @@ class Boot { return false; if (cc == cl) return true; - if (js.lib.Object.prototype.hasOwnProperty.call(cc, "__interfaces__")) { - var intf:Dynamic = cc.__interfaces__; + var intf:Dynamic = cc.__interfaces__; + if (intf != null + // ES6 classes inherit statics, so we want to avoid accessing inherited `__interfaces__` + #if (js_es >= 6) && (cc.__super__ == null || cc.__super__.__interfaces__ != intf) #end + ) { for (i in 0...intf.length) { var i:Dynamic = intf[i]; if (i == cl || __interfLoop(i, cl)) @@ -176,7 +159,7 @@ class Boot { return __interfLoop(cc.__super__, cl); } - @:ifFeature("typed_catch") @:pure private static function __instanceof(o:Dynamic, cl:Dynamic) { + @:pure private static function __instanceof(o:Dynamic, cl:Dynamic) { if (cl == null) return false; switch (cl) { diff --git a/std/js/Browser.hx b/std/js/Browser.hx index 0a1afcd1b846f6396c301009a5dddc18aa1d0b77..d6b1f8b4c4306c12d6b4827750a092bec89d00f6 100644 --- a/std/js/Browser.hx +++ b/std/js/Browser.hx @@ -26,11 +26,18 @@ import js.html.Storage; import js.html.XMLHttpRequest; class Browser { + /** The global scope typed with fields available only in a worker context. */ + public static var self(get, never):js.html.WorkerGlobalScope; + + static inline function get_self():js.html.WorkerGlobalScope { + return js.Lib.global; + } + /** The global window object. */ public static var window(get, never):js.html.Window; extern inline static function get_window() - return untyped __js__("window"); + return js.Syntax.code("window"); /** Shortcut to Window.document. */ public static var document(get, never):js.html.HTMLDocument; @@ -42,19 +49,19 @@ class Browser { public static var location(get, never):js.html.Location; extern inline static function get_location() - return window.location; + return js.Lib.global.location; /** Shortcut to Window.navigator. */ public static var navigator(get, never):js.html.Navigator; extern inline static function get_navigator() - return window.navigator; + return js.Lib.global.navigator; /** Shortcut to Window.console. */ public static var console(get, never):js.html.ConsoleInstance; extern inline static function get_console() - return window.console; + return js.Lib.global.console; /** * True if a window object exists, false otherwise. @@ -110,10 +117,10 @@ class Browser { * Explorer. */ public static function createXMLHttpRequest():XMLHttpRequest { - if (untyped __js__("typeof XMLHttpRequest") != "undefined") { + if (js.Syntax.code("typeof XMLHttpRequest") != "undefined") { return new XMLHttpRequest(); } - if (untyped __js__("typeof ActiveXObject") != "undefined") { + if (js.Syntax.code("typeof ActiveXObject") != "undefined") { return js.Syntax.construct("ActiveXObject", "Microsoft.XMLHTTP"); } throw "Unable to create XMLHttpRequest object."; diff --git a/std/js/Lib.hx b/std/js/Lib.hx index 06dc543c3c6585460e778eb77bdd34ca1ea01432..204d7eeadcf953ad80ee930c437d1e9a8ff5e212 100644 --- a/std/js/Lib.hx +++ b/std/js/Lib.hx @@ -31,7 +31,7 @@ class Lib { Inserts a 'debugger' statement that will make a breakpoint if a debugger is available. **/ public static inline function debug() { - untyped __js__("debugger"); + js.Syntax.code("debugger"); } /** @@ -40,11 +40,11 @@ class Lib { **/ @:deprecated("Lib.alert() is deprecated, use Browser.alert() instead") public static function alert(v:Dynamic) { - untyped __js__("alert")(js.Boot.__string_rec(v, "")); + js.Syntax.code("alert")(@:privateAccess js.Boot.__string_rec(v, "")); } public static inline function eval(code:String):Dynamic { - return untyped __js__("eval")(code); + return js.Syntax.code("eval")(code); } /** @@ -55,7 +55,19 @@ class Lib { is available, such as Node.js or RequireJS. **/ extern public static inline function require(module:String):Dynamic { - return untyped __js__("require")(module); + return js.Syntax.code("require")(module); + } + + /** + Native JavaScript `parseInt` function. + + Its specification is different from `Std.parseInt`, so one + might want to access the native one. + **/ + public static var parseInt(get, never):(string:String, ?radix:Int) -> Float; + + extern static inline function get_parseInt():(string:String, ?radix:Int) -> Float { + return js.Syntax.code("parseInt"); } /** @@ -68,7 +80,7 @@ class Lib { public static var undefined(get, never):Dynamic; static inline function get_undefined():Dynamic { - return untyped __js__("undefined"); + return js.Syntax.code("undefined"); } /** @@ -86,7 +98,7 @@ class Lib { public static var nativeThis(get, never):Dynamic; extern static inline function get_nativeThis():Dynamic { - return untyped __js__("this"); + return js.Syntax.code("this"); } /** @@ -108,7 +120,7 @@ class Lib { public static var global(get, never):Dynamic; extern static inline function get_global():Dynamic { - return untyped __define_feature__("js.Lib.global", __js__("$global")); // $global is generated by the compiler + return untyped __define_feature__("js.Lib.global", js.Syntax.code("$global")); // $global is generated by the compiler } /** diff --git a/std/js/Syntax.hx b/std/js/Syntax.hx index 83f3fd347abcd67b446b1ff8fee64d1f4d0c7391..efa6d6c26517ed074b21f5b666b485fa3be5a7ea 100644 --- a/std/js/Syntax.hx +++ b/std/js/Syntax.hx @@ -43,9 +43,17 @@ extern class Syntax { ```haxe console.log("hi", 42); ``` + + Emits a compilation error if the count of `args` does not match the count of placeholders in `code`. **/ static function code(code:String, args:Rest):Dynamic; + /** + Inject `code` directly into generated source. + The same as `js.Syntax.code` except this one does not provide code interpolation. + **/ + static function plainCode(code:String):Dynamic; + /** Generate `new cl(...args)` expression. **/ diff --git a/std/js/_std/Array.hx b/std/js/_std/Array.hx index 787ad51bf84dbad78cb854d28079b2293d8f1376..7691912bbfeb378b09bd1fa953d160ca9bf67513 100644 --- a/std/js/_std/Array.hx +++ b/std/js/_std/Array.hx @@ -19,6 +19,9 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ + +import haxe.iterators.ArrayKeyValueIterator; + @:coreApi extern class Array { var length(default, null):Int; @@ -44,6 +47,14 @@ extern class Array { return @:privateAccess HxOverrides.remove(this, x); } + inline function contains(x:T):Bool { + #if (js_es >= 6) + return (cast this).includes(x); + #else + return this.indexOf(x) != -1; + #end + } + #if (js_es >= 5) @:pure function indexOf(x:T, ?fromIndex:Int):Int; @:pure function lastIndexOf(x:T, ?fromIndex:Int):Int; @@ -74,8 +85,12 @@ extern class Array { return [for (v in this) if (f(v)) v]; } - @:runtime inline function iterator():Iterator { - return @:privateAccess HxOverrides.iter(this); + @:runtime inline function iterator():haxe.iterators.ArrayIterator { + return new haxe.iterators.ArrayIterator(this); + } + + @:runtime inline function keyValueIterator():ArrayKeyValueIterator { + return new ArrayKeyValueIterator(this); } inline function resize(len:Int):Void { diff --git a/std/js/_std/HxOverrides.hx b/std/js/_std/HxOverrides.hx index 348cd4174acf38245c0b80f12a9321949b9b0696..8f55624dec0cd0e7f58de9c619d8baef9baf1b97 100644 --- a/std/js/_std/HxOverrides.hx +++ b/std/js/_std/HxOverrides.hx @@ -138,13 +138,27 @@ class HxOverrides { }; } + @:ifFeature("anon_read.keyValueIterator", "dynamic_read.keyValueIterator", "closure_read.keyValueIterator") + static function keyValueIter( a : Array ) { + return new haxe.iterators.ArrayKeyValueIterator(a); + } + + @:pure + static function now(): Float return js.lib.Date.now(); + static function __init__() untyped { #if (js_es < 5) __feature__('HxOverrides.indexOf', - if (Array.prototype.indexOf) __js__("HxOverrides").indexOf = function(a, o, i) return Array.prototype.indexOf.call(a, o, i)); + if (Array.prototype.indexOf) js.Syntax.code("HxOverrides").indexOf = function(a, o, i) return Array.prototype.indexOf.call(a, o, i)); __feature__('HxOverrides.lastIndexOf', - if (Array.prototype.lastIndexOf) __js__("HxOverrides").lastIndexOf = function(a, o, i) return Array.prototype.lastIndexOf.call(a, o, i)); + if (Array.prototype.lastIndexOf) js.Syntax.code("HxOverrides").lastIndexOf = function(a, o, i) return Array.prototype.lastIndexOf.call(a, o, i)); #end + + __feature__('HxOverrides.now', + if (js.Syntax.typeof(performance) != 'undefined' && js.Syntax.typeof(performance.now) == 'function') { + HxOverrides.now = performance.now.bind(performance); + } + ); } } diff --git a/std/js/_std/Math.hx b/std/js/_std/Math.hx index 9e41b88ce4fb60891b4963a8704b0f83f872af92..e673d2e39487f402a709ca33d6aaaea96aac3eaf 100644 --- a/std/js/_std/Math.hx +++ b/std/js/_std/Math.hx @@ -19,6 +19,8 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ +import js.Syntax.code; + // Can't enable @:coreApi because some fields are now inline getters // @:coreApi @:keepInit @@ -27,17 +29,17 @@ extern class Math { static var NEGATIVE_INFINITY(get, null):Float; @:pure private static inline function get_NEGATIVE_INFINITY():Float { - return -(untyped __js__("Infinity")); + return -code("Infinity"); } static var POSITIVE_INFINITY(get, null):Float; @:pure private static inline function get_POSITIVE_INFINITY():Float { - return (untyped __js__("Infinity")); + return code("Infinity"); } static var NaN(get, null):Float; @:pure private static inline function get_NaN():Float { - return (untyped __js__("NaN")); + return code("NaN"); } @:pure static function abs(v:Float):Float; @@ -72,11 +74,11 @@ extern class Math { } @:pure static inline function isFinite(f:Float):Bool { - return (untyped __js__("isFinite"))(f); + return code("isFinite")(f); } @:pure static inline function isNaN(f:Float):Bool { - return (untyped __js__("isNaN"))(f); + return code("isNaN")(f); } static function __init__():Void { diff --git a/std/js/_std/Reflect.hx b/std/js/_std/Reflect.hx index 69dda1e4a36cb1298d43d1b4980fdca64f1d5186..36343cd2407451889d520fcecffa9fca5344d0eb 100644 --- a/std/js/_std/Reflect.hx +++ b/std/js/_std/Reflect.hx @@ -62,10 +62,10 @@ if (o != null) untyped { var hasOwnProperty = js.lib.Object.prototype.hasOwnProperty; - __js__("for( var f in o ) {"); + js.Syntax.code("for( var f in o ) {"); if (f != "__id__" && f != "hx__closures__" && hasOwnProperty.call(o, f)) a.push(f); - __js__("}"); + js.Syntax.code("}"); } return a; } @@ -119,7 +119,7 @@ @:overload(function(f:Array->Void):Dynamic {}) public static function makeVarArgs(f:Array->Dynamic):Dynamic { return function() { - var a = untyped Array.prototype.slice.call(__js__("arguments")); + var a = untyped Array.prototype.slice.call(js.Syntax.code("arguments")); return f(a); }; } diff --git a/std/js/_std/Std.hx b/std/js/_std/Std.hx index e3f2c2140b8c1289a199980860dc00d7caedf104..dc27c1f0a046e88bf98c29cae1fc7a60645910e9 100644 --- a/std/js/_std/Std.hx +++ b/std/js/_std/Std.hx @@ -26,6 +26,10 @@ import js.Syntax; @:keepInit @:coreApi class Std { public static inline function is(v:Dynamic, t:Dynamic):Bool { + return isOfType(v, t); + } + + public static inline function isOfType(v:Dynamic, t:Dynamic):Bool { return @:privateAccess js.Boot.__instanceof(v, t); } @@ -53,8 +57,9 @@ import js.Syntax; for(i in 0...x.length) { var c = StringTools.fastCodeAt(x, i); if(c <= 8 || (c >= 14 && c != ' '.code && c != '-'.code)) { - var v:Int = Syntax.code('parseInt({0}, ({0}[{1}]=="x" || {0}[{1}]=="X") ? 16 : 10)', x, i + 1); - return Math.isNaN(v) ? null : v; + var nc = StringTools.fastCodeAt(x, i + 1); + var v = js.Lib.parseInt(x, (nc == "x".code || nc == "X".code) ? 16 : 10); + return Math.isNaN(v) ? null : cast v; } } } @@ -62,7 +67,7 @@ import js.Syntax; } public static inline function parseFloat(x:String):Float { - return untyped __js__("parseFloat")(x); + return js.Syntax.code("parseFloat({0})", x); } public static function random(x:Int):Int { @@ -77,15 +82,15 @@ import js.Syntax; __feature__("js.Boot.isClass", Array.__name__ = __feature__("Type.getClassName", "Array", true)); __feature__("Date.*", { __feature__("js.Boot.getClass", - __js__('Date').prototype.__class__ = __feature__("Type.resolveClass", $hxClasses["Date"] = __js__('Date'), __js__('Date'))); - __feature__("js.Boot.isClass", __js__('Date').__name__ = "Date"); + js.Syntax.code('Date').prototype.__class__ = __feature__("Type.resolveClass", $hxClasses["Date"] = js.Syntax.code('Date'), js.Syntax.code('Date'))); + __feature__("js.Boot.isClass", js.Syntax.code('Date').__name__ = "Date"); }); - __feature__("Int.*", __js__('var Int = { };')); - __feature__("Dynamic.*", __js__('var Dynamic = { };')); - __feature__("Float.*", __js__('var Float = Number')); - __feature__("Bool.*", __js__('var Bool = Boolean')); - __feature__("Class.*", __js__('var Class = { };')); - __feature__("Enum.*", __js__('var Enum = { };')); + __feature__("Int.*", js.Syntax.code('var Int = { };')); + __feature__("Dynamic.*", js.Syntax.code('var Dynamic = { };')); + __feature__("Float.*", js.Syntax.code('var Float = Number')); + __feature__("Bool.*", js.Syntax.code('var Bool = Boolean')); + __feature__("Class.*", js.Syntax.code('var Class = { };')); + __feature__("Enum.*", js.Syntax.code('var Enum = { };')); #if (js_es < 5) __feature__("Array.map", if (Array.prototype.map == null) Array.prototype.map = function(f) { var a = []; diff --git a/std/js/_std/Type.hx b/std/js/_std/Type.hx index 5bf6602ccb4e1df1ddc78a46e6bdb00001de13e2..ec0346dfab26d87857be91e94a1d0972b8b462f4 100644 --- a/std/js/_std/Type.hx +++ b/std/js/_std/Type.hx @@ -129,14 +129,14 @@ enum ValueType { public static function createEmptyInstance(cl:Class):T untyped { - __js__("function empty() {}; empty.prototype = cl.prototype"); - return __js__("new empty()"); + js.Syntax.code("function empty() {}; empty.prototype = cl.prototype"); + return js.Syntax.code("new empty()"); } #else - public static function createInstance(cl:Class, args:Array):T - untyped { - return untyped __js__("new ({0})", Function.prototype.bind.apply(cl, [null].concat(args))); - } + public static function createInstance(cl:Class, args:Array):T { + var ctor = ((cast js.lib.Function).prototype.bind : js.lib.Function).apply(cl, [null].concat(args)); + return js.Syntax.code("new ({0})", ctor); // cannot use `js.Syntax.construct` because we need parens if `ctor` is fused in + } public static inline function createEmptyInstance(cl:Class):T { return js.lib.Object.create((cast cl).prototype); @@ -201,7 +201,7 @@ enum ValueType { #else public static function getInstanceFields(c:Class):Array { var a = []; - untyped __js__("for(var i in c.prototype) a.push(i)"); + js.Syntax.code("for(var i in c.prototype) a.push(i)"); a.remove("__class__"); a.remove("__properties__"); return a; diff --git a/std/js/_std/haxe/Exception.hx b/std/js/_std/haxe/Exception.hx new file mode 100644 index 0000000000000000000000000000000000000000..eb9ce7697bb4e63900130345b7571384190f56bc --- /dev/null +++ b/std/js/_std/haxe/Exception.hx @@ -0,0 +1,170 @@ +package haxe; + +import js.lib.Error; + +@:coreApi +class Exception extends NativeException { + public var message(get,never):String; + public var stack(get,never):CallStack; + public var previous(get,never):Null; + public var native(get,never):Any; + + @:ifFeature("haxe.Exception.get_stack") + @:noCompletion var __skipStack:Int; + @:noCompletion var __exceptionStack(get,set):Null; + @:noCompletion var __nativeException:Any; + @:noCompletion var __previousException:Null; + + static function caught(value:Any):Exception { + if(Std.isOfType(value, Exception)) { + return value; + } else if(Std.isOfType(value, Error)) { + return new Exception((cast value:Error).message, null, value); + } else { + return new ValueException(value, null, value); + } + } + + static function thrown(value:Any):Any { + if(Std.isOfType(value, Exception)) { + return (value:Exception).native; + } else if(Std.isOfType(value, Error)) { + return value; + } else { + var e = new ValueException(value); + untyped __feature__("haxe.Exception.get_stack", e.__shiftStack()); + return e; + } + } + + public function new(message:String, ?previous:Exception, ?native:Any) { + super(message); + (cast this).message = message; + __previousException = previous; + __nativeException = native != null ? native : this; + untyped __feature__('haxe.Exception.stack', { + __skipStack = 0; + var old = js.Syntax.code('Error.prepareStackTrace'); + js.Syntax.code('Error.prepareStackTrace = function(e) { return e.stack; }'); + if(Std.isOfType(native, Error)) { + (cast this).stack = native.stack; + } else { + var e:Error = null; + if ((cast Error).captureStackTrace) { + (cast Error).captureStackTrace(this, Exception); + e = cast this; + } else { + e = new Error(); + //Internet Explorer provides call stack only if error was thrown + if(js.Syntax.typeof(e.stack) == "undefined") { + js.Syntax.code('try { throw {0}; } catch(_) {}', e); + __skipStack++; + } + } + (cast this).stack = e.stack; + } + js.Syntax.code('Error.prepareStackTrace = {0}', old); + }); + } + + function unwrap():Any { + return __nativeException; + } + + public function toString():String { + return message; + } + + public function details():String { + return inline CallStack.exceptionToString(this); + } + + @:noCompletion + @:ifFeature("haxe.Exception.get_stack") + inline function __shiftStack():Void { + __skipStack++; + } + + function get_message():String { + return (cast this:Error).message; + } + + function get_previous():Null { + return __previousException; + } + + final function get_native():Any { + return __nativeException; + } + + function get_stack():CallStack { + return switch __exceptionStack { + case null: + __exceptionStack = NativeStackTrace.toHaxe(NativeStackTrace.normalize((cast this).stack), __skipStack); + case s: s; + } + } + + @:noCompletion + function setProperty(name:String, value:Any):Void { + try { + js.lib.Object.defineProperty(this, name, {value:value}); + } catch(e:Exception) { + js.Syntax.code('{0}[{1}] = {2}', this, name, value); + } + } + + @:noCompletion + inline function get___exceptionStack():CallStack { + return (cast this).__exceptionStack; + } + + @:noCompletion + inline function set___exceptionStack(value:CallStack):CallStack { + setProperty('__exceptionStack', value); + return value; + } + + @:noCompletion + inline function get___skipStack():Int { + return (cast this).__skipStack; + } + + @:noCompletion + inline function set___skipStack(value:Int):Int { + setProperty('__skipStack', value); + return value; + } + + @:noCompletion + inline function get___nativeException():Any { + return (cast this).__nativeException; + } + + @:noCompletion + inline function set___nativeException(value:Any):Any { + setProperty('__nativeException', value); + return value; + } + + @:noCompletion + inline function get___previousException():Null { + return (cast this).__previousException; + } + + @:noCompletion + inline function set___previousException(value:Null):Null { + setProperty('__previousException', value); + return value; + } +} + +@:dox(hide) +@:noCompletion +@:native('Error') +private extern class NativeException { + // private var message:String; //redefined in haxe.Exception + // private var stack(default, null):String; //redefined in haxe.Exception + + function new(?message:String); +} diff --git a/std/js/_std/haxe/NativeStackTrace.hx b/std/js/_std/haxe/NativeStackTrace.hx new file mode 100644 index 0000000000000000000000000000000000000000..f8cab5d0998aa8a9438053ddaebe6744c687cf70 --- /dev/null +++ b/std/js/_std/haxe/NativeStackTrace.hx @@ -0,0 +1,150 @@ +package haxe; + +import js.Syntax; +import js.lib.Error; +import haxe.CallStack.StackItem; + +// https://v8.dev/docs/stack-trace-api +@:native("Error") +private extern class V8Error { + static var prepareStackTrace:(error:Error, structuredStackTrace:Array)->Any; +} + +typedef V8CallSite = { + function getFunctionName():String; + function getFileName():String; + function getLineNumber():Int; + function getColumnNumber():Int; +} + +/** + Do not use manually. +**/ +@:dox(hide) +@:noCompletion +@:allow(haxe.Exception) +class NativeStackTrace { + static var lastError:Error; + + // support for source-map-support module + @:noCompletion + public static var wrapCallSite:V8CallSite->V8CallSite; + + @:ifFeature('haxe.NativeStackTrace.exceptionStack') + static public inline function saveStack(e:Error):Void { + lastError = e; + } + + static public function callStack():Any { + var e:Null = new Error(''); + var stack = tryHaxeStack(e); + //Internet Explorer provides call stack only if error was thrown + if(Syntax.typeof(stack) == "undefined") { + try throw e catch(e:Exception) {} + stack = e.stack; + } + return normalize(stack, 2); + } + + static public function exceptionStack():Any { + return normalize(tryHaxeStack(lastError)); + } + + static public function toHaxe(s:Null, skip:Int = 0):Array { + if (s == null) { + return []; + } else if (Syntax.typeof(s) == "string") { + // Return the raw lines in browsers that don't support prepareStackTrace + var stack:Array = (s:String).split("\n"); + if (stack[0] == "Error") + stack.shift(); + var m = []; + for (i in 0...stack.length) { + if(skip > i) continue; + var line = stack[i]; + var matched:Null> = Syntax.code('{0}.match(/^ at ([A-Za-z0-9_. ]+) \\(([^)]+):([0-9]+):([0-9]+)\\)$/)', line); + if (matched != null) { + var path = matched[1].split("."); + if(path[0] == "$hxClasses") { + path.shift(); + } + var meth = path.pop(); + var file = matched[2]; + var line = Std.parseInt(matched[3]); + var column = Std.parseInt(matched[4]); + m.push(FilePos(meth == "Anonymous function" ? LocalFunction() : meth == "Global code" ? null : Method(path.join("."), meth), file, line, + column)); + } else { + m.push(Module(StringTools.trim(line))); // A little weird, but better than nothing + } + } + return m; + } else if(skip > 0 && Syntax.code('Array.isArray({0})', s)) { + return (s:Array).slice(skip); + } else { + return cast s; + } + } + + static function tryHaxeStack(e:Null):Any { + if (e == null) { + return []; + } + // https://v8.dev/docs/stack-trace-api + var oldValue = V8Error.prepareStackTrace; + V8Error.prepareStackTrace = prepareHxStackTrace; + var stack = e.stack; + V8Error.prepareStackTrace = oldValue; + return stack; + } + + static function prepareHxStackTrace(e:Error, callsites:Array):Any { + var stack = []; + for (site in callsites) { + if (wrapCallSite != null) + site = wrapCallSite(site); + var method = null; + var fullName = site.getFunctionName(); + if (fullName != null) { + var idx = fullName.lastIndexOf("."); + if (idx >= 0) { + var className = fullName.substring(0, idx); + var methodName = fullName.substring(idx + 1); + method = Method(className, methodName); + } else { + method = Method(null, fullName); + } + } + var fileName = site.getFileName(); + var fileAddr = fileName == null ? -1 : fileName.indexOf("file:"); + if (wrapCallSite != null && fileAddr > 0) + fileName = fileName.substring(fileAddr + 6); + stack.push(FilePos(method, fileName, site.getLineNumber(), site.getColumnNumber())); + } + return stack; + } + + static function normalize(stack:Any, skipItems:Int = 0):Any { + if(Syntax.code('Array.isArray({0})', stack) && skipItems > 0) { + return (stack:Array).slice(skipItems); + } else if(Syntax.typeof(stack) == "string") { + switch (stack:String).substring(0, 6) { + case 'Error:' | 'Error\n': skipItems += 1; + case _: + } + return skipLines(stack, skipItems); + } else { + //nothing we can do + return stack; + } + } + + static function skipLines(stack:String, skip:Int, pos:Int = 0):String { + return if(skip > 0) { + pos = stack.indexOf('\n', pos); + return pos < 0 ? '' : skipLines(stack, --skip, pos + 1); + } else { + return stack.substring(pos); + } + } +} \ No newline at end of file diff --git a/std/js/_std/haxe/ds/IntMap.hx b/std/js/_std/haxe/ds/IntMap.hx index d72c4e455990e7bfc764945ac8a813b2dcdce7fd..4fb0453515137fbf826ac2138a943c31c546cd7b 100644 --- a/std/js/_std/haxe/ds/IntMap.hx +++ b/std/js/_std/haxe/ds/IntMap.hx @@ -50,7 +50,7 @@ package haxe.ds; public function keys():Iterator { var a = []; - untyped __js__("for( var key in {0} ) {1}", h, if (h.hasOwnProperty(key)) a.push(key | 0)); + js.Syntax.code("for( var key in {0} ) if({0}.hasOwnProperty(key)) {1}.push(key | 0)", h, a); return a.iterator(); } diff --git a/std/js/_std/haxe/ds/ObjectMap.hx b/std/js/_std/haxe/ds/ObjectMap.hx index 13b0043a3701a251b15e20634917affe62a96ef8..fb7e2780934a019432acde3e671208451d2f8e07 100644 --- a/std/js/_std/haxe/ds/ObjectMap.hx +++ b/std/js/_std/haxe/ds/ObjectMap.hx @@ -70,18 +70,18 @@ class ObjectMap implements haxe.Constraints.IMap { var id = getId(key); if (untyped h.__keys__[id] == null) return false; - untyped __js__("delete")(h[id]); - untyped __js__("delete")(h.__keys__[id]); + js.Syntax.delete(h, id); + js.Syntax.delete(h.__keys__, id); return true; } public function keys():Iterator { var a = []; untyped { - __js__("for( var key in this.h.__keys__ ) {"); + js.Syntax.code("for( var key in this.h.__keys__ ) {"); if (h.hasOwnProperty(key)) a.push(h.__keys__[key]); - __js__("}"); + js.Syntax.code("}"); } return a.iterator(); } diff --git a/std/js/_std/haxe/ds/StringMap.hx b/std/js/_std/haxe/ds/StringMap.hx index 8af195dd9f689403927fdeb9f238bab3a746b730..b768b0676fc24e4a2c7fc1ef5a96ebbdcbbfeebd 100644 --- a/std/js/_std/haxe/ds/StringMap.hx +++ b/std/js/_std/haxe/ds/StringMap.hx @@ -22,6 +22,105 @@ package haxe.ds; +import js.lib.Object; +import haxe.Constraints.IMap; +import haxe.DynamicAccess; + +#if (js_es >= 5) +@:coreApi class StringMap implements IMap { + var h:Dynamic; + + public inline function new() { + h = Object.create(null); + } + + public inline function exists(key:String):Bool { + return Object.prototype.hasOwnProperty.call(h, key); + } + + public inline function get(key:String):Null { + return h[cast key]; + } + + public inline function set(key:String, value:T):Void { + h[cast key] = value; + } + + public inline function remove(key:String):Bool { + return if (exists(key)) { + js.Syntax.delete(h, key); true; + } else { + false; + } + } + + public inline function keys():Iterator { + return keysIterator(h); + } + + public inline function iterator():Iterator { + return valueIterator(h); + } + + public inline function keyValueIterator():KeyValueIterator { + return kvIterator(h); + } + + public inline function copy():StringMap { + return createCopy(h); + } + + public inline function clear():Void { + h = Object.create(null); + } + + public inline function toString():String { + return stringify(h); + } + + // impl + + static function keysIterator(h:Dynamic):Iterator { + var keys = Object.keys(h), len = keys.length, idx = 0; + return { + hasNext: () -> idx < len, + next: () -> keys[idx++] + }; + } + + static function valueIterator(h:Dynamic):Iterator { + var keys = Object.keys(h), len = keys.length, idx = 0; + return { + hasNext: () -> idx < len, + next: () -> h[cast keys[idx++]] + }; + } + + static function kvIterator(h:Dynamic):KeyValueIterator { + var keys = Object.keys(h), len = keys.length, idx = 0; + return { + hasNext: () -> idx < len, + next: () -> {var k = keys[idx++]; {key: k, value: h[cast k]}} + }; + } + + static function createCopy(h:Dynamic):StringMap { + var copy = new StringMap(); + js.Syntax.code("for (var key in {0}) {1}[key] = {0}[key]", h, copy.h); + return copy; + } + + @:analyzer(no_optimize) + static function stringify(h:Dynamic):String { + var s = "{", first = true; + js.Syntax.code("for (var key in {0}) {", h); + js.Syntax.code("\tif ({0}) {0} = false; else {1} += ',';", first, s); + js.Syntax.code("\t{0} += key + ' => ' + {1}({2}[key]);", s, Std.string, h); + js.Syntax.code("}"); + return s + "}"; + } +} +#else private class StringMapIterator { var map:StringMap; var keys:Array; @@ -53,7 +152,7 @@ private class StringMapIterator { } inline function isReserved(key:String):Bool { - return untyped __js__("__map_reserved")[key] != null; + return js.Syntax.code("__map_reserved[{0}]", key) != null; } public inline function set(key:String, value:T):Void { @@ -113,17 +212,17 @@ private class StringMapIterator { function arrayKeys():Array { var out = []; untyped { - __js__("for( var key in this.h ) {"); + js.Syntax.code("for( var key in this.h ) {"); if (h.hasOwnProperty(key)) out.push(key); - __js__("}"); + js.Syntax.code("}"); } if (rh != null) untyped { - __js__("for( var key in this.rh ) {"); + js.Syntax.code("for( var key in this.rh ) {"); if (key.charCodeAt(0) == "$".code) out.push(key.substr(1)); - __js__("}"); + js.Syntax.code("}"); } return out; } @@ -165,6 +264,7 @@ private class StringMapIterator { } static function __init__():Void { - untyped __js__("var __map_reserved = {};"); + js.Syntax.code("var __map_reserved = {};"); } } +#end diff --git a/std/js/lib/ArrayBuffer.hx b/std/js/lib/ArrayBuffer.hx index c3027311d69064976f2d57d813b2135db8cc3639..49a5302157e5fe9cd7fbc8dbd9d1b9efffa7fc76 100644 --- a/std/js/lib/ArrayBuffer.hx +++ b/std/js/lib/ArrayBuffer.hx @@ -47,8 +47,8 @@ private class ArrayBufferCompat { static function __init__():Void untyped { // IE10 ArrayBuffer.slice polyfill - if (__js__("ArrayBuffer").prototype.slice == null) - __js__("ArrayBuffer").prototype.slice = sliceImpl; + if (js.Syntax.code("ArrayBuffer").prototype.slice == null) + js.Syntax.code("ArrayBuffer").prototype.slice = sliceImpl; } } #end diff --git a/std/js/lib/Date.hx b/std/js/lib/Date.hx index b1aaa43925035f9179075a230ca5f91e35599669..82fc19480f6c85c56e46344bbf6cd7ccdfab727c 100644 --- a/std/js/lib/Date.hx +++ b/std/js/lib/Date.hx @@ -246,6 +246,7 @@ extern class Date { /** Returns a string with a locality sensitive representation of the date portion of this date based on system settings. **/ + @:overload(function(?locales:Array, ?options:Dynamic):String {}) function toLocaleDateString(?locales:String, ?options:Dynamic):String; /** @@ -256,11 +257,13 @@ extern class Date { /** Returns a string with a locality sensitive representation of this date. Overrides the Object.prototype.toLocaleString() method. **/ + @:overload(function(?locales:Array, ?options:Dynamic):String {}) function toLocaleString(?locales:String, ?options:Dynamic):String; /** Returns a string with a locality sensitive representation of the time portion of this date based on system settings. **/ + @:overload(function(?locales:Array, ?options:Dynamic):String {}) function toLocaleTimeString(?locales:String, ?options:Dynamic):String; /** diff --git a/std/js/lib/Float32Array.hx b/std/js/lib/Float32Array.hx index 3b4f13de9a45524f067d1b58e60b58c96de57ad5..7a0c63b1a4aec04bc779c464c7f046204a3a5684 100644 --- a/std/js/lib/Float32Array.hx +++ b/std/js/lib/Float32Array.hx @@ -92,7 +92,7 @@ extern class Float32Array implements ArrayBufferView implements ArrayAccess; + @:pure function entries():js.lib.Iterator>; /** Tests whether all elements in the array pass the test provided by a function. @@ -162,7 +162,7 @@ extern class Float32Array implements ArrayBufferView implements ArrayAccess; + @:pure function keys():js.lib.Iterator; /** Returns the last (greatest) index of an element within the array equal to the specified value, or -1 if none is found. @@ -250,7 +250,7 @@ extern class Float32Array implements ArrayBufferView implements ArrayAccess; + @:pure function values():js.lib.Iterator; /** Returns a string representing the array and its elements. diff --git a/std/js/lib/Float64Array.hx b/std/js/lib/Float64Array.hx index ae0ffbddc37b251946021805b947f8949a04cc43..d05463f624c7f612147017971960896c6406c2c2 100644 --- a/std/js/lib/Float64Array.hx +++ b/std/js/lib/Float64Array.hx @@ -92,7 +92,7 @@ extern class Float64Array implements ArrayBufferView implements ArrayAccess; + @:pure function entries():js.lib.Iterator>; /** Tests whether all elements in the array pass the test provided by a function. @@ -162,7 +162,7 @@ extern class Float64Array implements ArrayBufferView implements ArrayAccess; + @:pure function keys():js.lib.Iterator; /** Returns the last (greatest) index of an element within the array equal to the specified value, or -1 if none is found. @@ -250,7 +250,7 @@ extern class Float64Array implements ArrayBufferView implements ArrayAccess; + @:pure function values():js.lib.Iterator; /** Returns a string representing the array and its elements. diff --git a/std/cs/internal/Exceptions.hx b/std/js/lib/HaxeIterator.hx similarity index 55% rename from std/cs/internal/Exceptions.hx rename to std/js/lib/HaxeIterator.hx index 318bf2a6cfb4dce9807889e52c8322d57858e4d9..e0f88cbb788318ea496ae392ffc0e6dac000b379 100644 --- a/std/cs/internal/Exceptions.hx +++ b/std/js/lib/HaxeIterator.hx @@ -20,44 +20,34 @@ * DEALINGS IN THE SOFTWARE. */ -package cs.internal; +package js.lib; -import cs.system.Exception; +/** + `HaxeIterator` wraps a JavaScript native iterator object to enable for-in iteration in haxe. + It can be used directly: `new HaxeIterator(jsIterator)` or via using: `using HaxeIterator`. +**/ +class HaxeIterator { -@:nativeGen @:keep @:native("haxe.lang.Exceptions") class Exceptions { - @:allow(haxe.CallStack) - @:meta(System.ThreadStaticAttribute) - static var exception:cs.system.Exception; -} + final jsIterator: js.lib.Iterator; + var lastStep: js.lib.Iterator.IteratorStep; -// should NOT be usable inside Haxe code - -@:classCode('override public string Message { get { return this.toString(); } }\n\n') -@:nativeGen @:keep @:native("haxe.lang.HaxeException") private class HaxeException extends Exception { - private var obj:Dynamic; - - public function new(obj:Dynamic) { - super(); - - if (Std.is(obj, HaxeException)) { - var _obj:HaxeException = cast obj; - obj = _obj.getObject(); - } - this.obj = obj; + public inline function new(jsIterator: js.lib.Iterator) { + this.jsIterator = jsIterator; + lastStep = jsIterator.next(); } - public function getObject():Dynamic { - return obj; + public inline function hasNext(): Bool { + return !lastStep.done; } - public function toString():String { - return Std.string(obj); + public inline function next(): T { + var v = lastStep.value; + lastStep = jsIterator.next(); + return v; } - public static function wrap(obj:Dynamic):Exception { - if (Std.is(obj, Exception)) - return obj; - - return new HaxeException(obj); + public static inline function iterator(jsIterator: js.lib.Iterator) { + return new HaxeIterator(jsIterator); } -} + +} \ No newline at end of file diff --git a/std/js/lib/Int16Array.hx b/std/js/lib/Int16Array.hx index ca4f32a4eac44b89fee3c13e99b1cbd3745459e6..642637230ceaac3e6c936f04d7d96db7a910760d 100644 --- a/std/js/lib/Int16Array.hx +++ b/std/js/lib/Int16Array.hx @@ -91,7 +91,7 @@ extern class Int16Array implements ArrayBufferView implements ArrayAccess { Returns a new Array Iterator object that contains the key/value pairs for each index in the array. See also [Array.prototype.entries()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries). */ - @:pure function entries():Iterator; + @:pure function entries():js.lib.Iterator>; /** Tests whether all elements in the array pass the test provided by a function. @@ -161,7 +161,7 @@ extern class Int16Array implements ArrayBufferView implements ArrayAccess { Returns a new Array Iterator that contains the keys for each index in the array. See also [Array.prototype.keys()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/keys). */ - @:pure function keys():Iterator; + @:pure function keys():js.lib.Iterator; /** Returns the last (greatest) index of an element within the array equal to the specified value, or -1 if none is found. @@ -248,7 +248,7 @@ extern class Int16Array implements ArrayBufferView implements ArrayAccess { Returns a new Array Iterator object that contains the values for each index in the array. See also [Array.prototype.values()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values). */ - @:pure function values():Iterator; + @:pure function values():js.lib.Iterator; /** Returns a string representing the array and its elements. diff --git a/std/js/lib/Int32Array.hx b/std/js/lib/Int32Array.hx index 15857f086cfc637bd86e0ad53238a027077aef9a..020f9df12c16022e50a058f2a92eeb2fcee8a654 100644 --- a/std/js/lib/Int32Array.hx +++ b/std/js/lib/Int32Array.hx @@ -91,7 +91,7 @@ extern class Int32Array implements ArrayBufferView implements ArrayAccess { Returns a new Array Iterator object that contains the key/value pairs for each index in the array. See also [Array.prototype.entries()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries). */ - @:pure function entries():Iterator; + @:pure function entries():js.lib.Iterator>; /** Tests whether all elements in the array pass the test provided by a function. @@ -161,7 +161,7 @@ extern class Int32Array implements ArrayBufferView implements ArrayAccess { Returns a new Array Iterator that contains the keys for each index in the array. See also [Array.prototype.keys()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/keys). */ - @:pure function keys():Iterator; + @:pure function keys():js.lib.Iterator; /** Returns the last (greatest) index of an element within the array equal to the specified value, or -1 if none is found. @@ -248,7 +248,7 @@ extern class Int32Array implements ArrayBufferView implements ArrayAccess { Returns a new Array Iterator object that contains the values for each index in the array. See also [Array.prototype.values()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values). */ - @:pure function values():Iterator; + @:pure function values():js.lib.Iterator; /** Returns a string representing the array and its elements. diff --git a/std/js/lib/Int8Array.hx b/std/js/lib/Int8Array.hx index e517cea24a0a3bb5f1627c3075f6ccc5cb51c10e..81223f6c426dbcb9bbf42cf69e8243a9f8a4ff7d 100644 --- a/std/js/lib/Int8Array.hx +++ b/std/js/lib/Int8Array.hx @@ -90,7 +90,7 @@ extern class Int8Array implements ArrayBufferView implements ArrayAccess { Returns a new Array Iterator object that contains the key/value pairs for each index in the array. See also [Array.prototype.entries()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries). */ - @:pure function entries():Iterator; + @:pure function entries():js.lib.Iterator>; /** Tests whether all elements in the array pass the test provided by a function. @@ -160,7 +160,7 @@ extern class Int8Array implements ArrayBufferView implements ArrayAccess { Returns a new Array Iterator that contains the keys for each index in the array. See also [Array.prototype.keys()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/keys). */ - @:pure function keys():Iterator; + @:pure function keys():js.lib.Iterator; /** Returns the last (greatest) index of an element within the array equal to the specified value, or -1 if none is found. @@ -247,7 +247,7 @@ extern class Int8Array implements ArrayBufferView implements ArrayAccess { Returns a new Array Iterator object that contains the values for each index in the array. See also [Array.prototype.values()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values). */ - @:pure function values():Iterator; + @:pure function values():js.lib.Iterator; /** Returns a string representing the array and its elements. diff --git a/std/js/lib/Iterator.hx b/std/js/lib/Iterator.hx index 1a9006d097c6cd9a3fb94c3c3cecc89dfaa98348..35ddea5ca7c10d618eba7fcd17ce3477abca706d 100644 --- a/std/js/lib/Iterator.hx +++ b/std/js/lib/Iterator.hx @@ -22,11 +22,25 @@ package js.lib; +/** + Native JavaScript iterator structure. To enable haxe for-in iteration, use `js.lib.HaxeIterator`, for example `for (v in new js.lib.HaxeIterator(jsIterator))` or add `using js.lib.HaxeIterator;` to your module + + See [Iteration Protocols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) +**/ typedef Iterator = { function next():IteratorStep; } +/** + Native JavaScript async iterator structure. + + See [for await...of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of) +**/ +typedef AsyncIterator = { + function next():Promise>; +} + typedef IteratorStep = { done:Bool, ?value:T -} +} \ No newline at end of file diff --git a/std/python/internal/HxException.hx b/std/js/lib/KeyValue.hx similarity index 78% rename from std/python/internal/HxException.hx rename to std/js/lib/KeyValue.hx index dddde87ab00cdd1271ef713750b0e989b1e65456..cb338322e0b3625be059cf27d99ff513b487a699 100644 --- a/std/python/internal/HxException.hx +++ b/std/js/lib/KeyValue.hx @@ -20,18 +20,20 @@ * DEALINGS IN THE SOFTWARE. */ -package python.internal; +package js.lib; -@:ifFeature("has_throw") -@:native("_HxException") -class HxException extends python.Exceptions.Exception { - @:ifFeature("has_throw") - public var val:Dynamic; +/** + Key/value access helper. +**/ +abstract KeyValue(Array) { + public var key(get, never):K; + public var value(get, never):V; - @:ifFeature("has_throw") - public function new(val:Dynamic) { - var message = UBuiltins.str(val); - super(message); - this.val = val; + inline function get_key():K { + return this[0]; + } + + inline function get_value():V { + return this[1]; } } diff --git a/std/js/lib/Map.hx b/std/js/lib/Map.hx index 04822ee591ab72a83e43a718eb2db028a693a24c..f7b1f4d42d90867b643770872b527d65a2b754af 100644 --- a/std/js/lib/Map.hx +++ b/std/js/lib/Map.hx @@ -22,8 +22,6 @@ package js.lib; -import js.lib.Iterator; - /** The (native) JavaScript Map object holds key-value pairs. Any value (both objects and primitive values) may be used as either a key @@ -88,31 +86,27 @@ extern class Map { Returns a new `Iterator` object that contains the keys for each element in the `js.Map` object in insertion order. **/ - function keys():Iterator; + function keys():js.lib.Iterator; /** Returns a new `Iterator` object that contains the values for each element in the `js.Map` object in insertion order. **/ - function values():Iterator; + function values():js.lib.Iterator; /** - Returns a new `Iterator` object that contains an array of `MapEntry` + Returns a new `Iterator` object that contains an array of `KeyValue` for each element in the `js.Map` object in insertion order. **/ - function entries():Iterator>; -} - -/** - Key/value access helper for `js.Map.entries()` and `js.Set.entries()`. -**/ -abstract MapEntry(Array) { - public var key(get, never):K; - public var value(get, never):V; + function entries():js.lib.Iterator>; - inline function get_key():K - return this[0]; + inline function iterator():js.lib.HaxeIterator { + return new HaxeIterator(this.values()); + } - inline function get_value():V - return this[1]; + inline function keyValueIterator():HaxeIterator> { + return new HaxeIterator(this.entries()); + } } + +@:deprecated typedef MapEntry = KeyValue; \ No newline at end of file diff --git a/std/js/lib/RegExp.hx b/std/js/lib/RegExp.hx index 1504a798973c91010f43ada9d1fd144fdc3ed656..87d93bf7a2dea88076fbd52b2e51c390c714d2e2 100644 --- a/std/js/lib/RegExp.hx +++ b/std/js/lib/RegExp.hx @@ -22,26 +22,85 @@ package js.lib; +import haxe.DynamicAccess; + /** Native JavaScript regular expressions. For cross-platform regular expressions, use Haxe `EReg` class or [regexp literals](https://haxe.org/manual/std-regex.html). + + @see **/ @:native("RegExp") extern class RegExp { + /** + Indicates whether or not the "g" flag is used with the regular expression. + **/ var global(default, null):Bool; + + /** + Indicates whether or not the "i" flag is used with the regular expression. + **/ var ignoreCase(default, null):Bool; + + /** + Indicates whether or not the "m" flag is used with the regular expression. + **/ var multiline(default, null):Bool; + + /** + The source text of the regexp object, it doesn't contain the two forward slashes on both sides and any flags. + **/ var source(default, null):String; + + /** + The index at which to start the next match. + **/ var lastIndex:Int; + + /** + Create a regular expression object for matching text with a pattern. + **/ function new(pattern:String, ?flags:String); + + /** + Execute a search for a match in a specified string. + Returns a result array, or null. + **/ function exec(str:String):Null; + + /** + Execute a search for a match between a regular expression and a specified string. + Returns true or false. + **/ function test(str:String):Bool; + + /** + Return a string representing the regular expression. + **/ function toString():String; } +/** + A return value of the `RegExp.exec` method. +**/ extern class RegExpMatch extends Array { + /** + The index of the search at which the result was found. + **/ var index:Int; + + /** + A copy of the search string. + **/ var input:String; + + /** + Named capturing groups or undefined if no named capturing groups were defined. + See [Groups and Ranges](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges) for more information. + + Note: Not all browsers support this feature; refer to the [compatibility table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Browser_compatibility). + **/ + var groups:Null>; } diff --git a/std/js/lib/Set.hx b/std/js/lib/Set.hx index 94fa49a117c80cd462cac61785be4fe1d0dfa270..27800f58a34775f2aa7b79cbe808ecb05ad72e46 100644 --- a/std/js/lib/Set.hx +++ b/std/js/lib/Set.hx @@ -22,9 +22,6 @@ package js.lib; -import js.lib.Map.MapEntry; -import js.lib.Iterator; - /** The `js.Set` object lets you store unique values of any type, whether primitive values or object references. @@ -81,13 +78,13 @@ extern class Set { Returns a new `js.lib.Iterator` object that contains the keys for each element in the `js.Set` object in insertion order. **/ - function keys():Iterator; + function keys():js.lib.Iterator; /** Returns a new `js.lib.Iterator` object that contains the values for each element in the `js.Set` object in insertion order. **/ - function values():Iterator; + function values():js.lib.Iterator; /** Returns a new `js.lib.Iterator` object that contains an array of @@ -96,5 +93,38 @@ extern class Set { This is kept similar to the `js.Map` object, so that each entry has the same value for its key and value here. **/ - function entries():Iterator>; + function entries():js.lib.Iterator>; + + inline function iterator():HaxeIterator { + return new HaxeIterator(this.values()); + } + + inline function keyValueIterator():SetKeyValueIterator { + return new SetKeyValueIterator(this); + } +} + +/** + key => value iterator for js.lib.Set, tracking the entry index for the key to match the behavior of haxe.ds.List +**/ +class SetKeyValueIterator { + final set:js.lib.Set; + final values:HaxeIterator; + var index = 0; + + public inline function new(set:js.lib.Set) { + this.set = set; + this.values = new HaxeIterator(set.values()); + } + + public inline function hasNext():Bool { + return values.hasNext(); + } + + public inline function next():{key:Int, value:T} { + return { + key: index++, + value: values.next(), + }; + } } diff --git a/std/js/lib/Symbol.hx b/std/js/lib/Symbol.hx index c193c42abf43a4e945cc2ad01f69a0b55fd0321a..61960149ce1d3aa17f65a78f68544fff0468b1c7 100644 --- a/std/js/lib/Symbol.hx +++ b/std/js/lib/Symbol.hx @@ -53,6 +53,11 @@ extern class Symbol { **/ static var iterator(default, null):Symbol; + /** + A method that returns the default AsyncIterator for an object. + **/ + static var asyncIterator(default, null):Symbol; + /** Retrieve symbol from a given `object`. diff --git a/std/js/lib/Uint16Array.hx b/std/js/lib/Uint16Array.hx index f1eec1b6b23d7a83d601f6e3e4afcaf6a550c4ca..d6e1c4c51514dfcd00b94e20445c2f47d7cedbe1 100644 --- a/std/js/lib/Uint16Array.hx +++ b/std/js/lib/Uint16Array.hx @@ -91,7 +91,7 @@ extern class Uint16Array implements ArrayBufferView implements ArrayAccess Returns a new Array Iterator object that contains the key/value pairs for each index in the array. See also [Array.prototype.entries()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries). */ - @:pure function entries():Iterator; + @:pure function entries():js.lib.Iterator>; /** Tests whether all elements in the array pass the test provided by a function. @@ -161,7 +161,7 @@ extern class Uint16Array implements ArrayBufferView implements ArrayAccess Returns a new Array Iterator that contains the keys for each index in the array. See also [Array.prototype.keys()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/keys). */ - @:pure function keys():Iterator; + @:pure function keys():js.lib.Iterator; /** Returns the last (greatest) index of an element within the array equal to the specified value, or -1 if none is found. @@ -248,7 +248,7 @@ extern class Uint16Array implements ArrayBufferView implements ArrayAccess Returns a new Array Iterator object that contains the values for each index in the array. See also [Array.prototype.values()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values). */ - @:pure function values():Iterator; + @:pure function values():js.lib.Iterator; /** Returns a string representing the array and its elements. diff --git a/std/js/lib/Uint32Array.hx b/std/js/lib/Uint32Array.hx index 75536c8cdb1f12e62c50bacea5df40cfba8eff88..75c414bed33928002d3b163d91848c5168868748 100644 --- a/std/js/lib/Uint32Array.hx +++ b/std/js/lib/Uint32Array.hx @@ -91,7 +91,7 @@ extern class Uint32Array implements ArrayBufferView implements ArrayAccess Returns a new Array Iterator object that contains the key/value pairs for each index in the array. See also [Array.prototype.entries()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries). */ - @:pure function entries():Iterator; + @:pure function entries():js.lib.Iterator>; /** Tests whether all elements in the array pass the test provided by a function. @@ -161,7 +161,7 @@ extern class Uint32Array implements ArrayBufferView implements ArrayAccess Returns a new Array Iterator that contains the keys for each index in the array. See also [Array.prototype.keys()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/keys). */ - @:pure function keys():Iterator; + @:pure function keys():js.lib.Iterator; /** Returns the last (greatest) index of an element within the array equal to the specified value, or -1 if none is found. @@ -248,7 +248,7 @@ extern class Uint32Array implements ArrayBufferView implements ArrayAccess Returns a new Array Iterator object that contains the values for each index in the array. See also [Array.prototype.values()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values). */ - @:pure function values():Iterator; + @:pure function values():js.lib.Iterator; /** Returns a string representing the array and its elements. diff --git a/std/js/lib/Uint8Array.hx b/std/js/lib/Uint8Array.hx index 6036cb3696d4cf5a5d8ad5f1c4ad5888eece5c6d..d1303eaf0c298ee9defa6331969a45f079479456 100644 --- a/std/js/lib/Uint8Array.hx +++ b/std/js/lib/Uint8Array.hx @@ -90,7 +90,7 @@ extern class Uint8Array implements ArrayBufferView implements ArrayAccess { Returns a new Array Iterator object that contains the key/value pairs for each index in the array. See also [Array.prototype.entries()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries). */ - @:pure function entries():Iterator; + @:pure function entries():js.lib.Iterator>; /** Tests whether all elements in the array pass the test provided by a function. @@ -160,7 +160,7 @@ extern class Uint8Array implements ArrayBufferView implements ArrayAccess { Returns a new Array Iterator that contains the keys for each index in the array. See also [Array.prototype.keys()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/keys). */ - @:pure function keys():Iterator; + @:pure function keys():js.lib.Iterator; /** Returns the last (greatest) index of an element within the array equal to the specified value, or -1 if none is found. @@ -247,7 +247,7 @@ extern class Uint8Array implements ArrayBufferView implements ArrayAccess { Returns a new Array Iterator object that contains the values for each index in the array. See also [Array.prototype.values()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values). */ - @:pure function values():Iterator; + @:pure function values():js.lib.Iterator; /** Returns a string representing the array and its elements. diff --git a/std/js/lib/Uint8ClampedArray.hx b/std/js/lib/Uint8ClampedArray.hx index 4a68168b9c0492fe523d65b0ff457b694996fbcd..b2d25165ce7135ef45ae9618ba3fcf65c9fa7131 100644 --- a/std/js/lib/Uint8ClampedArray.hx +++ b/std/js/lib/Uint8ClampedArray.hx @@ -92,7 +92,7 @@ extern class Uint8ClampedArray implements ArrayBufferView implements ArrayAccess Returns a new Array Iterator object that contains the key/value pairs for each index in the array. See also [Array.prototype.entries()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries). */ - @:pure function entries():Iterator; + @:pure function entries():js.lib.Iterator>; /** Tests whether all elements in the array pass the test provided by a function. @@ -162,7 +162,7 @@ extern class Uint8ClampedArray implements ArrayBufferView implements ArrayAccess Returns a new Array Iterator that contains the keys for each index in the array. See also [Array.prototype.keys()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/keys). */ - @:pure function keys():Iterator; + @:pure function keys():js.lib.Iterator; /** Returns the last (greatest) index of an element within the array equal to the specified value, or -1 if none is found. @@ -249,7 +249,7 @@ extern class Uint8ClampedArray implements ArrayBufferView implements ArrayAccess Returns a new Array Iterator object that contains the values for each index in the array. See also [Array.prototype.values()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values). */ - @:pure function values():Iterator; + @:pure function values():js.lib.Iterator; /** Returns a string representing the array and its elements. diff --git a/std/jvm/Closure.hx b/std/jvm/Closure.hx new file mode 100644 index 0000000000000000000000000000000000000000..3e07a4b4702df5be355860b472c9260de3f5fd14 --- /dev/null +++ b/std/jvm/Closure.hx @@ -0,0 +1,65 @@ +package jvm; + +import java.NativeArray; +import java.lang.reflect.Method; + +@:native("haxe.jvm.Closure") +@:nativeGen +@:keep +class Closure extends ClosureDispatch { + public var context:Dynamic; + public var method:Method; + + var isStatic:Bool; + var params:NativeArray>; + + public function new(context:Null, method:Method) { + super(); + this.context = context; + this.method = method; + isStatic = method.getModifiers() & java.lang.reflect.Modifier.STATIC != 0; + params = method.getParameterTypes(); + } + + public function bindTo(context:Dynamic) { + return new Closure(context, method); + } + + override public function equals(other:java.lang.Object) { + if (!Jvm.instanceof(other, Closure)) { + return false; + } + var other:Closure = cast other; + return context == other.context && method == other.method; + } + + public override function invokeDynamic(args:NativeArray):Dynamic { + if (isStatic && context != null) { + var newArgs = new NativeArray(args.length + 1); + haxe.ds.Vector.blit(cast args, 0, cast newArgs, 1, args.length); + newArgs[0] = context; + args = newArgs; + } + var args = switch (jvm.Jvm.unifyCallArguments(args, params, true)) { + case Some(args): + args; + case None: + args; + }; + try { + return method.invoke(context, args); + } catch (e:java.lang.reflect.InvocationTargetException) { + throw e.getCause(); + } + } +} + +@:native("haxe.jvm.ClosureDispatch") +extern class ClosureDispatch extends Function {} + +@:native("haxe.jvm.VarArgs") +extern class VarArgs extends Function { + var func:Function; + + public function new(func:Function):Void; +} diff --git a/std/jvm/DynamicObject.hx b/std/jvm/DynamicObject.hx index f855b38097f77d97af190b63b24674015b0a4bf5..2e51178003c6ff1cac382997048681dcfb9b5595 100644 --- a/std/jvm/DynamicObject.hx +++ b/std/jvm/DynamicObject.hx @@ -6,11 +6,11 @@ import haxe.ds.StringMap; @:native('haxe.jvm.DynamicObject') @:nativeGen class DynamicObject implements java.lang.Cloneable extends Object { - static var __hx_toString_depth = 0; + @:private static var __hx_toString_depth = 0; - var _hx_fields:Null>; + @:private var _hx_fields:Null>; - public var _hx_deletedAField:Null; + @:jvm.synthetic public var _hx_deletedAField:Null; public function toString() { if (__hx_toString_depth >= 5) { @@ -44,7 +44,7 @@ class DynamicObject implements java.lang.Cloneable extends Object { return buf.toString(); } - final public function _hx_deleteField(name:String) { + @:jvm.synthetic final public function _hx_deleteField(name:String) { _hx_initReflection(); _hx_deletedAField = true; try { @@ -53,27 +53,27 @@ class DynamicObject implements java.lang.Cloneable extends Object { return _hx_fields.remove(name); } - final public function _hx_getFields() { + @:jvm.synthetic final public function _hx_getFields() { _hx_initReflection(); return [for (key in _hx_fields.keys()) key]; } - override public function _hx_getField(name:String) { + @:jvm.synthetic override public function _hx_getField(name:String) { _hx_initReflection(); return _hx_fields.get(name); } - final public function _hx_hasField(name:String) { + @:jvm.synthetic final public function _hx_hasField(name:String) { _hx_initReflection(); return _hx_fields.exists(name); } - override public function _hx_setField(name:String, value:Dynamic) { + @:jvm.synthetic override public function _hx_setField(name:String, value:Dynamic) { _hx_initReflection(); _hx_fields.set(name, value); } - final public function _hx_clone() { + @:jvm.synthetic final public function _hx_clone() { var clone:DynamicObject = (cast this : java.lang.Object).clone(); if (_hx_fields != null) { clone._hx_fields = this._hx_fields.copy(); @@ -81,13 +81,13 @@ class DynamicObject implements java.lang.Cloneable extends Object { return clone; } - final function _hx_initReflection() { + @:jvm.synthetic final function _hx_initReflection() { if (_hx_fields == null) { _hx_fields = _hx_getKnownFields(); } } - function _hx_getKnownFields():StringMap { + @:jvm.synthetic function _hx_getKnownFields():StringMap { return new StringMap(); } } diff --git a/std/jvm/Enum.hx b/std/jvm/Enum.hx index 70beb157a5e1dcf3f1342caa84ee569b31ec51a3..4e30405d23142a2a2b6703de3c02edb1dd26e68c 100644 --- a/std/jvm/Enum.hx +++ b/std/jvm/Enum.hx @@ -31,7 +31,11 @@ class Enum extends java.lang.Enum { super(name, index); } - public function _hx_getParameters() { + @:overload public function equals(other:Enum) { + return super.equals(other); + } + + @:jvm.synthetic public function _hx_getParameters() { return new java.NativeArray(0); } diff --git a/std/jvm/Function.hx b/std/jvm/Function.hx new file mode 100644 index 0000000000000000000000000000000000000000..24a8762efc20e8ba457754a256442e3999c1c851 --- /dev/null +++ b/std/jvm/Function.hx @@ -0,0 +1,13 @@ +package jvm; + +import java.NativeArray; + +@:native("haxe.jvm.Function") +@:nativeGen +extern class Function implements java.lang.Runnable { + function new():Void; + function invokeDynamic(args:NativeArray):Dynamic; + function equals(other:java.lang.Object):Bool; + function invoke(arg1:java.lang.Object):java.lang.Object; + function run():Void; +} diff --git a/std/jvm/Jvm.hx b/std/jvm/Jvm.hx index 65b0ff6c8f430d87464c9f65b40ffa149d5e2006..4bfb01d23eb40ec5d105154e553ec73e5561ebad 100644 --- a/std/jvm/Jvm.hx +++ b/std/jvm/Jvm.hx @@ -22,21 +22,20 @@ package jvm; -import haxe.extern.Rest; -import haxe.Constraints; import Enum; +import haxe.Constraints; +import haxe.ds.Option; +import haxe.ds.Vector; +import haxe.extern.Rest; +import java.Init; +import java.NativeArray; +import java.lang.NullPointerException; import jvm.DynamicObject; -import jvm.Exception; import jvm.EmptyConstructor; import jvm.Object; import jvm.annotation.ClassReflectionInformation; import jvm.annotation.EnumReflectionInformation; import jvm.annotation.EnumValueReflectionInformation; -import java.lang.invoke.*; -import java.NativeArray; -import java.Init; -import haxe.ds.Vector; -import haxe.ds.Option; @:keep @:native('haxe.jvm.Jvm') @@ -45,8 +44,6 @@ class Jvm { extern static public function referenceEquals(v1:T, v2:T):Bool; - extern static public function invokedynamic(bootstrapMethod:Function, fieldName:String, staticArguments:Array, rest:Rest):T; - static public function stringCompare(v1:String, v2:String):Int { if (v1 == null) { return v2 == null ? 0 : 1; @@ -61,6 +58,16 @@ class Jvm { return Reflect.compare(v1, v2); } + static public function enumEq(v1:Dynamic, v2:Dynamic) { + if (!instanceof(v1, jvm.Enum)) { + return false; + } + if (!instanceof(v2, jvm.Enum)) { + return false; + } + return Type.enumEq(v1, v2); + } + // calls static public function getArgumentTypes(args:NativeArray):NativeArray> { @@ -127,7 +134,7 @@ class Jvm { continue; } if (arg == (cast java.lang.Double.DoubleClass) && argType == cast java.lang.Integer.IntegerClass) { - callArgs[i] = nullIntToNullFloat(args[i]); + callArgs[i] = numberToDouble(args[i]); } else { return None; } @@ -135,33 +142,81 @@ class Jvm { return Some(callArgs); } - static public function call(mh:java.lang.invoke.MethodHandle, args:NativeArray) { - var params = mh.type().parameterArray(); - return switch (unifyCallArguments(args, params, true)) { - case Some(args): mh.invokeWithArguments(args); - case None: mh.invokeWithArguments(args); - } + static public function call(func:jvm.Function, args:NativeArray) { + return func.invokeDynamic(args); } // casts + // TODO: add other dynamicToType methods - static public function dynamicToNullFloat(d:T):Null { - if (instanceof(d, java.lang.Integer.IntegerClass)) { - return nullIntToNullFloat(cast d); + static public function dynamicToByte(d:T):Null { + if (instanceof(d, java.lang.Number)) { + return numberToByte(cast d); } - // TODO: need a better strategy to avoid infinite recursion here return cast d; } - static public function nullIntToNullFloat(i:Null):Null { - if (i == null) { - return null; + static public function dynamicToShort(d:T):Null { + if (instanceof(d, java.lang.Number)) { + return numberToShort(cast d); + } + return cast d; + } + + static public function dynamicToInteger(d:T):Null { + if (instanceof(d, java.lang.Number)) { + return numberToInteger(cast d); + } + return cast d; + } + + static public function dynamicToLong(d:T):Null { + if (instanceof(d, java.lang.Number)) { + return numberToLong(cast d); } - return (cast i : java.lang.Number).intValue(); + return cast d; + } + + static public function dynamicToFloat(d:T):Null { + if (instanceof(d, java.lang.Number)) { + return numberToFloat(cast d); + } + return cast d; + } + + static public function dynamicToDouble(d:T):Null { + if (instanceof(d, java.lang.Number)) { + return numberToDouble(cast d); + } + return cast d; + } + + static public function numberToByte(n:java.lang.Number):Null { + return n == null ? null : n.byteValue(); + } + + static public function numberToShort(n:java.lang.Number):Null { + return n == null ? null : n.shortValue(); + } + + static public function numberToInteger(n:java.lang.Number):Null { + return n == null ? null : n.intValue(); + } + + static public function numberToLong(n:java.lang.Number):Null { + return n == null ? null : n.longValue(); + } + + static public function numberToFloat(n:java.lang.Number):Null { + return n == null ? null : n.floatValue(); + } + + static public function numberToDouble(n:java.lang.Number):Null { + return n == null ? null : n.doubleValue(); } static public function toByte(d:Dynamic) { - return d == null ? 0 : (d : java.lang.Byte).byteValue(); + return d == null ? 0 : (d : java.lang.Number).byteValue(); } static public function toChar(d:Dynamic) { @@ -181,11 +236,11 @@ class Jvm { } static public function toLong(d:Dynamic) { - return d == null ? 0 : (d : java.lang.Long).longValue(); + return d == null ? 0 : (d : java.lang.Number).longValue(); } static public function toShort(d:Dynamic) { - return d == null ? 0 : (d : java.lang.Short).shortValue(); + return d == null ? 0 : (d : java.lang.Number).shortValue(); } static public function toBoolean(d:Dynamic) { @@ -225,9 +280,21 @@ class Jvm { throw 'Cannot array-write on $obj'; } - static public function bootstrap(caller:MethodHandles.MethodHandles_Lookup, name:String, type:MethodType):CallSite { - var handle = caller.findStatic(caller.lookupClass(), name, type); - return new ConstantCallSite(handle); + static public function readFieldClosure(obj:Dynamic, name:String, parameterTypes:NativeArray>):Dynamic { + var cl = (obj : java.lang.Object).getClass(); + var method = cl.getMethod(name, parameterTypes); + if (method.isBridge()) { + /* This is probably not what we want... go through all methods and see if we find one that + isn't a bridge. This is pretty awkward, but I can't figure out how to use the Java reflection + API properly. */ + for (meth in cl.getMethods()) { + if (meth.getName() == name && !meth.isBridge() && method.getParameterTypes().length == parameterTypes.length) { + method = meth; + break; + } + } + } + return new jvm.Closure(obj, method); } static public function readFieldNoObject(obj:Dynamic, name:String):Dynamic { @@ -241,12 +308,12 @@ class Jvm { while (cl != null) { var methods = cl.getMethods(); for (m in methods) { - if (m.getName() == name) { - var method = java.lang.invoke.MethodHandles.lookup().unreflect(m); + if (m.getName() == name && !m.isSynthetic()) { + var context = null; if (!isStatic || cl == cast java.lang.Class) { - method = method.bindTo(obj); + context = obj; } - return method; + return new jvm.Closure(context, m); } } if (isStatic) { @@ -263,7 +330,10 @@ class Jvm { } static public function readField(obj:Dynamic, name:String):Dynamic { - if (obj == null || name == null) { + if (obj == null) { + throw new NullPointerException(name); + } + if (name == null) { return null; } if (instanceof(obj, jvm.Object)) { @@ -274,27 +344,27 @@ class Jvm { case "length": return (obj : String).length; case "charAt": - return (cast jvm.StringExt.charAt : java.lang.invoke.MethodHandle).bindTo(obj); + return (readFieldNoObject(jvm.StringExt, "charAt") : Closure).bindTo(obj); case "charCodeAt": - return (cast jvm.StringExt.charCodeAt : java.lang.invoke.MethodHandle).bindTo(obj); + return (readFieldNoObject(jvm.StringExt, "charCodeAt") : Closure).bindTo(obj); case "indexOf": - return (cast jvm.StringExt.indexOf : java.lang.invoke.MethodHandle).bindTo(obj); + return (readFieldNoObject(jvm.StringExt, "indexOf") : Closure).bindTo(obj); case "iterator": return function() return new haxe.iterators.StringIterator(obj); case "keyValueIterator": return function() return new haxe.iterators.StringKeyValueIterator(obj); case "lastIndexOf": - return (cast jvm.StringExt.lastIndexOf : java.lang.invoke.MethodHandle).bindTo(obj); + return (readFieldNoObject(jvm.StringExt, "lastIndexOf") : Closure).bindTo(obj); case "split": - return (cast jvm.StringExt.split : java.lang.invoke.MethodHandle).bindTo(obj); + return (readFieldNoObject(jvm.StringExt, "split") : Closure).bindTo(obj); case "substr": - return (cast jvm.StringExt.substr : java.lang.invoke.MethodHandle).bindTo(obj); + return (readFieldNoObject(jvm.StringExt, "substr") : Closure).bindTo(obj); case "substring": - return (cast jvm.StringExt.substring : java.lang.invoke.MethodHandle).bindTo(obj); + return (readFieldNoObject(jvm.StringExt, "substring") : Closure).bindTo(obj); case "toLowerCase": - return (cast jvm.StringExt.toLowerCase : java.lang.invoke.MethodHandle).bindTo(obj); + return (readFieldNoObject(jvm.StringExt, "toLowerCase") : Closure).bindTo(obj); case "toUpperCase": - return (cast jvm.StringExt.toUpperCase : java.lang.invoke.MethodHandle).bindTo(obj); + return (readFieldNoObject(jvm.StringExt, "toUpperCase") : Closure).bindTo(obj); } } return readFieldNoObject(obj, name); diff --git a/std/jvm/NativeTools.hx b/std/jvm/NativeTools.hx index e87fd56ad6d41e7d42b24889d18cd493e5634f36..837963c65d444eebe34ce1fad677d54196b71152 100644 --- a/std/jvm/NativeTools.hx +++ b/std/jvm/NativeTools.hx @@ -23,27 +23,27 @@ package jvm; extern class ObjectTools { - static public inline function object(t:T):java.lang.Object { + static inline function object(t:T):java.lang.Object { return cast t; } } extern class NativeClassTools { - static public inline function native(c:Class):java.lang.Class { + static inline function native(c:Class):java.lang.Class { return cast c; } - static public inline function haxe(c:java.lang.Class):Class { + static inline function haxe(c:java.lang.Class):Class { return cast c; } - static public inline function haxeEnum(c:java.lang.Class):std.Enum { + static inline function haxeEnum(c:java.lang.Class):std.Enum { return cast c; } } extern class NativeEnumTools { - static public inline function native(e:std.Enum):java.lang.Class { + static inline function native(e:std.Enum):java.lang.Class { return cast e; } } diff --git a/std/jvm/Object.hx b/std/jvm/Object.hx index 05f8adf94dc0093133868cc623fee32c8c3ff470..8c13fb2e8e24b59e1e690bab75503ce6585d13e4 100644 --- a/std/jvm/Object.hx +++ b/std/jvm/Object.hx @@ -28,11 +28,11 @@ package jvm; class Object { public function new() {} - public function _hx_getField(name:String) { + @:jvm.synthetic public function _hx_getField(name:String) { return Jvm.readFieldNoObject(this, name); } - public function _hx_setField(name:String, value:Dynamic) { + @:jvm.synthetic public function _hx_setField(name:String, value:Dynamic) { return Jvm.writeFieldNoObject(this, name, value); } } diff --git a/std/jvm/StringExt.hx b/std/jvm/StringExt.hx index 69e340719cc1989f4103fea53aebc86f30d721fa..c540d66b31a6f0b08aa903398092e8d98aedc192 100644 --- a/std/jvm/StringExt.hx +++ b/std/jvm/StringExt.hx @@ -25,6 +25,7 @@ package jvm; import java.NativeString; @:native("haxe.jvm.StringExt") +@:keep class StringExt { public static function fromCharCode(code:Int):String { var a = new java.NativeArray(1); @@ -51,6 +52,9 @@ class StringExt { } public static function lastIndexOf(me:String, str:String, ?startIndex:Int):Int { + if(str == '') { + return startIndex == null || startIndex > me.length ? me.length : startIndex; + } if (startIndex == null || startIndex > me.length || startIndex < 0) { startIndex = me.length - 1; } diff --git a/std/jvm/_std/Reflect.hx b/std/jvm/_std/Reflect.hx index 4b587c1d60ec496bb9530df2348cc57b181fb942..1f134c40cf3bb661f2f6c81c32b3ec6f49597612 100644 --- a/std/jvm/_std/Reflect.hx +++ b/std/jvm/_std/Reflect.hx @@ -38,6 +38,9 @@ class Reflect { } public static function field(o:Dynamic, field:String):Dynamic { + if (o == null) { + return null; + } return Jvm.readField(o, field); } @@ -84,7 +87,7 @@ class Reflect { } public static function isFunction(f:Dynamic):Bool { - return Jvm.instanceof(f, java.lang.invoke.MethodHandle); + return Jvm.instanceof(f, jvm.Function); } public static function compare(a:T, b:T):Int { @@ -120,15 +123,13 @@ class Reflect { if (c1 != (f2 : java.lang.Object).getClass()) { return false; } - try { - var arg0 = c1.getDeclaredField("argL0"); - arg0.setAccessible(true); - var arg1 = c1.getDeclaredField("argL1"); - arg1.setAccessible(true); - return arg0.get(f1) == arg0.get(f2) && arg1.get(f1) == arg1.get(f2); - } catch (_:Dynamic) { - return false; + if (Std.is(f1, jvm.Function)) { + if (!Std.is(f2, jvm.Function)) { + return false; + } + return (f1 : jvm.Function).equals(f2); } + return false; } public static function isObject(v:Dynamic):Bool { @@ -144,7 +145,7 @@ class Reflect { if (Jvm.instanceof(v, java.lang.Boolean.BooleanClass)) { return false; } - if (Jvm.instanceof(v, java.lang.invoke.MethodHandle)) { + if (Jvm.instanceof(v, jvm.Function)) { return false; } return true; @@ -174,9 +175,6 @@ class Reflect { @:overload(function(f:Array->Void):Dynamic {}) public static function makeVarArgs(f:Array->Dynamic):Dynamic { - var fAdapt = function(args:java.NativeArray) { - return f(@:privateAccess Array.ofNative(args)); - } - return (cast fAdapt : java.lang.invoke.MethodHandle).asVarargsCollector(cast java.NativeArray); + return new jvm.Closure.VarArgs((cast f : jvm.Function)); } } diff --git a/std/jvm/_std/Std.hx b/std/jvm/_std/Std.hx index 5cab34e15a678a59f3b65c1863411f37bb3123fc..f3f7e08ca73742948a5b44bad09fab5da076f2e7 100644 --- a/std/jvm/_std/Std.hx +++ b/std/jvm/_std/Std.hx @@ -24,7 +24,11 @@ import jvm.Jvm; @:coreApi class Std { - public static function is(v:Dynamic, t:Dynamic):Bool { + public static inline function is(v:Dynamic, t:Dynamic):Bool { + return isOfType(v, t); + } + + public static function isOfType(v:Dynamic, t:Dynamic):Bool { if (v == null || t == null) { return false; } @@ -58,47 +62,106 @@ class Std { return cast x; } - static var integerFormatter = java.text.NumberFormat.getIntegerInstance(java.util.Locale.US); - static var doubleFormatter = { - var fmt = new java.text.DecimalFormat(); - fmt.setParseBigDecimal(true); - fmt.setDecimalFormatSymbols(new java.text.DecimalFormatSymbols(java.util.Locale.US)); - fmt; - }; - public static function parseInt(x:String):Null { - try { - x = StringTools.trim(x); - var signChars = switch (cast x : java.NativeString).codePointAt(0) { - case '-'.code | '+'.code: 1; - case _: 0; + if (x == null) { + return null; + } + + var base = 10; + var len = x.length; + var foundCount = 0; + var sign = 0; + var firstDigitIndex = 0; + var lastDigitIndex = -1; + var previous = 0; + + for (i in 0...len) { + var c = StringTools.fastCodeAt(x, i); + switch c { + case _ if ((c > 8 && c < 14) || c == 32): + if (foundCount > 0) { + return null; + } + continue; + case '-'.code if (foundCount == 0): + sign = -1; + case '+'.code if (foundCount == 0): + sign = 1; + case '0'.code if (foundCount == 0 || (foundCount == 1 && sign != 0)): + case 'x'.code | 'X'.code if (previous == '0'.code && ((foundCount == 1 && sign == 0) || (foundCount == 2 && sign != 0))): + base = 16; + case _ if ('0'.code <= c && c <= '9'.code): + case _ if (base == 16 && (('a'.code <= c && c <= 'z'.code) || ('A'.code <= c && c <= 'Z'.code))): + case _: + break; } - if (x.length < 2 + signChars) { - return integerFormatter.parse(x).intValue(); + if ((foundCount == 0 && sign == 0) || (foundCount == 1 && sign != 0)) { + firstDigitIndex = i; } - switch ((cast x : java.NativeString).codePointAt(1 + signChars)) { - case 'x'.code | 'X'.code: - return java.lang.Integer.decode(x).intValue(); - case _: - return integerFormatter.parse(x).intValue(); + foundCount++; + lastDigitIndex = i; + previous = c; + } + if (firstDigitIndex <= lastDigitIndex) { + var digits = x.substring(firstDigitIndex + (base == 16 ? 2 : 0), lastDigitIndex + 1); + return try { + (sign == -1 ? -1 : 1) * java.lang.Integer.parseInt(digits, base); + } catch (e:java.lang.NumberFormatException) { + null; } - } catch (_:Dynamic) { - return null; } + return null; } public static function parseFloat(x:String):Float { - try { - x = StringTools.trim(x); - x = x.split("+").join(""); // TODO: stupid - return doubleFormatter.parse(x.toUpperCase()).doubleValue(); - } catch (_:Dynamic) { + if (x == null) { return Math.NaN; } + x = StringTools.ltrim(x); + var xn:java.NativeString = cast x; + var found = false, + hasDot = false, + hasSign = false, + hasE = false, + hasESign = false, + hasEData = false; + var i = -1; + + while (++i < x.length) { + var chr:Int = cast xn.charAt(i); + if (chr >= '0'.code && chr <= '9'.code) { + if (hasE) { + hasEData = true; + } + found = true; + } else + switch (chr) { + case 'e'.code | 'E'.code if (!hasE): + hasE = true; + case '.'.code if (!hasDot): + hasDot = true; + case '-'.code, '+'.code if (!found && !hasSign): + hasSign = true; + case '-'.code | '+'.code if (found && !hasESign && hasE && !hasEData): + hasESign = true; + case _: + break; + } + } + if (hasE && !hasEData) { + i--; + if (hasESign) + i--; + } + + if (i != x.length) { + x = x.substr(0, i); + } + return try java.lang.Double.DoubleClass.parseDouble(x) catch (e:Dynamic) Math.NaN; } inline public static function downcast(value:T, c:Class):S { - return Std.is(value, c) ? cast value : null; + return Std.isOfType(value, c) ? cast value : null; } @:deprecated('Std.instance() is deprecated. Use Std.downcast() instead.') diff --git a/std/jvm/_std/StringBuf.hx b/std/jvm/_std/StringBuf.hx new file mode 100644 index 0000000000000000000000000000000000000000..95140ace703422a6a034355a5e1953895376adba --- /dev/null +++ b/std/jvm/_std/StringBuf.hx @@ -0,0 +1,105 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +@:coreApi +class StringBuf { + private var b:java.lang.StringBuilder; + + public var length(get, never):Int; + + public function new():Void { + b = new java.lang.StringBuilder(); + } + + inline function get_length():Int { + return b.length(); + } + + public function add(x:T):Void { + if (jvm.Jvm.instanceof(x, java.lang.Double.DoubleClass)) { + b.append(jvm.Jvm.toString(cast x)); + } else { + b.append(x); + } + } + + @:overload + @:native("add") + @:ifFeature("StringBuf.add") + function addOpt(v:Bool):Void { + b.append(v); + } + + @:overload + @:native("add") + @:ifFeature("StringBuf.add") + function addOpt(v:java.types.Char16):Void { + b.append(v); + } + + @:overload + @:native("add") + @:ifFeature("StringBuf.add") + function addOpt(v:Float):Void { + b.append(v); + } + + @:overload + @:native("add") + @:ifFeature("StringBuf.add") + function addOpt(v:Single):Void { + b.append(v); + } + + @:overload + @:native("add") + @:ifFeature("StringBuf.add") + function addOpt(v:Int):Void { + b.append(v); + } + + @:overload + @:native("add") + @:ifFeature("StringBuf.add") + function addOpt(v:haxe.Int64):Void { + b.append(v); + } + + @:overload + @:native("add") + @:ifFeature("StringBuf.add") + function addOpt(v:String):Void { + b.append(v); + } + + public function addSub(s:String, pos:Int, ?len:Int):Void { + var l:Int = (len == null) ? s.length - pos : len; + b.append(s, pos, pos + l); + } + + public function addChar(c:Int):Void { + b.appendCodePoint(c); + } + + public function toString():String { + return b.toString(); + } +} diff --git a/std/jvm/_std/Type.hx b/std/jvm/_std/Type.hx index dc81f971692d6d74787d917c3d2f134ac8c81c28..7fbd8c44d1e27932140608ec6645a9244942bc78 100644 --- a/std/jvm/_std/Type.hx +++ b/std/jvm/_std/Type.hx @@ -1,7 +1,6 @@ -import java.lang.invoke.*; import java.lang.NoSuchMethodException; -import jvm.annotation.*; import jvm.Jvm; +import jvm.annotation.*; using jvm.NativeTools.NativeClassTools; using jvm.NativeTools.NativeEnumTools; @@ -133,43 +132,40 @@ class Type { public static function createInstance(cl:Class, args:Array):T { var args = @:privateAccess args.getNative(); var cl = cl.native(); - var argTypes = Jvm.getArgumentTypes(args); - var methodType = MethodType.methodType(cast Void, argTypes); - // 1. attempt: direct constructor lookup - try { - var ctor = MethodHandles.lookup().findConstructor(cl, methodType); - return ctor.invokeWithArguments(args); - } catch (_:NoSuchMethodException) {} - - // 2. attempt direct new lookup - try { - var ctor = MethodHandles.lookup().findVirtual(cl, "new", methodType); - var obj = cl.getConstructor(emptyClass).newInstance(emptyArg); - ctor.bindTo(obj).invokeWithArguments(args); - return obj; - } catch (_:NoSuchMethodException) {} - - // 3. attempt: unify actual constructor - for (ctor in cl.getDeclaredConstructors()) { - switch (Jvm.unifyCallArguments(args, ctor.getParameterTypes())) { - case Some(args): - return MethodHandles.lookup().unreflectConstructor(ctor).invokeWithArguments(args); - case None: - } - } - - // 4. attempt: unify new - for (ctor in cl.getDeclaredMethods()) { - if (ctor.getName() != "new") { + var ctors = cl.getConstructors(); + var emptyCtor:Null> = null; + // 1. Look for real constructor. If we find the EmptyConstructor constructor, store it + for (ctor in ctors) { + var params = ctor.getParameterTypes(); + if (params.length == 1 && params[0] == jvm.EmptyConstructor.native()) { + emptyCtor = cast ctor; continue; } - switch (Jvm.unifyCallArguments(args, ctor.getParameterTypes())) { + switch (Jvm.unifyCallArguments(args, params, true)) { case Some(args): - return MethodHandles.lookup().unreflect(ctor).invokeWithArguments(args); + ctor.setAccessible(true); + return ctor.newInstance(args); case None: } } - + // 2. If there was the EmptyConstructor constructor, look for a matching new method + if (emptyCtor != null) { + var methods = cl.getMethods(); + for (method in methods) { + if (method.getName() != "new") { + continue; + } + var params = method.getParameterTypes(); + switch (Jvm.unifyCallArguments(args, params, true)) { + case Some(args): + var obj = emptyCtor.newInstance(emptyArg); + method.setAccessible(true); + method.invoke(obj, args); + return obj; + case None: + } + } + } return null; } @@ -185,7 +181,7 @@ class Type { public static function createEnum(e:Enum, constr:String, ?params:Array):T { if (params == null || params.length == 0) { var v:Dynamic = Jvm.readField(e, constr); - if (!Std.is(v, e)) { + if (!Std.isOfType(v, e)) { throw 'Could not create enum value ${getEnumName(e)}.$constr: Unexpected value $v'; } return v; @@ -260,7 +256,7 @@ class Type { if (Jvm.instanceof(v, jvm.DynamicObject)) { return TObject; } - if (Jvm.instanceof(v, java.lang.invoke.MethodHandle)) { + if (Jvm.instanceof(v, jvm.Function)) { return TFunction; } var c = (cast v : java.lang.Object).getClass(); @@ -278,31 +274,9 @@ class Type { if (a == null) { return b == null; } - if (b == null) { - return false; - } var a:jvm.Enum = cast a; var b:jvm.Enum = cast b; - if (a.ordinal() != b.ordinal()) { - return false; - } - var params1 = a._hx_getParameters(); - var params2 = b._hx_getParameters(); - if (params1.length != params2.length) { - return false; - } - for (i in 0...params1.length) { - if (params1[i] != params2[i]) { - if (Jvm.instanceof(params1[i], jvm.Enum)) { - if (!enumEq(params1[i], params2[i])) { - return false; - } - } else { - return false; - } - } - } - return true; + return a.equals(b); } public static function enumConstructor(e:EnumValue):String { diff --git a/std/jvm/_std/haxe/ds/StringMap.hx b/std/jvm/_std/haxe/ds/StringMap.hx new file mode 100644 index 0000000000000000000000000000000000000000..4d77e119f484d8512989338045c9573e64147b12 --- /dev/null +++ b/std/jvm/_std/haxe/ds/StringMap.hx @@ -0,0 +1,91 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package haxe.ds; + +@:coreApi +class StringMap implements haxe.Constraints.IMap { + var hashMap:java.util.HashMap; + + @:overload + public function new():Void { + hashMap = new java.util.HashMap(); + } + + @:overload + function new(hashMap:java.util.HashMap):Void { + this.hashMap = hashMap; + } + + public function set(key:String, value:T):Void { + hashMap.put(key, value); + } + + public function get(key:String):Null { + return hashMap.get(key); + } + + public function exists(key:String):Bool { + return hashMap.containsKey(key); + } + + public function remove(key:String):Bool { + var has = exists(key); + hashMap.remove(key); + return has; + } + + public inline function keys():Iterator { + return hashMap.keySet().iterator(); + } + + @:runtime public inline function keyValueIterator():KeyValueIterator { + return new haxe.iterators.MapKeyValueIterator(this); + } + + public inline function iterator():Iterator { + return hashMap.values().iterator(); + } + + public function copy():StringMap { + return new StringMap(hashMap.clone()); + } + + public function toString():String { + var s = new StringBuf(); + s.add("{"); + var it = keys(); + for (i in it) { + s.add(i); + s.add(" => "); + s.add(Std.string(get(i))); + if (it.hasNext()) + s.add(", "); + } + s.add("}"); + return s.toString(); + } + + public function clear():Void { + hashMap.clear(); + } +} diff --git a/std/jvm/Exception.hx b/std/jvm/_std/sys/thread/Lock.hx similarity index 61% rename from std/jvm/Exception.hx rename to std/jvm/_std/sys/thread/Lock.hx index 1a7cf5e8069822df51c5036cef669394efb7699f..a2d92cd1a757be778d6aa2079982c993bc3f1fd9 100644 --- a/std/jvm/Exception.hx +++ b/std/jvm/_std/sys/thread/Lock.hx @@ -20,41 +20,36 @@ * DEALINGS IN THE SOFTWARE. */ -package jvm; +package sys.thread; -@:keep -@:native('haxe.jvm.Exception') -class Exception extends java.lang.Exception { - static public var exception = new java.lang.ThreadLocal(); +@:coreApi +class Lock { + var deque:Deque; - static public function setException(exc:java.lang.Throwable) { - exception.set(exc); + public function new() { + deque = new Deque(); } - static public function currentException() { - return exception.get(); - } - - public var value:T; - - public function new(value:T) { - super(); - this.value = value; - } - - @:overload override public function toString() { - return Std.string(value); - } - - public function unwrap() { - return value; - } - - static public function wrap(t:Null) { - if (Jvm.instanceof(t, java.lang.Exception)) { - return (cast t : java.lang.Exception); + public function wait(?timeout:Float):Bool { + if (deque.pop(false) == null) { + if (timeout == null) { + deque.pop(true); + return true; + } + var targetTime = Sys.time() + timeout; + while (Sys.time() < targetTime) { + if (deque.pop(false) != null) { + return true; + } + Sys.sleep(0.0001); + } + return false; } else { - return new Exception(t); + return true; } } + + public function release():Void { + deque.push(""); + } } diff --git a/std/jvm/_std/sys/thread/Thread.hx b/std/jvm/_std/sys/thread/Thread.hx new file mode 100644 index 0000000000000000000000000000000000000000..998a72a204b8be9f967acd782a100c1e43c64d13 --- /dev/null +++ b/std/jvm/_std/sys/thread/Thread.hx @@ -0,0 +1,80 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package sys.thread; + +import java.Lib; +import java.lang.Runnable; + +abstract Thread(HaxeThread) { + inline function new(t:HaxeThread) { + this = t; + } + + public static function create(callb:Void->Void):Thread { + var haxeThread = new HaxeThread(new java.lang.Thread((cast callb : Runnable))); + haxeThread.native.setDaemon(true); + haxeThread.native.start(); + return new Thread(haxeThread); + } + + public static function current():Thread { + var nativeThread = java.lang.Thread.currentThread(); + Lib.lock(HaxeThread.threadMap, { + var haxeThread = HaxeThread.threadMap.get(nativeThread); + return new Thread(haxeThread); + }); + return null; + } + + public static function readMessage(block:Bool):Dynamic { + return current().getHandle().messages.pop(block); + } + + public inline function sendMessage(msg:Dynamic):Void { + this.sendMessage(msg); + } + + private inline function getHandle():HaxeThread { + return this; + } +} + +class HaxeThread { + static public var threadMap = new haxe.ds.WeakMap(); + + @:keep + static var mainHaxeThread = new HaxeThread(java.lang.Thread.currentThread()); + + public var messages:Deque; + public var native:java.lang.Thread; + + public function new(native:java.lang.Thread) { + this.native = native; + this.messages = new Deque(); + Lib.lock(threadMap, threadMap.set(native, this)); + } + + public function sendMessage(msg:Dynamic):Void { + messages.add(msg); + } +} diff --git a/std/lua/Bit.hx b/std/lua/Bit.hx index 83ce4c1080db89b525ad51a6b9103a677c2b634f..bb2771ce102d1328a988b23db08b3ab3c58fc94d 100644 --- a/std/lua/Bit.hx +++ b/std/lua/Bit.hx @@ -27,15 +27,15 @@ package lua; **/ @:native("_hx_bit") extern class Bit { - public static function bnot(x:Float):Int; - public static function band(a:Float, b:Float):Int; - public static function bor(a:Float, b:Float):Int; - public static function bxor(a:Float, b:Float):Int; - public static function lshift(x:Float, places:Int):Int; - public static function rshift(x:Float, places:Int):Int; - public static function arshift(x:Float, places:Int):Int; - public static function mod(numerator:Float, denominator:Float):Int; - public static function __init__():Void { + static function bnot(x:Float):Int; + static function band(a:Float, b:Float):Int; + static function bor(a:Float, b:Float):Int; + static function bxor(a:Float, b:Float):Int; + static function lshift(x:Float, places:Int):Int; + static function rshift(x:Float, places:Int):Int; + static function arshift(x:Float, places:Int):Int; + static function mod(numerator:Float, denominator:Float):Int; + static function __init__():Void { untyped _hx_bit = __define_feature__("use._bitop", _hx_bit); } } diff --git a/std/lua/Boot.hx b/std/lua/Boot.hx index b0e7189014fcf84e0daa0fc2b63cfb97ec0dc542..c37534f31b0f110af290721ff72dabe5192882ae 100644 --- a/std/lua/Boot.hx +++ b/std/lua/Boot.hx @@ -22,7 +22,6 @@ package lua; -import haxe.Constraints.Function; import haxe.SysTools; @:dox(hide) @@ -40,8 +39,7 @@ class Boot { public static var platformBigEndian = NativeStringTools.byte(NativeStringTools.dump(function() {}), 7) > 0; - static var hiddenFields:Table = untyped __lua__("{__id__=true, hx__closures=true, super=true, prototype=true, __fields__=true, __ifields__=true, __class__=true, __properties__=true}"); + static var hiddenFields:Table = untyped __lua__("{__id__=true, hx__closures=true, super=true, prototype=true, __fields__=true, __ifields__=true, __class__=true, __properties__=true}"); static function __unhtml(s:String) return s.split("&").join("&").split("<").join("<").split(">").join(">"); @@ -71,9 +69,9 @@ class Boot { for the given class. **/ static inline public function getClass(o:Dynamic):Class { - if (Std.is(o, Array)) + if (Std.isOfType(o, Array)) return Array; - else if (Std.is(o, String)) + else if (Std.isOfType(o, String)) return String; else { var cl = untyped __define_feature__("lua.Boot.getClass", o.__class__); @@ -154,110 +152,6 @@ class Boot { throw "Cannot cast " + Std.string(o) + " to " + Std.string(t); } - /** - Helper method to generate a string representation of an enum - **/ - static function printEnum(o:Array, s:String) { - if (o.length == 2) { - return o[0]; - } else { - // parameterized enums are arrays - var str = o[0] + "("; - s += "\t"; - for (i in 2...o.length) { - if (i != 2) - str += "," + __string_rec(o[i], s); - else - str += __string_rec(o[i], s); - } - return str + ")"; - } - } - - /** - Helper method to generate a string representation of a class - **/ - static inline function printClass(c:Table, s:String):String { - return '{${printClassRec(c, '', s)}}'; - } - - /** - Helper method to generate a string representation of a class - **/ - static function printClassRec(c:Table, result = '', s:String):String { - var f = Boot.__string_rec; - untyped __lua__("for k,v in pairs(c) do if result ~= '' then result = result .. ', ' end result = result .. k .. ':' .. f(v, s.. '\t') end"); - return result; - } - - /** - Generate a string representation for arbitrary object. - **/ - @:ifFeature("has_enum") - static function __string_rec(o:Dynamic, s:String = "") { - if (s.length >= 5) - return "<...>"; - return switch (untyped __type__(o)) { - case "nil": "null"; - case "number": { - if (o == std.Math.POSITIVE_INFINITY) - "Infinity"; - else if (o == std.Math.NEGATIVE_INFINITY) - "-Infinity"; - else if (o == 0) - "0"; - else if (o != o) - "NaN"; - else - untyped tostring(o); - } - case "boolean": untyped tostring(o); - case "string": o; - case "userdata": { - var mt = lua.Lua.getmetatable(o); - if (mt != null && mt.__tostring != null) { - lua.Lua.tostring(o); - } else { - ""; - } - } - case "function": ""; - case "thread": ""; - case "table": { - if (o.__enum__ != null) - printEnum(o, s); - else if (o.toString != null && !isArray(o)) - o.toString(); - else if (isArray(o)) { - var o2:Array = untyped o; - if (s.length > 5) - "[...]" - else - '[${[for (i in o2) __string_rec(i, s + 1)].join(",")}]'; - } else if (o.__class__ != null) - printClass(o, s + "\t"); - else { - var fields = fieldIterator(o); - var buffer:Table = Table.create(); - var first = true; - Table.insert(buffer, "{ "); - for (f in fields) { - if (first) - first = false; - else - Table.insert(buffer, ", "); - Table.insert(buffer, '${Std.string(f)} : ${untyped __string_rec(o[f], s + "\t")}'); - } - Table.insert(buffer, " }"); - Table.concat(buffer, ""); - } - }; - default: { - throw "Unknown Lua type"; - null; - } - } - } /** Define an array from the given table @@ -302,17 +196,7 @@ class Boot { A 32 bit clamp function for numbers **/ public inline static function clampInt32(x:Float) { -#if lua_vanilla - if (x < Min_Int32 ) { - return Min_Int32; - } else if (x > Max_Int32) { - return Max_Int32; - } else { - return Math.floor(x); - } -#else - return untyped __define_feature__("lua.Boot.clamp", _hx_bit_clamp(x)); -#end + return untyped _hx_bit_clamp(x); } /** @@ -386,32 +270,6 @@ class Boot { } } - public static function fieldIterator(o:Table):Iterator { - if (Lua.type(o) != "table") { - return { - next: function() return null, - hasNext: function() return false - } - } - var tbl:Table = cast(untyped o.__fields__ != null) ? o.__fields__ : o; - var cur = Lua.pairs(tbl).next; - var next_valid = function(tbl, val) { - while (hiddenFields[untyped val] != null) { - val = cur(tbl, val).index; - } - return val; - } - var cur_val = next_valid(tbl, cur(tbl, null).index); - return { - next: function() { - var ret = cur_val; - cur_val = next_valid(tbl, cur(tbl, cur_val).index); - return ret; - }, - hasNext: function() return cur_val != null - } - } - static var os_patterns = [ 'Windows' => ['windows', '^mingw', '^cygwin'], 'Linux' => ['linux'], diff --git a/std/lua/Coroutine.hx b/std/lua/Coroutine.hx index db9114fc2b885f15eb7d04b6b94cbdff9e39b9be..4980a67194da77bfa73d806d2a768477dde07cd2 100644 --- a/std/lua/Coroutine.hx +++ b/std/lua/Coroutine.hx @@ -33,17 +33,17 @@ extern class Coroutine extends Thread { /** Creates a new coroutine, with body `f`. `f` must be a Lua function. **/ - public static function create(f:T):Coroutine; + static function create(f:T):Coroutine; /** Returns the running coroutine plus a boolean, true when the running coroutine is the main one. **/ - public static function running():CoroutineRunning; + static function running():CoroutineRunning; /** Returns the status of coroutine. **/ - public static function status(c:Coroutine):CoroutineState; + static function status(c:Coroutine):CoroutineState; /** Starts or continues the execution of coroutine. @@ -57,14 +57,14 @@ extern class Coroutine extends Thread { by the body function (if the coroutine terminates). If there is any error, `resume` returns `false` plus the error message. **/ - public static function resume(c:Coroutine, args:Rest):CoroutineResume; + static function resume(c:Coroutine, args:Rest):CoroutineResume; /** Suspends the execution of the calling coroutine. The coroutine cannot be running a C function, a metamethod, or an iterator. Any arguments to `yield` are passed as extra results to `resume`. **/ - public static function yield(args:Rest):T; + static function yield(args:Rest):T; /** Creates a new coroutine, with body `f`. @@ -73,7 +73,7 @@ extern class Coroutine extends Thread { Returns the same values returned by `resume`, except the first boolean. In case of error, propagates the error. **/ - public static function wrap(f:T):T; + static function wrap(f:T):T; } /** diff --git a/std/lua/Debug.hx b/std/lua/Debug.hx index a9e32a8be833757a5a1e3612d591daed227e6d5d..17b06b1c9223f83d79e37b7eebfa2944397f306a 100644 --- a/std/lua/Debug.hx +++ b/std/lua/Debug.hx @@ -34,25 +34,25 @@ extern class Debug { This function returns the name and the value of the local variable with index local of the function at level level of the stack. **/ - public static function getlocal(stackLevel:Int, idx:Int):Dynamic; + static function getlocal(stackLevel:Int, idx:Int):Dynamic; /** This function assigns the value value to the local variable with index local of the function at level level of the stack. Call `getinfo` to check whether the level is valid. **/ - public static function setlocal(stackLevel:Int, varName:String, value:Dynamic):Void; + static function setlocal(stackLevel:Int, varName:String, value:Dynamic):Void; /** Returns a table with information about a function. **/ - public static function getinfo(stackLevel:Int):DebugInfo; + static function getinfo(stackLevel:Int):DebugInfo; /** Sets the given function as a hook. When called without arguments, `Debug.sethook` turns off the hook. **/ - public static function sethook(?fun:Function, ?monitor:String):Void; + static function sethook(?fun:Function, ?monitor:String):Void; /** Enters an interactive mode with the user, running each string that the user enters. @@ -64,55 +64,55 @@ extern class Debug { Note that commands for `Debug.debug` are not lexically nested within any function, and so have no direct access to local variables. **/ - public static function debug():Void; + static function debug():Void; /** Returns the current hook settings of the thread, as three values: the current hook function, the current hook mask, and the current hook count (as set by the `Debug.sethook` function). **/ - public static function gethook(thread:Thread):Function; + static function gethook(thread:Thread):Function; /** Returns the registry table. **/ - public static function getregistry():AnyTable; + static function getregistry():AnyTable; /** Returns the metatable of the given `value` or `null` if it does not have a metatable. **/ - public static function getmetatable(value:AnyTable):AnyTable; + static function getmetatable(value:AnyTable):AnyTable; /** Sets the metatable for the given `value` to the given `table` (can be `null`). **/ - public static function setmetatable(value:AnyTable, table:AnyTable):Void; + static function setmetatable(value:AnyTable, table:AnyTable):Void; /** This function returns the name and the value of the upvalue with index `up` of the function `f`. The function returns `null` if there is no upvalue with the given index. **/ - public static function getupvalue(f:Function, up:Int):Dynamic; + static function getupvalue(f:Function, up:Int):Dynamic; /** This function assigns the value value to the upvalue with index up of the function `f`. The function returns `null` if there is no upvalue with the given index. Otherwise, it returns the name of the upvalue. **/ - public static function setupvalue(f:Function, up:Int, val:Dynamic):Void; + static function setupvalue(f:Function, up:Int, val:Dynamic):Void; /** Returns the Lua value associated to `val`. If `val` is not a `UserData`, returns `null`. **/ - public static function getuservalue(val:Dynamic):Dynamic; + static function getuservalue(val:Dynamic):Dynamic; /** Sets the given value as the Lua value associated to the given udata. `udata` must be a full `UserData`. **/ - public static function setuservalue(udata:Dynamic, val:Dynamic):Void; + static function setuservalue(udata:Dynamic, val:Dynamic):Void; /** Returns a string with a traceback of the call stack. @@ -120,19 +120,19 @@ extern class Debug { @param level (optional) tells at which level to start the traceback. default is `1`, the function calling traceback. **/ - public static function traceback(?thread:Thread, ?message:String, ?level:Int):String; + static function traceback(?thread:Thread, ?message:String, ?level:Int):String; /** Returns a unique identifier (as a light userdata) for the upvalue numbered `n` from the given function `f`. **/ - public static function upvalueid(f:Function, n:Int):Dynamic; + static function upvalueid(f:Function, n:Int):Dynamic; /** Make the `n1`-th upvalue of the Lua closure `f1` refer to the `n2`-th upvalue of the Lua closure `f2`. **/ - public static function upvaluejoin(f1:Function, n1:Int, f2:Function, n2:Int):Void; + static function upvaluejoin(f1:Function, n1:Int, f2:Function, n2:Int):Void; } /** diff --git a/std/lua/Ffi.hx b/std/lua/Ffi.hx index aec03deb9e2d61b9edbe36a1d3185d6c8e14759b..fa2a96637706f8e8d7f47ecd47e0ec793c54ecb6 100644 --- a/std/lua/Ffi.hx +++ b/std/lua/Ffi.hx @@ -28,34 +28,34 @@ import lua.Table; #if lua_jit @:luaRequire("ffi") extern class Ffi { - public function new(type:String, arg:Dynamic); + function new(type:String, arg:Dynamic); // Declaring and accessing external symbols - public static function cdef(def:String):Void; - public static var C:Dynamic; - public static function gc(cdata:Dynamic, finalizer:Function):Void; - public static function load(name:String, ?global:Bool):Dynamic; - public static function metatype(ct:Ctype, metatable:Table):Ctype; - public static function typeof(str:String):Ctype; + static function cdef(def:String):Void; + static var C:Dynamic; + static function gc(cdata:Dynamic, finalizer:Function):Void; + static function load(name:String, ?global:Bool):Dynamic; + static function metatype(ct:Ctype, metatable:Table):Ctype; + static function typeof(str:String):Ctype; // C Type functionality - public static function alignof(ct:Ctype):Int; - public static function istype(ct:Ctype, obj:Dynamic):Bool; - public static function offsetof(ct:Ctype, field:String):Int; - public static function sizeof(ct:Ctype, ?nelem:Int):Int; + static function alignof(ct:Ctype):Int; + static function istype(ct:Ctype, obj:Dynamic):Bool; + static function offsetof(ct:Ctype, field:String):Int; + static function sizeof(ct:Ctype, ?nelem:Int):Int; // Utility functionality - public static function errno(?newerr:Int):Int; - public static function fill(dst:Dynamic, len:Int, c:Int):Void; - public static function string(ptr:Dynamic, ?len:Int):String; + static function errno(?newerr:Int):Int; + static function fill(dst:Dynamic, len:Int, c:Int):Void; + static function string(ptr:Dynamic, ?len:Int):String; @:overload(function(dst:Dynamic, str:String):Dynamic {}) - public static function copy(dst:Dynamic, src:Dynamic, len:Int):String; + static function copy(dst:Dynamic, src:Dynamic, len:Int):String; // Target specific functionality - public static var os:String; - public static var arch:String; - public static function abi(param:String):Bool; + static var os:String; + static var arch:String; + static function abi(param:String):Bool; } extern class Ctype {} diff --git a/std/lua/FileHandle.hx b/std/lua/FileHandle.hx index 2b99aaa2922cd0352ce31c78da89afc2a43321df..fff4617d950127aeb93e639e2aba0d42717bc1a4 100644 --- a/std/lua/FileHandle.hx +++ b/std/lua/FileHandle.hx @@ -27,13 +27,13 @@ import haxe.extern.Rest; import sys.io.FileInput; extern class FileHandle extends UserData { - public function flush():Void; - public function read(arg:Rest>):String; - public function close():Void; + function flush():Void; + function read(arg:Rest>):String; + function close():Void; - public function write(str:String):Void; + function write(str:String):Void; @:overload(function():Int {}) @:overload(function(arg:String):Int {}) - public function seek(arg:String, pos:Int):Void; + function seek(arg:String, pos:Int):Void; } diff --git a/std/lua/Io.hx b/std/lua/Io.hx index 6d6ecd1a39ff447b2f6bbb83a98b52bfa654f638..bb2344f65cba4c5efa66ecfa3d060ba705ec1e56 100644 --- a/std/lua/Io.hx +++ b/std/lua/Io.hx @@ -29,19 +29,19 @@ import haxe.extern.Rest; **/ @:native("_G.io") extern class Io { - public static var stdin:FileHandle; - public static var stderr:FileHandle; - public static var stdout:FileHandle; + static var stdin:FileHandle; + static var stderr:FileHandle; + static var stdout:FileHandle; /** Function to close regular files. **/ - public static function close(?file:FileHandle):Void; + static function close(?file:FileHandle):Void; /** Saves any written data to file. **/ - public static function flush():Void; + static function flush():Void; /** When called with a file name, it opens the named file (in text mode), @@ -53,13 +53,13 @@ extern class Io { error code. **/ @:overload(function(file:String):Void {}) - public static function input(file:FileHandle):Void; + static function input(file:FileHandle):Void; /** Opens the given file name in read mode and returns an iterator function that, each time it is called, returns a new line from the file. **/ - public static function lines(?file:String):NativeIterator; + static function lines(?file:String):NativeIterator; /** This function opens a file, in the mode specified in the string mode. @@ -79,7 +79,7 @@ extern class Io { to open the file in binary mode. This string is exactly what is used in the standard C function fopen. **/ - public static function open(filename:String, ?mode:String):FileHandle; + static function open(filename:String, ?mode:String):FileHandle; /** Starts program `command` in a separated process and returns a file handle that @@ -88,10 +88,10 @@ extern class Io { This function is system dependent and is not available on all platforms. **/ - public static function popen(command:String, ?mode:String):FileHandle; + static function popen(command:String, ?mode:String):FileHandle; @:overload(function(?count:Int):String {}) - public static function read(?filename:String):String; + static function read(?filename:String):String; /** Writes the value of each of its arguments to the file. The arguments must @@ -99,20 +99,20 @@ extern class Io { To write other values, use `Lua.tostring` or `NativeStringTools.format` before write. **/ - public static function write(v:Rest):Void; + static function write(v:Rest):Void; - public static function output(?file:String):FileHandle; + static function output(?file:String):FileHandle; /** Returns a handle for a temporary file. This file is opened in update mode and it is automatically removed when the program ends. **/ - public static function tmpfile():FileHandle; + static function tmpfile():FileHandle; /** Checks whether `obj` is a valid file handle. **/ - public static function type(obj:FileHandle):IoType; + static function type(obj:FileHandle):IoType; } /** diff --git a/std/lua/Jit.hx b/std/lua/Jit.hx index 8d93e46c7cea261b877806b6e30e3a219ee6cb52..167dfc972c35d61907d0a9944ce680be4a69eceb 100644 --- a/std/lua/Jit.hx +++ b/std/lua/Jit.hx @@ -5,15 +5,15 @@ import haxe.Constraints.Function; #if lua_jit @:native("_G.jit") extern class Jit { - public static function on(?f:Function, ?recursive:Bool):Void; - public static function off(?f:Function, ?recursive:Bool):Void; - public static function flush(?f:Function, ?recursive:Bool):Void; - public static function status():Bool; - public static var version:String; - public static var version_num:Int; - public static var os:String; - public static var arch:String; - public static var opt:{start:Function}; - public static var util:Dynamic; + static function on(?f:Function, ?recursive:Bool):Void; + static function off(?f:Function, ?recursive:Bool):Void; + static function flush(?f:Function, ?recursive:Bool):Void; + static function status():Bool; + static var version:String; + static var version_num:Int; + static var os:String; + static var arch:String; + static var opt:{start:Function}; + static var util:Dynamic; } #end diff --git a/std/lua/Lib.hx b/std/lua/Lib.hx index 48e7b6e1a32965f698f072627be6aaf285f47c28..ae18c4cab32a694c997ca075e52cab8bfc321355 100644 --- a/std/lua/Lib.hx +++ b/std/lua/Lib.hx @@ -24,7 +24,6 @@ package lua; import lua.Lua; import lua.Io; -import lua.NativeStringTools; /** Platform-specific Lua Library. Provides some platform-specific functions @@ -47,20 +46,6 @@ class Lib { Io.flush(); } - /** - Copies the table argument and converts it to an Array - **/ - public inline static function tableToArray(t:Table, ?length:Int):Array { - return Boot.defArray(PairTools.copy(t), length); - } - - /** - Copies the table argument and converts it to an Object. - **/ - public inline static function tableToObject(t:Table):Dynamic { - return Boot.tableToObject(PairTools.copy(t)); - } - /** Perform Lua-style pattern quoting on a given string. **/ diff --git a/std/lua/Lua.hx b/std/lua/Lua.hx index cd66252f191ab504d65b81474e65b9261c5b676c..ef134a61e7bee84a08fc48cab82f3849719f9a6f 100644 --- a/std/lua/Lua.hx +++ b/std/lua/Lua.hx @@ -35,20 +35,20 @@ extern class Lua { A global variable that holds a string containing the current interpreter version. **/ - public static var _VERSION:String; + static var _VERSION:String; - public static var arg:Table; + static var arg:Table; /** Pushes onto the stack the metatable in the registry. **/ - public static function getmetatable(tbl:Table):Table; + static function getmetatable(tbl:Table):Table; /** Pops a table from the stack and sets it as the new metatable for the value at the given acceptable index. **/ - public static function setmetatable(tbl:Table, mtbl:Table):Table; + static function setmetatable(tbl:Table, mtbl:Table):Table; /** Pops a table from the stack and sets it as the new environment for the value @@ -56,7 +56,7 @@ extern class Lua { a thread nor a userdata, lua_setfenv returns `0`. Otherwise it returns `1`. **/ - public static function setfenv(i:Int, tbl:Table):Void; + static function setfenv(i:Int, tbl:Table):Void; /** Allows a program to traverse all fields of a table. @@ -75,7 +75,7 @@ extern class Lua { to a non-existent field in the table is assigned. Existing fields may however be modified. In particular, existing fields may be cleared. **/ - public static function next(k:Table, ?i:K):NextResult; + static function next(k:Table, ?i:K):NextResult; /** Receives an argument of any type and converts it to a string in a reasonable @@ -83,20 +83,20 @@ extern class Lua { For complete control of how numbers are converted, use`NativeStringTools.format`. **/ - public static function tostring(v:Dynamic):String; + static function tostring(v:Dynamic):String; - public static function ipairs(t:Table):IPairsResult; + static function ipairs(t:Table):IPairsResult; - public static function pairs(t:Table):PairsResult; + static function pairs(t:Table):PairsResult; - public static function require(module:String):Dynamic; + static function require(module:String):Dynamic; /** Converts the Lua value at the given acceptable base to `Int`. The Lua value must be a number or a string convertible to a number, otherwise `tonumber` returns `0`. **/ - public static function tonumber(str:String, ?base:Int):Int; + static function tonumber(str:String, ?base:Int):Int; /** Returns the Lua type of its only argument as a string. @@ -111,7 +111,7 @@ extern class Lua { * `"thread"` * `"userdata"` **/ - public static function type(v:Dynamic):String; + static function type(v:Dynamic):String; /** Receives any number of arguments, and prints their values to stdout, @@ -121,54 +121,54 @@ extern class Lua { For complete control of how numbers are converted, use `NativeStringTools.format`. **/ - public static function print(v:haxe.extern.Rest):Void; + static function print(v:haxe.extern.Rest):Void; /** If `n` is a number, returns all arguments after argument number `n`. Otherwise, `n` must be the string `"#"`, and select returns the total number of extra arguments it received. **/ - public static function select(n:Dynamic, rest:Rest):Dynamic; + static function select(n:Dynamic, rest:Rest):Dynamic; /** Gets the real value of `table[index]`, without invoking any metamethod. **/ - public static function rawget(t:Table, k:K):V; + static function rawget(t:Table, k:K):V; /** Sets the real value of `table[index]` to value, without invoking any metamethod. **/ - public static function rawset(t:Table, k:K, v:V):Void; + static function rawset(t:Table, k:K, v:V):Void; /** This function is a generic interface to the garbage collector. It performs different functions according to its first argument. **/ - public static function collectgarbage(opt:CollectGarbageOption, ?arg:Int):Int; + static function collectgarbage(opt:CollectGarbageOption, ?arg:Int):Int; /** Issues an error when the value of its argument `v` is `false` (i.e., `null` or `false`) otherwise, returns all its arguments. message is an error message. when absent, it defaults to "assertion failed!" **/ - public static function assert(v:T, ?message:String):T; + static function assert(v:T, ?message:String):T; /** Loads and runs the given file. **/ - public static function dofile(filename:String):Void; + static function dofile(filename:String):Void; /** Generates a Lua error. The error message (which can actually be a Lua value of any type) must be on the stack top. This function does a long jump, and therefore never returns. **/ - public static function error(message:String, ?level:Int):Void; + static function error(message:String, ?level:Int):Void; /** Calls a function in protected mode. **/ - public static function pcall(f:Function, rest:Rest):PCallResult; + static function pcall(f:Function, rest:Rest):PCallResult; /** Returns `true` if the two values in acceptable indices `v1` and `v2` are @@ -176,24 +176,24 @@ extern class Lua { Otherwise returns `false`. Also returns `false` if any of the indices are non valid. **/ - public static function rawequal(v1:Dynamic, v2:Dynamic):Bool; + static function rawequal(v1:Dynamic, v2:Dynamic):Bool; /** This function is similar to pcall, except that you can set a new error handler. **/ - public static function xpcall(f:Function, msgh:Function, rest:Rest):PCallResult; + static function xpcall(f:Function, msgh:Function, rest:Rest):PCallResult; /** Loads the chunk from file filename or from the standard input if no filename is given. **/ - public static function loadfile(filename:String):LoadResult; + static function loadfile(filename:String):LoadResult; /** Loads the chunk from given string. **/ - public static function load(code:haxe.extern.EitherTypeString>):LoadResult; + static function load(code:haxe.extern.EitherTypeString>):LoadResult; } /** diff --git a/std/lua/NativeStringTools.hx b/std/lua/NativeStringTools.hx index 9ac0cfacfc77bb66e48d57ec8102673f798d0eda..b108bb35769b775c6fa6961943a6b9efe7b463f8 100644 --- a/std/lua/NativeStringTools.hx +++ b/std/lua/NativeStringTools.hx @@ -34,7 +34,7 @@ extern class NativeStringTools { Receives a string and returns its length. The empty string `""` has length `0`. Embedded zeros are counted, so `"a\000bc\000"` has length `5`. **/ - public static function len(str:String):Int; + static function len(str:String):Int; /** Receives zero or more integers. Returns a string with length equal to the @@ -42,7 +42,7 @@ extern class NativeStringTools { code equal to its corresponding argument. Note that numerical codes are not necessarily portable across platforms. **/ - public static function char(codes:haxe.extern.Rest):String; + static function char(codes:haxe.extern.Rest):String; // TODO: make a note about handling matched groups with multireturn @@ -54,7 +54,7 @@ extern class NativeStringTools { with length `end`, and `sub(str, -end)` returns a suffix of `str` with length `start`. **/ - public static function sub(str:String, start:Int, ?end:Int):StringSub; + static function sub(str:String, start:Int, ?end:Int):StringSub; /** Looks for the first match of pattern in the string `str`. @@ -69,13 +69,13 @@ extern class NativeStringTools { a plain "find substring" operation, with no characters in pattern being considered "magic". Note that if plain is given, then `start` must be given as well. **/ - public static function find(str:String, target:String, ?start:Int, ?plain:Bool):StringFind; + static function find(str:String, target:String, ?start:Int, ?plain:Bool):StringFind; /** Returns the internal numerical codes of the characters `str[index]`. Note that numerical codes are not necessarily portable across platforms. **/ - public static function byte(str:String, ?index:Int):Int; + static function byte(str:String, ?index:Int):Int; /** Returns a formatted version of its variable number of arguments following @@ -99,14 +99,14 @@ extern class NativeStringTools { This function does not accept string values containing embedded zeros, except as arguments to the `q` option. **/ - public static function format(str:String, ?e1:Dynamic, ?e2:Dynamic, ?e3:Dynamic, ?e4:Dynamic):String; + static function format(str:String, ?e1:Dynamic, ?e2:Dynamic, ?e3:Dynamic, ?e4:Dynamic):String; /** **/ @:overload(function(str:String, pattern:String, replace:String->Void, ?n:Int):String {}) @:overload(function(str:String, pattern:String, replace:String->String, ?n:Int):String {}) - public static function gsub(str:String, pattern:String, replace:String, ?n:Int):String; + static function gsub(str:String, pattern:String, replace:String, ?n:Int):String; /** Returns an iterator function that, each time it is called, returns the next @@ -114,7 +114,7 @@ extern class NativeStringTools { then the whole match is produced in each call. **/ @:overload(function(str:String, pattern:String, match:Void->String, ?n:Int):String->Void {}) - public static function gmatch(str:String, pattern:String):Void->String; + static function gmatch(str:String, pattern:String):Void->String; /** Looks for the first match of pattern in the string s. If it finds one, @@ -123,28 +123,40 @@ extern class NativeStringTools { The optional argument `n` specifies where to start the search; its default value is `1` and can be negative. **/ - public static function match(str:String, pattern:String, ?n:Int):String; + static function match(str:String, pattern:String, ?n:Int):String; /** Receives a string and returns a copy of this string with all lowercase letters changed to uppercase. All other characters are left unchanged. The definition of what a lowercase letter is depends on the current locale. **/ - public static function upper(str:String):String; + static function upper(str:String):String; /** Receives a string and returns a copy of this string with all uppercase letters changed to lowercase. All other characters are left unchanged. The definition of what an uppercase letter is depends on the current locale. **/ - public static function lower(str:String):String; + static function lower(str:String):String; /** Returns a string containing a binary representation of the given function, so that a later loadstring on this string returns a copy of the function. function must be a Lua function without upvalues. **/ - public static function dump(d:Dynamic):Dynamic; + static function dump(d:Dynamic):Dynamic; + + + /** + Returns a string that is the concatenation of n copies of + the string s separated by the string sep. The default value + for sep is the empty string (that is, no separator). + Returns the empty string if n is not positive. (Note that + it is very easy to exhaust the memory of your machine with + a single call to this function.) + **/ + static function rep(s:String, n : Int, ?sep : String) : String; + } @:multiReturn extern class StringFind { diff --git a/std/lua/Os.hx b/std/lua/Os.hx index 8997143bf14e845c7af4cc2dd0df17e5b945be22..81dac82323871e02ff0fbaa521ef8971629690a0 100644 --- a/std/lua/Os.hx +++ b/std/lua/Os.hx @@ -31,17 +31,17 @@ extern class Os { Returns an approximation of the amount in seconds of CPU time used by the program. **/ - public static function clock():Float; + static function clock():Float; @:overload(function(format:String, time:Time):DateType {}) @:overload(function(format:String):DateType {}) - public static function date():DateType; + static function date():DateType; /** Returns the number of seconds from time `t1` to time `t2`. In POSIX, Windows, and some other systems, this value is exactly `t2-t1`. **/ - public static function difftime(t2:Time, t1:Time):Float; + static function difftime(t2:Time, t1:Time):Float; // TODO: multi-return @@ -52,40 +52,40 @@ extern class Os { nonzero if a shell is available and zero otherwise. **/ #if (lua_ver < 5.2) - public static function execute(?command:String):Int; + static function execute(?command:String):Int; #elseif (lua_ver >= 5.2) - public static function execute(?command:String):OsExecute; + static function execute(?command:String):OsExecute; #else - public static function execute(?command:String):Dynamic; + static function execute(?command:String):Dynamic; #end /** Calls the C function exit, with an optional code, to terminate the host program. The default value for code is the success code. **/ - public static function exit(code:Int):Int; + static function exit(code:Int):Int; /** Returns the value of the process environment variable `varname`, or `null` if the variable is not defined. **/ - public static function getenv(varname:String):String; + static function getenv(varname:String):String; /** Deletes the file or directory with the given name. Directories must be empty to be removed. **/ - public static function remove(filename:String):OsSuccess; + static function remove(filename:String):OsSuccess; /** Renames file or directory named `oldname` to `newname`. **/ - public static function rename(oldname:String, newname:String):OsSuccess; + static function rename(oldname:String, newname:String):OsSuccess; /** Sets the current locale of the program. **/ - public static function setlocale(locale:String, ?category:LocaleCategory):String; + static function setlocale(locale:String, ?category:LocaleCategory):String; /** Returns the current time when called without arguments, or a time @@ -97,7 +97,7 @@ extern class Os { In other systems, the meaning is not specified, and the number returned by time can be used only as an argument to date and difftime. **/ - public static function time(?arg:TimeParam):Time; + static function time(?arg:TimeParam):Time; /** Returns a string with a file name that can be used for a temporary file. @@ -107,7 +107,7 @@ extern class Os { When possible, you may prefer to use `Io.tmpfile`, which automatically removes the file when the program ends. **/ - public static function tmpname():String; + static function tmpname():String; } /** diff --git a/std/lua/Package.hx b/std/lua/Package.hx index 47573b59b53c39d2f57b4cd44a00abcbd22ccc86..bcd7f841fb740c4246dacd6a6708265c26adf7e3 100644 --- a/std/lua/Package.hx +++ b/std/lua/Package.hx @@ -30,42 +30,42 @@ extern class Package { /** A string describing some compile-time configurations for packages. **/ - public static var config:String; + static var config:String; /** The path used by require to search for a Lua loader. **/ - public static var path:String; + static var path:String; /** The path used by require to search for a C loader. **/ - public static var cpath:String; + static var cpath:String; /** A table used by require to control which modules are already loaded. **/ - public static var loaded:Table; + static var loaded:Table; /** A table to store loaders for specific modules. **/ - public static var preload:Table; + static var preload:Table; /** A table used by require to control how to load modules. Each entry in this table is a searcher function. **/ - public static var searchers:TableNull>; + static var searchers:TableNull>; /** Searches for the given `libname` in the given path `funcname`. A path is a string containing a sequence of templates separated by semicolons. **/ - public static function searchpath(name:String, path:String, ?sep:String, ?rep:String):Null; + static function searchpath(name:String, path:String, ?sep:String, ?rep:String):Null; /** Dynamically links the host program with the C library `libname`. **/ - public static function loadlib(libname:String, funcname:String):Void; + static function loadlib(libname:String, funcname:String):Void; } diff --git a/std/lua/Table.hx b/std/lua/Table.hx index 69dcd9996f7402749522b550aa2dc7bc3431985b..8615b10f47d441aee0522093b0fa40eb8bf508d1 100644 --- a/std/lua/Table.hx +++ b/std/lua/Table.hx @@ -22,16 +22,19 @@ package lua; +import lua.PairTools; + +import haxe.ds.ObjectMap; + /** This library provides generic functions for table manipulation. **/ -// TODO: use an abstract here? @:native("_G.table") extern class Table implements ArrayAccess implements Dynamic { - @:pure public static function create(?arr:Array, ?hsh:Dynamic):Table; + @:pure static function create(?arr:Array, ?hsh:Dynamic):Table; - public inline static function fromArray(arr:Array):Table { + inline static function fromArray(arr:Array):Table { var ret = Table.create(); for (idx in 0...arr.length) { ret[idx + 1] = arr[idx]; @@ -39,7 +42,7 @@ extern class Table implements ArrayAccess implements Dynamic { return ret; } - public inline static function fromMap(map:Map):Table { + inline static function fromMap(map:Map):Table { var ret = Table.create(); for (k in map.keys()) { ret[untyped k] = map.get(k); @@ -47,7 +50,7 @@ extern class Table implements ArrayAccess implements Dynamic { return ret; } - public inline static function fromDynamic(dyn:Dynamic):Table { + inline static function fromDynamic(dyn:Dynamic):Table { var ret = Table.create(); for (f in Reflect.fields(dyn)) { ret[untyped f] = Reflect.field(dyn, f); @@ -55,23 +58,46 @@ extern class Table implements ArrayAccess implements Dynamic { return ret; } + inline static function toMap(tbl : Table) : Map { + var obj = new ObjectMap(); + PairTools.pairsFold(tbl, (k,v,m) ->{ + obj.set(k,v); + return obj; + }, obj); + return cast obj; + } + + /** + Copies the table argument and converts it to an Object. + **/ + inline static function toObject(t:Table):Dynamic { + return Boot.tableToObject(PairTools.copy(t)); + } + + + inline static function toArray(tbl : Table, ?length:Int) : Array { + return Boot.defArray(PairTools.copy(tbl), length); + } + @:overload(function(table:Table):Void {}) - public static function concat(table:Table, ?sep:String, ?i:Int, ?j:Int):String; + static function concat(table:Table, ?sep:String, ?i:Int, ?j:Int):String; - public static function foreach(table:Table, f:A->B->Void):Void; - public static function foreachi(table:Table, f:A->B->Int->Void):Void; + #if (lua_ver == 5.1) + static function foreach(table:Table, f:A->B->Void):Void; + static function foreachi(table:Table, f:A->B->Int->Void):Void; + #end - public static function sort(table:Table, ?order:A->A->Bool):Void; + static function sort(table:Table, ?order:A->A->Bool):Void; @:overload(function(table:Table, value:B):Void {}) - public static function insert(table:Table, pos:Int, value:B):Void; + static function insert(table:Table, pos:Int, value:B):Void; @:overload(function(table:Table):Void {}) - public static function remove(table:Table, ?pos:Int):Void; + static function remove(table:Table, ?pos:Int):Void; #if (lua_ver >= 5.2) - public static function pack(args:haxe.extern.Rest):Table; - public static function unpack(args:lua.Table, ?min:Int, ?max:Int):Dynamic; + static function pack(args:haxe.extern.Rest):Table; + static function unpack(args:lua.Table, ?min:Int, ?max:Int):Dynamic; #end } diff --git a/std/lua/TableTools.hx b/std/lua/TableTools.hx index 9275914d026e5b1451b0adf42f0df2ca3ca9dd8c..bb9037c00c66c26cbca230e642eeb3a1d9e97d60 100644 --- a/std/lua/TableTools.hx +++ b/std/lua/TableTools.hx @@ -22,15 +22,18 @@ package lua; +import lua.Table.AnyTable; + /** - This library provides generic functions for table manipulation. + This library is an extern for a polyfill library of common lua table + methods. **/ @:native("_hx_table") extern class TableTools { - public static function pack(args:haxe.extern.Rest):Table; - public static function unpack(args:lua.Table, ?min:Int, ?max:Int):Dynamic; - public static function maxn(t:Table.AnyTable):Int; - public static function __init__():Void { + static function pack(args:haxe.extern.Rest):Table; + static function unpack(args:lua.Table, ?min:Int, ?max:Int):Dynamic; + static function maxn(t:AnyTable):Int; + static function __init__():Void { untyped __define_feature__("use._hx_table", null); } } diff --git a/std/lua/_lua/_hx_anon.lua b/std/lua/_lua/_hx_anon.lua index 3a5c965602c8d08d8cdd385b8cdc378027d8febc..15826b2d185de522695630f799263a4be6bd3d04 100644 --- a/std/lua/_lua/_hx_anon.lua +++ b/std/lua/_lua/_hx_anon.lua @@ -1,5 +1,10 @@ -local function _hx_anon_newindex(t,k,v) t.__fields__[k] = true; rawset(t,k,v); end -local _hx_anon_mt = {__newindex=_hx_anon_newindex} +local function _hx_obj_newindex(t,k,v) + t.__fields__[k] = true + rawset(t,k,v) +end + +local _hx_obj_mt = {__newindex=_hx_obj_newindex, __tostring=_hx_tostring} + local function _hx_a(...) local __fields__ = {}; local ret = {__fields__ = __fields__}; @@ -12,17 +17,32 @@ local function _hx_a(...) ret[v] = tab[cur+1]; cur = cur + 2 end - return setmetatable(ret, _hx_anon_mt) + return setmetatable(ret, _hx_obj_mt) end local function _hx_e() - return setmetatable({__fields__ = {}}, _hx_anon_mt) + return setmetatable({__fields__ = {}}, _hx_obj_mt) end local function _hx_o(obj) - return setmetatable(obj, _hx_anon_mt) + return setmetatable(obj, _hx_obj_mt) end local function _hx_new(prototype) - return setmetatable({__fields__ = {}}, {__newindex=_hx_anon_newindex, __index=prototype}) + return setmetatable({__fields__ = {}}, {__newindex=_hx_obj_newindex, __index=prototype, __tostring=_hx_tostring}) +end + +function _hx_field_arr(obj) + res = {} + idx = 0 + if obj.__fields__ ~= nil then + obj = obj.__fields__ + end + for k,v in pairs(obj) do + if _hx_hidden[k] == nil then + res[idx] = k + idx = idx + 1 + end + end + return _hx_tab_array(res, idx) end diff --git a/std/lua/_lua/_hx_bit.lua b/std/lua/_lua/_hx_bit.lua index 17d33995275711533926c4440e7273cd41f9154d..f0ca1be675801d7dda4de8bfb36e5a8445558db6 100644 --- a/std/lua/_lua/_hx_bit.lua +++ b/std/lua/_lua/_hx_bit.lua @@ -1,11 +1,16 @@ -- require this for lua 5.1 pcall(require, 'bit') if bit then - _hx_bit = bit + _hx_bit_raw = bit + _hx_bit = setmetatable({}, { __index = _hx_bit_raw }); else - local _hx_bit_raw = _G.require('bit32') + _hx_bit_raw = _G.require('bit32') _hx_bit = setmetatable({}, { __index = _hx_bit_raw }); -- lua 5.2 weirdness _hx_bit.bnot = function(...) return _hx_bit_clamp(_hx_bit_raw.bnot(...)) end; _hx_bit.bxor = function(...) return _hx_bit_clamp(_hx_bit_raw.bxor(...)) end; end +-- see https://github.com/HaxeFoundation/haxe/issues/8849 +_hx_bit.bor = function(...) return _hx_bit_clamp(_hx_bit_raw.bor(...)) end; +_hx_bit.band = function(...) return _hx_bit_clamp(_hx_bit_raw.band(...)) end; +_hx_bit.arshift = function(...) return _hx_bit_clamp(_hx_bit_raw.arshift(...)) end; diff --git a/std/lua/_lua/_hx_bit_clamp.lua b/std/lua/_lua/_hx_bit_clamp.lua index e39c024fc1e7cfa4c2ba81e797829b885a8f289e..20618caa59d8984abd3085193532e1660ebe7d97 100644 --- a/std/lua/_lua/_hx_bit_clamp.lua +++ b/std/lua/_lua/_hx_bit_clamp.lua @@ -1,10 +1,26 @@ -_hx_bit_clamp = function(v) - if v <= 2147483647 and v >= -2147483648 then - if v > 0 then return _G.math.floor(v) - else return _G.math.ceil(v) +if _hx_bit_raw then + _hx_bit_clamp = function(v) + if v <= 2147483647 and v >= -2147483648 then + if v > 0 then return _G.math.floor(v) + else return _G.math.ceil(v) + end end - end - if v > 2251798999999999 then v = v*2 end; - if (v ~= v or math.abs(v) == _G.math.huge) then return nil end - return _hx_bit.band(v, 2147483647 ) - math.abs(_hx_bit.band(v, 2147483648)) -end + if v > 2251798999999999 then v = v*2 end; + if (v ~= v or math.abs(v) == _G.math.huge) then return nil end + return _hx_bit_raw.band(v, 2147483647 ) - math.abs(_hx_bit_raw.band(v, 2147483648)) + end +else + _hx_bit_clamp = function(v) + if v < -2147483648 then + return -2147483648 + elseif v > 2147483647 then + return 2147483647 + elseif v > 0 then + return _G.math.floor(v) + else + return _G.math.ceil(v) + end + end +end; + + diff --git a/std/lua/_lua/_hx_tab_array.lua b/std/lua/_lua/_hx_tab_array.lua index 23d48a8fc391bf5e26e0b3b2965232a68dce1cfe..ec79ff45babecb6f7b611d24597a4832cf49b9a9 100644 --- a/std/lua/_lua/_hx_tab_array.lua +++ b/std/lua/_lua/_hx_tab_array.lua @@ -1,12 +1,23 @@ -local _hx_array_mt = { - __newindex = function(t,k,v) - local len = t.length - t.length = k >= len and (k + 1) or len - rawset(t,k,v) - end +local _hx_hidden = {__id__=true, hx__closures=true, super=true, prototype=true, __fields__=true, __ifields__=true, __class__=true, __properties__=true, __fields__=true, __name__=true} + +_hx_array_mt = { + __newindex = function(t,k,v) + local len = t.length + t.length = k >= len and (k + 1) or len + rawset(t,k,v) + end } -local function _hx_tab_array(tab,length) - tab.length = length - return setmetatable(tab, _hx_array_mt) +function _hx_is_array(o) + return type(o) == "table" + and o.__enum__ == nil + and getmetatable(o) == _hx_array_mt +end + + + +function _hx_tab_array(tab, length) + tab.length = length + return setmetatable(tab, _hx_array_mt) end + diff --git a/std/lua/_lua/_hx_tostring.lua b/std/lua/_lua/_hx_tostring.lua new file mode 100644 index 0000000000000000000000000000000000000000..5902ef8c94ec9e42b00658e8334f6335e026985e --- /dev/null +++ b/std/lua/_lua/_hx_tostring.lua @@ -0,0 +1,111 @@ + +function _hx_print_class(obj, depth) + local first = true + local result = '' + for k,v in pairs(obj) do + if _hx_hidden[k] == nil then + if first then + first = false + else + result = result .. ', ' + end + if _hx_hidden[k] == nil then + result = result .. k .. ':' .. _hx_tostring(v, depth+1) + end + end + end + return '{ ' .. result .. ' }' +end + +function _hx_print_enum(o, depth) + if o.length == 2 then + return o[0] + else + local str = o[0] .. "(" + for i = 2, (o.length-1) do + if i ~= 2 then + str = str .. "," .. _hx_tostring(o[i], depth+1) + else + str = str .. _hx_tostring(o[i], depth+1) + end + end + return str .. ")" + end +end + +function _hx_tostring(obj, depth) + if depth == nil then + depth = 0 + elseif depth > 5 then + return "<...>" + end + + local tstr = _G.type(obj) + if tstr == "string" then return obj + elseif tstr == "nil" then return "null" + elseif tstr == "number" then + if obj == _G.math.POSITIVE_INFINITY then return "Infinity" + elseif obj == _G.math.NEGATIVE_INFINITY then return "-Infinity" + elseif obj == 0 then return "0" + elseif obj ~= obj then return "NaN" + else return _G.tostring(obj) + end + elseif tstr == "boolean" then return _G.tostring(obj) + elseif tstr == "userdata" then + local mt = _G.getmetatable(obj) + if mt ~= nil and mt.__tostring ~= nil then + return _G.tostring(obj) + else + return "" + end + elseif tstr == "function" then return "" + elseif tstr == "thread" then return "" + elseif tstr == "table" then + if obj.__enum__ ~= nil then + return _hx_print_enum(obj, depth) + elseif obj.toString ~= nil and not _hx_is_array(obj) then return obj:toString() + elseif _hx_is_array(obj) then + if obj.length > 5 then + return "[...]" + else + str = "" + for i=0, (obj.length-1) do + if i == 0 then + str = str .. _hx_tostring(obj[i], depth+1) + else + str = str .. "," .. _hx_tostring(obj[i], depth+1) + end + end + return "[" .. str .. "]" + end + elseif obj.__class__ ~= nil then + return _hx_print_class(obj, depth) + else + first = true + buffer = {} + for k,v in pairs(obj) do + if _hx_hidden[k] == nil then + _G.table.insert(buffer, _hx_tostring(k, depth+1) .. ' : ' .. _hx_tostring(obj[k], depth+1)) + end + end + return "{ " .. table.concat(buffer, ", ") .. " }" + end + else + _G.error("Unknown Lua type", 0) + return "" + end +end + +function _hx_error(obj) + print(obj) + if obj.value then + _G.print("Runtime Error: " .. _hx_tostring(obj.value)); + else + _G.print("Runtime Error: " .. tostring(obj)); + end + + if _G.debug and _G.debug.traceback then + _G.print(debug.traceback()); + end +end + diff --git a/std/lua/_std/Array.hx b/std/lua/_std/Array.hx index a773273f520b04bccc2a8e9010095b1d9ec9b161..cb235f0ee57449ed6fcd472841dea3f7e0d1ebee 100644 --- a/std/lua/_std/Array.hx +++ b/std/lua/_std/Array.hx @@ -19,6 +19,9 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ + +import haxe.iterators.ArrayKeyValueIterator; + @:coreApi class Array { public var length(default, null):Int; @@ -189,6 +192,14 @@ class Array { return false; } + public function contains(x:T):Bool { + for (i in 0...length) { + if (this[i] == x) + return true; + } + return false; + } + public function indexOf(x:T, ?fromIndex:Int):Int { var end = length; if (fromIndex == null) @@ -235,12 +246,12 @@ class Array { return [for (i in this) if (f(i)) i]; } - public inline function iterator():Iterator { - var cur_length = 0; - return { - hasNext: function() return cur_length < length, - next: function() return this[cur_length++] - } + public inline function iterator():haxe.iterators.ArrayIterator { + return new haxe.iterators.ArrayIterator(this); + } + + public inline function keyValueIterator():ArrayKeyValueIterator { + return new ArrayKeyValueIterator(this); } public function resize(len:Int):Void { diff --git a/std/lua/_std/EReg.hx b/std/lua/_std/EReg.hx index dc4771fdecd99751821d92a83b4c21a86182b867..077a7fbd6ffd8e03b293fc20680b3944a3ce745e 100644 --- a/std/lua/_std/EReg.hx +++ b/std/lua/_std/EReg.hx @@ -78,9 +78,9 @@ class EReg { else if (n == 0) { var k = sub(s, m[1], m[2]).match; return k; - } else if (Std.is(m[3], lua.Table)) { + } else if (Std.isOfType(m[3], lua.Table)) { var mn = 2 * (n - 1); - if (Std.is(untyped m[3][mn + 1], Bool)) + if (Std.isOfType(untyped m[3][mn + 1], Bool)) return null; return sub(s, untyped m[3][mn + 1], untyped m[3][mn + 2]).match; } else { diff --git a/std/lua/_std/Reflect.hx b/std/lua/_std/Reflect.hx index 9382805ab644708b583fe9287b0255f7f6c01548..600dc01c1b1d4d66ad32aaa323506585134254e9 100644 --- a/std/lua/_std/Reflect.hx +++ b/std/lua/_std/Reflect.hx @@ -89,7 +89,7 @@ import lua.Boot; if (lua.Lua.type(o) == "string") { return Reflect.fields(untyped String.prototype); } else { - return [for (f in lua.Boot.fieldIterator(o)) f]; + return untyped _hx_field_arr(o); } } @@ -122,7 +122,7 @@ import lua.Boot; } public static function isEnumValue(v:Dynamic):Bool { - return v != null && Std.is(v, lua.Table) && v.__enum__ != null; + return v != null && Std.isOfType(v, lua.Table) && v.__enum__ != null; } public static function deleteField(o:Dynamic, field:String):Bool diff --git a/std/lua/_std/Std.hx b/std/lua/_std/Std.hx index 2d13dcb540e57c2d40808a1c323b9160301edb4b..b816c64a02e9a2f097a979f76d55290ee7627fcf 100644 --- a/std/lua/_std/Std.hx +++ b/std/lua/_std/Std.hx @@ -26,6 +26,10 @@ import lua.NativeStringTools; @:keepInit @:coreApi class Std { public static inline function is(v:Dynamic, t:Dynamic):Bool { + return isOfType(v, t); + } + + public static inline function isOfType(v:Dynamic, t:Dynamic):Bool { return untyped lua.Boot.__instanceof(v, t); } @@ -39,8 +43,8 @@ import lua.NativeStringTools; } @:keep - public static function string(s:Dynamic):String { - return untyped lua.Boot.__string_rec(s); + public static function string(s:Dynamic) : String { + return untyped _hx_tostring(s, 0); } public static function int(x:Float):Int { diff --git a/std/lua/_std/String.hx b/std/lua/_std/String.hx index b97d33b16820019545b766d943d12e8894d04d0c..e4210c97a5308bad91196cc9cb2e39c3b9467da3 100644 --- a/std/lua/_std/String.hx +++ b/std/lua/_std/String.hx @@ -67,6 +67,9 @@ class String { startIndex = 1; else startIndex += 1; + if (str == "") { + return indexOfEmpty(this, startIndex - 1); + } var r = BaseString.find(this, str, startIndex, true).begin; if (r != null && r > 0) return r - 1; @@ -74,14 +77,22 @@ class String { return -1; } + static function indexOfEmpty(s:String, startIndex:Int):Int { + var length = BaseString.len(s); + if(startIndex < 0) { + startIndex = length + startIndex; + if(startIndex < 0) startIndex = 0; + } + return startIndex > length ? length : startIndex; + } + public inline function lastIndexOf(str:String, ?startIndex:Int):Int { - var i = 0; var ret = -1; if (startIndex == null) startIndex = length; while (true) { var p = indexOf(str, ret + 1); - if (p == -1 || p > startIndex) + if (p == -1 || p > startIndex || p == ret) break; ret = p; } @@ -91,7 +102,6 @@ class String { public inline function split(delimiter:String):Array { var idx = 1; var ret = []; - var delim_offset = delimiter.length > 0 ? delimiter.length : 1; while (idx != null) { var newidx = 0; if (delimiter.length > 0) { diff --git a/std/lua/_std/Sys.hx b/std/lua/_std/Sys.hx index c7bfb350cd298217a6904b91f7056d8093d8b1ae..712696fadc237c81c7050ac086cc5adcd9f2483d 100644 --- a/std/lua/_std/Sys.hx +++ b/std/lua/_std/Sys.hx @@ -23,7 +23,7 @@ import lua.Boot; import lua.Io; import lua.Lua; -import lua.Os; +import lua.lib.luv.Os; import lua.lib.luv.Misc; import sys.io.FileInput; import sys.io.FileOutput; @@ -42,7 +42,7 @@ class Sys { public inline static function args():Array { var targs = lua.PairTools.copy(Lua.arg); - var args = lua.Lib.tableToArray(targs); + var args = lua.Table.toArray(targs); return args; } @@ -76,22 +76,8 @@ class Sys { } public static function environment():Map { - var map = new Map(); - var cmd = switch (Sys.systemName()) { - case "Windows": 'SET'; - default: 'printenv'; - } - var p = new sys.io.Process(cmd, []); - var code = p.exitCode(true); - var out = p.stdout.readAll().toString(); - p.close(); - var lines = out.split("\n"); - var m = new Map(); - for (l in lines) { - var parts = l.split("="); - m.set(parts.shift(), parts.join("=")); - } - return m; + var env = lua.lib.luv.Os.environ(); + return lua.Table.toMap(env); } @:deprecated("Use programPath instead") public static function executablePath():String { @@ -109,11 +95,11 @@ class Sys { Misc.chdir(s); public inline static function getEnv(s:String):String { - return Misc.os_getenv(s); + return Os.getenv(s); } public inline static function putEnv(s:String, v:String):Void { - Misc.os_setenv(s, v); + Os.setenv(s, v); } public inline static function setTimeLocale(loc:String):Bool { @@ -125,14 +111,16 @@ class Sys { lua.lib.luv.Thread.sleep(Math.floor(seconds * 1000)); public inline static function stderr():haxe.io.Output - return new FileOutput(Io.stderr); + return @:privateAccess new FileOutput(Io.stderr); public inline static function stdin():haxe.io.Input - return new FileInput(Io.stdin); + return @:privateAccess new FileInput(Io.stdin); public inline static function stdout():haxe.io.Output - return new FileOutput(Io.stdout); + return @:privateAccess new FileOutput(Io.stdout); - public static function time():Float - return lua.lib.luasocket.Socket.gettime(); + public static function time():Float { + var stamp = lua.lib.luv.Misc.gettimeofday(); + return stamp.seconds + (stamp.microseconds / 100000); + } } diff --git a/std/lua/_std/Type.hx b/std/lua/_std/Type.hx index 4336cf19add55177e0bd8391eb6799acf192f5cf..6ef614a5d54b77a541943deb89eae3ace76d3741 100644 --- a/std/lua/_std/Type.hx +++ b/std/lua/_std/Type.hx @@ -121,8 +121,9 @@ enum ValueType { public static function getInstanceFields(c:Class):Array { var p:Dynamic = untyped c.prototype; var a:Array = []; + while (p != null) { - for (f in lua.Boot.fieldIterator(p)) { + for (f in Reflect.fields(p)) { if (!Lambda.has(a, f)) a.push(f); } diff --git a/std/lua/_std/haxe/Exception.hx b/std/lua/_std/haxe/Exception.hx new file mode 100644 index 0000000000000000000000000000000000000000..333b01935e607d8ecfb4eee7e822e3c208a8718b --- /dev/null +++ b/std/lua/_std/haxe/Exception.hx @@ -0,0 +1,85 @@ +package haxe; + +@:coreApi +class Exception { + public var message(get,never):String; + public var stack(get,never):CallStack; + public var previous(get,never):Null; + public var native(get,never):Any; + + @:noCompletion var __exceptionMessage:String; + @:noCompletion var __exceptionStack:Null; + @:noCompletion var __nativeStack:Array; + @:noCompletion @:ifFeature("haxe.Exception.get_stack") var __skipStack:Int = 0; + @:noCompletion var __nativeException:Any; + @:noCompletion var __previousException:Null; + + static function caught(value:Any):Exception { + if(Std.is(value, Exception)) { + return value; + } else { + return new ValueException(value, null, value); + } + } + + static function thrown(value:Any):Any { + if(Std.isOfType(value, Exception)) { + return (value:Exception).native; + } else { + var e = new ValueException(value); + e.__shiftStack(); + return e; + } + } + + public function new(message:String, ?previous:Exception, ?native:Any) { + __exceptionMessage = message; + __previousException = previous; + if(native != null) { + __nativeException = native; + __nativeStack = NativeStackTrace.exceptionStack(); + } else { + __nativeException = this; + __nativeStack = NativeStackTrace.callStack(); + __skipStack = 1; + } + } + + function unwrap():Any { + return __nativeException; + } + + public function toString():String { + return message; + } + + public function details():String { + return inline CallStack.exceptionToString(this); + } + + @:noCompletion + @:ifFeature("haxe.Exception.get_stack") + inline function __shiftStack():Void { + __skipStack++; + } + + function get_message():String { + return __exceptionMessage; + } + + function get_previous():Null { + return __previousException; + } + + final function get_native():Any { + return __nativeException; + } + + function get_stack():CallStack { + return switch __exceptionStack { + case null: + __exceptionStack = NativeStackTrace.toHaxe(__nativeStack, __skipStack); + case s: s; + } + } +} diff --git a/std/lua/_std/haxe/NativeStackTrace.hx b/std/lua/_std/haxe/NativeStackTrace.hx new file mode 100644 index 0000000000000000000000000000000000000000..e94a634f8388ced13669868d24535dc372c3dd0b --- /dev/null +++ b/std/lua/_std/haxe/NativeStackTrace.hx @@ -0,0 +1,54 @@ +package haxe; + +import haxe.CallStack.StackItem; + +/** + Do not use manually. +**/ +@:dox(hide) +@:noCompletion +class NativeStackTrace { + @:ifFeature('haxe.NativeStackTrace.exceptionStack') + static public inline function saveStack(exception:Any):Void { + } + + static public function callStack():Array { + return switch lua.Debug.traceback() { + case null: []; + case s: s.split('\n').slice(3); + } + } + + static public function exceptionStack():Array { + return []; //Not implemented. Maybe try xpcal instead of pcal in genlua. + } + + static public function toHaxe(native:Array, skip:Int = 0):Array { + var stack = []; + var cnt = -1; + for (item in native) { + var parts = item.substr(1).split(":"); //`substr` to skip a tab at the beginning of a line + var file = parts[0]; + if(file == '[C]') { + continue; + } + ++cnt; + if(skip > cnt) { + continue; + } + var line = parts[1]; + var method = if(parts.length <= 2) { + null; + } else { + var methodPos = parts[2].indexOf("'"); + if(methodPos < 0) { + null; + } else { + Method(null, parts[2].substring(methodPos + 1, parts[2].length - 1)); + } + } + stack.push(FilePos(method, file, Std.parseInt(line))); + } + return stack; + } +} \ No newline at end of file diff --git a/std/lua/_std/haxe/iterators/StringIterator.hx b/std/lua/_std/haxe/iterators/StringIterator.hx new file mode 100644 index 0000000000000000000000000000000000000000..c344efc096df092b88d6eb87065794ea754f94b3 --- /dev/null +++ b/std/lua/_std/haxe/iterators/StringIterator.hx @@ -0,0 +1,50 @@ +/* + * Copyright (C)2005-2018 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package haxe.iterators; +import lua.lib.luautf8.Utf8; + +class StringIterator { + var codes : (String, Int)->StringCodePoint; + var codepoint : Int; + var str : String; + var position : Int; + public inline function new(s:String) { + this.codes = Utf8.codes(s); + this.str = s; + var cp = codes(str, 0); + this.codepoint = cp.codepoint; + this.position = cp.position; + } + + public inline function hasNext() { + return codepoint != null; + } + + public inline function next() { + var ret = codepoint; + var cp = codes(str, position); + codepoint = cp.codepoint; + position = cp.position; + return ret; + } +} diff --git a/std/lua/_std/sys/FileSystem.hx b/std/lua/_std/sys/FileSystem.hx index 0c1821f765a0ed77bc932d378076e167ce251b36..270b98cec2fdde11815c16aec601302c419deb88 100644 --- a/std/lua/_std/sys/FileSystem.hx +++ b/std/lua/_std/sys/FileSystem.hx @@ -23,9 +23,6 @@ package sys; import lua.Io; -import lua.Os; -import lua.Lib; -import lua.Table; import haxe.io.Path; import lua.lib.luv.fs.FileSystem as LFileSystem; @@ -40,7 +37,7 @@ class FileSystem { } public inline static function rename(path:String, newPath:String):Void { - var ret = Os.rename(path, newPath); + var ret = lua.Os.rename(path, newPath); if (!ret.success) { throw ret.message; } diff --git a/std/lua/_std/sys/io/File.hx b/std/lua/_std/sys/io/File.hx index cc9abc3838acb0777147b8bd1fca38c64b870bd5..ce5f693714ccdcd3de462a5dffa967c6615e098b 100644 --- a/std/lua/_std/sys/io/File.hx +++ b/std/lua/_std/sys/io/File.hx @@ -41,14 +41,14 @@ class File { } public static function append(path:String, binary:Bool = true):FileOutput { - return new FileOutput(Io.open(path, "a")); + return @:privateAccess new FileOutput(Io.open(path, "a")); } public static function update(path:String, binary:Bool = true):FileOutput { if (!FileSystem.exists(path)) { write(path).close(); } - return new FileOutput(Io.open(path, binary ? "r+b" : "r+")); + return @:privateAccess new FileOutput(Io.open(path, binary ? "r+b" : "r+")); } public static function copy(srcPath:String, dstPath:String):Void { @@ -73,14 +73,14 @@ class File { var fh = Io.open(path, binary ? 'rb' : 'r'); if (fh == null) throw 'Invalid path : $path'; - return new FileInput(fh); + return @:privateAccess new FileInput(fh); } public static function write(path:String, binary:Bool = true):FileOutput { var fh = Io.open(path, binary ? 'wb' : 'w'); if (fh == null) throw 'Invalid path : $path'; - return new FileOutput(fh); + return @:privateAccess new FileOutput(fh); } public static function saveBytes(path:String, bytes:haxe.io.Bytes):Void { diff --git a/std/lua/_std/sys/io/FileInput.hx b/std/lua/_std/sys/io/FileInput.hx index b1a77541f8fb25e3d815d6d39121de07812a755c..f4464ecac7006cf39b4994ad2e54145fffaa1713 100644 --- a/std/lua/_std/sys/io/FileInput.hx +++ b/std/lua/_std/sys/io/FileInput.hx @@ -35,7 +35,7 @@ class FileInput extends haxe.io.Input { var f:FileHandle; var _eof:Bool; - public function new(f:FileHandle) { + function new(f:FileHandle) { if (f == null) throw 'Invalid filehandle : $f'; this.bigEndian = Boot.platformBigEndian; diff --git a/std/lua/_std/sys/io/FileOutput.hx b/std/lua/_std/sys/io/FileOutput.hx index 5de715ef1d539b05ef7ef45b7b12d83fa1505dd5..5fd76a20c1abcf52d8fab72828e07a214109b449 100644 --- a/std/lua/_std/sys/io/FileOutput.hx +++ b/std/lua/_std/sys/io/FileOutput.hx @@ -28,7 +28,7 @@ import haxe.io.Bytes; class FileOutput extends haxe.io.Output { var f:FileHandle; - public function new(f:FileHandle) { + function new(f:FileHandle) { if (f == null) throw 'Invalid filehandle : $f'; this.f = f; diff --git a/std/lua/_std/sys/io/Process.hx b/std/lua/_std/sys/io/Process.hx index 926b45dcb2244474b922947679f986c9c50913b5..7414098fdaef5081408eb02e7bc2adcb2d35525f 100644 --- a/std/lua/_std/sys/io/Process.hx +++ b/std/lua/_std/sys/io/Process.hx @@ -89,15 +89,22 @@ class Process { var opt = {args: setArgs(cmd, args), stdio: stdio}; - var p:lua.lib.luv.Process.LuvSpawn; - p = lua.lib.luv.Process.spawn(_shell, opt, function(code:Int, signal:Signal) { + var p = lua.lib.luv.Process.spawn(_shell, opt, function(code:Int, signal:Signal) { _code = code; + if (!_handle.is_closing()){ + _handle.close(); + } + _stdin.shutdown(()->_stdin.close()); + _stderr.shutdown(()->_stderr.close()); + _stdout.shutdown(()->_stdout.close()); + }); + _handle = p.handle; if (p.handle == null) throw p.pid; + _pid = p.pid; - _handle = p.handle; } public function getPid():Int { @@ -105,10 +112,9 @@ class Process { } public function close():Void { - stdout.close(); - stdin.close(); - stderr.close(); - _handle.close(); + if (!_handle.is_closing()){ + _handle.close(); + } } public function exitCode(block:Bool = true):Null { diff --git a/std/lua/_std/sys/net/Host.hx b/std/lua/_std/sys/net/Host.hx index 5f65e413208e2fa49b3e033a0b6fb40cd56596f1..c915bc319491d9f19905183b5e5d863b64752992 100644 --- a/std/lua/_std/sys/net/Host.hx +++ b/std/lua/_std/sys/net/Host.hx @@ -25,6 +25,11 @@ package sys.net; import haxe.io.Bytes; import haxe.io.BytesInput; +import lua.NativeStringTools.find; + +import lua.lib.luv.net.Dns; +import lua.lib.luv.Os; + @:coreapi class Host { public var host(default, null):String; @@ -35,7 +40,7 @@ class Host { public function new(name:String):Void { host = name; - if (lua.NativeStringTools.find(name, "(%d+)%.(%d+)%.(%d+)%.(%d+)").begin != null) { + if (find(name, "(%d+)%.(%d+)%.(%d+)%.(%d+)").begin != null) { _ip = name; } else { var res = lua.lib.luv.net.Dns.getaddrinfo(name); @@ -57,10 +62,10 @@ class Host { } public function reverse():String { - return lua.lib.luv.net.Dns.getnameinfo({ip: _ip}).result; + return Dns.getnameinfo({ip: _ip}).result; } static public function localhost():String { - return lua.lib.luasocket.socket.Dns.gethostname(); + return Os.gethostname(); } } diff --git a/std/lua/_std/sys/net/Socket.hx b/std/lua/_std/sys/net/Socket.hx index fe64b5c4c0b35258a53efce1b11f2d5ca86baf44..23ce051c6146a5412d63d951a69d08b7489620c9 100644 --- a/std/lua/_std/sys/net/Socket.hx +++ b/std/lua/_std/sys/net/Socket.hx @@ -154,9 +154,9 @@ class Socket { sock.output = new SocketOutput(cast x); return sock; } - var read_arr = res.read == null ? [] : lua.Lib.tableToArray(res.read).map(convert_socket); + var read_arr = res.read == null ? [] : Table.toArray(res.read).map(convert_socket); - var write_arr = res.write == null ? [] : lua.Lib.tableToArray(res.write).map(convert_socket); + var write_arr = res.write == null ? [] : Table.toArray(res.write).map(convert_socket); return {read: read_arr, write: write_arr, others: []}; } } diff --git a/std/lua/lib/lrexlib/Rex.hx b/std/lua/lib/lrexlib/Rex.hx index 438eab09cf6c395ba5a8e8d6f28b52bd196fc2da..3bfe0f6f8c86660931e37c74bd8d55d1ed63c753 100644 --- a/std/lua/lib/lrexlib/Rex.hx +++ b/std/lua/lib/lrexlib/Rex.hx @@ -26,7 +26,7 @@ import haxe.extern.EitherType; @:luaRequire("rex_pcre") extern class Rex { - inline public static function create(expr:String, flag:EitherType):Rex { + inline static function create(expr:String, flag:EitherType):Rex { return untyped Rex['new'](expr, flag); } @@ -36,13 +36,13 @@ extern class Rex { @return matched string, or array of strings. **/ - public static function match(patt:EitherType, subj:String, ?init:Int, ?ef:Int):Dynamic; + static function match(patt:EitherType, subj:String, ?init:Int, ?ef:Int):Dynamic; /** The function searches for the first match of the regexp patt in the string `subj`, starting from offset `init`, subject to flags `cf` and `ef`. **/ - public static function find(patt:EitherType, subj:String, ?init:Int, ?ef:Int):Dynamic; + static function find(patt:EitherType, subj:String, ?init:Int, ?ef:Int):Dynamic; /** The function is intended for use in the generic for Lua construct. It is @@ -50,37 +50,37 @@ extern class Rex { parameter is a regular expression pattern representing separators between the sections. **/ - public static function split(subj:String, sep:EitherType, ?cf:Int, ?ef:Int):Void->String; + static function split(subj:String, sep:EitherType, ?cf:Int, ?ef:Int):Void->String; /** This function counts matches of the pattern `patt` in the string `subj`. **/ - public static function count(subj:String, patt:EitherType, cf:Int, ef:Int):Dynamic; + static function count(subj:String, patt:EitherType, cf:Int, ef:Int):Dynamic; - public static function flags(?tb:Dynamic):Dynamic; + static function flags(?tb:Dynamic):Dynamic; /** The function searches for the first match of the regexp in the string `subj`, starting from offset `init`, subject to execution flags `ef`. **/ - public function tfind(subj:String, ?init:Int, ?ef:Int):Dynamic; + function tfind(subj:String, ?init:Int, ?ef:Int):Dynamic; /** This function searches for the first match of the regexp in the string `subj`, starting from offset `init`, subject to execution flags `ef`. **/ - public function exec(subj:String, ?init:Int, ?ef:Int):Dynamic; + function exec(subj:String, ?init:Int, ?ef:Int):Dynamic; /** The function is intended for use in the generic for Lua construct. It returns an iterator for repeated matching of the pattern patt in the string `subj`, subject to flags `cf` and `ef`. **/ - public static function gmatch(subj:String, patt:EitherType, ?cf:Int, ?ef:Int):Void->String; + static function gmatch(subj:String, patt:EitherType, ?cf:Int, ?ef:Int):Void->String; /** This function searches for all matches of the pattern `patt` in the string `subj` and replaces them according to the parameters `repl` and `n`. **/ - public static function gsub(subj:String, patt:EitherType, repl:Dynamic, ?n:Int, ?cf:Int, ?ef:Int):String; + static function gsub(subj:String, patt:EitherType, repl:Dynamic, ?n:Int, ?cf:Int, ?ef:Int):String; } diff --git a/std/lua/lib/luasocket/Socket.hx b/std/lua/lib/luasocket/Socket.hx index ce11131ddb42468eec57e30c7991d22bbcfb9e3f..7f092d36ee27df19dfb60fb812388195bfedfcd3 100644 --- a/std/lua/lib/luasocket/Socket.hx +++ b/std/lua/lib/luasocket/Socket.hx @@ -26,14 +26,14 @@ import lua.lib.luasocket.socket.*; @:luaRequire("socket") extern class Socket { - public static var _DEBUG:Bool; - public static var _VERSION:String; - public static function tcp():Result; - public static function bind(address:String, port:Int, ?backlog:Int):Result; - public static function connect(address:String, port:Int, ?locaddr:String, ?locport:Int):Result; - public static function gettime():Float; - public static function select(recvt:Table, sendt:Table, ?timeout:Float):SelectResult; - public function close():Void; - public function getsockname():AddrInfo; - public function settimeout(value:Float, ?mode:TimeoutMode):Void; + static var _DEBUG:Bool; + static var _VERSION:String; + static function tcp():Result; + static function bind(address:String, port:Int, ?backlog:Int):Result; + static function connect(address:String, port:Int, ?locaddr:String, ?locport:Int):Result; + static function gettime():Float; + static function select(recvt:Table, sendt:Table, ?timeout:Float):SelectResult; + function close():Void; + function getsockname():AddrInfo; + function settimeout(value:Float, ?mode:TimeoutMode):Void; } diff --git a/std/lua/lib/luasocket/socket/Dns.hx b/std/lua/lib/luasocket/socket/Dns.hx index ce26fa6c129322decfa079c4829dede9274aae9b..510dcba9839b8e821335e3a5342f084127b1f222 100644 --- a/std/lua/lib/luasocket/socket/Dns.hx +++ b/std/lua/lib/luasocket/socket/Dns.hx @@ -24,5 +24,5 @@ package lua.lib.luasocket.socket; @:luaRequire("socket", "dns") extern class Dns { - public static function gethostname():String; + static function gethostname():String; } diff --git a/std/lua/lib/luasocket/socket/TcpClient.hx b/std/lua/lib/luasocket/socket/TcpClient.hx index 4e3a8c58209b5f2619083951d173b3a7031be531..63a97543bfb81b91c55c955eddabf0f622eded77 100644 --- a/std/lua/lib/luasocket/socket/TcpClient.hx +++ b/std/lua/lib/luasocket/socket/TcpClient.hx @@ -25,10 +25,10 @@ package lua.lib.luasocket.socket; import haxe.extern.EitherType; extern class TcpClient extends Socket { - public function getpeername():AddrInfo; - public function receive(pattern:EitherType, ?prefix:String):Result; - public function send(data:String, ?i:Int, ?j:Int):Result; - public function shutdown(mode:ShutdownMode):Result; - public function settimeout(value:Float, ?mode:TimeoutMode):Void; - public function setoption(option:TcpOption, value:EitherType):Void; + function getpeername():AddrInfo; + function receive(pattern:EitherType, ?prefix:String):Result; + function send(data:String, ?i:Int, ?j:Int):Result; + function shutdown(mode:ShutdownMode):Result; + function settimeout(value:Float, ?mode:TimeoutMode):Void; + function setoption(option:TcpOption, value:EitherType):Void; } diff --git a/std/lua/lib/luasocket/socket/TcpMaster.hx b/std/lua/lib/luasocket/socket/TcpMaster.hx index 77629b2a138066f859282715754ac7c2fb55cf0d..8a500ec6cde34b87237ce628ff4976186b4f7d6d 100644 --- a/std/lua/lib/luasocket/socket/TcpMaster.hx +++ b/std/lua/lib/luasocket/socket/TcpMaster.hx @@ -26,8 +26,8 @@ import haxe.extern.EitherType; extern class TcpMaster extends Socket { // transforms master to TcpServer - public function listen(backlog:Int):Void; + function listen(backlog:Int):Void; // transforms master to TcpClient - public function connect(address:String, port:Int):Void; - public function bind(address:String, port:Int):Void; + function connect(address:String, port:Int):Void; + function bind(address:String, port:Int):Void; } diff --git a/std/lua/lib/luasocket/socket/TcpServer.hx b/std/lua/lib/luasocket/socket/TcpServer.hx index da1551b216b0d0fd35acfe82f750ae7350c44b15..c67a0539452634722dfefe7f445a469afdfad5c8 100644 --- a/std/lua/lib/luasocket/socket/TcpServer.hx +++ b/std/lua/lib/luasocket/socket/TcpServer.hx @@ -25,7 +25,7 @@ package lua.lib.luasocket.socket; import lua.*; extern class TcpServer extends Socket { - public function accept():Result; - public function settimeout(value:Int, ?mode:TimeoutMode):Void; - public function setoption(option:String, value:TcpOption):Void; + function accept():Result; + function settimeout(value:Int, ?mode:TimeoutMode):Void; + function setoption(option:String, value:TcpOption):Void; } diff --git a/std/lua/lib/luautf8/Utf8.hx b/std/lua/lib/luautf8/Utf8.hx index 4b7e98307c90f944e769c8996082a0eae15464da..c34f174fffaf0309d9157cd12827f53c94bda1d2 100644 --- a/std/lua/lib/luautf8/Utf8.hx +++ b/std/lua/lib/luautf8/Utf8.hx @@ -12,7 +12,7 @@ extern class Utf8 { Receives a string and returns its length. The empty string `""` has length `0`. Embedded zeros are counted, so `"a\000bc\000"` has length `5`. **/ - public static function len(str:String):Int; + static function len(str:String):Int; /** Receives zero or more integers. Returns a string with length equal to the @@ -20,7 +20,7 @@ extern class Utf8 { code equal to its corresponding argument. Note that numerical codes are not necessarily portable across platforms. **/ - public static function char(codes:haxe.extern.Rest):String; + static function char(codes:haxe.extern.Rest):String; /** Returns the substring of `str` that starts at `start` and continues until `end`; @@ -30,12 +30,12 @@ extern class Utf8 { with length `end`, and `sub(str, -end)` returns a suffix of `str` with length `start`. **/ - public static function sub(str:String, start:Int, ?end:Int):StringSub; + static function sub(str:String, start:Int, ?end:Int):StringSub; /** Returns the character code at position `index` of `str`. **/ - public static function charCodeAt(str:String, index:Int):Int; + static function charCodeAt(str:String, index:Int):Int; /** Looks for the first match of pattern in the string `str`. @@ -50,20 +50,20 @@ extern class Utf8 { a plain "find substring" operation, with no characters in pattern being considered "magic". Note that if plain is given, then `start` must be given as well. **/ - public static function find(str:String, target:String, ?start:Int, ?plain:Bool):StringFind; + static function find(str:String, target:String, ?start:Int, ?plain:Bool):StringFind; /** Returns the internal numerical codes of the characters `str[index]`. Note that numerical codes are not necessarily portable across platforms. **/ - public static function byte(str:String, ?index:Int):Int; + static function byte(str:String, ?index:Int):Int; /** **/ @:overload(function(str:String, pattern:String, replace:String->Void, ?n:Int):String {}) @:overload(function(str:String, pattern:String, replace:String->String, ?n:Int):String {}) - public static function gsub(str:String, pattern:String, replace:String, ?n:Int):String; + static function gsub(str:String, pattern:String, replace:String, ?n:Int):String; /** Returns an iterator function that, each time it is called, returns the next @@ -71,7 +71,7 @@ extern class Utf8 { then the whole match is produced in each call. **/ @:overload(function(str:String, pattern:String, match:Void->String, ?n:Int):String->Void {}) - public static function gmatch(str:String, pattern:String):Void->String; + static function gmatch(str:String, pattern:String):Void->String; /** Looks for the first match of pattern in the string s. If it finds one, @@ -80,23 +80,23 @@ extern class Utf8 { The optional argument `n` specifies where to start the search; its default value is `1` and can be negative. **/ - public static function match(str:String, pattern:String, ?n:Int):String; + static function match(str:String, pattern:String, ?n:Int):String; /** Receives a string and returns a copy of this string with all lowercase letters changed to uppercase. All other characters are left unchanged. The definition of what a lowercase letter is depends on the current locale. **/ - public static function upper(str:String):String; + static function upper(str:String):String; /** Receives a string and returns a copy of this string with all uppercase letters changed to lowercase. All other characters are left unchanged. The definition of what an uppercase letter is depends on the current locale. **/ - public static function lower(str:String):String; + static function lower(str:String):String; - public static function codes(str:String):Void->StringCodePoint; + static function codes(str:String):String->Int->StringCodePoint; } @:multiReturn extern class StringFind { diff --git a/std/lua/lib/luv/Misc.hx b/std/lua/lib/luv/Misc.hx index e11e8b1a75cfe3cec638b14ea3d47cdcd1f52922..7375d4933197c947d20643aaff03ee3f4e8e63bd 100644 --- a/std/lua/lib/luv/Misc.hx +++ b/std/lua/lib/luv/Misc.hx @@ -24,45 +24,43 @@ package lua.lib.luv; @:luaRequire("luv") extern class Misc { - public static function chdir(path:String):Bool; + static function chdir(path:String):Bool; - public static function os_homedir():String; - public static function os_tmpdir():String; - public static function os_get_passwd():String; - public static function cpu_info():Table; + static function cpu_info():Table; - public static function cwd():String; - public static function exepath():String; - public static function get_process_title():String; - public static function get_total_memory():Int; - public static function get_free_memory():Int; - public static function getpid():Int; + static function cwd():String; + static function exepath():String; + static function get_process_title():String; + static function get_total_memory():Int; + static function get_free_memory():Int; + static function getpid():Int; - public static function os_getenv(env:String):String; - public static function os_setenv(env:String, value:String):Void; + static function getrusage():ResourceUsage; + static function guess_handle(handle:Int):String; + static function hrtime():Float; - // TODO Windows only? - public static function getuid():Int; - public static function setuid(from:Int, to:Int):String; - public static function getgid():Int; - public static function setgid(from:Int, to:Int):Void; - - public static function getrusage():ResourceUsage; - public static function guess_handle(handle:Int):String; - public static function hrtime():Float; + static function gettimeofday() : TimeOfDay; // TODO: implement this - // public static function interface_addresses() : String; - public static function loadavg():Float; - public static function resident_set_memory():Int; - public static function set_process_title(title:String):Bool; - public static function uptime():Int; - public static function version():Int; - public static function version_string():String; - - // TODO : Windows only - public static function print_all_handles():Table; - public static function print_active_handles():Table; + static function interface_addresses() : Dynamic; + + static function loadavg():Float; + static function resident_set_memory():Int; + static function set_process_title(title:String):Bool; + static function uptime():Int; + static function version():Int; + static function version_string():String; + + // Windows only + static function getuid():Int; + static function setuid(from:Int, to:Int):String; + static function getgid():Int; + static function setgid(from:Int, to:Int):Void; + + // Windows only + static function print_all_handles():Table; + static function print_active_handles():Table; + } typedef CpuInfo = { @@ -101,3 +99,9 @@ typedef MicroTimeStamp = { usec:Int, sec:Int } + +@:multiReturn +extern class TimeOfDay { + var seconds : Int; + var microseconds : Int; +} diff --git a/std/lua/lib/luv/Os.hx b/std/lua/lib/luv/Os.hx new file mode 100644 index 0000000000000000000000000000000000000000..62e5bd993fa0f4c8fd31994eb86312e13db4cad4 --- /dev/null +++ b/std/lua/lib/luv/Os.hx @@ -0,0 +1,72 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package lua.lib.luv; + +@:luaRequire("luv") +extern class Os { + @:native("os_homedir") + static function homedir():String; + + @:native("os_tmpdir") + static function tmpdir():String; + + @:native("os_get_passwd") + static function get_passwd():String; + + @:native("os_getenv") + static function getenv(env:String):String; + + @:native("os_setenv") + static function setenv(env:String, value:String):Void; + + @:native("os_unsetenv") + static function unsetenv(env:String):Void; + + @:native("os_gethostname") + static function gethostname():String; + + @:native("os_environ") + static function environ():Table; + + @:native("os_uname") + static function uname():Uname; + + @:native("os_getpid") + static function getpid():Int; + + @:native("os_getppid") + static function getppid():Int; + + @:native("os_getpriority") + static function getpriority(pid:Int):Int; + + @:native("os_setpriority") + static function setpriority(pid:Int, priority:Int):Bool; +} + +typedef Uname = { + sysname:String, + release:String, + version:String, + machine:String +} diff --git a/std/lua/lib/luv/fs/FileSystem.hx b/std/lua/lib/luv/fs/FileSystem.hx index 0f8e3678f1cca78a738e97f89995f75b74484cc5..75970fa022d0071eee0d4cab9e92e2aee2ac347c 100644 --- a/std/lua/lib/luv/fs/FileSystem.hx +++ b/std/lua/lib/luv/fs/FileSystem.hx @@ -126,9 +126,10 @@ extern class FileSystem { @:overload(function(oldpath:String, newpath:String, flags:Int, cb:String->Bool->Void):Request {}) static function symlink(oldpath:String, newpath:String, flags:Int):Bool; - // @:native("fs_readlink") - // @:overload(function(path : String, cb : String->String->Void) : Request {}) - // static function readlink(path : String) : String; + @:native("fs_readlink") + @:overload(function(path:String, cb:String->String->Void):Request {}) + static function readlink(path:String):String; + @:native("fs_realpath") @:overload(function(path:String, cb:String->String->Void):Request {}) static function realpath(path:String):String; @@ -140,6 +141,29 @@ extern class FileSystem { @:native("fs_fchown") @:overload(function(descriptor:FileDescriptor, uid:Int, gid:Int, cb:String->Bool->Void):Request {}) static function fchown(descriptor:FileDescriptor, uid:Int, gid:Int):Bool; + + /** + Not available on windows + **/ + @:native("fs_lchown") + @:overload(function(descriptor:FileDescriptor, uid:Int, gid:Int, cb:String->Bool->Void):Request {}) + static function lchown(descriptor:FileDescriptor, uid:Int, gid:Int):Bool; + + @:native("fs_statfs") + @:overload(function(path:String, cb:StatFs->Bool->Void):Request {}) + static function statfs(path:String):StatFs; + + @:native("fs_opendir") + @:overload(function(path:String, cb:Handle->Bool->Void):Request {}) + static function opendir(path:String):Handle; + + @:native("fs_readdir") + @:overload(function(dir:Handle, cb:Table->Bool->Void):Request {}) + static function readdir(path:String):Table; + + @:native("fs_closedir") + @:overload(function(dir:Handle, cb:Bool->Void):Request {}) + static function closedir(dir:Handle):Bool; } extern class ScanDirMarker {} @@ -150,6 +174,11 @@ extern class ScandirNext { var type:String; } +typedef NameType = { + name:String, + type:String +} + typedef Stat = { ino:Int, ctime:TimeStamp, @@ -174,3 +203,13 @@ typedef TimeStamp = { sec:Int, nsec:Int } + +typedef StatFs = { + type:Int, + bsize:Int, + blocks:Int, + bfree:Int, + bavail:Int, + files:Int, + ffree:Int +} diff --git a/std/lua/lib/luv/fs/Open.hx b/std/lua/lib/luv/fs/Open.hx index b696ee3e9b26e1f22686c55fd7c6a016ab034b45..75a1c1233b70e13eabcdc6afe1e2d966dc1351c0 100644 --- a/std/lua/lib/luv/fs/Open.hx +++ b/std/lua/lib/luv/fs/Open.hx @@ -23,16 +23,16 @@ package lua.lib.luv.fs; enum abstract Open(String) { - var ReadOnly = "r"; - var ReadOnlySync = "rs"; - var ReadWrite = "r+"; - var ReadWriteSync = "rs+"; - var ReadWriteAppend = "a+"; - var ReadWriteTruncate = "w+"; + var ReadOnly = "r"; + var ReadOnlySync = "rs"; + var ReadWrite = "r+"; + var ReadWriteSync = "rs+"; + var ReadWriteAppend = "a+"; + var ReadWriteTruncate = "w+"; var ReadWriteTruncateNewFile = "wx+"; - var ReadWriteAppendNewFile = "ax+"; - var WriteOnly = "w"; - var WriteNewFile = "wx"; - var Append = "a"; - var AppendNewFile = "ax"; + var ReadWriteAppendNewFile = "ax+"; + var WriteOnly = "w"; + var WriteNewFile = "wx"; + var Append = "a"; + var AppendNewFile = "ax"; } diff --git a/std/lua/lib/luv/net/Dns.hx b/std/lua/lib/luv/net/Dns.hx index 8a11e0d3bd579af58fa621343162dee604065300..dfe556f250b40aece73d0cb4989b99e3ddd32b93 100644 --- a/std/lua/lib/luv/net/Dns.hx +++ b/std/lua/lib/luv/net/Dns.hx @@ -25,10 +25,10 @@ package lua.lib.luv.net; @:luaRequire("luv") extern class Dns { @:overload(function(node:String, ?service:String, ?hints:AddrInfo, cb:String->Table->Void):Request {}) - public static function getaddrinfo(node:String, ?service:String, ?hints:AddrInfo):Result>; + static function getaddrinfo(node:String, ?service:String, ?hints:AddrInfo):Result>; - @:overload(function(ip:String, ?port:Int, ?family:String, cb:String->AddrInfo->Void):Request {}) - public static function getnameinfo(info:AddrInfo):Result; + @:overload(function(ip:String, ?port:Int, ?family:String, ?cb:String->AddrInfo->Void):Request {}) + static function getnameinfo(info:AddrInfo):Result; } typedef AddrInfo = { diff --git a/std/neko/Web.hx b/std/neko/Web.hx index 5623895b32e3c19f50a74990d9cb7711a1a9aa4d..0da591244dde848de09ba25d35f2e1a74bdefb2d 100644 --- a/std/neko/Web.hx +++ b/std/neko/Web.hx @@ -28,6 +28,7 @@ import haxe.ds.List; This class is used for accessing the local Web server and the current client request and information. **/ +@:deprecated('neko.Web is deprecated and will be removed from standard library in Haxe 4.2') class Web { /** Returns the GET and POST parameters. diff --git a/std/neko/_std/Array.hx b/std/neko/_std/Array.hx index 86867317d63e288e1c3148e1de1da2e62d3cc1ef..bdbabb4d481a266cf642f6d9719359e5b3d0e789 100644 --- a/std/neko/_std/Array.hx +++ b/std/neko/_std/Array.hx @@ -19,6 +19,9 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ + +import haxe.iterators.ArrayKeyValueIterator; + @:coreApi final class Array { private var __a:neko.NativeArray; @@ -51,19 +54,12 @@ return new1(neko.NativeArray.sub(this.__a, 0, this.length), this.length); } - public function iterator():Iterator { - return untyped { - a: this, - p: 0, - hasNext: function() { - return __this__.p < __this__.a.length; - }, - next: function() { - var i = __this__.a.__a[__this__.p]; - __this__.p += 1; - return i; - } - }; + public inline function iterator():haxe.iterators.ArrayIterator { + return new haxe.iterators.ArrayIterator(this); + } + + public inline function keyValueIterator():ArrayKeyValueIterator { + return new ArrayKeyValueIterator(this); } public function insert(pos:Int, x:T):Void { @@ -159,6 +155,19 @@ return false; } + public function contains(x:T):Bool { + var i = 0; + var l = this.length; + var a = this.__a; + while (i < l) { + if (a[i] == x) { + return true; + } + i += 1; + } + return false; + } + public function indexOf(x:T, ?fromIndex:Int):Int { var len = length; var i:Int = (fromIndex != null) ? fromIndex : 0; diff --git a/std/neko/_std/Std.hx b/std/neko/_std/Std.hx index cd321ffa91184e004888a6316f4ae15e875aea97..8da8bcf18a5bbcc318b1de56875f0d573b8d21e7 100644 --- a/std/neko/_std/Std.hx +++ b/std/neko/_std/Std.hx @@ -21,12 +21,16 @@ */ @:coreApi class Std { @:ifFeature("typed_cast") - public static function is(v:Dynamic, t:Dynamic):Bool { + public static inline function is(v:Dynamic, t:Dynamic):Bool { + return isOfType(v, t); + } + + public static function isOfType(v:Dynamic, t:Dynamic):Bool { return untyped neko.Boot.__instanceof(v, t); } public static function downcast(value:T, c:Class):S { - return Std.is(value, c) ? cast value : null; + return Std.isOfType(value, c) ? cast value : null; } @:deprecated('Std.instance() is deprecated. Use Std.downcast() instead.') diff --git a/std/neko/_std/String.hx b/std/neko/_std/String.hx index 19cb14c45c40c8ec250bac27e6b4270fa01e6d82..06115127248b446a2c5c745c6abce5cb4aede3dc 100644 --- a/std/neko/_std/String.hx +++ b/std/neko/_std/String.hx @@ -61,6 +61,9 @@ var l = __dollar__ssize(this.__s); if (startIndex == null || startIndex < -l) startIndex = 0; + if (str == '' && startIndex >= l) { + return l; + } if (startIndex > l) return -1; if (__dollar__ssize(str.__s) == 0) diff --git a/std/neko/_std/haxe/Exception.hx b/std/neko/_std/haxe/Exception.hx new file mode 100644 index 0000000000000000000000000000000000000000..e707b956999a5126098b5eefd64f9128eabf8851 --- /dev/null +++ b/std/neko/_std/haxe/Exception.hx @@ -0,0 +1,85 @@ +package haxe; + +@:coreApi +class Exception { + public var message(get,never):String; + public var stack(get,never):CallStack; + public var previous(get,never):Null; + public var native(get,never):Any; + + @:noCompletion var __exceptionMessage:String; + @:noCompletion var __exceptionStack:Null; + @:noCompletion var __nativeStack:Any; + @:noCompletion @:ifFeature("haxe.Exception.get_stack") var __skipStack:Int = 0; + @:noCompletion var __nativeException:Any; + @:noCompletion var __previousException:Null; + + static function caught(value:Any):Exception { + if(Std.is(value, Exception)) { + return value; + } else { + return new ValueException(value, null, value); + } + } + + static function thrown(value:Any):Any { + if(Std.isOfType(value, Exception)) { + return (value:Exception).native; + } else { + var e = new ValueException(value); + e.__shiftStack(); + return e; + } + } + + public function new(message:String, ?previous:Exception, ?native:Any) { + __exceptionMessage = message; + __previousException = previous; + if(native != null) { + __nativeStack = NativeStackTrace.exceptionStack(); + __nativeException = native; + } else { + __nativeStack = NativeStackTrace.callStack(); + __shiftStack(); + __nativeException = this; + } + } + + function unwrap():Any { + return __nativeException; + } + + public function toString():String { + return message; + } + + public function details():String { + return inline CallStack.exceptionToString(this); + } + + @:noCompletion + @:ifFeature("haxe.Exception.get_stack") + inline function __shiftStack():Void { + __skipStack++; + } + + function get_message():String { + return __exceptionMessage; + } + + function get_previous():Null { + return __previousException; + } + + final function get_native():Any { + return __nativeException; + } + + function get_stack():CallStack { + return switch __exceptionStack { + case null: + __exceptionStack = NativeStackTrace.toHaxe(__nativeStack, __skipStack); + case s: s; + } + } +} \ No newline at end of file diff --git a/std/neko/_std/haxe/NativeStackTrace.hx b/std/neko/_std/haxe/NativeStackTrace.hx new file mode 100644 index 0000000000000000000000000000000000000000..8f9e0dd1eb225f1294a3f8d49f0aee4e6b4ba4da --- /dev/null +++ b/std/neko/_std/haxe/NativeStackTrace.hx @@ -0,0 +1,51 @@ +package haxe; + +import haxe.CallStack.StackItem; + +private typedef NativeTrace = { + final skip:Int; + final stack:Dynamic; +} + +/** + Do not use manually. +**/ +@:dox(hide) +@:noCompletion +class NativeStackTrace { + @:ifFeature('haxe.NativeStackTrace.exceptionStack') + static public inline function saveStack(exception:Any):Void { + } + + static public inline function callStack():NativeTrace { + return { skip:1, stack:untyped __dollar__callstack() }; + } + + static public function exceptionStack():NativeTrace { + return { skip:0, stack:untyped __dollar__excstack() }; + } + + static public function toHaxe(native:NativeTrace, skip:Int = 0):Array { + skip += native.skip; + var a = new Array(); + var l = untyped __dollar__asize(native.stack); + var i = 0; + while (i < l) { + var x = native.stack[l - i - 1]; + //skip all CFunctions until we skip required amount of hx entries + if(x == null && skip > i) { + skip++; + } + if(skip > i++) { + continue; + } + if (x == null) + a.push(CFunction); + else if (untyped __dollar__typeof(x) == __dollar__tstring) + a.push(Module(new String(x))); + else + a.push(FilePos(null, new String(untyped x[0]), untyped x[1])); + } + return a; + } +} \ No newline at end of file diff --git a/std/neko/_std/haxe/Resource.hx b/std/neko/_std/haxe/Resource.hx new file mode 100644 index 0000000000000000000000000000000000000000..ea5b5f2e0a6a1dce82e44c7aaa1a8034204bc9f3 --- /dev/null +++ b/std/neko/_std/haxe/Resource.hx @@ -0,0 +1,53 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package haxe; + +@:coreApi +class Resource { + static var content:Array<{name:String, data:String, str:String}>; + + public static function listNames():Array { + return [for (x in content) x.name]; + } + + public static function getString(name:String):String { + for (x in content) + if (x.name == name) { + return new String(x.data); + } + return null; + } + + public static function getBytes(name:String):haxe.io.Bytes { + for (x in content) + if (x.name == name) { + return haxe.io.Bytes.ofData(cast x.data); + } + return null; + } + + static function __init__() : Void { + var tmp = untyped __resources__(); + content = untyped Array.new1(tmp, __dollar__asize(tmp)); + } +} diff --git a/std/neko/_std/haxe/crypto/Md5.hx b/std/neko/_std/haxe/crypto/Md5.hx new file mode 100644 index 0000000000000000000000000000000000000000..923e115fa434307026ddf8993939e17cc0808562 --- /dev/null +++ b/std/neko/_std/haxe/crypto/Md5.hx @@ -0,0 +1,36 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package haxe.crypto; + +class Md5 { + public static function encode(s:String):String { + return untyped new String(base_encode(make_md5(s.__s), "0123456789abcdef".__s)); + } + + public static function make(b:haxe.io.Bytes):haxe.io.Bytes { + return haxe.io.Bytes.ofData(make_md5(b.getData())); + } + + static var base_encode = neko.Lib.load("std", "base_encode", 2); + static var make_md5 = neko.Lib.load("std", "make_md5", 1); +} diff --git a/std/neko/_std/haxe/io/StringInput.hx b/std/neko/_std/haxe/io/StringInput.hx new file mode 100644 index 0000000000000000000000000000000000000000..9ae786665898ffc2031c08c95f077c7d1a3ee240 --- /dev/null +++ b/std/neko/_std/haxe/io/StringInput.hx @@ -0,0 +1,29 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package haxe.io; + +class StringInput extends BytesInput { + public function new(s:String) { + super(neko.Lib.bytesReference(s)); + } +} diff --git a/std/neko/_std/haxe/iterators/StringIteratorUnicode.hx b/std/neko/_std/haxe/iterators/StringIteratorUnicode.hx new file mode 100644 index 0000000000000000000000000000000000000000..29293c62a37611c318e520526d5377305d768b33 --- /dev/null +++ b/std/neko/_std/haxe/iterators/StringIteratorUnicode.hx @@ -0,0 +1,64 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +package haxe.iterators; + +class StringIteratorUnicode { + var byteOffset:Int = 0; + var s:String; + + public inline function new(s:String) { + this.s = s; + } + + public inline function hasNext() { + return byteOffset < s.length; + } + + public inline function next() { + var code:Int = codeAt(byteOffset); + if (code < 0xC0) { + byteOffset++; + } else if (code < 0xE0) { + code = ((code - 0xC0) << 6) + codeAt(byteOffset + 1) - 0x80; + byteOffset += 2; + } else if (code < 0xF0) { + code = ((code - 0xE0) << 12) + ((codeAt(byteOffset + 1) - 0x80) << 6) + codeAt(byteOffset + 2) - 0x80; + byteOffset += 3; + } else { + code = ((code - 0xF0) << 18) + + ((codeAt(byteOffset + 1) - 0x80) << 12) + + ((codeAt(byteOffset + 2) - 0x80) << 6) + + codeAt(byteOffset + 3) + - 0x80; + byteOffset += 4; + } + return code; + } + + inline function codeAt(index:Int):Int { + return untyped $sget(s.__s, index); + } + + static public inline function unicodeIterator(s:String) { + return new StringIteratorUnicode(s); + } +} diff --git a/std/neko/_std/haxe/iterators/StringKeyValueIteratorUnicode.hx b/std/neko/_std/haxe/iterators/StringKeyValueIteratorUnicode.hx new file mode 100644 index 0000000000000000000000000000000000000000..07f97a65c5365a984544d54fbe2e866849d63f6b --- /dev/null +++ b/std/neko/_std/haxe/iterators/StringKeyValueIteratorUnicode.hx @@ -0,0 +1,65 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +package haxe.iterators; + +class StringKeyValueIteratorUnicode { + var byteOffset:Int = 0; + var charOffset:Int = 0; + var s:String; + + public inline function new(s:String) { + this.s = s; + } + + public inline function hasNext() { + return byteOffset < s.length; + } + + public inline function next() { + var code:Int = codeAt(byteOffset); + if (code < 0xC0) { + byteOffset++; + } else if (code < 0xE0) { + code = ((code - 0xC0) << 6) + codeAt(byteOffset + 1) - 0x80; + byteOffset += 2; + } else if (code < 0xF0) { + code = ((code - 0xE0) << 12) + ((codeAt(byteOffset + 1) - 0x80) << 6) + codeAt(byteOffset + 2) - 0x80; + byteOffset += 3; + } else { + code = ((code - 0xF0) << 18) + + ((codeAt(byteOffset + 1) - 0x80) << 12) + + ((codeAt(byteOffset + 2) - 0x80) << 6) + + codeAt(byteOffset + 3) + - 0x80; + byteOffset += 4; + } + return {key: charOffset++, value: code}; + } + + inline function codeAt(index:Int):Int { + return untyped $sget(s.__s, index); + } + + static public inline function unicodeKeyValueIterator(s:String) { + return new StringKeyValueIteratorUnicode(s); + } +} diff --git a/std/php/ArrayIterator.hx b/std/php/ArrayIterator.hx new file mode 100644 index 0000000000000000000000000000000000000000..96b1b683d860e6c11045f7ba026aead25f2558cf --- /dev/null +++ b/std/php/ArrayIterator.hx @@ -0,0 +1,57 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package php; + +/** + @see https://www.php.net/manual/en/class.arrayiterator.php +**/ +@:native('ArrayIterator') +extern class ArrayIterator implements php.ArrayAccess implements SeekableIterator implements Countable implements Serializable { + @:phpClassConst static final STD_PROP_LIST:Int; + @:phpClassConst static final ARRAY_AS_PROPS:Int; + + function new(?array:NativeArray, ?flags:Int); + function append(value:V):Void; + function asort():Void; + function count():Int; + function current():V; + function getArrayCopy():NativeArray; + function getFlags():Int; + function key():K; + function ksort():Void; + function natcasesort():Void; + function natsort():Void; + function next():Void; + function offsetExists(offset:K):Bool; + function offsetGet(offset:K):V; + function offsetSet(offset:K, value:V):Void; + function offsetUnset(offset:K):Void; + function rewind():Void; + function seek(position:Int):Void; + function serialize():String; + function setFlags(flags:Int):Void; + function uasort(cmp_function:(a:V, b:V) -> Int):Void; + function uksort(cmp_function:(a:K, b:K) -> Int):Void; + function unserialize(serialized:String):Void; + function valid():Bool; +} diff --git a/std/php/Boot.hx b/std/php/Boot.hx index 8fd18ffb0b398403d8fe231906ad8e6556013450..c00eb3db8a1209b3ece9770eb0592d4b3e61a3d3 100644 --- a/std/php/Boot.hx +++ b/std/php/Boot.hx @@ -201,7 +201,7 @@ class Boot { Check if provided value is an anonymous object **/ public static inline function isAnon(v:Any):Bool { - return Std.is(v, HxAnon); + return Std.isOfType(v, HxAnon); } /** @@ -315,7 +315,7 @@ class Boot { /** Implementation for `cast(value, Class)` - @throws HxException if `value` cannot be casted to this type + @throws haxe.ValueError if `value` cannot be casted to this type **/ public static function typedCast(hxClass:HxClass, value:Dynamic):Dynamic { if (value == null) @@ -342,7 +342,7 @@ class Boot { return value; } case _: - if (value.is_object() && Std.is(value, cast hxClass)) { + if (value.is_object() && Std.isOfType(value, cast hxClass)) { return value; } } @@ -376,10 +376,10 @@ class Boot { return '[' + Global.implode(', ', strings) + ']'; } if (value.is_object()) { - if (Std.is(value, Array)) { + if (Std.isOfType(value, Array)) { return inline stringifyNativeIndexedArray(value.arr, maxRecursion - 1); } - if (Std.is(value, HxEnum)) { + if (Std.isOfType(value, HxEnum)) { var e:HxEnum = value; var result = e.tag; if (Global.count(e.params) > 0) { @@ -394,7 +394,7 @@ class Boot { if (value.method_exists('__toString')) { return value.__toString(); } - if (Std.is(value, StdClass)) { + if (Std.isOfType(value, StdClass)) { if (Global.isset(Syntax.field(value, 'toString')) && value.toString.is_callable()) { return value.toString(); } @@ -408,7 +408,7 @@ class Boot { if (isFunction(value)) { return ''; } - if (Std.is(value, HxClass)) { + if (Std.isOfType(value, HxClass)) { return '[class ' + getClassName((value : HxClass).phpClassName) + ']'; } else { return '[object ' + getClassName(Global.get_class(value)) + ']'; @@ -436,7 +436,7 @@ class Boot { if (isNumber(left) && isNumber(right)) { return Syntax.equal(left, right); } - if (Std.is(left, HxClosure) && Std.is(right, HxClosure)) { + if (Std.isOfType(left, HxClosure) && Std.isOfType(right, HxClosure)) { return (left : HxClosure).equals(right); } return Syntax.strictEqual(left, right); @@ -453,10 +453,15 @@ class Boot { return Syntax.add(left, right); } + @:deprecated('php.Boot.is() is deprecated. Use php.Boot.isOfType() instead') + public static inline function is(value:Dynamic, type:HxClass):Bool { + return isOfType(value, type); + } + /** - `Std.is()` implementation + `Std.isOfType()` implementation **/ - public static function is(value:Dynamic, type:HxClass):Bool { + public static function isOfType(value:Dynamic, type:HxClass):Bool { if (type == null) return false; @@ -483,7 +488,7 @@ class Boot { case 'php\\NativeArray', 'php\\_NativeArray\\NativeArray_Impl_': return value.is_array(); case 'Enum' | 'Class': - if (Std.is(value, HxClass)) { + if (Std.isOfType(value, HxClass)) { var valuePhpClass = (cast value : HxClass).phpClassName; var enumPhpClass = (cast HxEnum : HxClass).phpClassName; var isEnumType = Global.is_subclass_of(valuePhpClass, enumPhpClass); @@ -502,28 +507,28 @@ class Boot { Check if `value` is a `Class` **/ public static inline function isClass(value:Dynamic):Bool { - return Std.is(value, HxClass); + return Std.isOfType(value, HxClass); } /** Check if `value` is an enum constructor instance **/ public static inline function isEnumValue(value:Dynamic):Bool { - return Std.is(value, HxEnum); + return Std.isOfType(value, HxEnum); } /** Check if `value` is a function **/ public static inline function isFunction(value:Dynamic):Bool { - return Std.is(value, Closure) || Std.is(value, HxClosure); + return Std.isOfType(value, Closure) || Std.isOfType(value, HxClosure); } /** Check if `value` is an instance of `HxClosure` **/ public static inline function isHxClosure(value:Dynamic):Bool { - return Std.is(value, HxClosure); + return Std.isOfType(value, HxClosure); } /** @@ -584,11 +589,14 @@ class Boot { Creates Haxe-compatible closure of an instance method. @param obj - any object **/ - public static function getInstanceClosure(obj:{?__hx_closureCache:NativeAssocArray}, methodName:String) { + public static function getInstanceClosure(obj:{?__hx_closureCache:NativeAssocArray}, methodName:String):Null { var result = Syntax.coalesce(obj.__hx_closureCache[methodName], null); if (result != null) { return result; } + if(!Global.method_exists(obj, methodName) && !Global.isset(Syntax.field(obj, methodName))) { + return null; + } result = new HxClosure(obj, methodName); if (!Global.property_exists(obj, '__hx_closureCache')) { obj.__hx_closureCache = new NativeAssocArray(); @@ -670,7 +678,7 @@ private class HxClass { } else if (Boot.hasGetter(phpClassName, property)) { return Syntax.staticCall(phpClassName, 'get_$property'); } else if (phpClassName.method_exists(property)) { - return new HxClosure(phpClassName, property); + return Boot.getStaticClosure(phpClassName, property); } else { return Syntax.getStaticField(phpClassName, property); } @@ -972,7 +980,7 @@ private class HxClosure { if (target.is_null()) { throw "Unable to create closure on `null`"; } - callable = Std.is(target, HxAnon) ? Syntax.field(target, func) : Syntax.arrayDecl(target, func); + callable = Std.isOfType(target, HxAnon) ? Syntax.field(target, func) : Syntax.arrayDecl(target, func); } /** @@ -990,7 +998,7 @@ private class HxClosure { if (eThis == null) { eThis = target; } - if (Std.is(eThis, HxAnon)) { + if (Std.isOfType(eThis, HxAnon)) { return Syntax.field(eThis, func); } return Syntax.arrayDecl(eThis, func); @@ -1009,18 +1017,4 @@ private class HxClosure { public function callWith(newThis:Dynamic, args:NativeArray):Dynamic { return Global.call_user_func_array(getCallback(newThis), args); } -} - -/** - Special exception which is used to wrap non-throwable values -**/ -@:keep -@:dox(hide) -private class HxException extends Exception { - var e:Dynamic; - - public function new(e:Dynamic):Void { - this.e = e; - super(Boot.stringify(e)); - } -} +} \ No newline at end of file diff --git a/std/php/Closure.hx b/std/php/Closure.hx index 4d9d5591a233914e3bdc423de110c59c9242f35d..3f7f5493ac44467b7180cabf45d7297ec87dbe25 100644 --- a/std/php/Closure.hx +++ b/std/php/Closure.hx @@ -29,6 +29,6 @@ import haxe.extern.Rest; **/ @:native('Closure') extern class Closure { - public function bindTo(newthis:{}, newscope:Dynamic = "static"):Closure; - public function call(newthis:{}, args:Rest):Dynamic; + function bindTo(newthis:{}, newscope:Dynamic = "static"):Closure; + function call(newthis:{}, args:Rest):Dynamic; } diff --git a/std/php/Countable.hx b/std/php/Countable.hx new file mode 100644 index 0000000000000000000000000000000000000000..b4ec31c32f3c9fa705908c6405c3ae5a101e9174 --- /dev/null +++ b/std/php/Countable.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package php; + +/** + @see https://www.php.net/manual/en/class.countable.php +**/ +@:native('Countable') +extern interface Countable { + function count():Int; +} \ No newline at end of file diff --git a/std/php/Generator.hx b/std/php/Generator.hx index 471ab39d925ad4529a8dd8af3ad04d897b24e8a3..805c5855de05e1b5fa69b5b39f1acbb4827cd69a 100644 --- a/std/php/Generator.hx +++ b/std/php/Generator.hx @@ -23,8 +23,6 @@ package php; /** - @see http://php.net/manual/en/class.generator.php - Generator is not a Haxe Iterable. It can be iterated one time only. Unfortunately Haxe does not know that in PHP generators may have no `return` expression or `return value` with any type of `value`. Use `return null` or untyped cast to workaround this issue: @@ -45,6 +43,8 @@ package php; } trace(g.getReturn()); // "hello" ``` + + @see http://php.net/manual/en/class.generator.php **/ @:native('Generator') extern class Generator { diff --git a/std/php/IteratorAggregate.hx b/std/php/IteratorAggregate.hx index 4742b36254c9c7e769f200eea899ddef4494e071..46eceeec5bcaad53ece524939bd983ca894d307b 100644 --- a/std/php/IteratorAggregate.hx +++ b/std/php/IteratorAggregate.hx @@ -22,13 +22,10 @@ package php; +/** + @see https://www.php.net/manual/en/class.iteratoraggregate.php +**/ @:native('IteratorAggregate') -extern interface IteratorAggregate { - /** - This method is not public to not induce Haxe users to use it ;) - Use iterator() instead. - The return type would be Aggregator that is unusable in Haxe - **/ - private function getIterator():Iterator; // - +extern interface IteratorAggregate extends Traversable { + function getIterator():Traversable; } diff --git a/std/php/JsonSerializable.hx b/std/php/JsonSerializable.hx new file mode 100644 index 0000000000000000000000000000000000000000..0203f262b05eba68c58aeef1d55a0cdc2e2871de --- /dev/null +++ b/std/php/JsonSerializable.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package php; + +/** + @see https://www.php.net/manual/en/class.jsonserializable.php +**/ +@:native('JsonSerializable') +extern interface JsonSerializable { + function jsonSerialize():T; +} \ No newline at end of file diff --git a/std/php/NativeIterator.hx b/std/php/NativeIterator.hx new file mode 100644 index 0000000000000000000000000000000000000000..7f7ed3e67b37841a58605ee82819f5e350ca8464 --- /dev/null +++ b/std/php/NativeIterator.hx @@ -0,0 +1,36 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package php; + +/** + Native PHP interface. + @see https://www.php.net/manual/en/class.iterator.php +**/ +@:native('Iterator') +extern interface NativeIterator extends Traversable { + function current():V; + function key():K; + function next():Void; + function rewind():Void; + function valid():Bool; +} diff --git a/std/php/SeekableIterator.hx b/std/php/SeekableIterator.hx new file mode 100644 index 0000000000000000000000000000000000000000..1aa3e80836066180e46db1f4767ee7e15c607fca --- /dev/null +++ b/std/php/SeekableIterator.hx @@ -0,0 +1,31 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package php; + +/** + @see https://www.php.net/manual/en/class.seekableiterator.php +**/ +@:native('SeekableIterator') +extern interface SeekableIterator extends NativeIterator { + function seek(position:Int):Void; +} \ No newline at end of file diff --git a/std/php/Serializable.hx b/std/php/Serializable.hx new file mode 100644 index 0000000000000000000000000000000000000000..d90cc1d52bdf682463c5f8baabbb5004564a76aa --- /dev/null +++ b/std/php/Serializable.hx @@ -0,0 +1,32 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package php; + +/** + @see https://www.php.net/manual/en/class.serializable.php +**/ +@:native('Serializable') +extern interface Serializable { + function serialize():String; + function unserialize(serialized:String):Void; +} diff --git a/std/php/Syntax.hx b/std/php/Syntax.hx index 33446791a63548fb94f1a89fed67ef5d1fec11c0..7fb623d0ea27e92a0a2143bacb7abff5c046f1d9 100644 --- a/std/php/Syntax.hx +++ b/std/php/Syntax.hx @@ -186,7 +186,7 @@ extern class Syntax { /** Generates `$value instanceof $phpClassName`. - Haxe generates `Std.is(value, Type)` calls as `$value instanceof Type` automatically where possible. + Haxe generates `Std.isOfType(value, Type)` calls as `$value instanceof Type` automatically where possible. So you may need this only if you have a `Class` stored in a variable. **/ @:overload(function(value:AsVar, phpClassName:AsVar):Bool {}) diff --git a/std/php/Throwable.hx b/std/php/Throwable.hx index 31027655d624c76e8688499ac58094c214f73be1..9d938afaf624d3b6c8ba8ab8fa04545c34f0cb70 100644 --- a/std/php/Throwable.hx +++ b/std/php/Throwable.hx @@ -35,4 +35,4 @@ extern interface Throwable { function getTrace():NativeIndexedArray>; // an array of the backtrace function getTraceAsString():String; // formatted string of trace @:phpMagic function __toString():String; // formatted string for display -} +} \ No newline at end of file diff --git a/std/php/Web.hx b/std/php/Web.hx index b4cf758ed7c3169b15dc63f98371136235f9bcee..76e735809bbf660fe665d128099d9afd9ae2277c 100644 --- a/std/php/Web.hx +++ b/std/php/Web.hx @@ -32,6 +32,7 @@ import php.SuperGlobal.*; This class is used for accessing the local Web server and the current client request and information. **/ +@:deprecated('php.Web is deprecated and will be removed from standard library in Haxe 4.2. See php.SuperGlobal and php.Global for alternatives.') class Web { /** Returns the GET and POST parameters. diff --git a/std/php/_std/Array.hx b/std/php/_std/Array.hx index 8954941220a4090100d5661066ceae71b6b8137b..a4925487671107b94c3ef3d52d3550838033709b 100644 --- a/std/php/_std/Array.hx +++ b/std/php/_std/Array.hx @@ -21,11 +21,14 @@ */ import php.*; +import php.ArrayIterator as NativeArrayIterator; + +import haxe.iterators.ArrayKeyValueIterator; using php.Global; @:coreApi -final class Array implements ArrayAccess { +final class Array implements ArrayAccess implements IteratorAggregate implements Countable implements JsonSerializable> { public var length(default, null):Int; var arr:NativeIndexedArray; @@ -53,6 +56,10 @@ final class Array implements ArrayAccess { return wrap(result); } + public inline function contains(x:T):Bool { + return indexOf(x) != -1; + } + public function indexOf(x:T, ?fromIndex:Int):Int { if (fromIndex == null && !Boot.isHxClosure(x) && !Boot.isNumber(x)) { var index = Global.array_search(x, arr, true); @@ -84,8 +91,13 @@ final class Array implements ArrayAccess { } @:ifFeature("dynamic_read.iterator", "anon_optional_read.iterator", "anon_read.iterator") - public inline function iterator():Iterator { - return new ArrayIterator(this); + public inline function iterator():haxe.iterators.ArrayIterator { + return new haxe.iterators.ArrayIterator(this); + } + + @:keep + public inline function keyValueIterator():ArrayKeyValueIterator { + return new ArrayKeyValueIterator(this); } public function join(sep:String):String { @@ -120,20 +132,20 @@ final class Array implements ArrayAccess { } public inline function push(x:T):Int { - arr[length] = x; - return ++length; + arr[length++] = x; + return length; } public function remove(x:T):Bool { var result = false; - Syntax.foreach(arr, function(index:Int, value:T) { - if (value == x) { + for(index in 0...length) { + if (arr[index] == x) { Global.array_splice(arr, index, 1); length--; result = true; - Syntax.code('break'); + break; } - }); + } return result; } @@ -194,12 +206,12 @@ final class Array implements ArrayAccess { length = len; } - @:noCompletion + @:noCompletion @:keep function offsetExists(offset:Int):Bool { return offset < length; } - @:noCompletion + @:noCompletion @:keep function offsetGet(offset:Int):Ref { try { return arr[offset]; @@ -208,7 +220,7 @@ final class Array implements ArrayAccess { } } - @:noCompletion + @:noCompletion @:keep function offsetSet(offset:Int, value:T):Void { if (length <= offset) { for(i in length...offset + 1) { @@ -220,7 +232,7 @@ final class Array implements ArrayAccess { Syntax.code("return {0}", value); } - @:noCompletion + @:noCompletion @:keep function offsetUnset(offset:Int):Void { if (offset >= 0 && offset < length) { Global.array_splice(arr, offset, 1); @@ -228,43 +240,33 @@ final class Array implements ArrayAccess { } } - static function wrap(arr:NativeIndexedArray):Array { - var a = new Array(); - a.arr = arr; - a.length = Global.count(arr); - return a; - } -} - -private class ArrayIterator { - var idx:Int; - var arr:Array; - - public inline function new(arr:Array) { - this.arr = arr; - idx = 0; + @:noCompletion @:keep + private function getIterator():Traversable { + return new NativeArrayIterator(arr); } - public inline function hasNext():Bool { - return idx < arr.length; + @:noCompletion @:keep + @:native('count') //to not interfere with `Lambda.count` + private function _hx_count():Int { + return length; } - public inline function next():T { - return arr[idx++]; + @:noCompletion @:keep + function jsonSerialize():NativeIndexedArray { + return arr; } - @:keep - @:phpMagic - function __get(method:String) { - return switch (method) { - case 'hasNext', 'next': Boot.closure(this, method); - case _: null; - } + static function wrap(arr:NativeIndexedArray):Array { + var a = new Array(); + a.arr = arr; + a.length = Global.count(arr); + return a; } } /** - This one is required for `Array` + Following interfaces are required to make `Array` mimic native arrays for usage + from a 3rd party PHP code. **/ @:native('ArrayAccess') private extern interface ArrayAccess { @@ -273,3 +275,19 @@ private extern interface ArrayAccess { private function offsetSet(offset:K, value:V):Void; private function offsetUnset(offset:K):Void; } + +@:native('JsonSerializable') +private extern interface JsonSerializable { + private function jsonSerialize():T; +} + +@:native('IteratorAggregate') +private extern interface IteratorAggregate extends Traversable { + private function getIterator():Traversable; +} + +@:native('Countable') +private extern interface Countable { + @:native('count') //to not interfere with `Lambda.count` + private function _hx_count():Int; +} \ No newline at end of file diff --git a/std/php/_std/Std.hx b/std/php/_std/Std.hx index f1736c1cb9427d9600bf18108cf62f0100911f27..75d3b914ea6a78cae58304a9ee46881e21f8372f 100644 --- a/std/php/_std/Std.hx +++ b/std/php/_std/Std.hx @@ -26,16 +26,20 @@ import php.Syntax; @:coreApi class Std { public static inline function is(v:Dynamic, t:Dynamic):Bool { - return Boot.is(v, t); + return isOfType(v, t); + } + + public static inline function isOfType(v:Dynamic, t:Dynamic):Bool { + return Boot.isOfType(v, t); } public static inline function downcast(value:T, c:Class):S { - return Boot.is(value, cast c) ? cast value : null; + return Boot.isOfType(value, cast c) ? cast value : null; } @:deprecated('Std.instance() is deprecated. Use Std.downcast() instead.') public static inline function instance(value:T, c:Class):S { - return Boot.is(value, cast c) ? cast value : null; + return Boot.isOfType(value, cast c) ? cast value : null; } public static function string(s:Dynamic):String { diff --git a/std/php/_std/Type.hx b/std/php/_std/Type.hx index 5f6bef138dcd291bfc298c8b86d8bdc30e175854..0e89cdbdf53c5f0f2e56ca3b90e48ddc9c337eec 100644 --- a/std/php/_std/Type.hx +++ b/std/php/_std/Type.hx @@ -266,7 +266,7 @@ enum ValueType { if (v.is_object()) { if (Reflect.isFunction(v)) return TFunction; - if (Std.is(v, StdClass)) + if (Std.isOfType(v, StdClass)) return TObject; if (Boot.isClass(v)) return TObject; diff --git a/std/php/_std/haxe/CallStack.hx b/std/php/_std/haxe/CallStack.hx deleted file mode 100644 index 7c47fe9b5f3ca51f629ee2b3000c41788baaa162..0000000000000000000000000000000000000000 --- a/std/php/_std/haxe/CallStack.hx +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C)2005-2019 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package haxe; - -import php.*; - -private typedef NativeTrace = NativeIndexedArray>; - -enum StackItem { - CFunction; - Module(m:String); - FilePos(s:Null, file:String, line:Int, ?column:Null); - Method(classname:Null, method:String); - LocalFunction(?v:Int); -} - -class CallStack { - /** - If defined this function will be used to transform call stack entries. - @param String - generated php file name. - @param Int - Line number in generated file. - **/ - static public var mapPosition:String->Int->Null<{?source:String, ?originalLine:Int}>; - - @:ifFeature("haxe.CallStack.exceptionStack") - static var lastExceptionTrace:NativeTrace; - - public static function callStack():Array { - return makeStack(Global.debug_backtrace(Const.DEBUG_BACKTRACE_IGNORE_ARGS)); - } - - public static function exceptionStack():Array { - return makeStack(lastExceptionTrace == null ? new NativeIndexedArray() : lastExceptionTrace); - } - - public static function toString(stack:Array) { - var b = new StringBuf(); - for (s in stack) { - b.add("\nCalled from "); - itemToString(b, s); - } - return b.toString(); - } - - static function itemToString(b:StringBuf, s) { - switch (s) { - case CFunction: - b.add("a C function"); - case Module(m): - b.add("module "); - b.add(m); - case FilePos(s, file, line, _): - if (s != null) { - itemToString(b, s); - b.add(" ("); - } - b.add(file); - b.add(" line "); - b.add(line); - if (s != null) - b.add(")"); - case Method(cname, meth): - b.add(cname == null ? "" : cname); - b.add("."); - b.add(meth); - case LocalFunction(n): - b.add("local function"); - } - } - - @:ifFeature("haxe.CallStack.exceptionStack") - static function saveExceptionTrace(e:Throwable):Void { - lastExceptionTrace = e.getTrace(); - - // Reduce exception stack to the place where exception was caught - var currentTrace = Global.debug_backtrace(Const.DEBUG_BACKTRACE_IGNORE_ARGS); - var count = Global.count(currentTrace); - - for (i in -(count - 1)...1) { - var exceptionEntry:NativeAssocArray = Global.end(lastExceptionTrace); - - if (!Global.isset(exceptionEntry['file']) || !Global.isset(currentTrace[-i]['file'])) { - Global.array_pop(lastExceptionTrace); - } else if (currentTrace[-i]['file'] == exceptionEntry['file'] && currentTrace[-i]['line'] == exceptionEntry['line']) { - Global.array_pop(lastExceptionTrace); - } else { - break; - } - } - - // Remove arguments from trace to avoid blocking some objects from GC - var count = Global.count(lastExceptionTrace); - for (i in 0...count) { - lastExceptionTrace[i]['args'] = new NativeArray(); - } - - var thrownAt = new NativeAssocArray(); - thrownAt['function'] = ''; - thrownAt['line'] = e.getLine(); - thrownAt['file'] = e.getFile(); - thrownAt['class'] = ''; - thrownAt['args'] = new NativeArray(); - Global.array_unshift(lastExceptionTrace, thrownAt); - } - - static function makeStack(native:NativeTrace):Array { - var result = []; - var count = Global.count(native); - - for (i in 0...count) { - var entry = native[i]; - var item = null; - - if (i + 1 < count) { - var next = native[i + 1]; - - if (!Global.isset(next['function'])) - next['function'] = ''; - if (!Global.isset(next['class'])) - next['class'] = ''; - - if ((next['function'] : String).indexOf('{closure}') >= 0) { - item = LocalFunction(); - } else if (Global.strlen(next['class']) > 0 && Global.strlen(next['function']) > 0) { - var cls = Boot.getClassName(next['class']); - item = Method(cls, next['function']); - } - } - if (Global.isset(entry['file'])) { - if (mapPosition != null) { - var pos = mapPosition(entry['file'], entry['line']); - if (pos != null && pos.source != null && pos.originalLine != null) { - entry['file'] = pos.source; - entry['line'] = pos.originalLine; - } - } - result.push(FilePos(item, entry['file'], entry['line'])); - } else if (item != null) { - result.push(item); - } - } - - return result; - } -} diff --git a/std/php/_std/haxe/Exception.hx b/std/php/_std/haxe/Exception.hx new file mode 100644 index 0000000000000000000000000000000000000000..5bc454d490d59c795f9c35caa1cedd4b5ee3d2b8 --- /dev/null +++ b/std/php/_std/haxe/Exception.hx @@ -0,0 +1,103 @@ +package haxe; + +import php.Throwable; +import php.NativeAssocArray; +import php.NativeIndexedArray; + +@:coreApi +class Exception extends NativeException { + public var message(get,never):String; + public var stack(get,never):CallStack; + public var previous(get,never):Null; + public var native(get,never):Any; + + @:noCompletion var __exceptionStack:Null; + @:noCompletion var __nativeException:Throwable; + @:noCompletion var __skipStack:Int = 0; + @:noCompletion var __previousException:Null; + + static function caught(value:Any):Exception { + if(Std.is(value, Exception)) { + return value; + } else if(Std.isOfType(value, Throwable)) { + return new Exception((value:Throwable).getMessage(), null, value); + } else { + return new ValueException(value, null, value); + } + } + + static function thrown(value:Any):Any { + if(Std.isOfType(value, Exception)) { + return (value:Exception).native; + } else if(Std.isOfType(value, Throwable)) { + return value; + } else { + var e = new ValueException(value); + e.__skipStack = 1; + return e; + } + } + + public function new(message:String, ?previous:Exception, ?native:Any) { + super(message, 0, previous); + this.__previousException = previous; + if(native != null && Std.isOfType(native, Throwable)) { + __nativeException = native; + } else { + __nativeException = cast this; + } + } + + function unwrap():Any { + return __nativeException; + } + + public function toString():String { + return message; + } + + public function details():String { + return inline CallStack.exceptionToString(this); + } + + function get_message():String { + return this.getMessage(); + } + + function get_previous():Null { + return __previousException; + } + + final function get_native():Any { + return __nativeException; + } + + function get_stack():CallStack { + return switch __exceptionStack { + case null: + var nativeTrace = NativeStackTrace.complementTrace(__nativeException.getTrace(), native); + __exceptionStack = NativeStackTrace.toHaxe(nativeTrace, __skipStack); + case s: s; + } + } +} + +@:dox(hide) +@:noCompletion +@:native('Exception') +private extern class NativeException { + @:noCompletion private function new(?message:String, ?code:Int, ?previous:NativeException):Void; + + @:noCompletion private var code:Int; + @:noCompletion private var file:String; + @:noCompletion private var line:Int; + + @:noCompletion final private function getPrevious():Throwable; + @:noCompletion private function getMessage():String; + @:noCompletion private function getCode():Int; + @:noCompletion private function getFile():String; + @:noCompletion private function getLine():Int; + @:noCompletion private function getTrace():NativeIndexedArray>; + @:noCompletion private function getTraceAsString():String; + @:noCompletion @:phpMagic private function __toString():String; +} \ No newline at end of file diff --git a/std/php/_std/haxe/Json.hx b/std/php/_std/haxe/Json.hx index 7a30854222e9fc8161f54b038c918b27997ec7e3..e4cc2ef0b7b2ec4b4b78a9886a4815dab2584800 100644 --- a/std/php/_std/haxe/Json.hx +++ b/std/php/_std/haxe/Json.hx @@ -87,7 +87,7 @@ class Json { } static function convertBeforeEncode(value:Dynamic):Dynamic { - if (Std.is(value, Array)) { + if (Std.isOfType(value, Array)) { var result = new NativeIndexedArray(); Syntax.foreach(value.arr, function(index:Int, item:Dynamic) { result[index] = convertBeforeEncode(item); diff --git a/std/php/_std/haxe/NativeStackTrace.hx b/std/php/_std/haxe/NativeStackTrace.hx new file mode 100644 index 0000000000000000000000000000000000000000..10e704a00b831345d462703d4116958912d8b1c2 --- /dev/null +++ b/std/php/_std/haxe/NativeStackTrace.hx @@ -0,0 +1,115 @@ +package haxe; + +import php.*; +import haxe.CallStack.StackItem; + +private typedef NativeTrace = NativeIndexedArray>; + +/** + Do not use manually. +**/ +@:dox(hide) +@:noCompletion +@:allow(haxe.Exception) +class NativeStackTrace { + /** + If defined this function will be used to transform call stack entries. + @param String - generated php file name. + @param Int - Line number in generated file. + **/ + static public var mapPosition:String->Int->Null<{?source:String, ?originalLine:Int}>; + + static var lastExceptionTrace:Null; + + @:ifFeature('haxe.NativeStackTrace.exceptionStack') + static public function saveStack(e:Throwable) { + var nativeTrace = e.getTrace(); + + // Reduce exception stack to the place where exception was caught + var currentTrace = Global.debug_backtrace(Const.DEBUG_BACKTRACE_IGNORE_ARGS); + var count = Global.count(currentTrace); + + for (i in -(count - 1)...1) { + var exceptionEntry:NativeAssocArray = Global.end(nativeTrace); + + if (!Global.isset(exceptionEntry['file']) || !Global.isset(currentTrace[-i]['file'])) { + Global.array_pop(nativeTrace); + } else if (currentTrace[-i]['file'] == exceptionEntry['file'] && currentTrace[-i]['line'] == exceptionEntry['line']) { + Global.array_pop(nativeTrace); + } else { + break; + } + } + + // Remove arguments from trace to avoid blocking some objects from GC + var count = Global.count(nativeTrace); + for (i in 0...count) { + nativeTrace[i]['args'] = new NativeArray(); + } + + lastExceptionTrace = complementTrace(nativeTrace, e); + } + + static public inline function callStack():NativeTrace { + return Global.debug_backtrace(Const.DEBUG_BACKTRACE_IGNORE_ARGS); + } + + static public function exceptionStack():NativeTrace { + return lastExceptionTrace == null ? new NativeIndexedArray() : lastExceptionTrace; + } + + static public function toHaxe(native:NativeTrace, skip:Int = 0):Array { + var result = []; + var count = Global.count(native); + + for (i in 0...count) { + if(skip > i) { + continue; + } + + var entry = native[i]; + var item = null; + + if (i + 1 < count) { + var next = native[i + 1]; + + if (!Global.isset(next['function'])) + next['function'] = ''; + if (!Global.isset(next['class'])) + next['class'] = ''; + + if ((next['function'] : String).indexOf('{closure}') >= 0) { + item = LocalFunction(); + } else if (Global.strlen(next['class']) > 0 && Global.strlen(next['function']) > 0) { + var cls = Boot.getClassName(next['class']); + item = Method(cls, next['function']); + } + } + if (Global.isset(entry['file'])) { + if (mapPosition != null) { + var pos = mapPosition(entry['file'], entry['line']); + if (pos != null && pos.source != null && pos.originalLine != null) { + entry['file'] = pos.source; + entry['line'] = pos.originalLine; + } + } + result.push(FilePos(item, entry['file'], entry['line'])); + } else if (item != null) { + result.push(item); + } + } + + return result; + } + + static function complementTrace(nativeTrace:NativeTrace, e:Throwable):NativeTrace { + var thrownAt = new NativeAssocArray(); + thrownAt['function'] = ''; + thrownAt['line'] = e.getLine(); + thrownAt['file'] = e.getFile(); + thrownAt['class'] = ''; + thrownAt['args'] = new NativeArray(); + Global.array_unshift(nativeTrace, thrownAt); + return nativeTrace; + } +} \ No newline at end of file diff --git a/std/php/_std/haxe/io/BytesBuffer.hx b/std/php/_std/haxe/io/BytesBuffer.hx index 708d1124fd77733eaa4f1c91fe69695bff6dbef9..4f7bb565f3f0dab3ab63f2364e4b421590d33ec3 100644 --- a/std/php/_std/haxe/io/BytesBuffer.hx +++ b/std/php/_std/haxe/io/BytesBuffer.hx @@ -23,6 +23,7 @@ package haxe.io; import php.*; +import haxe.io.Error; class BytesBuffer { var b:NativeString; diff --git a/std/php/db/PDO.hx b/std/php/db/PDO.hx index 89a94847c894da5ff2b09e1b899a5d1129403d97..03e5307f20365dc631ab5f02861f68be8bc47888 100644 --- a/std/php/db/PDO.hx +++ b/std/php/db/PDO.hx @@ -26,70 +26,70 @@ import php.*; @:native('PDO') extern class PDO { - @:phpClassConst static var PARAM_BOOL:Int; - @:phpClassConst static var PARAM_NULL:Int; - @:phpClassConst static var PARAM_INT:Int; - @:phpClassConst static var PARAM_STR:Int; - @:phpClassConst static var PARAM_LOB:Int; - @:phpClassConst static var PARAM_STMT:Int; - @:phpClassConst static var PARAM_INPUT_OUTPUT:Int; - @:phpClassConst static var FETCH_LAZY:Int; - @:phpClassConst static var FETCH_ASSOC:Int; - @:phpClassConst static var FETCH_NAMED:Int; - @:phpClassConst static var FETCH_NUM:Int; - @:phpClassConst static var FETCH_BOTH:Int; - @:phpClassConst static var FETCH_OBJ:Int; - @:phpClassConst static var FETCH_BOUND:Int; - @:phpClassConst static var FETCH_COLUMN:Int; - @:phpClassConst static var FETCH_CLASS:Int; - @:phpClassConst static var FETCH_INTO:Int; - @:phpClassConst static var FETCH_FUNC:Int; - @:phpClassConst static var FETCH_GROUP:Int; - @:phpClassConst static var FETCH_UNIQUE:Int; - @:phpClassConst static var FETCH_KEY_PAIR:Int; - @:phpClassConst static var FETCH_CLASSTYPE:Int; - @:phpClassConst static var FETCH_SERIALIZE:Int; - @:phpClassConst static var FETCH_PROPS_LATE:Int; - @:phpClassConst static var ATTR_AUTOCOMMIT:Int; - @:phpClassConst static var ATTR_PREFETCH:Int; - @:phpClassConst static var ATTR_TIMEOUT:Int; - @:phpClassConst static var ATTR_ERRMODE:Int; - @:phpClassConst static var ATTR_SERVER_VERSION:Int; - @:phpClassConst static var ATTR_CLIENT_VERSION:Int; - @:phpClassConst static var ATTR_SERVER_INFO:Int; - @:phpClassConst static var ATTR_CONNECTION_STATUS:Int; - @:phpClassConst static var ATTR_CASE:Int; - @:phpClassConst static var ATTR_CURSOR_NAME:Int; - @:phpClassConst static var ATTR_CURSOR:Int; - @:phpClassConst static var ATTR_DRIVER_NAME:String; - @:phpClassConst static var ATTR_ORACLE_NULLS:Int; - @:phpClassConst static var ATTR_PERSISTENT:Int; - @:phpClassConst static var ATTR_STATEMENT_CLASS:Int; - @:phpClassConst static var ATTR_FETCH_TABLE_NAMES:Int; - @:phpClassConst static var ATTR_STRINGIFY_FETCHES:Int; - @:phpClassConst static var ATTR_EMULATE_PREPARES:Int; - @:phpClassConst static var ERRMODE_SILENT:Int; - @:phpClassConst static var ERRMODE_WARNING:Int; - @:phpClassConst static var ERRMODE_EXCEPTION:Int; - @:phpClassConst static var CASE_NATURAL:Int; - @:phpClassConst static var CASE_LOWER:Int; - @:phpClassConst static var CASE_UPPER:Int; - @:phpClassConst static var NULL_NATURAL:Int; - @:phpClassConst static var FETCH_ORI_PRIOR:Int; - @:phpClassConst static var FETCH_ORI_FIRST:Int; - @:phpClassConst static var FETCH_ORI_LAST:Int; - @:phpClassConst static var FETCH_ORI_ABS:Int; - @:phpClassConst static var FETCH_ORI_REL:Int; - @:phpClassConst static var CURSOR_FWDONLY:Int; - @:phpClassConst static var CURSOR_SCROLL:Int; - @:phpClassConst static var ERR_NONE:String; - @:phpClassConst static var PARAM_EVT_ALLOC:Int; - @:phpClassConst static var PARAM_EVT_FREE:Int; - @:phpClassConst static var PARAM_EVT_EXEC_PRE:Int; - @:phpClassConst static var PARAM_EVT_EXEC_POST:Int; - @:phpClassConst static var PARAM_EVT_FETCH_PRE:Int; - @:phpClassConst static var PARAM_EVT_FETCH_POST:Int; - @:phpClassConst static var PARAM_EVT_NORMALIZE:Int; + @:phpClassConst static final PARAM_BOOL:Int; + @:phpClassConst static final PARAM_NULL:Int; + @:phpClassConst static final PARAM_INT:Int; + @:phpClassConst static final PARAM_STR:Int; + @:phpClassConst static final PARAM_LOB:Int; + @:phpClassConst static final PARAM_STMT:Int; + @:phpClassConst static final PARAM_INPUT_OUTPUT:Int; + @:phpClassConst static final FETCH_LAZY:Int; + @:phpClassConst static final FETCH_ASSOC:Int; + @:phpClassConst static final FETCH_NAMED:Int; + @:phpClassConst static final FETCH_NUM:Int; + @:phpClassConst static final FETCH_BOTH:Int; + @:phpClassConst static final FETCH_OBJ:Int; + @:phpClassConst static final FETCH_BOUND:Int; + @:phpClassConst static final FETCH_COLUMN:Int; + @:phpClassConst static final FETCH_CLASS:Int; + @:phpClassConst static final FETCH_INTO:Int; + @:phpClassConst static final FETCH_FUNC:Int; + @:phpClassConst static final FETCH_GROUP:Int; + @:phpClassConst static final FETCH_UNIQUE:Int; + @:phpClassConst static final FETCH_KEY_PAIR:Int; + @:phpClassConst static final FETCH_CLASSTYPE:Int; + @:phpClassConst static final FETCH_SERIALIZE:Int; + @:phpClassConst static final FETCH_PROPS_LATE:Int; + @:phpClassConst static final ATTR_AUTOCOMMIT:Int; + @:phpClassConst static final ATTR_PREFETCH:Int; + @:phpClassConst static final ATTR_TIMEOUT:Int; + @:phpClassConst static final ATTR_ERRMODE:Int; + @:phpClassConst static final ATTR_SERVER_VERSION:Int; + @:phpClassConst static final ATTR_CLIENT_VERSION:Int; + @:phpClassConst static final ATTR_SERVER_INFO:Int; + @:phpClassConst static final ATTR_CONNECTION_STATUS:Int; + @:phpClassConst static final ATTR_CASE:Int; + @:phpClassConst static final ATTR_CURSOR_NAME:Int; + @:phpClassConst static final ATTR_CURSOR:Int; + @:phpClassConst static final ATTR_DRIVER_NAME:String; + @:phpClassConst static final ATTR_ORACLE_NULLS:Int; + @:phpClassConst static final ATTR_PERSISTENT:Int; + @:phpClassConst static final ATTR_STATEMENT_CLASS:Int; + @:phpClassConst static final ATTR_FETCH_TABLE_NAMES:Int; + @:phpClassConst static final ATTR_STRINGIFY_FETCHES:Int; + @:phpClassConst static final ATTR_EMULATE_PREPARES:Int; + @:phpClassConst static final ERRMODE_SILENT:Int; + @:phpClassConst static final ERRMODE_WARNING:Int; + @:phpClassConst static final ERRMODE_EXCEPTION:Int; + @:phpClassConst static final CASE_NATURAL:Int; + @:phpClassConst static final CASE_LOWER:Int; + @:phpClassConst static final CASE_UPPER:Int; + @:phpClassConst static final NULL_NATURAL:Int; + @:phpClassConst static final FETCH_ORI_PRIOR:Int; + @:phpClassConst static final FETCH_ORI_FIRST:Int; + @:phpClassConst static final FETCH_ORI_LAST:Int; + @:phpClassConst static final FETCH_ORI_ABS:Int; + @:phpClassConst static final FETCH_ORI_REL:Int; + @:phpClassConst static final CURSOR_FWDONLY:Int; + @:phpClassConst static final CURSOR_SCROLL:Int; + @:phpClassConst static final ERR_NONE:String; + @:phpClassConst static final PARAM_EVT_ALLOC:Int; + @:phpClassConst static final PARAM_EVT_FREE:Int; + @:phpClassConst static final PARAM_EVT_EXEC_PRE:Int; + @:phpClassConst static final PARAM_EVT_EXEC_POST:Int; + @:phpClassConst static final PARAM_EVT_FETCH_PRE:Int; + @:phpClassConst static final PARAM_EVT_FETCH_POST:Int; + @:phpClassConst static final PARAM_EVT_NORMALIZE:Int; function new(dns:String, ?username:String, ?password:String, ?options:NativeArray):Void; function beginTransaction():Bool; diff --git a/std/php/reflection/ReflectionClass.hx b/std/php/reflection/ReflectionClass.hx index 7639f2e77fa028f893ccc9fe975800cab6f07ed6..edf55d3e2eb97fae533050d6aa92050bd7cd9b98 100644 --- a/std/php/reflection/ReflectionClass.hx +++ b/std/php/reflection/ReflectionClass.hx @@ -26,9 +26,9 @@ import haxe.extern.Rest; @:native('ReflectionClass') extern class ReflectionClass implements Reflector { - @:phpClassConst static var IS_IMPLICIT_ABSTRACT:Int; - @:phpClassConst static var IS_EXPLICIT_ABSTRACT:Int; - @:phpClassConst static var IS_FINAL:Int; + @:phpClassConst static final IS_IMPLICIT_ABSTRACT:Int; + @:phpClassConst static final IS_EXPLICIT_ABSTRACT:Int; + @:phpClassConst static final IS_FINAL:Int; static function export(argument:Dynamic, returnValue:Bool = false):String; diff --git a/std/php/reflection/ReflectionMethod.hx b/std/php/reflection/ReflectionMethod.hx index 187faf3239d82d3287f2d6988b71e0143569be61..0c6819b6fb5f9f7932cab76f80f452cd7861fcbf 100644 --- a/std/php/reflection/ReflectionMethod.hx +++ b/std/php/reflection/ReflectionMethod.hx @@ -27,30 +27,30 @@ import haxe.extern.Rest; @:native('ReflectionMethod') extern class ReflectionMethod extends ReflectionFunctionAbstract { - @:phpClassConst static var IS_STATIC:Int; - @:phpClassConst static var IS_PUBLIC:Int; - @:phpClassConst static var IS_PROTECTED:Int; - @:phpClassConst static var IS_PRIVATE:Int; - @:phpClassConst static var IS_ABSTRACT:Int; - @:phpClassConst static var IS_FINAL:Int; + @:phpClassConst static final IS_STATIC:Int; + @:phpClassConst static final IS_PUBLIC:Int; + @:phpClassConst static final IS_PROTECTED:Int; + @:phpClassConst static final IS_PRIVATE:Int; + @:phpClassConst static final IS_ABSTRACT:Int; + @:phpClassConst static final IS_FINAL:Int; - // public var class : String; - public static function export(className:String, name:String, ?returnValue:Bool):String; + // var class : String; + static function export(className:String, name:String, ?returnValue:Bool):String; - public function new(cls:Dynamic, name:String):Void; - public function getClosure(object:{}):Function; - public function getDeclaringClass():ReflectionClass; - public function getModifiers():Int; - public function getPrototype():ReflectionMethod; - public function invoke(object:{}, args:Rest):Dynamic; - public function invokeArgs(object:{}, args:NativeIndexedArray):Dynamic; - public function isAbstract():Bool; - public function isConstructor():Bool; - public function isDestructor():Bool; - public function isFinal():Bool; - public function isPrivate():Bool; - public function isProtected():Bool; - public function isPublic():Bool; - public function isStatic():Bool; - public function setAccessible(accessible:Bool):Void; + function new(cls:Dynamic, name:String):Void; + function getClosure(object:{}):Function; + function getDeclaringClass():ReflectionClass; + function getModifiers():Int; + function getPrototype():ReflectionMethod; + function invoke(object:{}, args:Rest):Dynamic; + function invokeArgs(object:{}, args:NativeIndexedArray):Dynamic; + function isAbstract():Bool; + function isConstructor():Bool; + function isDestructor():Bool; + function isFinal():Bool; + function isPrivate():Bool; + function isProtected():Bool; + function isPublic():Bool; + function isStatic():Bool; + function setAccessible(accessible:Bool):Void; } diff --git a/std/php/reflection/ReflectionProperty.hx b/std/php/reflection/ReflectionProperty.hx index fc01bf788e44abbe71d7863a382d8b0b8a681592..2a46942f3b24241f89f3bdc71dda1e6c2efe27da 100644 --- a/std/php/reflection/ReflectionProperty.hx +++ b/std/php/reflection/ReflectionProperty.hx @@ -24,10 +24,10 @@ package php.reflection; @:native('ReflectionProperty') extern class ReflectionProperty implements Reflector { - @:phpClassConst static var IS_STATIC:Int; - @:phpClassConst static var IS_:Int; - @:phpClassConst static var IS_PROTECTED:Int; - @:phpClassConst static var IS_PRIVATE:Int; + @:phpClassConst static final IS_STATIC:Int; + @:phpClassConst static final IS_:Int; + @:phpClassConst static final IS_PROTECTED:Int; + @:phpClassConst static final IS_PRIVATE:Int; var name:String; diff --git a/std/python/Boot.hx b/std/python/Boot.hx index 88d6f00bd3e4a1e2517c97bb26ed0c174a15783d..50027b08a0d911ca685ef6a54e1be91976c09eff 100644 --- a/std/python/Boot.hx +++ b/std/python/Boot.hx @@ -28,7 +28,6 @@ import python.internal.Internal; import python.internal.StringImpl; import python.internal.EnumImpl; import python.internal.HxOverrides; -import python.internal.HxException; import python.internal.AnonObject; import python.internal.UBuiltins; import python.lib.Inspect; @@ -334,6 +333,8 @@ class Boot { createClosure(o, ArrayImpl.copy); case "iterator": createClosure(o, ArrayImpl.iterator); + case "keyValueIterator": + createClosure(o, ArrayImpl.keyValueIterator); case "insert": createClosure(o, ArrayImpl.insert); case "join": @@ -350,6 +351,8 @@ class Boot { createClosure(o, ArrayImpl.indexOf); case "lastIndexOf": createClosure(o, ArrayImpl.lastIndexOf); + case "contains": + createClosure(o, ArrayImpl.contains); case "remove": createClosure(o, ArrayImpl.remove); case "reverse": diff --git a/std/python/Bytearray.hx b/std/python/Bytearray.hx index 4094e6065126c95fada79e5ec739b2b7a9f1471a..b54060ed130d0f3e9d59dc304b27768e9878570f 100644 --- a/std/python/Bytearray.hx +++ b/std/python/Bytearray.hx @@ -26,13 +26,13 @@ import python.Syntax; @:native("bytearray") extern class Bytearray implements ArrayAccess { - public var length(get, never):Int; + var length(get, never):Int; @:overload(function():Void {}) @:overload(function(it:Array):Void {}) @:overload(function(it:NativeIterable):Void {}) @:overload(function(size:Int):Void {}) - public function new(source:String, encoding:String, ?errors:Dynamic):Void; + function new(source:String, encoding:String, ?errors:Dynamic):Void; private inline function get_length():Int { return python.internal.UBuiltins.len(this); @@ -41,15 +41,15 @@ extern class Bytearray implements ArrayAccess { function append(x:Int):Void; function extend(t:Bytearray):Void; - public inline function get(i:Int):Int { + inline function get(i:Int):Int { return Syntax.arrayAccess(this, i); } - public inline function set(i:Int, v:Int):Void { + inline function set(i:Int, v:Int):Void { this.__setitem__(i, v); } - public function __setitem__(i:Int, v:Int):Void; + function __setitem__(i:Int, v:Int):Void; - public function decode(encoding:String = "utf-8", errors:String = "strict"):String; + function decode(encoding:String = "utf-8", errors:String = "strict"):String; } diff --git a/std/python/Bytes.hx b/std/python/Bytes.hx index f9e67108c91070f6771a6124fee73730d0958a16..86d4e91a63a9c43fd5236605d3faecfd07504486 100644 --- a/std/python/Bytes.hx +++ b/std/python/Bytes.hx @@ -26,5 +26,5 @@ import python.Bytearray; @:native("bytes") extern class Bytes extends Bytearray { - // public function decode(encoding:String="utf-8", errors:String="strict"):String; + // function decode(encoding:String="utf-8", errors:String="strict"):String; } diff --git a/std/python/Syntax.hx b/std/python/Syntax.hx index eb785e6e440ac7c35f3ab13204ff02c602788f9d..f350b73fcd41885e180ac2cad08224a98ff80870 100644 --- a/std/python/Syntax.hx +++ b/std/python/Syntax.hx @@ -22,144 +22,83 @@ package python; -#if macro -import haxe.macro.Expr; -import haxe.macro.Context; -import haxe.macro.ExprTools; -#end import haxe.extern.Rest; @:noPackageRestrict @:noClosure extern class Syntax { - #if macro - static var self = macro python.Syntax; - #end - @:noUsing macro public static function importModule(module:String):haxe.macro.Expr { - return macro($self.code($v{"import " + module}) : Void); - } + @:noUsing macro public static function importModule(module:String):haxe.macro.Expr; - @:noUsing macro public static function importAs(module:String, className:String):haxe.macro.Expr { - var n = className.split(".").join("_"); - var e = "import " + module + " as " + n; + @:noUsing macro public static function importAs(module:String, className:String):haxe.macro.Expr; - return macro($self.code($v{e}) : Void); - } - - #if !macro @:overload(function(className:String, args:Rest):Dynamic {}) static function construct(cls:Class, args:Rest):T; - #end @:noUsing @:deprecated("python.Syntax.newInstance() is deprecated. Use python.Syntax.construct() instead.") - macro public static function newInstance(c:Expr, params:Array):haxe.macro.Expr { - return macro $self._newInstance($c, $a{params}); - } + macro public static function newInstance(c:haxe.macro.Expr, params:Array):haxe.macro.Expr; extern static function _newInstance(c:Dynamic, args:Array):Dynamic; @:noUsing - extern public static function isIn(a:Dynamic, b:Dynamic):Bool; + extern static function isIn(a:Dynamic, b:Dynamic):Bool; @:noUsing - extern public static function delete(a:Dynamic):Void; + extern static function delete(a:Dynamic):Void; @:noUsing - extern public static function binop(a:Dynamic, op:String, b:Dynamic):Dynamic; + extern static function binop(a:Dynamic, op:String, b:Dynamic):Dynamic; @:noUsing - extern public static function assign(a:Dynamic, b:Dynamic):Void; + extern static function assign(a:Dynamic, b:Dynamic):Void; - #if !macro - public static function code(code:String, args:Rest):Dynamic; - #end + static function code(code:String, args:Rest):Dynamic; @:noUsing @:deprecated("python.Syntax.pythonCode() is deprecated. Use python.Syntax.code() instead.") - macro public static function pythonCode(b:ExprOf, rest:Array):Expr { - if (rest == null) - rest = []; - return macro @:pos(Context.currentPos()) untyped $self._pythonCode($b, $a{rest}); - }; + macro public static function pythonCode(b:ExprOf, rest:Array):haxe.macro.Expr; - #if !macro @:noUsing - public static function _pythonCode(b:String, args:Array):T; - #end + static function _pythonCode(b:String, args:Array):T; + @:noUsing - macro public static function arrayAccess(x:Expr, rest:Array):ExprOf { - return macro $self._arrayAccess($x, $a{rest}); - } + macro public static function arrayAccess(x:haxe.macro.Expr, rest:Array):haxe.macro.Expr.ExprOf; @:noUsing - macro public static function arrayAccessWithTrailingColon(x:Expr, rest:Array):ExprOf { - return macro $self._arrayAccess($x, $a{rest}, true); - } + macro public static function arrayAccessWithTrailingColon(x:haxe.macro.Expr, rest:Array):haxe.macro.Expr.ExprOf; extern static function _arrayAccess(a:Dynamic, args:Array, ?trailingColon:Bool = false):Dynamic; @:noUsing - extern public static function arraySet(a:Dynamic, i:Dynamic, v:Dynamic):Dynamic; + extern static function arraySet(a:Dynamic, i:Dynamic, v:Dynamic):Dynamic; extern static function _foreach(id:Dynamic, it:Dynamic, block:Dynamic):Dynamic; @:noUsing - macro public static function foreach(v:Expr, it:Expr, b:Expr):haxe.macro.Expr { - var id = switch (v.expr) { - case EConst(CIdent(x)): x; - case _: Context.error("unexpected " + ExprTools.toString(v) + ": const ident expected", v.pos); - } - - var iter = try { - var it = macro($it.__iter__() : python.NativeIterator.NativeIteratorRaw); - Context.typeof(it); - it; - } catch (e:Dynamic) { - macro($it : python.NativeIterable.NativeIterableRaw); - } - - return macro { - var $id = null; - $self._foreach($v, $it, cast $b); - } - } - - @:noUsing macro public static function importFromAs(from:String, module:String, className:String):haxe.macro.Expr { - var n = className.split(".").join("_"); - - var e = "from " + from + " import " + module + " as " + n; - - return macro($self.code($v{e}) : Void); - } + macro public static function foreach(v:haxe.macro.Expr, it:haxe.macro.Expr, b:haxe.macro.Expr):haxe.macro.Expr; + + @:noUsing macro public static function importFromAs(from:String, module:String, className:String):haxe.macro.Expr; @:noUsing - macro public static function callField(o:Expr, field:ExprOf, params:Array):haxe.macro.Expr { - return macro @:pos(o.pos) $self.call($self.field($o, $field), $a{params}); - } + macro public static function callField(o:haxe.macro.Expr, field:haxe.macro.Expr.ExprOf, params:Array):haxe.macro.Expr; extern static function call(e:Dynamic, args:Array):Dynamic; @:noUsing - extern public static function field(o:Dynamic, field:String):Dynamic; + extern static function field(o:Dynamic, field:String):Dynamic; @:noUsing - macro public static function tuple(args:Array):Dynamic { - var args = macro $a{args}; - return macro $self._tuple($args); - } + macro public static function tuple(args:Array):haxe.macro.Expr; extern static function _tuple(args:Array):Dynamic; @:noUsing - extern public static function varArgs(args:Array):Dynamic; + extern static function varArgs(args:Array):Dynamic; - macro public static function callNamedUntyped(e:Expr, args:Expr):Expr { - return macro @:pos(e.pos) $self._callNamedUntyped($e, $args); - } + macro public static function callNamedUntyped(e:haxe.macro.Expr, args:haxe.macro.Expr):haxe.macro.Expr; extern static function _callNamedUntyped(e:Dynamic, args:Dynamic):Dynamic; - extern public static function opPow(a:Int, b:Int):Int; + extern static function opPow(a:Int, b:Int):Int; } diff --git a/std/python/Syntax.macro.hx b/std/python/Syntax.macro.hx new file mode 100644 index 0000000000000000000000000000000000000000..d7cabcb2b52c2cc57ae3baed04eb852202c69017 --- /dev/null +++ b/std/python/Syntax.macro.hx @@ -0,0 +1,113 @@ +/* + * Copyright (C)2005-2019 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package python; + +import haxe.macro.Expr; +import haxe.macro.Context; +import haxe.macro.ExprTools; + +@:noPackageRestrict +@:noClosure +class Syntax { + @:noUsing + macro public static function importModule(module:String):Expr { + return macro python.Syntax.code($v{"import " + module}); + } + + @:noUsing + macro public static function importAs(module:String, className:String):ExprOf { + var n = className.split(".").join("_"); + var e = "import " + module + " as " + n; + + return macro python.Syntax.code($v{e}); + } + + @:noUsing + @:deprecated("python.Syntax.newInstance() is deprecated. Use python.Syntax.construct() instead.") + macro public static function newInstance(c:Expr, params:Array):Expr { + return macro python.Syntax._newInstance($c, $a{params}); + } + + @:noUsing + @:deprecated("python.Syntax.pythonCode() is deprecated. Use python.Syntax.code() instead.") + macro public static function pythonCode(b:ExprOf, rest:Array):Expr { + if (rest == null) + rest = []; + return macro @:pos(Context.currentPos()) untyped python.Syntax._pythonCode($b, $a{rest}); + } + + @:noUsing + macro public static function arrayAccess(x:Expr, rest:Array):ExprOf { + return macro python.Syntax._arrayAccess($x, $a{rest}); + } + + @:noUsing + macro public static function arrayAccessWithTrailingColon(x:Expr, rest:Array):ExprOf { + return macro python.Syntax._arrayAccess($x, $a{rest}, true); + } + + @:noUsing + macro public static function foreach(v:Expr, it:Expr, b:Expr):Expr { + var id = switch (v.expr) { + case EConst(CIdent(x)): x; + case _: Context.error("unexpected " + ExprTools.toString(v) + ": const ident expected", v.pos); + } + + var iter = try { + var it = macro($it.__iter__() : python.NativeIterator.NativeIteratorRaw); + Context.typeof(it); + it; + } catch (e:Dynamic) { + macro($it : python.NativeIterable.NativeIterableRaw); + } + + return macro { + var $id = null; + python.Syntax._foreach($v, $it, cast $b); + } + } + + @:noUsing + macro public static function importFromAs(from:String, module:String, className:String):ExprOf { + var n = className.split(".").join("_"); + + var e = "from " + from + " import " + module + " as " + n; + + return macro python.Syntax.code($v{e}); + } + + @:noUsing + macro public static function callField(o:Expr, field:ExprOf, params:Array):Expr { + return macro @:pos(o.pos) python.Syntax.call(python.Syntax.field($o, $field), $a{params}); + } + + @:noUsing + macro public static function tuple(args:Array):Dynamic { + var args = macro $a{args}; + return macro python.Syntax._tuple($args); + } + + macro public static function callNamedUntyped(e:Expr, args:Expr):Expr { + return macro @:pos(e.pos) python.Syntax._callNamedUntyped($e, $args); + } +} diff --git a/std/python/VarArgs.hx b/std/python/VarArgs.hx index 38080381342b6c6bf94e7d4bbfa95a9a6c8c17ee..e34020dba86784989efbbe6c535aad238622b05e 100644 --- a/std/python/VarArgs.hx +++ b/std/python/VarArgs.hx @@ -46,7 +46,7 @@ abstract VarArgs(Dynamic) { } @:to public inline function toArray():Array { - return if (!Std.is(raw(), Array)) list(raw()) else (raw() : Array); + return if (!Std.isOfType(raw(), Array)) list(raw()) else (raw() : Array); } @:from static inline function fromArray(d:Array):VarArgs { diff --git a/std/python/_std/Array.hx b/std/python/_std/Array.hx index 42f81e0c9314a39026cce241152c7587bfcfe93d..b643efc7415e63c32d6a41caaf2480ed1b52648e 100644 --- a/std/python/_std/Array.hx +++ b/std/python/_std/Array.hx @@ -24,91 +24,100 @@ import python.internal.ArrayImpl; import python.NativeIterator; #end +import haxe.iterators.ArrayKeyValueIterator; @:native("list") @:coreApi extern class Array implements ArrayAccess { - public var length(default, null):Int; + var length(default, null):Int; - public function new():Void; + function new():Void; - public inline function concat(a:Array):Array { + inline function concat(a:Array):Array { return ArrayImpl.concat(this, a); } - public inline function copy():Array { + inline function copy():Array { return ArrayImpl.copy(this); } - @:runtime public inline function iterator():Iterator { - return ArrayImpl.iterator(this); + @:runtime inline function iterator():haxe.iterators.ArrayIterator { + return new haxe.iterators.ArrayIterator(this); } - public inline function insert(pos:Int, x:T):Void { + @:runtime inline public function keyValueIterator():ArrayKeyValueIterator { + return new ArrayKeyValueIterator(this); + } + + inline function insert(pos:Int, x:T):Void { ArrayImpl.insert(this, pos, x); } - @:runtime public inline function join(sep:String):String { + @:runtime inline function join(sep:String):String { return ArrayImpl.join(this, sep); } - public inline function toString():String { + inline function toString():String { return ArrayImpl.toString(this); } - @:runtime public inline function pop():Null { + @:runtime inline function pop():Null { return ArrayImpl.pop(this); } - @:runtime public inline function push(x:T):Int { + @:runtime inline function push(x:T):Int { return ArrayImpl.push(this, x); } - public inline function unshift(x:T):Void { + inline function unshift(x:T):Void { ArrayImpl.unshift(this, x); } - public inline function indexOf(x:T, ?fromIndex:Int):Int { + inline function indexOf(x:T, ?fromIndex:Int):Int { return ArrayImpl.indexOf(this, x, fromIndex); } - public inline function lastIndexOf(x:T, ?fromIndex:Int):Int { + inline function lastIndexOf(x:T, ?fromIndex:Int):Int { return ArrayImpl.lastIndexOf(this, x, fromIndex); } - public inline function remove(x:T):Bool { + inline function remove(x:T):Bool { return ArrayImpl.remove(this, x); } - public inline function reverse():Void { + inline function contains(x:T):Bool { + return ArrayImpl.contains(this,x); + } + + inline function reverse():Void { ArrayImpl.reverse(this); } - @:runtime public inline function shift():Null { + @:runtime inline function shift():Null { return ArrayImpl.shift(this); } - public inline function slice(pos:Int, ?end:Int):Array { + inline function slice(pos:Int, ?end:Int):Array { return ArrayImpl.slice(this, pos, end); } - public inline function sort(f:T->T->Int):Void { + inline function sort(f:T->T->Int):Void { ArrayImpl.sort(this, f); } - public inline function splice(pos:Int, len:Int):Array { + inline function splice(pos:Int, len:Int):Array { return ArrayImpl.splice(this, pos, len); } - @:runtime public inline function map(f:T->S):Array { + @:runtime inline function map(f:T->S):Array { return ArrayImpl.map(this, f); } - @:runtime public inline function filter(f:T->Bool):Array { + @:runtime inline function filter(f:T->Bool):Array { return ArrayImpl.filter(this, f); } - public inline function resize(len:Int):Void { + inline function resize(len:Int):Void { ArrayImpl.resize(this, len); } diff --git a/std/python/_std/Math.hx b/std/python/_std/Math.hx index 89d605418da884abd00fae55683d036a6fad6c2a..7ccc7f1a4fb82a21917badfa71b1b4dfa5516bba 100644 --- a/std/python/_std/Math.hx +++ b/std/python/_std/Math.hx @@ -33,23 +33,23 @@ extern class Math { static var NaN(default, null):Float; - public static inline function abs(v:Float):Float { + static inline function abs(v:Float):Float { return (Math : Dynamic).fabs(v); } - public static inline function min(a:Float, b:Float):Float { + static inline function min(a:Float, b:Float):Float { return if (isNaN(a)) a else if (isNaN(b)) b else UBuiltins.min(a, b); } - public static inline function max(a:Float, b:Float):Float { + static inline function max(a:Float, b:Float):Float { return if (isNaN(a)) a else if (isNaN(b)) b else UBuiltins.max(a, b); } - public static inline function sin(v:Float):Float { + static inline function sin(v:Float):Float { return if (v == POSITIVE_INFINITY || v == NEGATIVE_INFINITY) NaN else python.lib.Math.sin(v); } - public static inline function cos(v:Float):Float { + static inline function cos(v:Float):Float { return if (v == POSITIVE_INFINITY || v == NEGATIVE_INFINITY) NaN else python.lib.Math.cos(v); } @@ -59,7 +59,7 @@ extern class Math { static function atan(v:Float):Float; static function atan2(y:Float, x:Float):Float; - public static inline function exp(v:Float):Float { + static inline function exp(v:Float):Float { if (v == NEGATIVE_INFINITY) { return 0.0; } else if (v == POSITIVE_INFINITY) { @@ -69,17 +69,17 @@ extern class Math { } } - public static inline function log(v:Float):Float { + static inline function log(v:Float):Float { return if (v == 0.0) NEGATIVE_INFINITY else if (v < 0.0) NaN else python.lib.Math.log(v); } static function pow(v:Float, exp:Float):Float; - public static inline function sqrt(v:Float):Float { + static inline function sqrt(v:Float):Float { return if (v < 0) NaN else python.lib.Math.sqrt(v); } - public static inline function round(v:Float):Int { + static inline function round(v:Float):Int { return Math.floor(v + 0.5); } diff --git a/std/python/_std/Std.hx b/std/python/_std/Std.hx index 0d67757f271a71ead0ba0119b16e54b98efbcb10..6911bc747e7b56337c463a8fe6418d0e3b88c80b 100644 --- a/std/python/_std/Std.hx +++ b/std/python/_std/Std.hx @@ -49,9 +49,14 @@ import python.Syntax; return Boot.isMetaType(v, t); } + @:ifFeature("typed_cast") + public static inline function is(v:Dynamic, t:Dynamic):Bool { + return isOfType(v, t); + } + @:access(python.Boot) @:ifFeature("typed_cast") - public static function is(v:Dynamic, t:Dynamic):Bool { + public static function isOfType(v:Dynamic, t:Dynamic):Bool { if (v == null && t == null) { return false; } diff --git a/std/python/_std/String.hx b/std/python/_std/String.hx index 4c3d32374bd760bc9cef94bad0b215916f1750e8..d5b2030662bba0140c143df691e04750c0ad001e 100644 --- a/std/python/_std/String.hx +++ b/std/python/_std/String.hx @@ -31,19 +31,19 @@ extern class String { function new(string:String):Void; - @:runtime public inline function toUpperCase():String { + @:runtime inline function toUpperCase():String { return StringImpl.toUpperCase(this); } - @:runtime public inline function toLowerCase():String { + @:runtime inline function toLowerCase():String { return StringImpl.toLowerCase(this); } - inline public function charAt(index:Int):String { + inline function charAt(index:Int):String { return StringImpl.charAt(this, index); } - inline public function charCodeAt(index:Int):Null { + inline function charCodeAt(index:Int):Null { return StringImpl.charCodeAt(this, index); } @@ -59,7 +59,7 @@ extern class String { return StringImpl.split(this, delimiter); } - inline public function substr(pos:Int, ?len:Int):String { + inline function substr(pos:Int, ?len:Int):String { return StringImpl.substr(this, pos, len); } @@ -70,7 +70,7 @@ extern class String { inline function toString():String return StringImpl.toString(this); - public static inline function fromCharCode(code:Int):String { + static inline function fromCharCode(code:Int):String { return StringImpl.fromCharCode(code); } } diff --git a/std/python/_std/Type.hx b/std/python/_std/Type.hx index b422c017e754bfd891c5624eee7aab0918f4cc04..9321cbbf2af44f4ed81ffd8aa94a0b4cc26c0483 100644 --- a/std/python/_std/Type.hx +++ b/std/python/_std/Type.hx @@ -248,7 +248,7 @@ enum ValueType { var ret = []; for (ctor in ctors) { var v = Reflect.field(e, ctor); - if (Std.is(v, e)) + if (Std.isOfType(v, e)) ret.push(v); } diff --git a/std/python/_std/haxe/Exception.hx b/std/python/_std/haxe/Exception.hx new file mode 100644 index 0000000000000000000000000000000000000000..e7b5e9baf9dd4a0775beb2c5d510d8dbda6c1123 --- /dev/null +++ b/std/python/_std/haxe/Exception.hx @@ -0,0 +1,94 @@ +package haxe; + +import python.Exceptions.BaseException; +import python.Exceptions.Exception in PyException; +import python.lib.Traceback; +import python.internal.UBuiltins; + +private typedef PyStackItem = python.Tuple.Tuple4; + +@:coreApi +class Exception extends PyException { + public var message(get,never):String; + public var stack(get,never):CallStack; + public var previous(get,never):Null; + public var native(get,never):Any; + + @:noCompletion var __exceptionStack:Null; + @:noCompletion var __nativeStack:Array; + @:noCompletion @:ifFeature("haxe.Exception.get_stack") var __skipStack:Int = 0; + @:noCompletion var __nativeException:BaseException; + @:noCompletion var __previousException:Null; + + static function caught(value:Any):Exception { + if(Std.is(value, Exception)) { + return value; + } else if(Std.isOfType(value, BaseException)) { + return new Exception(UBuiltins.str(value), null, value); + } else { + return new ValueException(value, null, value); + } + } + + static function thrown(value:Any):Any { + if(Std.isOfType(value, Exception)) { + return (value:Exception).native; + } else if(Std.isOfType(value, BaseException)) { + return value; + } else { + var e = new ValueException(value); + e.__shiftStack(); + return e; + } + } + + public function new(message:String, ?previous:Exception, ?native:Any) { + super(message); + this.__previousException = previous; + if(native != null && Std.isOfType(native, BaseException)) { + __nativeException = native; + __nativeStack = NativeStackTrace.exceptionStack(); + } else { + __nativeException = cast this; + __nativeStack = NativeStackTrace.callStack(); + } + } + + function unwrap():Any { + return __nativeException; + } + + public function toString():String { + return message; + } + + public function details():String { + return inline CallStack.exceptionToString(this); + } + + @:noCompletion + @:ifFeature("haxe.Exception.get_stack") + inline function __shiftStack():Void { + __skipStack++; + } + + function get_message():String { + return UBuiltins.str(this); + } + + function get_previous():Null { + return __previousException; + } + + final function get_native():Any { + return __nativeException; + } + + function get_stack():CallStack { + return switch __exceptionStack { + case null: + __exceptionStack = NativeStackTrace.toHaxe(__nativeStack, __skipStack); + case s: s; + } + } +} \ No newline at end of file diff --git a/std/python/_std/haxe/NativeStackTrace.hx b/std/python/_std/haxe/NativeStackTrace.hx new file mode 100644 index 0000000000000000000000000000000000000000..bce5ea54eb76fa52262e7124221c00eaf713ae4a --- /dev/null +++ b/std/python/_std/haxe/NativeStackTrace.hx @@ -0,0 +1,46 @@ +package haxe; + +import haxe.CallStack.StackItem; + +private typedef NativeTrace = Array>; + +/** + Do not use manually. +**/ +@:dox(hide) +@:noCompletion +class NativeStackTrace { + @:ifFeature('haxe.NativeStackTrace.exceptionStack') + static public inline function saveStack(exception:Any):Void { + } + + static public inline function callStack():NativeTrace { + var infos = python.lib.Traceback.extract_stack(); + infos.pop(); + infos.reverse(); + return infos; + } + + static public function exceptionStack():NativeTrace { + var exc = python.lib.Sys.exc_info(); + if (exc._3 != null) { + var infos = python.lib.Traceback.extract_tb(exc._3); + infos.reverse(); + return infos; + } else { + return []; + } + } + + static public function toHaxe(native:NativeTrace, skip:Int = 0):Array { + var stack = []; + for(i in 0...native.length) { + if(skip > i) { + continue; + } + var elem = native[i]; + stack.push(FilePos(Method(null, elem._3), elem._1, elem._2)); + } + return stack; + } +} \ No newline at end of file diff --git a/std/python/_std/sys/io/FileInput.hx b/std/python/_std/sys/io/FileInput.hx index e3afd9f78963a79011be887a301bd0924d89672b..2176a47ecef6d25541ed0f895f6bcd4e9c04b581 100644 --- a/std/python/_std/sys/io/FileInput.hx +++ b/std/python/_std/sys/io/FileInput.hx @@ -30,7 +30,7 @@ import python.io.IFileInput; class FileInput extends Input { var impl:IFileInput; - public function new(impl:IFileInput) { + function new(impl:IFileInput) { this.impl = impl; } diff --git a/std/python/_std/sys/io/FileOutput.hx b/std/python/_std/sys/io/FileOutput.hx index e94343212bc8f0bc67b6953cbd9d3e0ecebad273..1519cd9df4bf4070e637ea439dc99a53093b65aa 100644 --- a/std/python/_std/sys/io/FileOutput.hx +++ b/std/python/_std/sys/io/FileOutput.hx @@ -31,7 +31,7 @@ import python.io.IFileOutput; class FileOutput extends Output { var impl:IFileOutput; - public function new(impl:IFileOutput) { + function new(impl:IFileOutput) { this.impl = impl; } diff --git a/std/python/internal/ArrayImpl.hx b/std/python/internal/ArrayImpl.hx index 3b6258289f1417cb4da37dbf1b18d76fb98ce333..1d0adf030f286728c40e2cd79a9b56f31e735531 100644 --- a/std/python/internal/ArrayImpl.hx +++ b/std/python/internal/ArrayImpl.hx @@ -45,6 +45,11 @@ class ArrayImpl { return new HaxeIterator(Syntax.callField(x, "__iter__")); } + @:ifFeature("dynamic_read.keyValueIterator", "anon_optional_read.keyValueIterator", "python.internal.ArrayImpl.keyValueIterator") + public static inline function keyValueIterator(x:Array) : KeyValueIterator { + return new haxe.iterators.ArrayKeyValueIterator(x); + } + @:ifFeature("dynamic_read.indexOf", "anon_optional_read.indexOf", "python.internal.ArrayImpl.indexOf") public static function indexOf(a:Array, x:T, ?fromIndex:Int):Int { var len = a.length; @@ -108,6 +113,11 @@ class ArrayImpl { } } + @:ifFeature("dynamic_read.contains", "anon_optional_read.contains", "python.internal.ArrayImpl.contains") + public static inline function contains(x:Array,e : T) : Bool { + return Syntax.isIn(e, x); + } + @:ifFeature("dynamic_read.shift", "anon_optional_read.shift", "python.internal.ArrayImpl.shift") public static inline function shift(x:Array):Null { if (x.length == 0) diff --git a/std/python/internal/HxOverrides.hx b/std/python/internal/HxOverrides.hx index e885e194d580e69c7734230505bfa21b6615a5de..1281dc5898e7608d913796e76947448fb88de0d6 100644 --- a/std/python/internal/HxOverrides.hx +++ b/std/python/internal/HxOverrides.hx @@ -40,6 +40,14 @@ class HxOverrides { return Syntax.callField(x, "iterator"); } + @:ifFeature("dynamic_read.keyValueIterator", "anon_optional_read.keyValueIterator", "anon_read.keyValueIterator") + static public function keyValueIterator(x) { + if (Boot.isArray(x)) { + return (x:Array).keyValueIterator(); + } + return Syntax.callField(x, "keyValueIterator"); + } + @:ifFeature("dynamic_binop_==", "dynamic_binop_!=") static function eq(a:Dynamic, b:Dynamic):Bool { if (Boot.isArray(a) || Boot.isArray(b)) { diff --git a/std/python/internal/StringImpl.hx b/std/python/internal/StringImpl.hx index de1b316c827360892b70d2e6df7a28d2db8e5df2..719b9fc4fbc0c5d25d303604a26691ee288a1322 100644 --- a/std/python/internal/StringImpl.hx +++ b/std/python/internal/StringImpl.hx @@ -45,6 +45,13 @@ class StringImpl { public static inline function lastIndexOf(s:String, str:String, ?startIndex:Int):Int { if (startIndex == null) { return Syntax.callField(s, "rfind", str, 0, s.length); + } else if(str == "") { + var length = s.length; + if(startIndex < 0) { + startIndex = length + startIndex; + if(startIndex < 0) startIndex = 0; + } + return startIndex > length ? length : startIndex; } else { var i = Syntax.callField(s, "rfind", str, 0, startIndex + 1); var startLeft = i == -1 ? UBuiltins.max(0, startIndex + 1 - str.length) : i + 1; @@ -72,7 +79,19 @@ class StringImpl { if (startIndex == null) return Syntax.callField(s, "find", str); else - return Syntax.callField(s, "find", str, startIndex); + return indexOfImpl(s, str, startIndex); + } + + static function indexOfImpl(s:String, str:String, startIndex:Int) { + if(str == "") { + var length = s.length; + if(startIndex < 0) { + startIndex = length + startIndex; + if(startIndex < 0) startIndex = 0; + } + return startIndex > length ? length : startIndex; + } + return Syntax.callField(s, "find", str, startIndex); } @:ifFeature("dynamic_read.toString", "anon_optional_read.toString", "python.internal.StringImpl.toString") diff --git a/std/python/io/IoTools.hx b/std/python/io/IoTools.hx index a082349c653d0a2b2a3e7b2c1513347d13ff93c2..0c78a9f0c9965bc038ff2066658deb7f8f90df9a 100644 --- a/std/python/io/IoTools.hx +++ b/std/python/io/IoTools.hx @@ -34,19 +34,19 @@ import python.lib.io.IOBase.SeekSet; class IoTools { public static function createFileInputFromText(t:TextIOBase) { - return new FileInput(new FileTextInput(t)); + return @:privateAccess new FileInput(new FileTextInput(t)); } public static function createFileInputFromBytes(t:RawIOBase) { - return new FileInput(new FileBytesInput(t)); + return @:privateAccess new FileInput(new FileBytesInput(t)); } public static function createFileOutputFromText(t:TextIOBase) { - return new FileOutput(new FileTextOutput(t)); + return @:privateAccess new FileOutput(new FileTextOutput(t)); } public static function createFileOutputFromBytes(t:RawIOBase) { - return new FileOutput(new FileBytesOutput(t)); + return @:privateAccess new FileOutput(new FileBytesOutput(t)); } public static function seekInTextMode(stream:TextIOBase, tell:Void->Int, p:Int, pos:sys.io.FileSeek) { diff --git a/std/python/lib/Builtins.hx b/std/python/lib/Builtins.hx index 75d0001f6b1adf74582a2c407e16e77a138ed403..0b4a5c78f523303929c606699bfbb66efc0802af 100644 --- a/std/python/lib/Builtins.hx +++ b/std/python/lib/Builtins.hx @@ -32,20 +32,20 @@ import python.NativeIterator; @:pythonImport("builtins") extern class Builtins { @:overload(function(f:Int):Int {}) - public static function abs(x:Float):Float; - public static function all(i:Iterable):Bool; - public static function any(i:Iterable):Bool; + static function abs(x:Float):Float; + static function all(i:Iterable):Bool; + static function any(i:Iterable):Bool; - public static function bool(x:Dynamic):Bool; + static function bool(x:Dynamic):Bool; - public static function issubclass(x:Class, from:Class):Bool; - public static function callable(x:Dynamic):Bool; + static function issubclass(x:Class, from:Class):Bool; + static function callable(x:Dynamic):Bool; @:overload(function(obj:Dynamic, f:Tuple):Bool {}) - public static function isinstance(obj:Dynamic, cl:Dynamic):Bool; + static function isinstance(obj:Dynamic, cl:Dynamic):Bool; - public static function hasattr(obj:Dynamic, attr:String):Bool; - public static function getattr(obj:Dynamic, attr:String):Dynamic; + static function hasattr(obj:Dynamic, attr:String):Bool; + static function getattr(obj:Dynamic, attr:String):Dynamic; @:overload(function(f:Set):Int {}) @:overload(function(f:StringBuf):Int {}) @@ -55,102 +55,102 @@ extern class Builtins { @:overload(function(f:DictView):Int {}) @:overload(function(f:Bytearray):Int {}) @:overload(function(f:Tuple):Int {}) - public static function len(x:String):Int; + static function len(x:String):Int; - public static function open(file:String, mode:String, ?buffering:Int = -1, ?encoding:String = null, ?errors:String, ?newline:String, ?closefd:Bool, + static function open(file:String, mode:String, ?buffering:Int = -1, ?encoding:String = null, ?errors:String, ?newline:String, ?closefd:Bool, ?opener:String->Int->FileDescriptor):IOBase; - // public static function divmod():Void; - // public static function input():Void; - // public static function staticmethod():Void; - // public static function enumerate():Void; + // static function divmod():Void; + // static function input():Void; + // static function staticmethod():Void; + // static function enumerate():Void; @:overload(function(x:Dynamic, base:Int):Int {}) - public static function int(x:Dynamic):Int; - public static function ord(s:String):Int; - public static function str(o:Dynamic):String; - - // public static function eval():Void; - // public static function pow():Void; - // public static function sum():Void; - // public static function basestring():Void; - // public static function execfile():Void; - public static function print(o:Dynamic):Void; - - // public static function super():Void; - // public static function bin():Void; - // public static function file():Void; - public static function iter(d:DictView):NativeIterator; - - // public static function property():Void; + static function int(x:Dynamic):Int; + static function ord(s:String):Int; + static function str(o:Dynamic):String; + + // static function eval():Void; + // static function pow():Void; + // static function sum():Void; + // static function basestring():Void; + // static function execfile():Void; + static function print(o:Dynamic):Void; + + // static function super():Void; + // static function bin():Void; + // static function file():Void; + static function iter(d:DictView):NativeIterator; + + // static function property():Void; /* @:overload(function ():Tuple {}) - public static function tuple(a:Array):Tuple; + static function tuple(a:Array):Tuple; */ - // public static function range():Void; - public static function type():Void; + // static function range():Void; + static function type():Void; /* @:overload(function (it:Array):python.Bytearray {}) @:overload(function (it:NativeIterable):python.Bytearray {}) @:overload(function (size:Int):python.Bytearray {}) - public static function bytearray(source:String,encoding:String,?errors:Dynamic):python.Bytearray; + static function bytearray(source:String,encoding:String,?errors:Dynamic):python.Bytearray; */ - public static function float(x:Dynamic):Float; + static function float(x:Dynamic):Float; @:overload(function(f:Array):Array {}) @:overload(function(f:Tuple):Array {}) @:overload(function(f:Dict.DictView):Array {}) @:overload(function(f:String):Array {}) - public static function list(i:NativeIterable):Array; + static function list(i:NativeIterable):Array; @:overload(function(f:A->Bool, i:NativeIterable):NativeIterator {}) - public static function filter(f:A->Bool, i:Array):NativeIterator; - - // public static function raw_input():Void; - // public static function unichr():Void; - // public static function format():Void; - // public static function locals():Void; - // public static function reduce():Void; - // public static function unicode():Void; - public static function chr(c:Int):String; - - // public static function frozenset():Void; - // public static function long():Void; - // public static function reload():Void; - // public static function vars():Void; - // public static function classmethod():Void; - public static function map(fn:A->B, it:NativeIterable):NativeIterator; - public static function repr(o:Dynamic):String; - // public static function xrange():Void; - // public static function cmp():Void; - // public static function globals():Void; + static function filter(f:A->Bool, i:Array):NativeIterator; + + // static function raw_input():Void; + // static function unichr():Void; + // static function format():Void; + // static function locals():Void; + // static function reduce():Void; + // static function unicode():Void; + static function chr(c:Int):String; + + // static function frozenset():Void; + // static function long():Void; + // static function reload():Void; + // static function vars():Void; + // static function classmethod():Void; + static function map(fn:A->B, it:NativeIterable):NativeIterator; + static function repr(o:Dynamic):String; + // static function xrange():Void; + // static function cmp():Void; + // static function globals():Void; @:overload(function(a1:Float, a2:Float, rest:Rest):Float {}) - public static function max(a1:Int, a2:Int, rest:Rest):Int; - - // public static function reversed():Void; - // public static function zip():Void; - // public static function compile():Void; - // public static function memoryview():Void; - public static function round(f:Float):Int; - // public static function __import__():Void; - // public static function complex():Void; - // public static function hash():Void; + static function max(a1:Int, a2:Int, rest:Rest):Int; + + // static function reversed():Void; + // static function zip():Void; + // static function compile():Void; + // static function memoryview():Void; + static function round(f:Float):Int; + // static function __import__():Void; + // static function complex():Void; + // static function hash():Void; @:overload(function(a1:Float, a2:Float, rest:Rest):Float {}) - public static function min(a1:Int, a2:Int, rest:Rest):Int; - // public static function set():Void; - // public static function apply():Void; - public static function delattr(o:Dynamic, attr:String):Void; - // public static function help():Void; - // public static function next():Void; - public static function setattr(o:Dynamic, attr:String, val:Dynamic):Void; - // public static function buffer():Void; - // public static function dict():Void; - // public static function hex():Void; - // public static function object():Void; - // public static function slice():Void; - // public static function coerce():Void; - // public static function dir():Void; - public static function id(x:{}):Int; - // public static function oct():Void; - // public static function sorted():Void; - // public static function intern():Void; + static function min(a1:Int, a2:Int, rest:Rest):Int; + // static function set():Void; + // static function apply():Void; + static function delattr(o:Dynamic, attr:String):Void; + // static function help():Void; + // static function next():Void; + static function setattr(o:Dynamic, attr:String, val:Dynamic):Void; + // static function buffer():Void; + // static function dict():Void; + // static function hex():Void; + // static function object():Void; + // static function slice():Void; + // static function coerce():Void; + // static function dir():Void; + static function id(x:{}):Int; + // static function oct():Void; + // static function sorted():Void; + // static function intern():Void; } diff --git a/std/python/lib/Functools.hx b/std/python/lib/Functools.hx index 81f96ff9b32cb9bf613e048a17cb93eefd239f0f..09053ed8f1d3bdb06e0a2f3f0ce94b9128dc101a 100644 --- a/std/python/lib/Functools.hx +++ b/std/python/lib/Functools.hx @@ -24,5 +24,5 @@ package python.lib; @:pythonImport("functools") extern class Functools { - public static function cmp_to_key(f:A->A->Int):Dynamic; + static function cmp_to_key(f:A->A->Int):Dynamic; } diff --git a/std/python/lib/Glob.hx b/std/python/lib/Glob.hx index 1d01c7e295cc1e7115fbc26f704b42103c490a69..cf8b99707dd0d80d6ea735d34faf9463815934c0 100644 --- a/std/python/lib/Glob.hx +++ b/std/python/lib/Glob.hx @@ -26,6 +26,6 @@ import python.NativeIterator; @:pythonImport("glob") extern class Glob { - public static function glob(pathname:String):Array; - public static function iglob(pathname:String):NativeIterator; + static function glob(pathname:String):Array; + static function iglob(pathname:String):NativeIterator; } diff --git a/std/python/lib/Inspect.hx b/std/python/lib/Inspect.hx index b0a25afe70a4654e05ab0f58ea7b424d3b16606d..904f4ea39de82c8b00e8f170591c85510313f782 100644 --- a/std/python/lib/Inspect.hx +++ b/std/python/lib/Inspect.hx @@ -32,7 +32,7 @@ extern class Inspect { static function isfunction(object:Dynamic):Bool; static function getsourcefile(object:Dynamic):String; - static public inline function isInterface(cls:Class):Bool { + static inline function isInterface(cls:Class):Bool { return untyped __define_feature__("python._hx_is_interface", c._hx_is_interface); } } diff --git a/std/python/lib/Io.hx b/std/python/lib/Io.hx index 6fbee2c2c1b83c41ade3baafd0d3ed4b39df53c9..604ea9d1a940d671337b78a38a40773e3639b84b 100644 --- a/std/python/lib/Io.hx +++ b/std/python/lib/Io.hx @@ -26,8 +26,8 @@ import python.lib.io.IOBase; @:pythonImport("io") extern class Io { - public static var DEFAULT_BUFFER_SIZE:Int; + static var DEFAULT_BUFFER_SIZE:Int; - public static function open(file:String, mode:String, ?buffering:Int = -1, ?encoding:String = null, ?errors:String, ?newline:String, ?closefd:Bool, + static function open(file:String, mode:String, ?buffering:Int = -1, ?encoding:String = null, ?errors:String, ?newline:String, ?closefd:Bool, ?opener:String->Int->FileDescriptor):IOBase; } diff --git a/std/python/lib/Json.hx b/std/python/lib/Json.hx index 834afa1a8bfdb670b47bb54c0901eb42539b2dc6..5c1c0970a2be7be020e8c07388534bc87d451114 100644 --- a/std/python/lib/Json.hx +++ b/std/python/lib/Json.hx @@ -47,6 +47,6 @@ typedef JsonLoadsOptions = { @:pythonImport("json") extern class Json { - public static function loads(s:String, ?options:KwArgs):Dict; - public static function dumps(x:Dynamic, ?options:KwArgs):String; + static function loads(s:String, ?options:KwArgs):Dict; + static function dumps(x:Dynamic, ?options:KwArgs):String; } diff --git a/std/python/lib/Math.hx b/std/python/lib/Math.hx index 9d1c0cd5563826f7a247d4a670f5f88bf1ecc715..06cf93d23fe4c8dc8cb84cc64877bd0f4c215ce2 100644 --- a/std/python/lib/Math.hx +++ b/std/python/lib/Math.hx @@ -24,15 +24,15 @@ package python.lib; @:pythonImport("math") extern class Math { - public static function isnan(f:Float):Bool; + static function isnan(f:Float):Bool; - public static var pi:Float; + static var pi:Float; - public static function sqrt(f:Float):Float; - public static function log(f:Float):Float; - public static function cos(f:Float):Float; - public static function sin(f:Float):Float; - public static function tan(f:Float):Float; + static function sqrt(f:Float):Float; + static function log(f:Float):Float; + static function cos(f:Float):Float; + static function sin(f:Float):Float; + static function tan(f:Float):Float; static function asin(v:Float):Float; static function acos(v:Float):Float; static function atan(v:Float):Float; diff --git a/std/python/lib/Msvcrt.hx b/std/python/lib/Msvcrt.hx index aec2bad8487d6a1ab52ab1608621185a15457085..e82de3e4122605b24aa5cfc7776cbb19f30a1e2a 100644 --- a/std/python/lib/Msvcrt.hx +++ b/std/python/lib/Msvcrt.hx @@ -24,6 +24,6 @@ package python.lib; @:pythonImport("msvcrt", ignoreError = true) extern class Msvcrt { - public static function getch():python.Bytes; - public static function getwch():String; + static function getch():python.Bytes; + static function getwch():String; } diff --git a/std/python/lib/Os.hx b/std/python/lib/Os.hx index c3b64b8a40b67d340b124f624b11802b4bd1300d..61de669cf160925f508ddd550aa4191fee6ceaf8 100644 --- a/std/python/lib/Os.hx +++ b/std/python/lib/Os.hx @@ -27,66 +27,66 @@ import python.Tuple; import python.Dict; extern class Stat { - public var st_mode:Int; - public var st_ino:Int; - public var st_dev:Int; - public var st_nlink:Int; - public var st_uid:Int; - public var st_gid:Int; - public var st_size:Int; - public var st_atime:Int; - public var st_mtime:Int; - public var st_ctime:Int; - - @:optional public var st_blocks:Int; - @:optional public var st_blksize:Int; - @:optional public var st_rdev:Int; - @:optional public var st_flags:Int; - - @:optional public var st_gen:Int; - @:optional public var st_birthtime:Int; - - @:optional public var st_rsize:Int; - @:optional public var st_creator:Int; - @:optional public var st_type:Int; + var st_mode:Int; + var st_ino:Int; + var st_dev:Int; + var st_nlink:Int; + var st_uid:Int; + var st_gid:Int; + var st_size:Int; + var st_atime:Int; + var st_mtime:Int; + var st_ctime:Int; + + @:optional var st_blocks:Int; + @:optional var st_blksize:Int; + @:optional var st_rdev:Int; + @:optional var st_flags:Int; + + @:optional var st_gen:Int; + @:optional var st_birthtime:Int; + + @:optional var st_rsize:Int; + @:optional var st_creator:Int; + @:optional var st_type:Int; } @:pythonImport("os") extern class Os { - public static var environ:Dict; + static var environ:Dict; - public static function putenv(name:String, value:String):Void; + static function putenv(name:String, value:String):Void; - public static function chdir(path:String):Void; + static function chdir(path:String):Void; - public static function unlink(path:String):Void; - public static function remove(path:String):Void; + static function unlink(path:String):Void; + static function remove(path:String):Void; - public static function getcwd():String; + static function getcwd():String; - public static function getcwdb():Bytes; + static function getcwdb():Bytes; - public static function removedirs(path:String):Void; + static function removedirs(path:String):Void; - public static function rename(src:String, dest:String):Void; + static function rename(src:String, dest:String):Void; - public static function renames(oldName:String, newName:String):Void; + static function renames(oldName:String, newName:String):Void; - public static function rmdir(path:String):Void; + static function rmdir(path:String):Void; - public static function stat(path:String):Stat; + static function stat(path:String):Stat; - public static function fchdir(fd:FileDescriptor):Void; + static function fchdir(fd:FileDescriptor):Void; - public static function listdir(path:String = "."):Array; + static function listdir(path:String = "."):Array; - public static function walk(top:String, topdown:Bool = true, onerror:OSError->Void = null, + static function walk(top:String, topdown:Bool = true, onerror:OSError->Void = null, followlinks:Bool = false):Tuple3, Array>; - public static var sep(default, null):String; - public static var pathsep(default, null):String; + static var sep(default, null):String; + static var pathsep(default, null):String; - public static function makedirs(path:String, mode:Int = 511 /* Oktal 777 */, exist_ok:Bool = false):Void; + static function makedirs(path:String, mode:Int = 511 /* Oktal 777 */, exist_ok:Bool = false):Void; - public static function mkdir(path:String, mode:Int = 511 /* Oktal 777 */):Void; + static function mkdir(path:String, mode:Int = 511 /* Oktal 777 */):Void; } diff --git a/std/python/lib/Pprint.hx b/std/python/lib/Pprint.hx index 6b1125acc58ba86c0fa377b59b83a0637b78986d..24d928c5cdc9996f8044876aa8bb24e9de067dac 100644 --- a/std/python/lib/Pprint.hx +++ b/std/python/lib/Pprint.hx @@ -24,7 +24,7 @@ package python.lib; @:pythonImport("pprint") extern class Pprint { - public static function pprint(x:Dynamic):Void; + static function pprint(x:Dynamic):Void; - public static function pformat(object:Dynamic, indent:Int = 1, width:Int = 80, depth:Int = null):String; + static function pformat(object:Dynamic, indent:Int = 1, width:Int = 80, depth:Int = null):String; } diff --git a/std/python/lib/Re.hx b/std/python/lib/Re.hx index 46e6adbb1393d7cfbc6743dad771312ade5a1bc9..b14ef424e7ee49d08cf1f0d85d6211c8113d5618 100644 --- a/std/python/lib/Re.hx +++ b/std/python/lib/Re.hx @@ -36,38 +36,38 @@ typedef Pattern = Choice; typedef Repl = ChoiceString>; extern class MatchObject { - public var pos(default, null):Int; - public var endpos(default, null):Int; - public var lastindex(default, null):Int; - public var lastgroup(default, null):Int; - public var re(default, null):Regex; - public var string(default, null):String; + var pos(default, null):Int; + var endpos(default, null):Int; + var lastindex(default, null):Int; + var lastgroup(default, null):Int; + var re(default, null):Regex; + var string(default, null):String; - public function expand(template:String):String; + function expand(template:String):String; @:overload(function(x:String):String {}) - public function group(?i:Int = 0):String; + function group(?i:Int = 0):String; - public function groups(defaultVal:String = null):Tuple; - public function groupdict(defaultVal:Dict = null):Dict; + function groups(defaultVal:String = null):Tuple; + function groupdict(defaultVal:Dict = null):Dict; @:overload(function(x:String):Int {}) - public function start(?i:Int = 0):Int; + function start(?i:Int = 0):Int; @:overload(function(x:String):Int {}) - public function end(?i:Int = 0):Int; + function end(?i:Int = 0):Int; - public function span(?i:Int):Tuple2; + function span(?i:Int):Tuple2; - public inline function groupById(s:String):String { + inline function groupById(s:String):String { return group(s); } - public inline function startById(s:String):Int { + inline function startById(s:String):Int { return start(s); } - public inline function endById(s:String):Int { + inline function endById(s:String):Int { return end(s); } } @@ -87,93 +87,93 @@ private class RegexHelper { } extern class Regex { - public function search(string:String, pos:Int = 0, ?endpos:Int):Null; - public function match(string:String, pos:Int = 0, ?endpos:Int):Null; + function search(string:String, pos:Int = 0, ?endpos:Int):Null; + function match(string:String, pos:Int = 0, ?endpos:Int):Null; - public function split(string:String, maxsplit:Int = 0):Array; + function split(string:String, maxsplit:Int = 0):Array; - public inline function findallString(string:String, ?pos:Int, ?endpos:Int):Array { + inline function findallString(string:String, ?pos:Int, ?endpos:Int):Array { return cast this.findallDynamic(string, pos, endpos); } - public inline function findallDynamic(string:String, ?pos:Int, ?endpos:Int):Array { + inline function findallDynamic(string:String, ?pos:Int, ?endpos:Int):Array { return RegexHelper.findallDynamic(this, string, pos, endpos); } - public inline function findallTuple(string:String, ?pos:Int, ?endpos:Int):Array> { + inline function findallTuple(string:String, ?pos:Int, ?endpos:Int):Array> { return cast this.findallDynamic(string, pos, endpos); } - public inline function findallArray(string:String, ?pos:Int, ?endpos:Int):Array> { + inline function findallArray(string:String, ?pos:Int, ?endpos:Int):Array> { return findallTuple(string, pos, endpos).map(function(t) return t.toArray()); } - public function finditer(string:String, ?pos:Int, ?endpos:Int):NativeIterator; + function finditer(string:String, ?pos:Int, ?endpos:Int):NativeIterator; - public function sub(repl:Repl, string:String, count:Int = 0):String; - public function subn(repl:Repl, string:String, count:Int = 0):String; + function sub(repl:Repl, string:String, count:Int = 0):String; + function subn(repl:Repl, string:String, count:Int = 0):String; - public var flags(default, null):Int; - public var groups(default, null):Int; - public var groupindex(default, null):Dict; - public var pattern(default, null):String; + var flags(default, null):Int; + var groups(default, null):Int; + var groupindex(default, null):Dict; + var pattern(default, null):String; } @:pythonImport("re") extern class Re { - public static var A:Int; - public static var ASCII:Int; - public static var DEBUG:Int; - public static var I:Int; - public static var IGNORECASE:Int; + static var A:Int; + static var ASCII:Int; + static var DEBUG:Int; + static var I:Int; + static var IGNORECASE:Int; - public static var L:Int; - public static var LOCALE:Int; + static var L:Int; + static var LOCALE:Int; - public static var M:Int; - public static var MULTILINE:Int; + static var M:Int; + static var MULTILINE:Int; - public static var S:Int; - public static var DOTALL:Int; + static var S:Int; + static var DOTALL:Int; - public static var X:Int; - public static var VERBOSE:Int; + static var X:Int; + static var VERBOSE:Int; - public static var U:Int; - public static var UNICODE:Int; + static var U:Int; + static var UNICODE:Int; - public static function compile(pattern:String, ?flags:Int = 0):Regex; + static function compile(pattern:String, ?flags:Int = 0):Regex; - public static function match(pattern:Pattern, string:String, flags:Int = 0):Null; + static function match(pattern:Pattern, string:String, flags:Int = 0):Null; - public static function search(pattern:Pattern, string:String, flags:Int = 0):Null; + static function search(pattern:Pattern, string:String, flags:Int = 0):Null; - public static function split(pattern:Pattern, string:String, maxsplit:Int = 0, flags:Int = 0):Array; + static function split(pattern:Pattern, string:String, maxsplit:Int = 0, flags:Int = 0):Array; - public static inline function findallDynamic(pattern:Pattern, string:String, flags:Int = 0):Array { + static inline function findallDynamic(pattern:Pattern, string:String, flags:Int = 0):Array { return python.Syntax.field(pattern, "findall")(string, flags); } - public static inline function findallString(pattern:Pattern, string:String, flags:Int = 0):Array { + static inline function findallString(pattern:Pattern, string:String, flags:Int = 0):Array { return python.Syntax.field(pattern, "findall")(string, flags); } - public static inline function findallTuple(pattern:Pattern, string:String, flags:Int = 0):Array> { + static inline function findallTuple(pattern:Pattern, string:String, flags:Int = 0):Array> { return python.Syntax.field(pattern, "findall")(string, flags); } - public static inline function findallArray(pattern:Pattern, string:String, flags:Int = 0):Array> { + static inline function findallArray(pattern:Pattern, string:String, flags:Int = 0):Array> { return findallTuple(pattern, string, flags).map(function(t) return t.toArray()); } - public static function finditer(pattern:Pattern, string:String, flags:Int = 0):NativeIterator; + static function finditer(pattern:Pattern, string:String, flags:Int = 0):NativeIterator; @:overload(function(pattern:Pattern, repl:String, string:String, ?count:Int = 0, ?flags:Int = 0):String {}) - public static function sub(pattern:Pattern, repl:MatchObject->String, string:String, ?count:Int = 0, ?flags:Int = 0):String; + static function sub(pattern:Pattern, repl:MatchObject->String, string:String, ?count:Int = 0, ?flags:Int = 0):String; - public static function subn(pattern:Pattern, repl:Repl, string:String, count:Int = 0, flags:Int = 0):String; + static function subn(pattern:Pattern, repl:Repl, string:String, count:Int = 0, flags:Int = 0):String; - public static function escape(string:String):String; + static function escape(string:String):String; - public static function purge():Void; + static function purge():Void; } diff --git a/std/python/lib/Shutil.hx b/std/python/lib/Shutil.hx index f2cf04938867e676c274ef67f1dc084082fc55c8..ae645c8ec3f419d745a7a7b2ee7d3cd02c60279f 100644 --- a/std/python/lib/Shutil.hx +++ b/std/python/lib/Shutil.hx @@ -24,10 +24,10 @@ package python.lib; @:pythonImport("shutil") extern class Shutil { - public static function rmtree(path:String, ?ignore_errors:Bool = false, ?onerror:python.Exceptions.BaseException->Void):Void; + static function rmtree(path:String, ?ignore_errors:Bool = false, ?onerror:python.Exceptions.BaseException->Void):Void; - public static function copyfile(src:String, dst:String):Void; + static function copyfile(src:String, dst:String):Void; - public static function copy(src:String, dst:String):Void; - public static function copy2(src:String, dst:String):Void; + static function copy(src:String, dst:String):Void; + static function copy2(src:String, dst:String):Void; } diff --git a/std/python/lib/Ssl.hx b/std/python/lib/Ssl.hx index 7ac48e73760137e38b938c27e5d36d902f82c4c6..7093ef037dee359d9cc2a68e50f2f0a80ecce6fe 100644 --- a/std/python/lib/Ssl.hx +++ b/std/python/lib/Ssl.hx @@ -27,14 +27,14 @@ import python.lib.ssl.SSLContext; @:pythonImport("ssl") extern class Ssl { @:require(python_version >= 3.4) - public static function create_default_context(purpose:String):SSLContext; + static function create_default_context(purpose:String):SSLContext; /** Prevents a TLSv1 connection. This option is only applicable in conjunction with PROTOCOL_TLS. It prevents the peers from choosing TLSv1 as the protocol version. **/ - public static var OP_NO_TLSv1:Int; + static var OP_NO_TLSv1:Int; /** Prevents a TLSv1.1 connection. This option is only applicable in conjunction @@ -44,20 +44,20 @@ extern class Ssl { since python 3.4 **/ @:require(python_version >= 3.4) - public static var OP_NO_TLSv1_1:Int; + static var OP_NO_TLSv1_1:Int; - public static var OP_NO_SSLv3:Int; - public static var OP_NO_SSLv2:Int; + static var OP_NO_SSLv3:Int; + static var OP_NO_SSLv2:Int; - public static var OP_NO_COMPRESSION:Int; + static var OP_NO_COMPRESSION:Int; #if (python_version >= 3.6) @:deprecated("deprecated, use PROTOCOL_TLS instead") #end - public static var PROTOCOL_SSLv23:String; + static var PROTOCOL_SSLv23:String; @:require(python_version >= 3.6) - public static var PROTOCOL_TLS:String; + static var PROTOCOL_TLS:String; - public static var CERT_REQUIRED:Int; + static var CERT_REQUIRED:Int; } diff --git a/std/python/lib/Subprocess.hx b/std/python/lib/Subprocess.hx index 4008e3ad63fc5237ddeaa7c5311d978b29286f1e..8384217a38e4687b79173540c5d38951b8a9efaa 100644 --- a/std/python/lib/Subprocess.hx +++ b/std/python/lib/Subprocess.hx @@ -25,28 +25,28 @@ package python.lib; import haxe.extern.EitherType; extern class StartupInfo { - public var dwFlags:Int; + var dwFlags:Int; - public var wShowWindow:Int; + var wShowWindow:Int; } @:pythonImport("subprocess") extern class Subprocess { - public static function STARTUPINFO():StartupInfo; + static function STARTUPINFO():StartupInfo; - public static var STD_INPUT_HANDLE:Int; - public static var STD_OUTPUT_HANDLE:Int; - public static var STD_ERROR_HANDLE:Int; - public static var SW_HIDE:Int; - public static var STARTF_USESTDHANDLES:Int; - public static var STARTF_USESHOWWINDOW:Int; + static var STD_INPUT_HANDLE:Int; + static var STD_OUTPUT_HANDLE:Int; + static var STD_ERROR_HANDLE:Int; + static var SW_HIDE:Int; + static var STARTF_USESTDHANDLES:Int; + static var STARTF_USESHOWWINDOW:Int; - public static var CREATE_NEW_CONSOLE:Int; - public static var CREATE_NEW_PROCESS_GROUP:Int; + static var CREATE_NEW_CONSOLE:Int; + static var CREATE_NEW_PROCESS_GROUP:Int; - public static var PIPE:Int; + static var PIPE:Int; - public static var STDOUT:Int; + static var STDOUT:Int; - public static function call(args:EitherType>, ?kwArgs:python.KwArgs):Int; + static function call(args:EitherType>, ?kwArgs:python.KwArgs):Int; } diff --git a/std/python/lib/Sys.hx b/std/python/lib/Sys.hx index 15f7cb3a0cfa55a48993a76bf47937294a6fd015..bccd213eb41266a7bd4a69e5094a3080d78113ca 100644 --- a/std/python/lib/Sys.hx +++ b/std/python/lib/Sys.hx @@ -33,26 +33,26 @@ extern class Frame {} @:pythonImport("sys") extern class Sys { - public static var argv(default, never):Array; + static var argv(default, never):Array; - public static var executable(default, never):String; + static var executable(default, never):String; - public static function exit(x:Int):Void; + static function exit(x:Int):Void; - public static function getfilesystemencoding():String; + static function getfilesystemencoding():String; - public static var version:String; - public static var platform:String; + static var version:String; + static var platform:String; - public static var stdout(default, never):TextIOBase; - public static var stdin(default, never):TextIOBase; - public static var stderr(default, never):TextIOBase; + static var stdout(default, never):TextIOBase; + static var stdin(default, never):TextIOBase; + static var stderr(default, never):TextIOBase; - public static function getsizeof(t:Dynamic):Int; + static function getsizeof(t:Dynamic):Int; - public static var maxsize:Int; + static var maxsize:Int; - public static function exc_info():Tuple3, T, TB>; + static function exc_info():Tuple3, T, TB>; - public static var version_info:Tuple5; + static var version_info:Tuple5; } diff --git a/std/python/lib/Tempfile.hx b/std/python/lib/Tempfile.hx index 013bdd586c766bea5033310034735fb5e32c7237..fdb4d4a356f79bf6f6083ce66fa1317e1bbb732b 100644 --- a/std/python/lib/Tempfile.hx +++ b/std/python/lib/Tempfile.hx @@ -24,5 +24,5 @@ package python.lib; @:pythonImport("tempfile") extern class Tempfile { - public static function gettempdir():String; + static function gettempdir():String; } diff --git a/std/python/lib/Termios.hx b/std/python/lib/Termios.hx index 5d6c191877134492ada6f8de3c25b09420a7dd51..3b63eafeb8c84dbc1ea08a49d42dd5e665b86fe4 100644 --- a/std/python/lib/Termios.hx +++ b/std/python/lib/Termios.hx @@ -26,10 +26,10 @@ abstract TermiosSettings(Dynamic) {} @:pythonImport("termios", ignoreError = true) extern class Termios { - public static var TCSADRAIN:Int; - public static var ECHO:Int; + static var TCSADRAIN:Int; + static var ECHO:Int; - public static function tcgetattr(fileNo:Int):TermiosSettings; + static function tcgetattr(fileNo:Int):TermiosSettings; - public static function tcsetattr(fileNo:Int, when:Int, settings:TermiosSettings):Void; + static function tcsetattr(fileNo:Int, when:Int, settings:TermiosSettings):Void; } diff --git a/std/python/lib/ThreadLowLevel.hx b/std/python/lib/ThreadLowLevel.hx index 8adcd9cbe3ced66d8e6bab73088107185c9f1a47..fab56514b846b2b889af46fc00b103010fcd7f2d 100644 --- a/std/python/lib/ThreadLowLevel.hx +++ b/std/python/lib/ThreadLowLevel.hx @@ -26,5 +26,5 @@ import python.Tuple; @:pythonImport("_thread") extern class ThreadLowLevel { - public static function start_new_thread(f:Void->Void, args:Tuple):Dynamic; + static function start_new_thread(f:Void->Void, args:Tuple):Dynamic; } diff --git a/std/python/lib/Threading.hx b/std/python/lib/Threading.hx index ebfec85edf9b8e4230b6a92492e6b887dc730252..7dd1a86c61f8a6a7abd8b2267d67f537cbb7b99c 100644 --- a/std/python/lib/Threading.hx +++ b/std/python/lib/Threading.hx @@ -26,14 +26,14 @@ import python.lib.threading.Thread; @:pythonImport("threading") extern class Threading { - public static function active_count():Int; - public static function current_thread():Thread; - public static function get_ident():Int; - public static function enumerate():Array; - public static function main_thread():Thread; - public static function settrace(func:Dynamic):Void; - public static function setprofile(func:Dynamic):Void; - public static function stack_size(?size:Int):Int; - public static function local():Dynamic; - public static var TIMEOUT_MAX:Float; + static function active_count():Int; + static function current_thread():Thread; + static function get_ident():Int; + static function enumerate():Array; + static function main_thread():Thread; + static function settrace(func:Dynamic):Void; + static function setprofile(func:Dynamic):Void; + static function stack_size(?size:Int):Int; + static function local():Dynamic; + static var TIMEOUT_MAX:Float; } diff --git a/std/python/lib/Time.hx b/std/python/lib/Time.hx index 52ed3392d6baa89f82ddaeb8678f901931619394..ab28830ab2cf788515eea134188ddf8579def7bd 100644 --- a/std/python/lib/Time.hx +++ b/std/python/lib/Time.hx @@ -26,8 +26,8 @@ import python.lib.time.StructTime; @:pythonImport("time") extern class Time { - public static function time():Float; - public static function clock():Float; - public static function sleep(t:Float):Void; - public static function mktime(s:StructTime):Float; + static function time():Float; + static function clock():Float; + static function sleep(t:Float):Void; + static function mktime(s:StructTime):Float; } diff --git a/std/python/lib/Timeit.hx b/std/python/lib/Timeit.hx index 54264c44cd8197213c72ceda3c584d0584692aeb..6d9f44eca93dfa851969436d1cad3ab6562490cd 100644 --- a/std/python/lib/Timeit.hx +++ b/std/python/lib/Timeit.hx @@ -24,5 +24,5 @@ package python.lib; @:pythonImport("timeit") extern class Timeit { - public static function default_timer():Float; + static function default_timer():Float; } diff --git a/std/python/lib/Traceback.hx b/std/python/lib/Traceback.hx index 8bc3cd172f15073ee722e33637e03bf43df5020c..40d58a7c0759655e77c1a970ae079548355ab409 100644 --- a/std/python/lib/Traceback.hx +++ b/std/python/lib/Traceback.hx @@ -28,8 +28,8 @@ import python.Tuple; @:pythonImport("traceback") extern class Traceback { - public static function extract_stack(?f:Frame, ?limit:Int):Array; - public static function extract_tb(tb:Sys.TB, ?limit:Int):Array; + static function extract_stack(?f:Frame, ?limit:Int):Array; + static function extract_tb(tb:Sys.TB, ?limit:Int):Array; } private typedef StackItem = Tuple4; diff --git a/std/python/lib/Tty.hx b/std/python/lib/Tty.hx index 22c4498c56f5f13d75a97fa5d3f4c01f17e5d8c6..4aaaf9a792154d9afe0fcd7b2cb35539b802a633 100644 --- a/std/python/lib/Tty.hx +++ b/std/python/lib/Tty.hx @@ -24,5 +24,5 @@ package python.lib; @:pythonImport("tty", ignoreError = true) extern class Tty { - public static function setraw(fileNo:Int):Void; + static function setraw(fileNo:Int):Void; } diff --git a/std/python/lib/codecs/Codec.hx b/std/python/lib/codecs/Codec.hx index e5d3c5ec4263967f54677b036598be430f1386e7..46d74263200722e10bf0a71cef7fa74b5e5e793e 100644 --- a/std/python/lib/codecs/Codec.hx +++ b/std/python/lib/codecs/Codec.hx @@ -27,11 +27,11 @@ import python.Tuple.Tuple2; @:pythonImport("codecs", "Codec") extern class Codec implements ICodec { - public function encode(input:Dynamic, ?errors:String = "strict"):Tuple2; - public function decode(input:Dynamic, ?errors:String = "strict"):Tuple2; + function encode(input:Dynamic, ?errors:String = "strict"):Tuple2; + function decode(input:Dynamic, ?errors:String = "strict"):Tuple2; } @:remove extern interface ICodec { - public function encode(input:Dynamic, ?errors:String = "strict"):Tuple2; - public function decode(input:Dynamic, ?errors:String = "strict"):Tuple2; + function encode(input:Dynamic, ?errors:String = "strict"):Tuple2; + function decode(input:Dynamic, ?errors:String = "strict"):Tuple2; } diff --git a/std/python/lib/codecs/StreamReader.hx b/std/python/lib/codecs/StreamReader.hx index 6bae8c805f7968b0f785ff12c068328de4e089ff..7dd4b8e7518bd823d8c046a10f2e14e3fe22b6b6 100644 --- a/std/python/lib/codecs/StreamReader.hx +++ b/std/python/lib/codecs/StreamReader.hx @@ -26,15 +26,15 @@ import python.lib.codecs.Codec; @:pythonImport("codecs", "StreamReader") extern class StreamReader extends Codec implements IStreamReader { - public function read(?size:Int, ?chars:Int, ?firstline:Bool):String; - public function readline(?size:Int, ?keepsend:Bool = false):String; - public function readlines(?sizehint:Int, ?keepsend:Bool = false):Array; - public function reset():Void; + function read(?size:Int, ?chars:Int, ?firstline:Bool):String; + function readline(?size:Int, ?keepsend:Bool = false):String; + function readlines(?sizehint:Int, ?keepsend:Bool = false):Array; + function reset():Void; } @:remove extern interface IStreamReader extends ICodec { - public function read(?size:Int, ?chars:Int, ?firstline:Bool):String; - public function readline(?size:Int, ?keepsend:Bool = false):String; - public function readlines(?sizehint:Int, ?keepsend:Bool = false):Array; - public function reset():Void; + function read(?size:Int, ?chars:Int, ?firstline:Bool):String; + function readline(?size:Int, ?keepsend:Bool = false):String; + function readlines(?sizehint:Int, ?keepsend:Bool = false):Array; + function reset():Void; } diff --git a/std/python/lib/codecs/StreamReaderWriter.hx b/std/python/lib/codecs/StreamReaderWriter.hx index d8ef573a06f03506084ee3518fda91abf7d5fb07..affb8e21ef975bc69030ec5826b0562b28dd4765 100644 --- a/std/python/lib/codecs/StreamReaderWriter.hx +++ b/std/python/lib/codecs/StreamReaderWriter.hx @@ -28,8 +28,8 @@ import python.lib.codecs.StreamWriter; @:pythonImport("codecs", "StreamReaderWriter") extern class StreamReaderWriter extends StreamReader implements IStreamWriter { - public function write(object:Dynamic):Void; - public function writelines(list:Array):Void; + function write(object:Dynamic):Void; + function writelines(list:Array):Void; } @:remove extern interface IStreamReaderWriter extends IStreamReader extends IStreamWriter {} diff --git a/std/python/lib/codecs/StreamWriter.hx b/std/python/lib/codecs/StreamWriter.hx index 356e429f2ae3a6fee710a5223a4a2dfc5dc8dc95..45f64c3e5c69acb9f09a00e6cf1a8c54a00f5d07 100644 --- a/std/python/lib/codecs/StreamWriter.hx +++ b/std/python/lib/codecs/StreamWriter.hx @@ -26,13 +26,13 @@ import python.lib.codecs.Codec; @:pythonImport("codecs", "StreamWriter") extern class StreamWriter extends Codec implements ICodec { - public function write(object:Dynamic):Void; - public function writelines(list:Array):Void; - public function reset():Void; + function write(object:Dynamic):Void; + function writelines(list:Array):Void; + function reset():Void; } @:remove extern interface IStreamWriter extends ICodec { - public function write(object:Dynamic):Void; - public function writelines(list:Array):Void; - public function reset():Void; + function write(object:Dynamic):Void; + function writelines(list:Array):Void; + function reset():Void; } diff --git a/std/python/lib/datetime/Datetime.hx b/std/python/lib/datetime/Datetime.hx index 53ca5d1b242f050ce11ff76aea9dd42db77b0b54..ea32873890d465ec065a0133d1fae3f04f227bfb 100644 --- a/std/python/lib/datetime/Datetime.hx +++ b/std/python/lib/datetime/Datetime.hx @@ -26,31 +26,31 @@ import python.lib.time.StructTime; @:pythonImport("datetime", "datetime") extern class Datetime { - public function new(year:Int, month:Int, day:Int, hour:Int = 0, minute:Int = 0, second:Int = 0, microsecond:Int = 0, tzinfo:Tzinfo = null); + function new(year:Int, month:Int, day:Int, hour:Int = 0, minute:Int = 0, second:Int = 0, microsecond:Int = 0, tzinfo:Tzinfo = null); - public static var min:Datetime; - public static var max:Datetime; - public static var resolution:Timedelta; + static var min:Datetime; + static var max:Datetime; + static var resolution:Timedelta; - public var year:Int; - public var month:Int; - public var day:Int; - public var hour:Int; - public var minute:Int; - public var second:Int; - public var microsecond:Int; - public var tzinfo:Tzinfo; + var year:Int; + var month:Int; + var day:Int; + var hour:Int; + var minute:Int; + var second:Int; + var microsecond:Int; + var tzinfo:Tzinfo; - public static function today():Datetime; - public static function now(?tzinfo:Tzinfo):Datetime; - public static function utcnow():Datetime; - public static function fromtimestamp(timestamp:Float, tzInfo:Tzinfo = null):Datetime; - public static function utcfromtimestamp(timestamp:Int):Datetime; - public static function fromordinal(ordinal:Int):Datetime; + static function today():Datetime; + static function now(?tzinfo:Tzinfo):Datetime; + static function utcnow():Datetime; + static function fromtimestamp(timestamp:Float, tzInfo:Tzinfo = null):Datetime; + static function utcfromtimestamp(timestamp:Int):Datetime; + static function fromordinal(ordinal:Int):Datetime; - public function timetuple():StructTime; - public function strftime(format:String):String; - public function replace(kwargs:python.KwArgs<{ + function timetuple():StructTime; + function strftime(format:String):String; + function replace(kwargs:python.KwArgs<{ ?year:Int, ?month:Int, ?day:Int, @@ -61,12 +61,12 @@ extern class Datetime { ?tzinfo:Tzinfo }>):Datetime; /* 0-6 */ - public function weekday():Int; + function weekday():Int; /* 1-7 */ - public function isoweekday():Int; - public function utcoffset():Int; + function isoweekday():Int; + function utcoffset():Int; // python 3.3 - public function timestamp():Float; - public function astimezone(?tz:Tzinfo):Datetime; + function timestamp():Float; + function astimezone(?tz:Tzinfo):Datetime; } diff --git a/std/python/lib/datetime/Timezone.hx b/std/python/lib/datetime/Timezone.hx index 7de1e95bc6a6eb1bcc33a52add881941bb9d9642..cf735eedd928349dfebcec349b147ac674e41395 100644 --- a/std/python/lib/datetime/Timezone.hx +++ b/std/python/lib/datetime/Timezone.hx @@ -24,5 +24,5 @@ package python.lib.datetime; @:pythonImport("datetime", "timezone") extern class Timezone extends Tzinfo { - public static var utc(default, never):Tzinfo; + static var utc(default, never):Tzinfo; } diff --git a/std/python/lib/io/BufferedIOBase.hx b/std/python/lib/io/BufferedIOBase.hx index e568ab107cd4431598e462d9140c7435d3814f79..6e262be1944726fd6594a3ed4773c60b3ee1faae 100644 --- a/std/python/lib/io/BufferedIOBase.hx +++ b/std/python/lib/io/BufferedIOBase.hx @@ -29,21 +29,21 @@ import python.Bytearray; @:pythonImport("io", "BufferedIOBase") extern class BufferedIOBase extends IOBase implements IBufferedIOBase { /* not always available */ - public var raw:RawIOBase; + var raw:RawIOBase; - public function write(b:Bytearray):Int; - public function readinto(b:Bytearray):Int; - public function detach():RawIOBase; - public function read(n:Int = -1):Null; - public function read1(n:Int = -1):Null; + function write(b:Bytearray):Int; + function readinto(b:Bytearray):Int; + function detach():RawIOBase; + function read(n:Int = -1):Null; + function read1(n:Int = -1):Null; } @:remove extern interface IBufferedIOBase extends IIOBase { - public var raw:RawIOBase; + var raw:RawIOBase; - public function write(b:Bytearray):Int; - public function readinto(b:Bytearray):Int; - public function detach():RawIOBase; - public function read(n:Int = -1):Null; - public function read1(n:Int = -1):Null; + function write(b:Bytearray):Int; + function readinto(b:Bytearray):Int; + function detach():RawIOBase; + function read(n:Int = -1):Null; + function read1(n:Int = -1):Null; } diff --git a/std/python/lib/io/BufferedReader.hx b/std/python/lib/io/BufferedReader.hx index 3fe7dfb1daad80710ceb12000a007c288f109ac5..33c09ab3a043f031eebe7401775cf2e6cbbeaf8f 100644 --- a/std/python/lib/io/BufferedReader.hx +++ b/std/python/lib/io/BufferedReader.hx @@ -27,11 +27,11 @@ import python.lib.io.BufferedIOBase; @:pythonImport("io", "BufferedReader") extern class BufferedReader extends BufferedIOBase implements IBufferedReader { - public function new(raw:RawIOBase):Void; + function new(raw:RawIOBase):Void; - public function peek(?n:Int):Null; + function peek(?n:Int):Null; } @:remove extern interface IBufferedReader extends IBufferedIOBase { - public function peek(?n:Int):Null; + function peek(?n:Int):Null; } diff --git a/std/python/lib/io/BufferedWriter.hx b/std/python/lib/io/BufferedWriter.hx index 0bb4893495620c677bd4a017e2f2162d40df4f4c..61ddb1393dd361194d68d22e966ae5ebd4b0d488 100644 --- a/std/python/lib/io/BufferedWriter.hx +++ b/std/python/lib/io/BufferedWriter.hx @@ -27,9 +27,9 @@ import python.lib.io.BufferedIOBase; @:pythonImport("io", "BufferedWriter") extern class BufferedWriter extends BufferedIOBase implements IBufferedWriter { - public function new(raw:RawIOBase):Void; + function new(raw:RawIOBase):Void; } @:remove extern interface IBufferedWriter extends IBufferedIOBase { - public function flush():Void; + function flush():Void; } diff --git a/std/python/lib/io/BytesIO.hx b/std/python/lib/io/BytesIO.hx index 810492f3dd23ef0c17b0c0132d8d87d64dd78981..3d6143370acf85a20cc0a2763a68405e9f4d00c3 100644 --- a/std/python/lib/io/BytesIO.hx +++ b/std/python/lib/io/BytesIO.hx @@ -24,5 +24,5 @@ package python.lib.io; @:pythonImport("io", "BytesIO") extern class BytesIO extends python.lib.io.BufferedIOBase { - public function new(base:python.lib.io.IOBase); + function new(base:python.lib.io.IOBase); } diff --git a/std/python/lib/io/FileIO.hx b/std/python/lib/io/FileIO.hx index a57141921c7d2ad7bd2e3af1cc2fc306d7eb0cc5..18dc29583dcdf85b34e3fc1468e292479f06e5c1 100644 --- a/std/python/lib/io/FileIO.hx +++ b/std/python/lib/io/FileIO.hx @@ -29,10 +29,10 @@ extern class FileIO extends RawIOBase { /** The mode as given in the constructor. **/ - public var mode:String; + var mode:String; /** The file name. This is the file descriptor of the file when no name is given in the constructor. **/ - public var name:String; + var name:String; } diff --git a/std/python/lib/io/IOBase.hx b/std/python/lib/io/IOBase.hx index 5c0d54fcd57e12e092085ffe5101c8d9a8611baf..68f1872da16a364becc2dc31aff8b486d7bbc334 100644 --- a/std/python/lib/io/IOBase.hx +++ b/std/python/lib/io/IOBase.hx @@ -30,31 +30,31 @@ enum abstract SeekSet(Int) { @:pythonImport("io", "IOBase") extern class IOBase implements IIOBase { - public function close():Void; - public function flush():Void; - public function readline(limit:Int = -1):String; - public function readable():Bool; - public var closed(default, null):Bool; - public function readlines(hint:Int = -1):Array; - public function tell():Int; - public function writable():Bool; - public function seekable():Bool; - public function fileno():Int; - public function seek(offset:Int, whence:SeekSet):Int; - public function truncate(size:Int):Int; + function close():Void; + function flush():Void; + function readline(limit:Int = -1):String; + function readable():Bool; + var closed(default, null):Bool; + function readlines(hint:Int = -1):Array; + function tell():Int; + function writable():Bool; + function seekable():Bool; + function fileno():Int; + function seek(offset:Int, whence:SeekSet):Int; + function truncate(size:Int):Int; } @:remove extern interface IIOBase { - public function close():Void; - public function flush():Void; - public function readline(limit:Int = -1):String; - public function readable():Bool; - public var closed(default, null):Bool; - public function readlines(hint:Int = -1):Array; - public function tell():Int; - public function writable():Bool; - public function seekable():Bool; - public function fileno():Int; - public function seek(offset:Int, whence:SeekSet):Int; - public function truncate(size:Int):Int; + function close():Void; + function flush():Void; + function readline(limit:Int = -1):String; + function readable():Bool; + var closed(default, null):Bool; + function readlines(hint:Int = -1):Array; + function tell():Int; + function writable():Bool; + function seekable():Bool; + function fileno():Int; + function seek(offset:Int, whence:SeekSet):Int; + function truncate(size:Int):Int; } diff --git a/std/python/lib/io/RawIOBase.hx b/std/python/lib/io/RawIOBase.hx index ac38448bf5e33aef249b4afaa9e4005f615ddc2c..d207a1f9ed9c88d126710172603f89c96b0ed741 100644 --- a/std/python/lib/io/RawIOBase.hx +++ b/std/python/lib/io/RawIOBase.hx @@ -27,15 +27,15 @@ import python.lib.io.IOBase; @:pythonImport("io", "RawIOBase") extern class RawIOBase extends IOBase implements IRawIOBase { - public function readall():Bytes; - public function read(n:Int = -1):Null; - public function write(b:Bytearray):Null; - public function readinto(b:Bytearray):Null; + function readall():Bytes; + function read(n:Int = -1):Null; + function write(b:Bytearray):Null; + function readinto(b:Bytearray):Null; } @:remove extern interface IRawIOBase extends IIOBase { - public function readall():Bytes; - public function read(n:Int = -1):Null; - public function write(b:Bytearray):Null; - public function readinto(b:Bytearray):Null; + function readall():Bytes; + function read(n:Int = -1):Null; + function write(b:Bytearray):Null; + function readinto(b:Bytearray):Null; } diff --git a/std/python/lib/io/StringIO.hx b/std/python/lib/io/StringIO.hx index 1016ad3f375ac100d9287cb1dcd05b26cb77779f..8404486c93f068af140faf86a5c1141cd4608560 100644 --- a/std/python/lib/io/StringIO.hx +++ b/std/python/lib/io/StringIO.hx @@ -27,6 +27,6 @@ import python.Syntax; @:pythonImport("io", "StringIO") extern class StringIO extends TextIOBase { - public function new(?s:String):Void; - public function getvalue():String; + function new(?s:String):Void; + function getvalue():String; } diff --git a/std/python/lib/io/TextIOBase.hx b/std/python/lib/io/TextIOBase.hx index 364742916478bdd83a45b95eb899277a0920fcf6..b61c2ff6054b52d632a1e6fd32c600fd2ca0d343 100644 --- a/std/python/lib/io/TextIOBase.hx +++ b/std/python/lib/io/TextIOBase.hx @@ -28,29 +28,29 @@ import python.lib.io.IOBase; @:pythonImport("io", "TextIOBase") extern class TextIOBase extends IOBase implements ITextIOBase { - public var encoding:String; - public var error:String; - public var newlines:Null>>; + var encoding:String; + var error:String; + var newlines:Null>>; - public function detach():BufferedIOBase; + function detach():BufferedIOBase; - public function write(s:String):Int; + function write(s:String):Int; - public function read(n:Int):String; + function read(n:Int):String; - public var buffer:BufferedIOBase; + var buffer:BufferedIOBase; } @:remove extern interface ITextIOBase extends IIOBase { - public var encoding:String; - public var error:String; - public var newlines:Null>>; + var encoding:String; + var error:String; + var newlines:Null>>; - public var buffer:BufferedIOBase; + var buffer:BufferedIOBase; - public function detach():BufferedIOBase; + function detach():BufferedIOBase; - public function write(s:String):Int; + function write(s:String):Int; - public function read(n:Int):String; + function read(n:Int):String; } diff --git a/std/python/lib/io/TextIOWrapper.hx b/std/python/lib/io/TextIOWrapper.hx index 45363d5920eb9e257bbca2ef738ac31a557ee047..09070a120227c116310a434acb062bee9cfabd98 100644 --- a/std/python/lib/io/TextIOWrapper.hx +++ b/std/python/lib/io/TextIOWrapper.hx @@ -37,7 +37,7 @@ typedef TextIOWrapperOptions = { @:pythonImport("io", "TextIOWrapper") extern class TextIOWrapper extends TextIOBase { - public function new(buffer:BufferedIOBase, ?options:KwArgs):Void; + function new(buffer:BufferedIOBase, ?options:KwArgs):Void; - public var line_buffering:Bool; + var line_buffering:Bool; } diff --git a/std/python/lib/json/JSONDecoder.hx b/std/python/lib/json/JSONDecoder.hx index 45f01df60455464d2a91a6179b2f9a3850950231..3b6dd2949891033a5e6aca305bf7294b530a9920 100644 --- a/std/python/lib/json/JSONDecoder.hx +++ b/std/python/lib/json/JSONDecoder.hx @@ -35,8 +35,8 @@ typedef JSONDecoderOptions = { @:pythonImport("json", "JSONDecoder") extern class JSONDecoder { - public function new(?options:KwArgs):Void; + function new(?options:KwArgs):Void; - public function decode(o:String):Dynamic; - public function raw_decode(o:String):Tuple2; + function decode(o:String):Dynamic; + function raw_decode(o:String):Tuple2; } diff --git a/std/python/lib/json/JSONEncoder.hx b/std/python/lib/json/JSONEncoder.hx index 06b29d22bcf13ed2d97e46ebe5c725d3fab23914..9c2bbc3de05460c0f1c982edae5cd76c2bdf3e88 100644 --- a/std/python/lib/json/JSONEncoder.hx +++ b/std/python/lib/json/JSONEncoder.hx @@ -37,9 +37,9 @@ typedef JSONEncoderOptions = { @:pythonImport("json", "JSONEncoder") extern class JSONEncoder { - public function new(?options:KwArgs):Void; + function new(?options:KwArgs):Void; - @:native("default") public function def(o:Dynamic):Dynamic; + @:native("default") function def(o:Dynamic):Dynamic; - public function encode(o:Dynamic):String; + function encode(o:Dynamic):String; } diff --git a/std/python/lib/os/Path.hx b/std/python/lib/os/Path.hx index e4967ddfa9a7567a6ef9fb94e8a7b7e7a98dc61f..be0a3643a7342c6a915f696958cb449bcff1a2ba 100644 --- a/std/python/lib/os/Path.hx +++ b/std/python/lib/os/Path.hx @@ -27,56 +27,56 @@ import python.Tuple; @:pythonImport("os", "path") extern class Path { - public static var sep:String; - public static function exists(path:String):Bool; + static var sep:String; + static function exists(path:String):Bool; - public static function abspath(path:String):String; + static function abspath(path:String):String; - public static function basename(path:String):String; + static function basename(path:String):String; - public static function commonprefix(paths:Array):String; + static function commonprefix(paths:Array):String; - public static function lexists(path:String):Bool; + static function lexists(path:String):Bool; - public static function expanduser(path:String):String; + static function expanduser(path:String):String; - public static function expandvars(path:String):String; + static function expandvars(path:String):String; - public static function getmtime(path:String):Float; + static function getmtime(path:String):Float; - public static function getatime(path:String):Float; + static function getatime(path:String):Float; - public static function getctime(path:String):Float; + static function getctime(path:String):Float; - public static function getsize(path:String):Int; + static function getsize(path:String):Int; - public static function isabs(path:String):Bool; + static function isabs(path:String):Bool; - public static function isfile(path:String):Bool; + static function isfile(path:String):Bool; - public static function isdir(path:String):Bool; + static function isdir(path:String):Bool; - public static function dirname(path:String):String; + static function dirname(path:String):String; - public static function islink(path:String):Bool; + static function islink(path:String):Bool; - public static function ismount(path:String):Bool; + static function ismount(path:String):Bool; - public static function join(path:String, paths:Rest):String; + static function join(path:String, paths:Rest):String; - public static function normpath(path:String):String; + static function normpath(path:String):String; - public static function realpath(path:String):String; + static function realpath(path:String):String; - public static function relpath(path:String):String; + static function relpath(path:String):String; - public static function samefile(path1:String, path2:String):String; + static function samefile(path1:String, path2:String):String; - public static function split(path:String):Tuple2; + static function split(path:String):Tuple2; - public static function splitdrive(path:String):Tuple2; + static function splitdrive(path:String):Tuple2; - public static function splitext(path:String):Tuple2; + static function splitext(path:String):Tuple2; - public static function supports_unicode_filenames():Bool; + static function supports_unicode_filenames():Bool; } diff --git a/std/python/lib/ssl/Purpose.hx b/std/python/lib/ssl/Purpose.hx index 1e875dc03aab9841cddb2d2b99588733b4c69f06..c8d4310091381fb7ba1ff1af7fdcc09a7742eb20 100644 --- a/std/python/lib/ssl/Purpose.hx +++ b/std/python/lib/ssl/Purpose.hx @@ -25,6 +25,6 @@ package python.lib.ssl; @:require(python_version >= 3.4) @:pythonImport("ssl", "Purpose") extern class Purpose { - public static var SERVER_AUTH:String; - public static var CLIENT_AUTH:String; + static var SERVER_AUTH:String; + static var CLIENT_AUTH:String; } diff --git a/std/python/lib/ssl/SSLContext.hx b/std/python/lib/ssl/SSLContext.hx index 6879e449d433d25d3cecd9d33bc9b86cab5cb8bb..33655097144f09c327788a7493769fb8618b018e 100644 --- a/std/python/lib/ssl/SSLContext.hx +++ b/std/python/lib/ssl/SSLContext.hx @@ -26,25 +26,25 @@ import python.lib.ssl.SSLSocket; @:pythonImport("ssl", "SSLContext") extern class SSLContext { - public function new(protocol:String):Void; + function new(protocol:String):Void; #if (python_version >= 3.6) - public function wrap_socket(s:python.lib.socket.Socket, server_side:Bool = false, do_handshake_on_connect:Bool = true, suppress_ragged_eofs:Bool = true, + function wrap_socket(s:python.lib.socket.Socket, server_side:Bool = false, do_handshake_on_connect:Bool = true, suppress_ragged_eofs:Bool = true, server_hostname:String = null, session:SSLSession = null):python.lib.ssl.SSLSocket; #else - public function wrap_socket(s:python.lib.socket.Socket, server_side:Bool = false, do_handshake_on_connect:Bool = true, suppress_ragged_eofs:Bool = true, + function wrap_socket(s:python.lib.socket.Socket, server_side:Bool = false, do_handshake_on_connect:Bool = true, suppress_ragged_eofs:Bool = true, server_hostname:String = null):python.lib.ssl.SSLSocket; #end - public var options:Int; + var options:Int; @:require(python_version >= 3.4) - public var check_hostname:Bool; + var check_hostname:Bool; - public var verify_mode:Int; - public function load_verify_locations(cafile:String = null, capath:String = null, cadata:String = null):Void; - public function set_default_verify_paths():Void; + var verify_mode:Int; + function load_verify_locations(cafile:String = null, capath:String = null, cadata:String = null):Void; + function set_default_verify_paths():Void; @:require(python_version >= 3.4) - public function load_default_certs():Void; - // public function load_cert_chain(certfile:String, keyfile:String = null, password:String = null):Void; - // public function set_servername_callback(callback:SSLSocket -> String -> SSLContext -> Void ):Void; + function load_default_certs():Void; + // function load_cert_chain(certfile:String, keyfile:String = null, password:String = null):Void; + // function set_servername_callback(callback:SSLSocket -> String -> SSLContext -> Void ):Void; } diff --git a/std/python/lib/subprocess/Popen.hx b/std/python/lib/subprocess/Popen.hx index dbb3083eb64f50d8cbf20383aae4f266ce8f749d..507c5a2f5ec7a7306760d1807c6a4aa424a7b2cf 100644 --- a/std/python/lib/subprocess/Popen.hx +++ b/std/python/lib/subprocess/Popen.hx @@ -48,7 +48,7 @@ typedef PopenOptions = { @:pythonImport("subprocess", "Popen") extern class Popen { - public static inline function create(args:EitherType>, o:PopenOptions):Popen { + static inline function create(args:EitherType>, o:PopenOptions):Popen { o.bufsize = if (Reflect.hasField(o, "bufsize")) o.bufsize else 0; o.executable = if (Reflect.hasField(o, "executable")) o.executable else null; o.stdin = if (Reflect.hasField(o, "stdin")) o.stdin else null; @@ -73,20 +73,20 @@ extern class Popen { } } - public function new(args:Array, bufsize:Int = 0, executable:String = null, stdin:Int = null, stdout:Int = null, stderr:Int = null, + function new(args:Array, bufsize:Int = 0, executable:String = null, stdin:Int = null, stdout:Int = null, stderr:Int = null, preexec_fn:Void->Void = null, close_fds:Bool = false, shell:Bool = false, cwd:String = null, env:Dict = null, universal_newlines:Bool = false, startupinfo:StartupInfo = null, creationflags:Int = 0):Void; - public function kill():Void; - public function wait(?timeout:Null):Null; - public function poll():Null; - public function terminate():Void; + function kill():Void; + function wait(?timeout:Null):Null; + function poll():Null; + function terminate():Void; - public var stdout:FileIO; - public var stderr:FileIO; - public var stdin:FileIO; - public var returncode:Int; - public var pid:Int; + var stdout:FileIO; + var stderr:FileIO; + var stdin:FileIO; + var returncode:Int; + var pid:Int; - public function communicate(input:Bytes = null, timeout:Null = null):Tuple2; + function communicate(input:Bytes = null, timeout:Null = null):Tuple2; } diff --git a/std/python/lib/threading/Lock.hx b/std/python/lib/threading/Lock.hx index 566a01c6071a62179db4b3973186ff3fc76ee8b3..ac98eed26955864cc89ad977b6d151cf1c984fc0 100644 --- a/std/python/lib/threading/Lock.hx +++ b/std/python/lib/threading/Lock.hx @@ -24,7 +24,7 @@ package python.lib.threading; @:pythonImport("threading", "Lock") extern class Lock { - public function new():Void; - public function acquire(?blocking:Bool, ?timeout:Float):Bool; - public function release():Void; + function new():Void; + function acquire(?blocking:Bool, ?timeout:Float):Bool; + function release():Void; } diff --git a/std/python/lib/threading/RLock.hx b/std/python/lib/threading/RLock.hx index 6b425df9724b63ae0386cfa5bf9ea53bbfcd64c5..ae53626fd0994fe7cd8208fb808e9d9eeca7fc55 100644 --- a/std/python/lib/threading/RLock.hx +++ b/std/python/lib/threading/RLock.hx @@ -24,7 +24,7 @@ package python.lib.threading; @:pythonImport("threading", "RLock") extern class RLock { - public function new():Void; - public function acquire(?blocking:Bool, ?timeout:Float):Bool; - public function release():Void; + function new():Void; + function acquire(?blocking:Bool, ?timeout:Float):Bool; + function release():Void; } diff --git a/std/python/lib/threading/Thread.hx b/std/python/lib/threading/Thread.hx index a3faf9f11ade4d08f7e14cc6722ea801bf4b16a7..4d6e6c20a1d46334ebc8ac906d5d72d285c49f86 100644 --- a/std/python/lib/threading/Thread.hx +++ b/std/python/lib/threading/Thread.hx @@ -33,12 +33,12 @@ typedef ThreadOptions = { @:pythonImport("threading", "Thread") extern class Thread { - public var name:String; - public var ident:Int; - public var daemon:Bool; - public function new(?options:KwArgs):Void; - public function start():Void; - public function run():Void; - public function join(?timeout:Float):Void; - public function is_alive():Bool; + var name:String; + var ident:Int; + var daemon:Bool; + function new(?options:KwArgs):Void; + function start():Void; + function run():Void; + function join(?timeout:Float):Void; + function is_alive():Bool; } diff --git a/std/python/lib/xml/etree/ElementTree.hx b/std/python/lib/xml/etree/ElementTree.hx index 9e258cdefd68fa39b1b10a4dd661cef3b401a364..fa5e53fb62fe3f7bbf178b5086b72982a007314e 100644 --- a/std/python/lib/xml/etree/ElementTree.hx +++ b/std/python/lib/xml/etree/ElementTree.hx @@ -31,31 +31,31 @@ extern class XMLParser {} @:pythonImport("xml.etree.ElementTree", "Element") extern class Element { - public function getroot():ElementTree; - public var tag:String; - public var attrib:Dict; - public var text:Null; + function getroot():ElementTree; + var tag:String; + var attrib:Dict; + var text:Null; - public function get(key:String, def:T = null):T; - public function set(key:String, val:String):Void; + function get(key:String, def:T = null):T; + function set(key:String, val:String):Void; - public function copy():Element; + function copy():Element; - public function keys():Array; - public function items():Array>; + function keys():Array; + function items():Array>; - public function iter(tag:String):NativeIterable; - public function iterfind(tag:String, namespaces:Dict = null):NativeIterator; - public function find(match:String, namespaces:Dict = null):Null; - public function findall(match:String, namespaces:Dict = null):Array; + function iter(tag:String):NativeIterable; + function iterfind(tag:String, namespaces:Dict = null):NativeIterator; + function find(match:String, namespaces:Dict = null):Null; + function findall(match:String, namespaces:Dict = null):Array; } @:pythonImport("xml.etree.ElementTree") extern class ElementTree { - public static function XML(text:String, ?parser:XMLParser):Element; - public static function parse(xml:String):ElementTree; + static function XML(text:String, ?parser:XMLParser):Element; + static function parse(xml:String):ElementTree; - public function iter(tag:String):NativeIterable; - public function find(match:String, namespaces:Dict = null):Null; - public function getroot():Element; + function iter(tag:String):NativeIterable; + function find(match:String, namespaces:Dict = null):Null; + function getroot():Element; } diff --git a/std/sys/Http.hx b/std/sys/Http.hx index 85977c6aed891462255897c0225c8282f6e1202c..f5a93d0a9b8de231c64902686eb0fbac5f9b43f2 100644 --- a/std/sys/Http.hx +++ b/std/sys/Http.hx @@ -104,7 +104,7 @@ class Http extends haxe.http.HttpBase { sock = new java.net.SslSocket(); #elseif python sock = new python.net.SslSocket(); - #elseif (!no_ssl && (hxssl || hl || cpp || (neko && !(macro || interp)))) + #elseif (!no_ssl && (hxssl || hl || cpp || (neko && !(macro || interp) || eval))) sock = new sys.ssl.Socket(); #elseif (neko || cpp) throw "Https is only supported with -lib hxssl"; @@ -239,9 +239,9 @@ class Http extends haxe.http.HttpBase { else sock.connect(new Host(host), port); if (multipart) - writeBody(b,file.io,file.size,boundary,sock) + writeBody(b, file.io, file.size, boundary, sock) else - writeBody(b,null,0,null,sock); + writeBody(b, null, 0, null, sock); readHttpResponse(api, sock); sock.close(); } catch (e:Dynamic) { @@ -478,13 +478,13 @@ class Http extends haxe.http.HttpBase { } /** - Makes a synchronous request to `url`. + Makes a synchronous request to `url`. - This creates a new Http instance and makes a GET request by calling its - `request(false)` method. + This creates a new Http instance and makes a GET request by calling its + `request(false)` method. - If `url` is null, the result is unspecified. - **/ + If `url` is null, the result is unspecified. +**/ public static function requestUrl(url:String):String { var h = new Http(url); var r = null; diff --git a/std/sys/io/FileOutput.hx b/std/sys/io/FileOutput.hx index f334c386ac9ca1d13a7718861b5f3fdbfdf09a2f..4cf406c8c64cba89ee5a6ed00953febf3ead9fbf 100644 --- a/std/sys/io/FileOutput.hx +++ b/std/sys/io/FileOutput.hx @@ -26,6 +26,6 @@ package sys.io; Use `sys.io.File.write` to create a `FileOutput`. **/ extern class FileOutput extends haxe.io.Output { - public function seek(p:Int, pos:FileSeek):Void; - public function tell():Int; + function seek(p:Int, pos:FileSeek):Void; + function tell():Int; } diff --git a/std/sys/ssl/Certificate.hx b/std/sys/ssl/Certificate.hx index 16b705b48039dc0587a622e422c9d405cee11fe4..d0261d38575de23c6e075e2fbe9de0227d324447 100644 --- a/std/sys/ssl/Certificate.hx +++ b/std/sys/ssl/Certificate.hx @@ -23,31 +23,31 @@ package sys.ssl; extern class Certificate { - public static function loadFile(file:String):Certificate; + static function loadFile(file:String):Certificate; - public static function loadPath(path:String):Certificate; + static function loadPath(path:String):Certificate; - public static function fromString(str:String):Certificate; + static function fromString(str:String):Certificate; - public static function loadDefaults():Certificate; + static function loadDefaults():Certificate; - public var commonName(get, null):Null; + var commonName(get, null):Null; - public var altNames(get, null):Array; + var altNames(get, null):Array; - public var notBefore(get, null):Date; + var notBefore(get, null):Date; - public var notAfter(get, null):Date; + var notAfter(get, null):Date; - public function subject(field:String):Null; + function subject(field:String):Null; - public function issuer(field:String):Null; + function issuer(field:String):Null; - public function next():Null; + function next():Null; - public function add(pem:String):Void; + function add(pem:String):Void; - public function addDER(der:haxe.io.Bytes):Void; + function addDER(der:haxe.io.Bytes):Void; private function get_commonName():Null; diff --git a/std/sys/thread/Deque.hx b/std/sys/thread/Deque.hx index 779e8f43f8f549fb0101884e932ae7ec262ce29e..183e05e5d17b224a5ac14e45b9656b1fcf3c6a28 100644 --- a/std/sys/thread/Deque.hx +++ b/std/sys/thread/Deque.hx @@ -34,17 +34,17 @@ package sys.thread; /** Create a new Deque instance which is initially empty. **/ - public function new():Void; + function new():Void; /** Adds an element at the end of `this` Deque. **/ - public function add(i:T):Void; + function add(i:T):Void; /** Adds an element at the front of `this` Deque. **/ - public function push(i:T):Void; + function push(i:T):Void; /** Tries to retrieve an element from the front of `this` Deque. @@ -55,5 +55,5 @@ package sys.thread; Otherwise, execution blocks until an element is available and returns it. **/ - public function pop(block:Bool):Null; + function pop(block:Bool):Null; } diff --git a/std/sys/thread/Lock.hx b/std/sys/thread/Lock.hx index 70bea3fd70cfbd0c7d45c67fac13efd503655b04..5d7af2c5092eddd46fd2cc97ea19c0996c04eb70 100644 --- a/std/sys/thread/Lock.hx +++ b/std/sys/thread/Lock.hx @@ -37,37 +37,37 @@ package sys.thread; Usage example: - ``` - var lock = new Lock(); - var elements = [1, 2, 3]; - for (element in elements) { - // Create one thread per element - new Thread(function() { - trace(element); - Sys.sleep(1); - // Release once per thread = 3 times - lock.release(); - }); - } - for (_ in elements) { - // Wait 3 times - lock.wait(); - } - trace("All threads finished"); + ```haxe + var lock = new Lock(); + var elements = [1, 2, 3]; + for (element in elements) { + // Create one thread per element + new Thread(function() { + trace(element); + Sys.sleep(1); + // Release once per thread = 3 times + lock.release(); + }); + } + for (_ in elements) { + // Wait 3 times + lock.wait(); + } + trace("All threads finished"); ``` **/ extern class Lock { /** Creates a new Lock which is initially locked. **/ - public function new():Void; + function new():Void; /** Waits for the lock to be released, or `timeout` (in seconds) to expire. Returns `true` if the lock is released and `false` if a time-out occurs. **/ - public function wait(?timeout:Float):Bool; + function wait(?timeout:Float):Bool; /** Releases the lock once. @@ -76,5 +76,5 @@ extern class Lock { it. Each call to `release` allows exactly one call to `wait` to execute. **/ - public function release():Void; + function release():Void; } diff --git a/std/sys/thread/Mutex.hx b/std/sys/thread/Mutex.hx index 19f1823bf93e719a041417a863f742408950e6e1..d1569ace21caa2fe24fc0fbdf8f5944e1511081d 100644 --- a/std/sys/thread/Mutex.hx +++ b/std/sys/thread/Mutex.hx @@ -30,30 +30,30 @@ package sys.thread; Creates a mutex, which can be used to acquire a temporary lock to access some ressource. The main difference with a lock is that a mutex must always be released by the owner thread. - */ +**/ extern class Mutex { /** Creates a mutex. **/ - public function new():Void; + function new():Void; /** The current thread acquire the mutex or wait if not available. The same thread can acquire several times the same mutex but must release it as many times it has been acquired. **/ - public function acquire():Void; + function acquire():Void; /** Try to acquire the mutex, returns true if acquire or false if it's already locked by another thread. **/ - public function tryAcquire():Bool; + function tryAcquire():Bool; /** Release a mutex that has been acquired by the current thread. The behavior is undefined if the current thread does not own the mutex. **/ - public function release():Void; + function release():Void; } diff --git a/std/sys/thread/Tls.hx b/std/sys/thread/Tls.hx index 129aa5c9c1480ea4d598471edeee016a3c410e76..d096fb687bf3d236f629ec011757bce265e928dd 100644 --- a/std/sys/thread/Tls.hx +++ b/std/sys/thread/Tls.hx @@ -33,7 +33,7 @@ package sys.thread; garbage collected. Keep the value reachable to avoid crashes. **/ extern class Tls { - public var value(get, set):T; + var value(get, set):T; /** Creates thread local storage. This is placeholder that can store @@ -41,5 +41,5 @@ extern class Tls { Set the tls value to `null` before exiting the thread or the memory will never be collected. **/ - public function new():Void; + function new():Void; } diff --git a/tests/Brewfile b/tests/Brewfile index c30420cc0b7f89bc6094da26927d19e8408077fc..c1b15a58f8503c7618b0fbfd77c46dec0fbe4e1b 100644 --- a/tests/Brewfile +++ b/tests/Brewfile @@ -7,3 +7,4 @@ brew "pcre" brew "awscli" brew "cmake" brew "pkg-config" +brew "mbedtls" \ No newline at end of file diff --git a/tests/README.md b/tests/README.md index b17024f6a8d854683e2ecb62514cbafc96864eea..160344f42f9eab5e96bbc1ea4c9c78f64eb76bca 100644 --- a/tests/README.md +++ b/tests/README.md @@ -45,7 +45,7 @@ It is possible to run it in local machines too: 1. Change to this directory. 2. Compile the script: `haxe RunCi.hxml`. - 3. Define the test target by `export TEST=$TARGET` (or `set "TEST=$TARGET"` on Windows), where `$TARGET` should be a comma-seperated list of targets, e.g. `neko,macro`. Possible targets are `macro`, `neko`, `js`, `lua`, `php`, `cpp`, `flash9`, `as3`, `java`, `cs`, `python`, and `third-party`. However, `flash9`, `as3`, and `third-party` are not likely to work on local machines (TODO). + 3. Define the test target by `export TEST=$TARGET` (or `set "TEST=$TARGET"` on Windows), where `$TARGET` should be a comma-seperated list of targets, e.g. `neko,macro`. Possible targets are `macro`, `neko`, `js`, `lua`, `php`, `cpp`, `flash9`, `java`, `cs`, `python`, and `third-party`. However, `flash9` and `third-party` are not likely to work on local machines (TODO). 4. Run it: `neko RunCi.n`. Note that the script will try to look for test dependencies and install them if they are not found. Look at the `getXXXDependencies` functions for the details. diff --git a/tests/RunCi.hx b/tests/RunCi.hx index 5da13ce7f390b040fc1c86b5266803535bcc1c07..d8ae8fd5e0b2e7324f5ae270f7048bf7739336c4 100644 --- a/tests/RunCi.hx +++ b/tests/RunCi.hx @@ -1,3 +1,4 @@ +import haxe.Exception; import runci.TestTarget; import runci.System; import runci.System.*; @@ -98,12 +99,10 @@ class RunCi { runci.targets.Cs.run(args); case Flash9: runci.targets.Flash.run(args); - case As3: - runci.targets.As3.run(args); case Hl: runci.targets.Hl.run(args); case t: - throw "unknown target: " + t; + throw new Exception("unknown target: " + t); } } catch(f:Failure) { success = false; @@ -120,6 +119,7 @@ class RunCi { successMsg('test ${test} succeeded'); } else { failMsg('test ${test} failed'); + break; } echoServer.kill(); diff --git a/tests/benchs/.vscode/settings.json b/tests/benchs/.vscode/settings.json index dff5fb49ef49fee272d510655fdf229e62be5d75..50327afb729ba5b9431c740c4309aa371f8f96d1 100644 --- a/tests/benchs/.vscode/settings.json +++ b/tests/benchs/.vscode/settings.json @@ -1,10 +1,10 @@ { - "haxe.displayConfigurations": [ + "haxe.configurations": [ {"label": "Neko", "args": ["build.hxml", "-neko", "export/run.n", "-cmd", "neko export/run.n"]}, {"label": "JavaScript", "args": ["build.hxml", "-js","export/run.js", "-lib", "hxnodejs", "-cmd", "node export/run.js"]}, {"label": "Python", "args": ["build.hxml", "-python", "export/run.py", "-cmd", "python3 export/run.py"]}, {"label": "C++", "args": ["build.hxml", "-cpp", "export/cpp", "-cmd", "cmd /C export\\cpp\\Main.exe"]}, - {"label": "CPPIA", "args": ["build.hxml", "-cppia","export/cppia.txt"]}, + {"label": "CPPIA", "args": ["build.hxml", "-cppia","export/run.cppia", "-cmd", "haxelib run hxcpp export/run.cppia"]}, {"label": "HashLink/JIT", "args": ["build.hxml", "-hl", "export/run.hl", "-cmd", "hl export/run.hl"]}, {"label": "HashLink/Interp", "args": ["build.hxml", "-hl", "export/run.hl", "-D", "interp"]}, {"label": "Lua 5.1", "args": ["build.hxml", "-lua", "export/run.lua", "-cmd", "C:\\WINDOWS\\Sysnative\\bash.exe -c 'lua5.1 export/run.lua'"]}, diff --git a/tests/benchs/src/Macro.hx b/tests/benchs/src/Macro.hx index 26ce13e2add876dfebf8084c8029259906d70098..af360fe9cd0b5b7eb82367e8a47e51d1ea544483 100644 --- a/tests/benchs/src/Macro.hx +++ b/tests/benchs/src/Macro.hx @@ -1,9 +1,11 @@ +#if macro import haxe.macro.Context; import haxe.macro.Expr; import haxe.io.Path; using StringTools; using sys.FileSystem; +#end class Macro { static var singleCaseField = null; diff --git a/tests/benchs/src/Main.hx b/tests/benchs/src/Main.hx index 91011d5cdc6e0e6561ceff9c41387520c5ea3d52..2fb10078687562f10f2bc12d7b29d34af53046de 100644 --- a/tests/benchs/src/Main.hx +++ b/tests/benchs/src/Main.hx @@ -6,12 +6,22 @@ class Main { var cases = Macro.getCases("cases"); var printer = new ResultPrinter(); function print(result:SuiteResult) { - Sys.println(printer.print(result)); + println(printer.print(result)); } for (benchCase in cases) { - Sys.println('Case: ${benchCase.name}'); + println('Case: ${benchCase.name}'); benchCase.exec.run(print); } } + + static public inline function println(msg:String) { + #if sys + Sys.println(msg); + #elseif js + js.Syntax.code('console.log({0})', msg); + #else + trace(msg); + #end + } } \ No newline at end of file diff --git a/tests/benchs/src/cases/Calls.hx b/tests/benchs/src/cases/Calls.hx index 1e9249951c3f2259ad8395355dd3fd90d849f188..4d593b9396edb68768ef3e7a3f23c0cf81f9d5e7 100644 --- a/tests/benchs/src/cases/Calls.hx +++ b/tests/benchs/src/cases/Calls.hx @@ -35,13 +35,17 @@ class CallClassChild extends CallClass { override function overrideCall2(s2:String, s2:String) { return null; } } +typedef TInstanceCall0 = { function instanceCall0():String; }; +typedef TInstanceCall1 = { function instanceCall1(s1:String):String; } +typedef TInstanceCall2 = { function instanceCall2(s1:String, s2:String):String; } + class Calls extends TestCase { @:analyzer(ignore) function measureCall0() { var c = new CallClass(); var cSub:CallClass = new CallClassChild(); var cInterface:CallInterface = c; - var cAnon:{ function instanceCall0():String; } = c; + var cAnon:TInstanceCall0 = c; var cActualAnon = { instanceCall0: function ():String { return null; @@ -75,9 +79,7 @@ class Calls extends TestCase { var c = new CallClass(); var cSub:CallClass = new CallClassChild(); var cInterface:CallInterface = c; - var cAnon:{ - function instanceCall1(s1:String):String; - } = c; + var cAnon:TInstanceCall1 = c; var cActualAnon = { instanceCall1: function (s1:String):String { return null; @@ -111,9 +113,7 @@ class Calls extends TestCase { var c = new CallClass(); var cSub:CallClass = new CallClassChild(); var cInterface:CallInterface = c; - var cAnon:{ - function instanceCall2(s1:String, s2:String):String; - } = c; + var cAnon:TInstanceCall2 = c; var cActualAnon = { instanceCall2: function (s1:String, s2:String):String { return null; diff --git a/tests/benchs/src/cases/Regexp.hx b/tests/benchs/src/cases/Regexp.hx new file mode 100644 index 0000000000000000000000000000000000000000..9ac052c148c135b84cfe2bf8974c90c26a3280c5 --- /dev/null +++ b/tests/benchs/src/cases/Regexp.hx @@ -0,0 +1,14 @@ +package cases; + +import hxbenchmark.Suite; + +@:analyzer(ignore) +class Regexp extends TestCase { + function measureReplace() { + var str = StringTools.lpad('', '"', 10 * 1024); + var r = ~/"/g; + var suite = new Suite('~/"/g.replace(string, "")'); + suite.add("10Kb string", r.replace(str, "")); + return suite.run(); + } +} \ No newline at end of file diff --git a/tests/benchs/src/cases/StringCreate.hx b/tests/benchs/src/cases/StringCreate.hx new file mode 100644 index 0000000000000000000000000000000000000000..69312cab33eae13d159ad1342d7e4e5a630eaf8f --- /dev/null +++ b/tests/benchs/src/cases/StringCreate.hx @@ -0,0 +1,70 @@ +package cases; + +import hxbenchmark.Suite; + +using StringTools; + +class StringCreate extends TestCase { + @:analyzer(no_optimize) + function measureCreate() { + var suite = new Suite("10000 iterations"); + var s100 = StringTools.lpad("", "abcdefghijklmnopqrstuvwxzy", 100); + var s1000 = StringTools.lpad("", "abcdefghijklmnopqrstuvwxzy", 1000); + var s10000 = StringTools.lpad("", "abcdefghijklmnopqrstuvwxzy", 10000); + suite.add("concat 0", { + var s = ""; + for (i in 0...10000) { + s += ""; + } + }); + suite.add("concat 1", { + var s = ""; + for (i in 0...10000) { + s += "a"; + } + }); + // suite.add("concat 100", { + // var s = ""; + // for (i in 0...10000) { + // s += s100; + // } + // }); + // suite.add("concat 1000", { + // var s = ""; + // for (i in 0...10000) { + // s += s1000; + // } + // }); + suite.add("substr 100", { + var s100 = s100; + for (i in 0...10000) { + s100.substr(13, 1); + } + }); + suite.add("substr 1000", { + var s1000 = s1000; + for (i in 0...10000) { + s1000.substr(13, 1); + } + }); + // suite.add("substr 10000", { + // var s10000 = s10000; + // for (i in 0...10000) { + // s10000.substr(13, 1); + // } + // }); + suite.add("replace 100", { + var s100 = s100; + for (i in 0...10000) { + s100.replace("l", "L"); + } + }); + // suite.add("replace 1000", { + // var s1000 = s1000; + // for (i in 0...10000) { + // s1000.replace("l", "L"); + // } + // }); + return suite.run(); + } +} \ No newline at end of file diff --git a/tests/display/.vscode/launch.json b/tests/display/.vscode/launch.json index 0b74adc396e778700b6d911e84d64f97a383b129..110d7274bee857bda4d3f1cedea0d2532c035495 100644 --- a/tests/display/.vscode/launch.json +++ b/tests/display/.vscode/launch.json @@ -5,7 +5,9 @@ "name": "Interpreter", "type": "haxe-eval", "request": "launch", - "args": ["build.hxml", "-lib", "test-adapter"] + "args": [ + "build.hxml" + ] } ] } \ No newline at end of file diff --git a/tests/display/build.hxml b/tests/display/build.hxml index c6541398651aca78e721d7ff23e26e547bc2a041..b751ec6b93958780baeffb8e7dfa78535eadc53b 100644 --- a/tests/display/build.hxml +++ b/tests/display/build.hxml @@ -4,4 +4,5 @@ -lib utest -lib haxeserver --interp --D use-rtti-doc \ No newline at end of file +-D use-rtti-doc +#-D test=9133 \ No newline at end of file diff --git a/tests/display/src-shared/Marker.hx b/tests/display/src-shared/Marker.hx index 1abe2b1a21b31e8e47e1e5ea15f8ad681272effb..c3b0ee91dd744f8ac93bc77e64e90cded4bd4f0b 100644 --- a/tests/display/src-shared/Marker.hx +++ b/tests/display/src-shared/Marker.hx @@ -1,3 +1,6 @@ +import haxe.Exception; +import haxe.display.Position; + class Marker { static var markerRe = ~/{-(\d+)-}/g; diff --git a/tests/display/src/ModuleSymbolEntry.hx b/tests/display/src/ModuleSymbolEntry.hx index 79d7bb930ac248cf7c83882a6cfebc2e9f452846..5b557496d1893bb9ec0a71ba880a5769441d71b8 100644 --- a/tests/display/src/ModuleSymbolEntry.hx +++ b/tests/display/src/ModuleSymbolEntry.hx @@ -1,21 +1,28 @@ // Taken from vshaxe... not ideal to copy it here private enum abstract ModuleSymbolKind(Int) { - var MClass = 1; - var MInterface = 2; - var MEnum = 3; - var MTypedef = 4; - var MAbstract = 5; - var MField = 6; - var MProperty = 7; - var MMethod = 8; - var MConstructor = 9; - var MFunction = 10; - var MVariable = 11; + var Class = 1; + var Interface; + var Enum; + var TypeAlias; + var Abstract; + var Field; + var Property; + var Method; + var Constructor; + var Function; + var Variable; + var Struct; + var EnumAbstract; + var Operator; + var EnumMember; + var Constant; } typedef ModuleSymbolEntry = { var name:String; var kind:ModuleSymbolKind; + // var range:Range; var ?containerName:String; + var ?isDeprecated:Bool; } diff --git a/tests/display/src/cases/DocumentSymbols.hx b/tests/display/src/cases/DocumentSymbols.hx index 0ecb61786f27cde1ece0d6392919cc51811bb560..271b9219653f353a04db95bf24734fd0d676afae 100644 --- a/tests/display/src/cases/DocumentSymbols.hx +++ b/tests/display/src/cases/DocumentSymbols.hx @@ -12,12 +12,12 @@ class DocumentSymbols extends DisplayTestCase { **/ function testClassFields() { checkDocumentSymbols([ - {name: "Some", kind: MClass, containerName: null}, - {name: "main", kind: MMethod, containerName: "Some"}, - {name: "x", kind: MField, containerName: "Some"}, - {name: "y", kind: MField, containerName: "Some"}, - {name: "z", kind: MProperty, containerName: "Some"}, - {name: "new", kind: MConstructor, containerName: "Some"} + {name: "Some", kind: Class, containerName: null}, + {name: "main", kind: Method, containerName: "Some"}, + {name: "x", kind: Field, containerName: "Some"}, + {name: "y", kind: Field, containerName: "Some"}, + {name: "z", kind: Property, containerName: "Some"}, + {name: "new", kind: Constructor, containerName: "Some"} ], ctx.documentSymbols()); } @@ -28,8 +28,8 @@ class DocumentSymbols extends DisplayTestCase { **/ function testInterface() { checkDocumentSymbols([ - {name: "Some", kind: MInterface, containerName: null}, - {name: "test", kind: MMethod, containerName: "Some"} + {name: "Some", kind: Interface, containerName: null}, + {name: "test", kind: Method, containerName: "Some"} ], ctx.documentSymbols()); } @@ -41,9 +41,9 @@ class DocumentSymbols extends DisplayTestCase { **/ function testEnum() { checkDocumentSymbols([ - {name: "E", kind: MEnum, containerName: null}, - {name: "A", kind: MMethod, containerName: "E"}, - {name: "B", kind: MMethod, containerName: "E"} + {name: "E", kind: Enum, containerName: null}, + {name: "A", kind: EnumMember, containerName: "E"}, + {name: "B", kind: EnumMember, containerName: "E"} ], ctx.documentSymbols()); } @@ -54,8 +54,8 @@ class DocumentSymbols extends DisplayTestCase { **/ function testTypedef() { checkDocumentSymbols([ - {name: "T", kind: MTypedef, containerName: null}, - {name: "x", kind: MField, containerName: "T"} + {name: "T", kind: Struct, containerName: null}, + {name: "x", kind: Field, containerName: "T"} ], ctx.documentSymbols()); } @@ -63,13 +63,33 @@ class DocumentSymbols extends DisplayTestCase { abstract A(Int) { public function new() { } function f() { } + @:op(A + B) function add(i:Int); } **/ function testAbstract() { checkDocumentSymbols([ - {name: "A", kind: MAbstract, containerName: null}, - {name: "new", kind: MConstructor, containerName: "A"}, - {name: "f", kind: MMethod, containerName: "A"} + {name: "A", kind: Abstract, containerName: null}, + {name: "new", kind: Constructor, containerName: "A"}, + {name: "f", kind: Method, containerName: "A"}, + {name: "add", kind: Operator, containerName: "A"}, + {name: "i", kind: Variable, containerName: "A.add"} + ], ctx.documentSymbols()); + } + + /** + enum abstract E(Int) { + static inline var FOO = "test"; + var A; + @:op(A + B) function add(i:Int); + } + **/ + function testEnumAbstract() { + checkDocumentSymbols([ + {name: "E", kind: EnumAbstract, containerName: null}, + {name: "FOO", kind: Constant, containerName: "E"}, + {name: "A", kind: EnumMember, containerName: "E"}, + {name: "add", kind: Operator, containerName: "E"}, + {name: "i", kind: Variable, containerName: "E.add"} ], ctx.documentSymbols()); } @@ -85,18 +105,25 @@ class DocumentSymbols extends DisplayTestCase { **/ function testExpression() { checkDocumentSymbols([ - {name: "Main", kind: MClass, containerName: null}, - {name: "main", kind: MMethod, containerName: "Main"}, - {name: "a", kind: MVariable, containerName: "Main.main"}, - {name: "b", kind: MVariable, containerName: "Main.main"}, - {name: "c", kind: MVariable, containerName: "Main.main"}, - {name: "d", kind: MVariable, containerName: "Main.main"}, - {name: "e", kind: MVariable, containerName: "Main.main"}, - {name: "f", kind: MFunction, containerName: "Main.main"} + {name: "Main", kind: Class, containerName: null}, + {name: "main", kind: Method, containerName: "Main"}, + {name: "a", kind: Variable, containerName: "Main.main"}, + {name: "b", kind: Variable, containerName: "Main.main"}, + {name: "c", kind: Variable, containerName: "Main.main"}, + {name: "d", kind: Variable, containerName: "Main.main"}, + {name: "e", kind: Variable, containerName: "Main.main"}, + {name: "f", kind: Function, containerName: "Main.main"} ], ctx.documentSymbols()); } function checkDocumentSymbols(expected:Array, actual:Array, ?pos:haxe.PosInfos) { - arrayCheck(expected, actual, function(entry) return entry.kind + ":" + entry.name + ":" + entry.containerName, pos); + for (entry in expected) { + entry.containerName = "cases.DocumentSymbols" + if (entry.containerName == null) { + ""; + } else { + "." + entry.containerName; + } + } + arrayCheck(expected, actual, entry -> entry.kind + ":" + entry.name + ":" + entry.containerName, pos); } } diff --git a/tests/display/src/cases/Issue5306.hx b/tests/display/src/cases/Issue5306.hx index 69d1284986c8eb8ce73e8c24b93a8f2b402a953f..e2c972a0cd2c280732e24a6d2dede96ed2261634 100644 --- a/tests/display/src/cases/Issue5306.hx +++ b/tests/display/src/cases/Issue5306.hx @@ -7,19 +7,19 @@ class Issue5306 extends DisplayTestCase { class Main { static function main() { var ib:Array; - ib[0] = 0; ib[1] = 1; ib[2] + ib[0] = 0; ib[1] = 1; {-7-}ib[2]{-8-} {-5-}trace{-6-}("test"); } } **/ function test() { var expected:Array> = [ - { - kind: DKUnusedImport, - range: diagnosticsRange(pos(1), pos(2)), - severity: Warning, - args: [] - }, + // { + // kind: DKUnusedImport, + // range: diagnosticsRange(pos(1), pos(2)), + // severity: Warning, + // args: [] + // }, { kind: DKCompilerError, range: diagnosticsRange(pos(3), pos(4)), @@ -31,6 +31,12 @@ class Issue5306 extends DisplayTestCase { range: diagnosticsRange(pos(5), pos(6)), severity: Error, args: "Missing ;" + }, + { + kind: DKCompilerError, + range: diagnosticsRange(pos(7), pos(8)), + severity: Warning, + args: "This code has no effect" } ]; arrayEq(expected, diagnostics()); diff --git a/tests/display/src/cases/Issue7114.hx b/tests/display/src/cases/Issue7114.hx index 0d2cf4cd38d9d2009a25d998d5e1b11594da2d9d..e278936aa4b153f17e13d28d2c774558d05206d2 100644 --- a/tests/display/src/cases/Issue7114.hx +++ b/tests/display/src/cases/Issue7114.hx @@ -9,53 +9,51 @@ class Issue7114 extends DisplayTestCase { using haxe.macro.ExprTools; class Macro { - public static macro function example_macro(e:Expr):Expr - { - trace('Block before macro:\n${ e.toString() }'); + public static macro function example_macro(e:Expr):Expr { + trace('Block before macro:\n${e.toString()}'); - function injectCasts(ident:String, ct:ComplexType, expr:Expr):Expr - { - if (expr == null) return null; - switch (expr.expr) { - case EConst(CIdent(id)) if (id==ident): - var rtn = macro ((cast $i{ ident }):$ct); - rtn.pos = expr.pos; - return rtn; - default: - } + function injectCasts(ident:String, ct:ComplexType, expr:Expr):Expr { + if (expr == null) + return null; + switch (expr.expr) { + case EConst(CIdent(id)) if (id == ident): + var rtn = macro((cast $i{ident}) : $ct); + rtn.pos = expr.pos; + return rtn; + default: + } - return ExprTools.map(expr, function(e:Expr) return injectCasts(ident, ct, e) ); - } + return ExprTools.map(expr, function(e:Expr) return injectCasts(ident, ct, e)); + } - var blk = injectCasts('macro_override_cast', (macro :String), e); + var blk = injectCasts('macro_override_cast', (macro:String), e); - var rtn = macro { - var macro_injected:String = "injected"; - var macro_override_var:String = cast macro_override_var; - $blk; - }; + var rtn = macro { + var macro_injected:String = "injected"; + var macro_override_var:String = cast macro_override_var; + $blk; + }; - trace('Block after macro:\n${ rtn.toString() }'); - return rtn; - } + trace('Block after macro:\n${rtn.toString()}'); + return rtn; + } + } class Test { - static function main() { + static function main() { + var macro_override_var:SomeDynamic = "barbar"; + var macro_override_cast:SomeDynamic = "foofoo"; - var macro_override_var:SomeDynamic = "barbar"; - var macro_override_cast:SomeDynamic = "foofoo"; - - Macro.example_macro({ - macro_injected.{-1-} - macro_override_var.{-2-} - macro_override_cast.{-3-} - }); - } + Macro.example_macro({ + macro_injected.{-1-} + macro_override_var.{-2-} + macro_override_cast.{-3-} + }); + } } abstract SomeDynamic(Dynamic) from Dynamic { - public function oh_no__wrong_completions() {} - } + public function oh_no__wrong_completions() {} } **/ function test() { diff --git a/tests/display/src/cases/Issue7703.hx b/tests/display/src/cases/Issue7703.hx new file mode 100644 index 0000000000000000000000000000000000000000..3bff7a27cea3a9d6cb1fb0d45f6b60ebdff86d93 --- /dev/null +++ b/tests/display/src/cases/Issue7703.hx @@ -0,0 +1,23 @@ +package cases; + +class Issue7703 extends DisplayTestCase { + /** + class Main { + public static function main() { + f{-1-}oo({-2-}""); + {-3-} + } + + static macro function foo(s:String) { + return macro {}; + } + } + **/ + function test() { + var expectedType = "(s : String) -> haxe.macro.Expr"; + var fields = toplevel(pos(1)); + eq(true, hasToplevel(fields, "static", "foo", expectedType)); + eq(expectedType, type(pos(1))); + sigEq(0, [["s:String"]], signature(pos(2))); + } +} diff --git a/tests/display/src/cases/Issue7864.hx b/tests/display/src/cases/Issue7864.hx new file mode 100644 index 0000000000000000000000000000000000000000..016dac8cdc621329716b394951a623e5cf656116 --- /dev/null +++ b/tests/display/src/cases/Issue7864.hx @@ -0,0 +1,18 @@ +package cases; + +class Issue7864 extends DisplayTestCase { + /** + @{-1-} + class Main { + static function main() { + } + } + + @{-2-} + class Test {} + **/ + function test() { + eq(true, hasField(fields(pos(1)), "@:enum", "", "metadata")); + eq(true, hasField(fields(pos(2)), "@:enum", "", "metadata")); + } +} diff --git a/tests/display/src/cases/Issue7944.hx b/tests/display/src/cases/Issue7944.hx new file mode 100644 index 0000000000000000000000000000000000000000..914612581398b7387a56fc8ae0ff49fdf264e4e2 --- /dev/null +++ b/tests/display/src/cases/Issue7944.hx @@ -0,0 +1,21 @@ +package cases; + +class Issue7944 extends DisplayTestCase { + /** + class Main { + static function main() {} + + {-1-}fun{-2-} f() {} + } + **/ + function test() { + arrayEq([ + { + kind: DKParserError, + severity: Error, + range: diagnosticsRange(pos(1), pos(2)), + args: "Unexpected fun" + } + ], diagnostics()); + } +} diff --git a/tests/display/src/cases/Issue7945.hx b/tests/display/src/cases/Issue7945.hx index 74d028aa8489ffab063330d25fdfede614afdca1..6ee2c3c35e0395e82b1784d5092947182c7621ed 100644 --- a/tests/display/src/cases/Issue7945.hx +++ b/tests/display/src/cases/Issue7945.hx @@ -10,7 +10,7 @@ class Issue7945 extends DisplayTestCase { kind: DKParserError, severity: Error, range: diagnosticsRange(pos(1), pos(2)), - args: "Unexpected too" + args: "Expected { or to or from" } ], diagnostics()); } diff --git a/tests/display/src/cases/Issue7948.hx b/tests/display/src/cases/Issue7948.hx new file mode 100644 index 0000000000000000000000000000000000000000..9c2bdcebc2711e12967019e35857343a73f28882 --- /dev/null +++ b/tests/display/src/cases/Issue7948.hx @@ -0,0 +1,39 @@ +package cases; + +class Issue7948 extends DisplayTestCase { + /** + class Main { + {-1-}class{-2-} Moin { + + } + } + **/ + function test() { + arrayEq([ + { + kind: DKParserError, + severity: Error, + range: diagnosticsRange(pos(1), pos(2)), + args: "Unexpected class" + } + ], diagnostics()); + } + + /** + class Main { + static function main() + trace("Test"); + } + {-1-}}{-2-} + **/ + function test2() { + arrayEq([ + { + kind: DKParserError, + severity: Error, + range: diagnosticsRange(pos(1), pos(2)), + args: "Unexpected }" + } + ], diagnostics()); + } +} diff --git a/tests/display/src/cases/Issue8789.hx b/tests/display/src/cases/Issue8789.hx new file mode 100644 index 0000000000000000000000000000000000000000..18de8238cc797f3bdbd9b3d08f838924d717fd24 --- /dev/null +++ b/tests/display/src/cases/Issue8789.hx @@ -0,0 +1,23 @@ +package cases; + +class Issue8789 extends DisplayTestCase { + /** + abstract Int8(Int) { + inline function new(value:Int) { + this = value; + } + + inline function pvt() {} + + public function test() { + var i = new Int8{-1-}(10); + i.{-2-} + } + } + **/ + function test() { + var r = toplevel(pos(1)); + eq(true, hasToplevel(r, "type", "Int8")); + eq(true, hasField(fields(pos(2)), "pvt", "Void -> Void")); + } +} diff --git a/tests/display/src/cases/Issue9077.hx b/tests/display/src/cases/Issue9077.hx new file mode 100644 index 0000000000000000000000000000000000000000..02cc9932ef32da9de7bc694e76414d34dca47ee5 --- /dev/null +++ b/tests/display/src/cases/Issue9077.hx @@ -0,0 +1,28 @@ +package cases; + +class Issue9077 extends DisplayTestCase { + /** + class Main { + macro static function m(shouldContain:Bool):haxe.macro.Expr { + var cls = haxe.macro.Context.getLocalClass(); + var pos = shouldContain && cls != null ? cls.get().pos : haxe.macro.Context.currentPos(); + if(haxe.macro.Context.containsDisplayPosition(pos)) { + return macro 'contains'; + } else { + return macro false; + } + } + + static function main() { + var str = m(true); + st{-1-}r; + var str = m(false); + st{-2-}r; + } + } + **/ + function test() { + eq("String", type(pos(1))); + eq("Bool", type(pos(2))); + } +} diff --git a/tests/display/src/cases/Issue9084.hx b/tests/display/src/cases/Issue9084.hx new file mode 100644 index 0000000000000000000000000000000000000000..12bfb3603673ac668799ab6ec46d2a9a68598605 --- /dev/null +++ b/tests/display/src/cases/Issue9084.hx @@ -0,0 +1,18 @@ +package cases; + +class Issue9084 extends DisplayTestCase { + /** + class A { + public function {-2-}new{-3-}() {} + } + + class Main { + static function main() { + A.n{-1-}ew; + } + } + **/ + function test() { + eq(range(2, 3), position(pos(1))); + } +} diff --git a/tests/display/src/cases/Issue9101.hx b/tests/display/src/cases/Issue9101.hx new file mode 100644 index 0000000000000000000000000000000000000000..019d858b2f15fe528aaec1620c925ae8886b7e60 --- /dev/null +++ b/tests/display/src/cases/Issue9101.hx @@ -0,0 +1,14 @@ +package cases; + +class Issue9101 extends DisplayTestCase { + /** + typedef T = { + ?{-1-}t{-2-}e{-3-}st:Int + } + **/ + function testCatch_noTypeHint() { + eq("Null", type(pos(1))); + eq("Null", type(pos(2))); + eq("Null", type(pos(3))); + } +} diff --git a/tests/display/src/cases/Issue9133.hx b/tests/display/src/cases/Issue9133.hx new file mode 100644 index 0000000000000000000000000000000000000000..d0b7c8bcdc7e26a0809881294934a79a63b7b516 --- /dev/null +++ b/tests/display/src/cases/Issue9133.hx @@ -0,0 +1,57 @@ +package cases; + +import utest.Assert; + +using Lambda; + +class Issue9133 extends DisplayTestCase { + /** + class Main { + static function main() { + var i = 1; + var s = ""; + + var map:Map = [ + {-1-} + **/ + function test1() { + var fields = toplevel(pos(1)); + var i1 = fields.findIndex(item -> item.kind == "local" && item.name == "i"); + var i2 = fields.findIndex(item -> item.kind == "local" && item.name == "s"); + Assert.isTrue(i1 < i2); + Assert.isTrue(i1 != -1); + } + + /** + class Main { + static function main() { + var i = 1; + var s = ""; + + var map:Map = [ + i => 1, + {-1-} + **/ + function test2() { + // Note: One could argue if `i` should really be suggested here because it currently + // causes a `Duplicate key` error. See https://github.com/HaxeFoundation/haxe/issues/9144 + // for more context. + var fields = toplevel(pos(1)); + var i1 = fields.findIndex(item -> item.kind == "local" && item.name == "i"); + var i2 = fields.findIndex(item -> item.kind == "local" && item.name == "s"); + Assert.isTrue(i1 < i2); + Assert.isTrue(i1 != -1); + } + + /** + class Main { + static function main() { + var i = 0; + {-1-}// comment + **/ + function test3() { + var fields = toplevel(pos(1)); + var i1 = fields.findIndex(item -> item.kind == "local" && item.name == "i"); + Assert.isTrue(i1 != -1); + } +} diff --git a/tests/display/src/cases/Issue9142.hx b/tests/display/src/cases/Issue9142.hx new file mode 100644 index 0000000000000000000000000000000000000000..f6dc01f58830aee01b9c4f94074ccbd2891cfed0 --- /dev/null +++ b/tests/display/src/cases/Issue9142.hx @@ -0,0 +1,159 @@ +package cases; + +class Issue9142 extends DisplayTestCase { + /** + import NonExistent; + + class Main { + static function main() { + "fo{-1-}o" + } + } + **/ + function testNonExistentImport() { + eq("String", type(pos(1))); + } + + /** + import lowercase; + + class Main { + static function main() { + "fo{-1-}o" + } + } + **/ + function testLowercaseImport() { + eq("String", type(pos(1))); + } + + /** + import haxe.Int64.__Int64; + + class Main { + static function main() { + "fo{-1-}o" + } + } + **/ + function testPrivateImport() { + eq("String", type(pos(1))); + } + + /** + import StringTools as st; + + class Main { + static function main() { + "fo{-1-}o" + } + } + **/ + function testLowercaseAliasImport() { + eq("String", type(pos(1))); + } + + /** + import StringTools.NonExistent; + + class Main { + static function main() { + "fo{-1-}o" + } + } + **/ + function testNonExistentSubtypeImport() { + eq("String", type(pos(1))); + } + + /** + import StringTools.StringTools.NonExistent; + + class Main { + static function main() { + "fo{-1-}o" + } + } + **/ + function testNonExistentSubtypeFieldImport() { + eq("String", type(pos(1))); + } + + /** + import StringTools.StringTools.nonExistent; + + class Main { + static function main() { + "fo{-1-}o" + } + } + **/ + function testNonExistentSubtypeFieldImport2() { + eq("String", type(pos(1))); + } + + /** + import StringTools.StrongTools.NonExistent; + + class Main { + static function main() { + "fo{-1-}o" + } + } + **/ + function testNonExistentSubtypeFieldImport3() { + eq("String", type(pos(1))); + } + + /** + import StringTools.StrongTools.nonExistent; + + class Main { + static function main() { + "fo{-1-}o" + } + } + **/ + function testNonExistentSubtypeFieldImport4() { + eq("String", type(pos(1))); + } + + /** + import StringTools.StringTools.StringTools.StringTools; + + class Main { + static function main() { + "fo{-1-}o" + } + } + **/ + function testTooMuchImport() { + eq("String", type(pos(1))); + } + + /** + import StringTools.StringTools.StringTools.StringTools.*; + + class Main { + static function main() { + "fo{-1-}o" + } + } + **/ + function testTooMuchImportAll() { + eq("String", type(pos(1))); + } + + /** + import StringTools.StrongTools.*; + + class Main { + static function main() { + "fo{-1-}o" + } + } + **/ + function testNonExistentSubtypeAll() { + eq("String", type(pos(1))); + } +} diff --git a/tests/display/src/cases/Issue9319.hx b/tests/display/src/cases/Issue9319.hx new file mode 100644 index 0000000000000000000000000000000000000000..090db80bde6f25fd8f1de38c3a3e8ba83c4b28ec --- /dev/null +++ b/tests/display/src/cases/Issue9319.hx @@ -0,0 +1,14 @@ +package cases; + +class Issue9319 extends DisplayTestCase { + /** + class Main { + static function main() { + try {} catch(e{-1-}) {} + } + } + **/ + function testCatch_noTypeHint() { + eq("haxe.Exception", type(pos(1))); + } +} diff --git a/tests/misc/compile.hxml b/tests/misc/compile.hxml index b0e2e03b51522d46f66f8b26378146d38f918ab8..6504a35683062dcd7823385c9c79dc88036f022e 100644 --- a/tests/misc/compile.hxml +++ b/tests/misc/compile.hxml @@ -1,3 +1,4 @@ -p src # -D MISC_TEST_FILTER=6790 ---run Main \ No newline at end of file +-main Main +--interp \ No newline at end of file diff --git a/tests/misc/cs/projects/Issue8347/Main.hx b/tests/misc/cs/projects/Issue8347/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..ce97ed29781fa0948bc61ca653afc6739c57242b --- /dev/null +++ b/tests/misc/cs/projects/Issue8347/Main.hx @@ -0,0 +1,7 @@ +import cs.system.reflection.AssemblyDelaySignAttribute; + +@:cs.assemblyMeta(Test) +class Main {} + +@:cs.assemblyStrict(cs.system.reflection.AssemblyDelaySignAttribute(true)) +class Main2 {} diff --git a/tests/misc/cs/projects/Issue8347/compile-fail.hxml b/tests/misc/cs/projects/Issue8347/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..0201ad45c7a1b7180bbfd595f49defa2155550ae --- /dev/null +++ b/tests/misc/cs/projects/Issue8347/compile-fail.hxml @@ -0,0 +1,5 @@ +-cp src +Main +fail.NotFirstType +-cs cs-fail +-D no-compilation diff --git a/tests/misc/cs/projects/Issue8347/compile-fail.hxml.stderr b/tests/misc/cs/projects/Issue8347/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..7a807b3e17ea5143b95bebde179d946de7fad4d4 --- /dev/null +++ b/tests/misc/cs/projects/Issue8347/compile-fail.hxml.stderr @@ -0,0 +1,4 @@ +src/fail/NotFirstType.hx:8: characters 1-22 : @:cs.assemblyStrict can only be used on the first class of a module +Main.hx:4: characters 1-14 : @:cs.assemblyMeta cannot be used on top level modules +Main.hx:7: characters 1-15 : @:cs.assemblyStrict can only be used on the first class of a module +Main.hx:7: characters 1-15 : @:cs.assemblyStrict cannot be used on top level modules diff --git a/tests/misc/cs/projects/Issue8347/compile.hxml b/tests/misc/cs/projects/Issue8347/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..11bc490c1a15243606bfa3fe4a4a0c7bc01df0c2 --- /dev/null +++ b/tests/misc/cs/projects/Issue8347/compile.hxml @@ -0,0 +1,3 @@ +-cp src +pack.Main +-cs bin diff --git a/tests/misc/cs/projects/Issue8347/src/fail/NotFirstType.hx b/tests/misc/cs/projects/Issue8347/src/fail/NotFirstType.hx new file mode 100644 index 0000000000000000000000000000000000000000..00bf05b61d4815018993731dcefdf6fe0a52186d --- /dev/null +++ b/tests/misc/cs/projects/Issue8347/src/fail/NotFirstType.hx @@ -0,0 +1,9 @@ +package fail; + +import cs.system.reflection.AssemblyDelaySignAttribute; + +enum SomeEnum {} + +@:cs.assemblyStrict(cs.system.reflection.AssemblyDelaySignAttribute(true)) +class NotFirstType {} + diff --git a/tests/misc/cs/projects/Issue8347/src/pack/Main.hx b/tests/misc/cs/projects/Issue8347/src/pack/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..87173d8dc173558d0cb72ef4aa8f5febd2c963ff --- /dev/null +++ b/tests/misc/cs/projects/Issue8347/src/pack/Main.hx @@ -0,0 +1,7 @@ +package pack; + +import cs.system.reflection.AssemblyDelaySignAttribute; + +@:cs.assemblyMeta(System.Reflection.AssemblyDefaultAliasAttribute("test")) +@:cs.assemblyStrict(cs.system.reflection.AssemblyDelaySignAttribute(true)) +class Main {} diff --git a/tests/misc/cs/projects/Issue8487/Main1.hx b/tests/misc/cs/projects/Issue8487/Main1.hx new file mode 100644 index 0000000000000000000000000000000000000000..6b5473fa5ac2a659a211dc87c7bc708eb90aeda9 --- /dev/null +++ b/tests/misc/cs/projects/Issue8487/Main1.hx @@ -0,0 +1,6 @@ +@:cs.using("System") +class Main1 { + public static function main():Void { + trace('ok'); + } +} diff --git a/tests/misc/cs/projects/Issue8487/Main2.hx b/tests/misc/cs/projects/Issue8487/Main2.hx new file mode 100644 index 0000000000000000000000000000000000000000..e35077279f281302bff1c9e12321c27b331c5893 --- /dev/null +++ b/tests/misc/cs/projects/Issue8487/Main2.hx @@ -0,0 +1,8 @@ +interface I {} + +@:cs.using("System") +class Main2 { + public static function main():Void { + trace('ko'); + } +} diff --git a/tests/misc/cs/projects/Issue8487/compile-fail.hxml b/tests/misc/cs/projects/Issue8487/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..dc8ec7d9a8f3558b6668dd340eafd990a51a1b63 --- /dev/null +++ b/tests/misc/cs/projects/Issue8487/compile-fail.hxml @@ -0,0 +1,2 @@ +-cs bin +-main Main2 diff --git a/tests/misc/cs/projects/Issue8487/compile-fail.hxml.stderr b/tests/misc/cs/projects/Issue8487/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..5f8cb28eb468ad81f684dba08a1e92394d815adb --- /dev/null +++ b/tests/misc/cs/projects/Issue8487/compile-fail.hxml.stderr @@ -0,0 +1 @@ +Main2.hx:3: characters 1-11 : @:cs.using can only be used on the first type of a module diff --git a/tests/misc/cs/projects/Issue8487/compile.hxml b/tests/misc/cs/projects/Issue8487/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fd2c2f07b6c8cd90d7d09f7241fddbd8c91a0937 --- /dev/null +++ b/tests/misc/cs/projects/Issue8487/compile.hxml @@ -0,0 +1,2 @@ +-cs bin +-main Main1 diff --git a/tests/misc/java/projects/Issue9210/Main.java b/tests/misc/java/projects/Issue9210/Main.java new file mode 100644 index 0000000000000000000000000000000000000000..44908756b630e0843068b7030ec718df5b10a201 --- /dev/null +++ b/tests/misc/java/projects/Issue9210/Main.java @@ -0,0 +1,14 @@ +import haxe.ds.Option; + +class Main { + public static void main(String[] args) { + Option option = Option.Some("test"); + if (option instanceof Option.Some) { + if (((Option.Some) option).v.equals("test")) { + System.exit(0); + } + } + System.out.println("Failed to match Some(\"test\")."); + System.exit(1); + } +} diff --git a/tests/misc/java/projects/Issue9210/Run.hx b/tests/misc/java/projects/Issue9210/Run.hx new file mode 100644 index 0000000000000000000000000000000000000000..14597c27869ae3f390bfeb34b3c20db9975dca9c --- /dev/null +++ b/tests/misc/java/projects/Issue9210/Run.hx @@ -0,0 +1,6 @@ +class Run { + static function main() { + var separator = if (Sys.systemName() == "Windows") ";" else ":"; + Sys.exit(Sys.command('java -cp "bin/*${separator}bin" Main')); + } +} diff --git a/tests/misc/java/projects/Issue9210/compile.hxml b/tests/misc/java/projects/Issue9210/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..1c2d888084fc9609c3c6501d0ba6874227c19acc --- /dev/null +++ b/tests/misc/java/projects/Issue9210/compile.hxml @@ -0,0 +1,11 @@ +--java bin +-D jvm +haxe.ds.Option + +--next + +--cmd javac -d bin -cp "bin/*" Main.java + +--next + +--run Run diff --git a/tests/misc/lua/projects/Issue9402/Main.hx b/tests/misc/lua/projects/Issue9402/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..379b5b7864838548b4c5929ce3401fe8ea2f3807 --- /dev/null +++ b/tests/misc/lua/projects/Issue9402/Main.hx @@ -0,0 +1,8 @@ +import haxe.Timer; + +class Main { + static function main() { + Sys.stderr().writeString('Success'); + Sys.stderr().flush(); + } +} \ No newline at end of file diff --git a/tests/misc/lua/projects/Issue9402/compile.hxml b/tests/misc/lua/projects/Issue9402/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..0fa80d924ca269310dafb1464068ae79c1b42d5a --- /dev/null +++ b/tests/misc/lua/projects/Issue9402/compile.hxml @@ -0,0 +1,3 @@ +-main Main +-lua bin/test.lua +--cmd lua bin/test.lua \ No newline at end of file diff --git a/tests/misc/lua/projects/Issue9402/compile.hxml.stderr b/tests/misc/lua/projects/Issue9402/compile.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..51da4200abb928986170b996f71fb3dbeba71c1d --- /dev/null +++ b/tests/misc/lua/projects/Issue9402/compile.hxml.stderr @@ -0,0 +1 @@ +Success \ No newline at end of file diff --git a/tests/misc/lua/run.hxml b/tests/misc/lua/run.hxml new file mode 100644 index 0000000000000000000000000000000000000000..b72a6e8015f79b90f1a33b56ffd247f513c52a0d --- /dev/null +++ b/tests/misc/lua/run.hxml @@ -0,0 +1,2 @@ +-cp ../src +--run Main \ No newline at end of file diff --git a/tests/misc/projects/Issue1968/compile.hxml.stderr b/tests/misc/projects/Issue1968/compile.hxml.stderr index b6615cde59031ccee4890755da00dd6bfd1c9655..4624d5d880a453767d8d271f9b91f3d46988b63d 100644 --- a/tests/misc/projects/Issue1968/compile.hxml.stderr +++ b/tests/misc/projects/Issue1968/compile.hxml.stderr @@ -1,3 +1,3 @@ -$$normPath(::cwd::/Main.hx, true):4: characters 28-29 +$$normPath(::cwd::/Main.hx):4: characters 28-29 diff --git a/tests/misc/projects/Issue2087/compile-fail.hxml.stderr b/tests/misc/projects/Issue2087/compile-fail.hxml.stderr index 46ece41697506705d6e87af4d19eec771886f6c9..388d354116726b6e4669deb5eddcc5a413247e85 100644 --- a/tests/misc/projects/Issue2087/compile-fail.hxml.stderr +++ b/tests/misc/projects/Issue2087/compile-fail.hxml.stderr @@ -1 +1 @@ -Main.hx:3: characters 3-7 : Type not found : haxe.Resauce \ No newline at end of file +Main.hx:3: characters 3-15 : Type not found : haxe.Resauce \ No newline at end of file diff --git a/tests/misc/projects/Issue2969/compile-fail.hxml.stderr b/tests/misc/projects/Issue2969/compile-fail.hxml.stderr index b974040d2d9f49a624b71a9f42013fdfbe96a488..b34ec3b3d4cd63cf4c277095d9023b7760a0efda 100644 --- a/tests/misc/projects/Issue2969/compile-fail.hxml.stderr +++ b/tests/misc/projects/Issue2969/compile-fail.hxml.stderr @@ -1,5 +1,5 @@ -Main.hx:9: lines 9-11 : Field a has different type than in A +Main.hx:10: characters 18-19 : Field a has different type than in A Main.hx:2: characters 2-29 : Interface field is defined here -Main.hx:9: lines 9-11 : error: Int should be String -Main.hx:9: lines 9-11 : have: (...) -> Int -Main.hx:9: lines 9-11 : want: (...) -> String \ No newline at end of file +Main.hx:10: characters 18-19 : error: Int should be String +Main.hx:10: characters 18-19 : have: (...) -> Int +Main.hx:10: characters 18-19 : want: (...) -> String \ No newline at end of file diff --git a/tests/misc/projects/Issue2991/compile.hxml.stderr b/tests/misc/projects/Issue2991/compile.hxml.stderr index 8889bb4714ebd299b0680c3e54a822492a500b46..fe70bd99298dfb16dc07bf2854a42aab574a5871 100644 --- a/tests/misc/projects/Issue2991/compile.hxml.stderr +++ b/tests/misc/projects/Issue2991/compile.hxml.stderr @@ -1,3 +1,3 @@ -$$normPath(::cwd::/Main.hx, true):6: characters 13-14 +$$normPath(::cwd::/Main.hx):6: characters 13-14 diff --git a/tests/misc/projects/Issue2993/compile.hxml.stderr b/tests/misc/projects/Issue2993/compile.hxml.stderr index e15e8f19cdad6e44db59171a933826dbe1254f48..41b31aab8827e75f03f1428309fcec037c57cc33 100644 --- a/tests/misc/projects/Issue2993/compile.hxml.stderr +++ b/tests/misc/projects/Issue2993/compile.hxml.stderr @@ -1,3 +1,3 @@ -$$normPath(::cwd::/Main.hx, true):2: characters 16-19 +$$normPath(::cwd::/Main.hx):2: characters 16-19 diff --git a/tests/misc/projects/Issue2995/position.hxml.stderr b/tests/misc/projects/Issue2995/position.hxml.stderr index 97f4137305bf52a86e67affba5db589cefd37cb9..58ebe806aac8be94595157ab77e5b59481e5399b 100644 --- a/tests/misc/projects/Issue2995/position.hxml.stderr +++ b/tests/misc/projects/Issue2995/position.hxml.stderr @@ -1,3 +1,3 @@ -$$normPath(::cwd::/Main.hx, true):2: characters 14-17 +$$normPath(::cwd::/Main.hx):2: characters 14-17 diff --git a/tests/misc/projects/Issue2995/usage.hxml.stderr b/tests/misc/projects/Issue2995/usage.hxml.stderr index f7c2bfd6a9ef7190857a8a5835507989b7146f7c..a1d9e4d480a9ca7aa29f68426d7747388b4ba7eb 100644 --- a/tests/misc/projects/Issue2995/usage.hxml.stderr +++ b/tests/misc/projects/Issue2995/usage.hxml.stderr @@ -1,4 +1,4 @@ -$$normPath(::cwd::/Main.hx, true):5: characters 17-27 -$$normPath(::cwd::/Main.hx, true):9: characters 9-19 +$$normPath(::cwd::/Main.hx):5: characters 17-27 +$$normPath(::cwd::/Main.hx):9: characters 9-19 diff --git a/tests/misc/projects/Issue2996/compile1.hxml.stderr b/tests/misc/projects/Issue2996/compile1.hxml.stderr index f16feba32483dd17307b3ef12944c47e01f29e51..50e88f178e988f8b47880edccf37a15c5767d82b 100644 --- a/tests/misc/projects/Issue2996/compile1.hxml.stderr +++ b/tests/misc/projects/Issue2996/compile1.hxml.stderr @@ -1,3 +1,3 @@ -$$normPath(::cwd::/A.hx, true):1: characters 1-22 +$$normPath(::cwd::/A.hx):1: characters 1-22 \ No newline at end of file diff --git a/tests/misc/projects/Issue2996/compile2.hxml.stderr b/tests/misc/projects/Issue2996/compile2.hxml.stderr index 0bd4745792a5c8e3e52c828107ac8c49bd197994..861c61324f99e0a94696bd7325c9f82e7657bc5f 100644 --- a/tests/misc/projects/Issue2996/compile2.hxml.stderr +++ b/tests/misc/projects/Issue2996/compile2.hxml.stderr @@ -1,3 +1,3 @@ -$$normPath(::cwd::/pack/B.hx, true):3: characters 1-11 +$$normPath(::cwd::/pack/B.hx):3: characters 1-11 diff --git a/tests/misc/projects/Issue2997/compile1.hxml.stderr b/tests/misc/projects/Issue2997/compile1.hxml.stderr index c23703cafc877076120ccb0aa47722a80c255512..7fd4bfa35b530f062e1c20c84ed8055eb1c418d8 100644 --- a/tests/misc/projects/Issue2997/compile1.hxml.stderr +++ b/tests/misc/projects/Issue2997/compile1.hxml.stderr @@ -1,3 +1,3 @@ -$$normPath(::cwd::/Main.hx, true):2: characters 9-10 +$$normPath(::cwd::/Main.hx):2: characters 9-10 \ No newline at end of file diff --git a/tests/misc/projects/Issue3361/compile1-fail.hxml.stderr b/tests/misc/projects/Issue3361/compile1-fail.hxml.stderr index a7ad02ebaacb5627f4432f97a099d92f5cccad21..089d9a4d384ffa120a5dab04cb5c5b6c03bd4d16 100644 --- a/tests/misc/projects/Issue3361/compile1-fail.hxml.stderr +++ b/tests/misc/projects/Issue3361/compile1-fail.hxml.stderr @@ -1,5 +1,5 @@ -Main.hx:5: lines 5-8 : Field v has different type than in I +Main.hx:6: characters 13-14 : Field v has different type than in I Main.hx:2: characters 2-29 : Interface field is defined here -Main.hx:5: lines 5-8 : error: String should be Dynamic -Main.hx:5: lines 5-8 : have: (Dynamic) -> ... -Main.hx:5: lines 5-8 : want: (String) -> ... \ No newline at end of file +Main.hx:6: characters 13-14 : error: String should be Dynamic +Main.hx:6: characters 13-14 : have: (Dynamic) -> ... +Main.hx:6: characters 13-14 : want: (String) -> ... \ No newline at end of file diff --git a/tests/misc/projects/Issue3361/compile2-fail.hxml.stderr b/tests/misc/projects/Issue3361/compile2-fail.hxml.stderr index 16f8dd9950c14d749c138c6bf9e9ce663156501b..b2070d57c64a488f66d9129890a48759ac80363c 100644 --- a/tests/misc/projects/Issue3361/compile2-fail.hxml.stderr +++ b/tests/misc/projects/Issue3361/compile2-fail.hxml.stderr @@ -1,5 +1,5 @@ -Main2.hx:6: characters 2-46 : Field f has different type than in I +Main2.hx:6: characters 26-27 : Field f has different type than in I Main2.hx:2: characters 2-44 : Interface field is defined here -Main2.hx:6: characters 2-46 : error: String should be Dynamic -Main2.hx:6: characters 2-46 : have: (Dynamic) -> ... -Main2.hx:6: characters 2-46 : want: (String) -> ... \ No newline at end of file +Main2.hx:6: characters 26-27 : error: String should be Dynamic +Main2.hx:6: characters 26-27 : have: (Dynamic) -> ... +Main2.hx:6: characters 26-27 : want: (String) -> ... \ No newline at end of file diff --git a/tests/misc/projects/Issue3417/compile-fail.hxml.stderr b/tests/misc/projects/Issue3417/compile-fail.hxml.stderr index 59246a36baaf05ee7cd382dd0321663997676c3d..3fd051f173ebf4314d10f0f53124884aa52ee775 100644 --- a/tests/misc/projects/Issue3417/compile-fail.hxml.stderr +++ b/tests/misc/projects/Issue3417/compile-fail.hxml.stderr @@ -1,3 +1,3 @@ -Main.hx:6: characters 5-27 : Field f has different type than in I +Main.hx:6: characters 21-22 : Field f has different type than in I Main.hx:2: characters 5-28 : Interface field is defined here -Main.hx:6: characters 5-27 : Different number of function arguments \ No newline at end of file +Main.hx:6: characters 21-22 : Different number of function arguments \ No newline at end of file diff --git a/tests/misc/projects/Issue4378/compile-fail.hxml.stderr b/tests/misc/projects/Issue4378/compile-fail.hxml.stderr index ddf928aafdfa5536939fa59ced42ce00cfc822a8..f47ba7644b704d5e234b0be34dee66cec88e574f 100644 --- a/tests/misc/projects/Issue4378/compile-fail.hxml.stderr +++ b/tests/misc/projects/Issue4378/compile-fail.hxml.stderr @@ -1,5 +1,5 @@ -Main.hx:5: lines 5-7 : Field test has different type than in I +Main.hx:5: characters 18-22 : Field test has different type than in I Main.hx:16: characters 2-32 : Interface field is defined here -Main.hx:5: lines 5-7 : error: String should be Dynamic -Main.hx:5: lines 5-7 : have: (Dynamic) -> ... -Main.hx:5: lines 5-7 : want: (String) -> ... \ No newline at end of file +Main.hx:5: characters 18-22 : error: String should be Dynamic +Main.hx:5: characters 18-22 : have: (Dynamic) -> ... +Main.hx:5: characters 18-22 : want: (String) -> ... \ No newline at end of file diff --git a/tests/misc/projects/Issue4720/compile.hxml.stderr b/tests/misc/projects/Issue4720/compile.hxml.stderr index 42120f29ba67510aaf2e559bb992e09dc9ca2b88..215e2f55f4480a0d8ff6f90d68084b13b864e8ac 100644 --- a/tests/misc/projects/Issue4720/compile.hxml.stderr +++ b/tests/misc/projects/Issue4720/compile.hxml.stderr @@ -2,7 +2,7 @@ Main.hx:8: characters 9-15 : Warning : Usage of this typedef is deprecated Main.hx:9: characters 9-19 : Warning : Usage of this typedef is deprecated Main.hx:10: characters 9-14 : Warning : Usage of this typedef is deprecated Main.hx:18: characters 13-19 : Warning : This typedef is deprecated in favor of MyClass -Main.hx:19: characters 9-19 : Warning : Usage of this typedef is deprecated +Main.hx:19: characters 9-14 : Warning : Usage of this typedef is deprecated Main.hx:20: characters 13-22 : Warning : This typedef is deprecated in favor of MyAbstract Main.hx:32: characters 9-13 : Warning : Usage of this enum is deprecated Main.hx:36: characters 9-14 : Warning : Usage of this enum field is deprecated @@ -10,7 +10,7 @@ Main.hx:4: characters 9-16 : Warning : Usage of this class is deprecated Main.hx:5: characters 9-20 : Warning : Usage of this class is deprecated Main.hx:6: characters 9-15 : Warning : Usage of this enum is deprecated Main.hx:15: characters 9-22 : Warning : Usage of this class is deprecated -Main.hx:16: characters 9-20 : Warning : Usage of this enum is deprecated +Main.hx:16: characters 9-15 : Warning : Usage of this enum is deprecated Main.hx:17: characters 9-29 : Warning : Usage of this class is deprecated Main.hx:18: characters 9-21 : Warning : Usage of this class is deprecated Main.hx:20: characters 9-28 : Warning : Usage of this class is deprecated diff --git a/tests/misc/projects/Issue4803/compile-fail.hxml.stderr b/tests/misc/projects/Issue4803/compile-fail.hxml.stderr index 80534c0305bed82ed600e08d7eee53a06f323783..3688592c41d6ed0db63902c67fc0ec2309d56f30 100644 --- a/tests/misc/projects/Issue4803/compile-fail.hxml.stderr +++ b/tests/misc/projects/Issue4803/compile-fail.hxml.stderr @@ -4,7 +4,7 @@ Main.hx:16: lines 16-19 : Too many arguments Main.hx:16: lines 16-19 : Overload resolution failed for (handler : (Event -> Void)) -> JQuery Main.hx:18: characters 8-17 : Object requires field y Main.hx:18: characters 8-17 : For function argument 'handler' -Main.hx:16: lines 16-19 : Overload resolution failed for (?eventData : Dynamic, handler : (Event -> Void)) -> JQuery +Main.hx:16: lines 16-19 : Overload resolution failed for (?eventData : Null, handler : (Event -> Void)) -> JQuery Main.hx:18: characters 8-17 : Object requires field y Main.hx:18: characters 8-17 : For optional function argument 'eventData' Main.hx:16: lines 16-19 : End of overload failure reasons \ No newline at end of file diff --git a/tests/misc/projects/Issue5123/compile.hxml.stderr b/tests/misc/projects/Issue5123/compile.hxml.stderr index 226ae94bb1d20994cb4d8ea17b721d33cc303312..e74465e2d267843760a12b9220b0ba1743040b12 100644 --- a/tests/misc/projects/Issue5123/compile.hxml.stderr +++ b/tests/misc/projects/Issue5123/compile.hxml.stderr @@ -1,3 +1,3 @@ -$$normPath(::cwd::/Main.hx, true):5: characters 18-35 +$$normPath(::cwd::/Main.hx):5: characters 18-35 diff --git a/tests/misc/projects/Issue5525/Main.hx b/tests/misc/projects/Issue5525/Main.hx index 9aee913f60c81e58a9082aeba01868799a1a7f1e..8ea412dffd64c716ff7e423288e67ff63b6e4c1b 100644 --- a/tests/misc/projects/Issue5525/Main.hx +++ b/tests/misc/projects/Issue5525/Main.hx @@ -12,7 +12,7 @@ class Main { @:arrayAccess abstract A { inline public function new() { - this = untyped __js__("{}"); + this = js.Syntax.code("{}"); } } @@ -21,6 +21,6 @@ typedef TB = B; @:arrayAccess abstract B(TB) { inline public function new() { - this = untyped __js__("{}"); + this = js.Syntax.code("{}"); } } \ No newline at end of file diff --git a/tests/misc/projects/Issue5525/compile-fail.hxml b/tests/misc/projects/Issue5525/compile-fail.hxml index fab0aeecc3dd8ce41c99d29d48c23ec66b19d3c1..45e77643dc5dc8e9477616fc5b8aee4e26abe491 100644 --- a/tests/misc/projects/Issue5525/compile-fail.hxml +++ b/tests/misc/projects/Issue5525/compile-fail.hxml @@ -1 +1,2 @@ ---main Main \ No newline at end of file +--main Main +--js bin/test.js \ No newline at end of file diff --git a/tests/misc/projects/Issue5949/compile-fail.hxml.stderr b/tests/misc/projects/Issue5949/compile-fail.hxml.stderr index 22411af2b65f5ffdcb046d655040cfd8a2f4b2f5..eff50e391f17c887c475af0739a64a78dab2f1f7 100644 --- a/tests/misc/projects/Issue5949/compile-fail.hxml.stderr +++ b/tests/misc/projects/Issue5949/compile-fail.hxml.stderr @@ -1,3 +1,3 @@ -Main.hx:11: characters 16-47 : Field a has different @:native value than in superclass -Main.hx:6: characters 2-24 : Base field is defined here +Main.hx:11: characters 11-14 : Field a has different @:native value than in superclass +Main.hx:6: characters 18-19 : Base field is defined here Main.hx:10: lines 10-12 : Defined in this class \ No newline at end of file diff --git a/tests/misc/projects/Issue6435/Main.js.hx b/tests/misc/projects/Issue6435/Main.js.hx new file mode 100644 index 0000000000000000000000000000000000000000..dd89a0dc652d814c64b982312c93736bab5b6377 --- /dev/null +++ b/tests/misc/projects/Issue6435/Main.js.hx @@ -0,0 +1,3 @@ +class Main { + static function main() {} +} \ No newline at end of file diff --git a/tests/misc/projects/Issue6435/compile.hxml b/tests/misc/projects/Issue6435/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..1f0692172cff8fb8d81016672b52061f59459dad --- /dev/null +++ b/tests/misc/projects/Issue6435/compile.hxml @@ -0,0 +1,3 @@ +-main Main +-js bin/test.js +--display Main.js.hx@0@diagnostics \ No newline at end of file diff --git a/tests/misc/projects/Issue6699/compile-fail.hxml.stderr b/tests/misc/projects/Issue6699/compile-fail.hxml.stderr index 4455f4cff4ebf7f5dad2abc654363d4cfaae5974..641672f8b546b8615dc6218e36fb8f04803d58c9 100644 --- a/tests/misc/projects/Issue6699/compile-fail.hxml.stderr +++ b/tests/misc/projects/Issue6699/compile-fail.hxml.stderr @@ -1 +1 @@ -Main.hx:7: lines 7-8 : Field foo should be declared with 'override' since it is inherited from superclass A \ No newline at end of file +Main.hx:7: characters 11-14 : Field foo should be declared with 'override' since it is inherited from superclass A \ No newline at end of file diff --git a/tests/misc/projects/Issue6796/Main.hx b/tests/misc/projects/Issue6796/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..e11fbbb76b75771366d7a1f98262cf7e793f32e9 --- /dev/null +++ b/tests/misc/projects/Issue6796/Main.hx @@ -0,0 +1,5 @@ +class Main { + public static function main() { + Sys.println(main["foo"]); + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue6796/compile-fail.hxml b/tests/misc/projects/Issue6796/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue6796/compile-fail.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue6796/compile-fail.hxml.stderr b/tests/misc/projects/Issue6796/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..b463875206d2b8895c15d6f27b64556b30a98044 --- /dev/null +++ b/tests/misc/projects/Issue6796/compile-fail.hxml.stderr @@ -0,0 +1,2 @@ +Main.hx:3: characters 21-25 : Array access is not allowed on Void -> Unknown<0> +Main.hx:3: characters 21-25 : For function argument 'v' \ No newline at end of file diff --git a/tests/misc/projects/Issue6810/Fail.hx b/tests/misc/projects/Issue6810/Fail.hx new file mode 100644 index 0000000000000000000000000000000000000000..8a77bd2d7990b55190a911821ef01eef453298e3 --- /dev/null +++ b/tests/misc/projects/Issue6810/Fail.hx @@ -0,0 +1,14 @@ +import haxe.Constraints.NotVoid; + +typedef FakeVoid = Void; + +class Fail { + public static function main() { + test(void); + test(fakeVoid); + } + + static function void():Void {} + static function fakeVoid():FakeVoid {} + static function test(f:Void->T):T return f(); +} diff --git a/tests/misc/projects/Issue6810/Main.hx b/tests/misc/projects/Issue6810/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..c0c2c3453110ad27920cf905c7963efd32eaedb5 --- /dev/null +++ b/tests/misc/projects/Issue6810/Main.hx @@ -0,0 +1,11 @@ +import haxe.Constraints.NotVoid; + +class Main { + public static function main() { + test(function() return 42); + test(function() return "test"); + } + + static function test(f:Void->T):T return f(); +} + diff --git a/tests/misc/projects/Issue6810/compile-fail.hxml b/tests/misc/projects/Issue6810/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..7acf375871c62509021101beb07ca3476d96a5ac --- /dev/null +++ b/tests/misc/projects/Issue6810/compile-fail.hxml @@ -0,0 +1 @@ +Fail diff --git a/tests/misc/projects/Issue6810/compile-fail.hxml.stderr b/tests/misc/projects/Issue6810/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..2243844f0f349923e0e29a38aa120390fd759dd8 --- /dev/null +++ b/tests/misc/projects/Issue6810/compile-fail.hxml.stderr @@ -0,0 +1,4 @@ +Fail.hx:8: characters 3-7 : Constraint check failure for test.T +Fail.hx:8: characters 3-7 : FakeVoid should be haxe.NotVoid +Fail.hx:7: characters 3-7 : Constraint check failure for test.T +Fail.hx:7: characters 3-7 : Void should be haxe.NotVoid diff --git a/tests/misc/projects/Issue6810/compile.hxml b/tests/misc/projects/Issue6810/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..42409e72918a42a82dd3b99f48443419487fab57 --- /dev/null +++ b/tests/misc/projects/Issue6810/compile.hxml @@ -0,0 +1 @@ +-main Main diff --git a/tests/misc/projects/Issue7447/Main.hx b/tests/misc/projects/Issue7447/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..bc8869dd54d610a4663dc9f2f9b38725589b1aae --- /dev/null +++ b/tests/misc/projects/Issue7447/Main.hx @@ -0,0 +1,12 @@ +class Main { + static function main() { + var v; + trace(() -> v); + } +} + +abstract Abstr(Int) { + public inline function new() { + trace(() -> this); + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue7447/compile.hxml b/tests/misc/projects/Issue7447/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue7447/compile.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue7447/compile.hxml.stderr b/tests/misc/projects/Issue7447/compile.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..7c5d4eb31b5a53f3be4818fde35231e7bc5a464d --- /dev/null +++ b/tests/misc/projects/Issue7447/compile.hxml.stderr @@ -0,0 +1,2 @@ +Main.hx:4: characters 15-16 : Warning : Local variable v might be used before being initialized +Main.hx:10: characters 15-19 : Warning : this might be used before assigning a value to it \ No newline at end of file diff --git a/tests/misc/projects/Issue7526/compile-fail.hxml.stderr b/tests/misc/projects/Issue7526/compile-fail.hxml.stderr index 5ac7df5e9c2fe35814156eecf8e28de3a3fc8cdd..1df59d2062005488784fa4618535e662ec63b710 100644 --- a/tests/misc/projects/Issue7526/compile-fail.hxml.stderr +++ b/tests/misc/projects/Issue7526/compile-fail.hxml.stderr @@ -1,4 +1,4 @@ Main.hx:16: characters 9-29 : Class should be { member : Int } Main.hx:16: characters 9-29 : The field member is not public -Main.hx:17: characters 9-29 : Class<_Main.A_Impl_> should be { member : Int } +Main.hx:17: characters 9-29 : Abstract should be { member : Int } Main.hx:17: characters 9-29 : The field member is not public \ No newline at end of file diff --git a/tests/misc/projects/Issue7559/Main.hx b/tests/misc/projects/Issue7559/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..ded0d6119e88c0b838e5c343d0c56257d23eb8c8 --- /dev/null +++ b/tests/misc/projects/Issue7559/Main.hx @@ -0,0 +1,54 @@ +class Main { + static function main() { + final base:NullChild = {}; + final base:BaseEmpty = {}; + final base:ChildEmpty = {}; + final base:Base = {}; + final child:Child = {base: 200, child: 100}; + final child:Child = {child: 100}; + final child:OptionalChild = {}; + final child:OptionalEmptyChild = {}; + final child:FatChild = {}; + final child:FatEmptyChild = {}; + } +} +@:structInit +class BaseNullEmpty { + final base:Null; +} +@:structInit +class NullChild extends BaseNullEmpty { + @:optional final child: Int; +} +@:structInit +class BaseEmpty { + final base:Int; +} +@:structInit +class Base { + final base = 0; +} +@:structInit +class OptionalChild extends Base { + @:optional final child: Int; +} +@:structInit +class OptionalEmptyChild extends BaseEmpty { + @:optional final child: Int; +} +@:structInit +class Child extends Base { + final child: Int; +} +@:structInit +class ChildEmpty extends BaseEmpty { + final child: Int; +} +@:structInit +class FatChild extends Child { + final fatChild: Int; +} +@:structInit +class FatEmptyChild extends ChildEmpty { + final fatChild: Int; +} diff --git a/tests/misc/projects/Issue7559/compile-fail.hxml b/tests/misc/projects/Issue7559/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..e2a3d27a1903cc58c64892f2c3cacd367f3533ef --- /dev/null +++ b/tests/misc/projects/Issue7559/compile-fail.hxml @@ -0,0 +1,2 @@ +--main Main +--interp diff --git a/tests/misc/projects/Issue7559/compile-fail.hxml.stderr b/tests/misc/projects/Issue7559/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..60fa26b03689c26b91d8d299197f7ef1647ae809 --- /dev/null +++ b/tests/misc/projects/Issue7559/compile-fail.hxml.stderr @@ -0,0 +1,6 @@ +Main.hx:3: characters 26-28 : Object requires field base +Main.hx:4: characters 26-28 : Object requires field base +Main.hx:5: characters 27-29 : Object requires fields: child, base +Main.hx:10: characters 36-38 : Object requires field base +Main.hx:11: characters 26-28 : Object requires fields: fatChild, child +Main.hx:12: characters 31-33 : Object requires fields: fatChild, child, base diff --git a/tests/misc/projects/Issue7809/ReturnEarly.hx b/tests/misc/projects/Issue7809/ReturnEarly.hx new file mode 100644 index 0000000000000000000000000000000000000000..fe535177d66193c9f23361112dfabc5630d76467 --- /dev/null +++ b/tests/misc/projects/Issue7809/ReturnEarly.hx @@ -0,0 +1,6 @@ +abstract ReturnEarly(Int) from Int { + public function new(i:Int):Void { + return; + this = i; + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue7809/ReturnValue.hx b/tests/misc/projects/Issue7809/ReturnValue.hx new file mode 100644 index 0000000000000000000000000000000000000000..bd08feef3782238012f261478a64bdf591b74c7d --- /dev/null +++ b/tests/misc/projects/Issue7809/ReturnValue.hx @@ -0,0 +1,6 @@ +abstract ReturnValue(Int) from Int { + public function new(i:Int):Void { + this = i; + return 123; + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue7809/ReturnVoid.hx b/tests/misc/projects/Issue7809/ReturnVoid.hx new file mode 100644 index 0000000000000000000000000000000000000000..cd7a27d64e586f7f4472d775bc909027749dec6c --- /dev/null +++ b/tests/misc/projects/Issue7809/ReturnVoid.hx @@ -0,0 +1,6 @@ +abstract ReturnVoid(Int) from Int { + public function new(i:Int):Void { + this = i; + return; + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue7809/returnEarly-fail.hxml b/tests/misc/projects/Issue7809/returnEarly-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..6f35943fa4815b508b05cdb9013cbdba2fdb3f33 --- /dev/null +++ b/tests/misc/projects/Issue7809/returnEarly-fail.hxml @@ -0,0 +1 @@ +ReturnEarly \ No newline at end of file diff --git a/tests/misc/projects/Issue7809/returnEarly-fail.hxml.stderr b/tests/misc/projects/Issue7809/returnEarly-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..1c9e5a9923980e2d8620293a129b8679add691d8 --- /dev/null +++ b/tests/misc/projects/Issue7809/returnEarly-fail.hxml.stderr @@ -0,0 +1 @@ +ReturnEarly.hx:3: characters 3-9 : Missing this = value \ No newline at end of file diff --git a/tests/misc/projects/Issue7809/returnValue-fail.hxml b/tests/misc/projects/Issue7809/returnValue-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..895b999c50f8a64e677fb5db01e833d9f8606d13 --- /dev/null +++ b/tests/misc/projects/Issue7809/returnValue-fail.hxml @@ -0,0 +1 @@ +ReturnValue \ No newline at end of file diff --git a/tests/misc/projects/Issue7809/returnValue-fail.hxml.stderr b/tests/misc/projects/Issue7809/returnValue-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..ad13325f647e1867af4da1c75f31796bd63b2b29 --- /dev/null +++ b/tests/misc/projects/Issue7809/returnValue-fail.hxml.stderr @@ -0,0 +1 @@ +ReturnValue.hx:4: characters 3-13 : Cannot return a value from constructor \ No newline at end of file diff --git a/tests/misc/projects/Issue7809/returnVoid.hxml b/tests/misc/projects/Issue7809/returnVoid.hxml new file mode 100644 index 0000000000000000000000000000000000000000..d1100e205be1444c20993b8e50dbad3797d491c6 --- /dev/null +++ b/tests/misc/projects/Issue7809/returnVoid.hxml @@ -0,0 +1 @@ +ReturnVoid \ No newline at end of file diff --git a/tests/misc/projects/Issue7968/Foo.hx b/tests/misc/projects/Issue7968/Foo.hx new file mode 100644 index 0000000000000000000000000000000000000000..1ad9b2ef31e886cb6fa6b167bb451071f3dd4e48 --- /dev/null +++ b/tests/misc/projects/Issue7968/Foo.hx @@ -0,0 +1,2 @@ +typedef A = Int; +typedef A = Float; diff --git a/tests/misc/projects/Issue7968/Main.hx b/tests/misc/projects/Issue7968/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..362238670786c86cfa7db4906f03b2595e63736f --- /dev/null +++ b/tests/misc/projects/Issue7968/Main.hx @@ -0,0 +1,5 @@ +import Foo; +class Main { + static function main() { + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue7968/compile-fail.hxml b/tests/misc/projects/Issue7968/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..42409e72918a42a82dd3b99f48443419487fab57 --- /dev/null +++ b/tests/misc/projects/Issue7968/compile-fail.hxml @@ -0,0 +1 @@ +-main Main diff --git a/tests/misc/projects/Issue7968/compile-fail.hxml.stderr b/tests/misc/projects/Issue7968/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..70620971f0ce8b9e866429365bdb109f31ff28c9 --- /dev/null +++ b/tests/misc/projects/Issue7968/compile-fail.hxml.stderr @@ -0,0 +1,2 @@ +Foo.hx:2: characters 1-18 : Type name A is already defined in this module +Foo.hx:1: characters 1-16 : Previous declaration here diff --git a/tests/misc/projects/Issue8019/compile2-fail.hxml.stderr b/tests/misc/projects/Issue8019/compile2-fail.hxml.stderr index f486f47020147ea528b4ceae696a268a02daaed7..3c1d5b60ff6a5d80b311f66bfc81652459698372 100644 --- a/tests/misc/projects/Issue8019/compile2-fail.hxml.stderr +++ b/tests/misc/projects/Issue8019/compile2-fail.hxml.stderr @@ -1,2 +1 @@ -Type not found : 0.Foo -Main.hx:4: lines 4-15 : Defined in this class \ No newline at end of file +Main.hx:6: characters 3-19 : Type not found : 0.Foo \ No newline at end of file diff --git a/tests/misc/projects/Issue8019/compile3-fail.hxml.stderr b/tests/misc/projects/Issue8019/compile3-fail.hxml.stderr index df0eec0a118566b9dc440fcd4960e9837c23f991..4db3fc6982d6aa9663e1372fdc70adb505c47ed7 100644 --- a/tests/misc/projects/Issue8019/compile3-fail.hxml.stderr +++ b/tests/misc/projects/Issue8019/compile3-fail.hxml.stderr @@ -1,3 +1,3 @@ -Macro2.hx:7: characters 17-18 : Module name must not be empty -Macro2.hx:7: characters 17-18 : "0" is not a valid module name -Macro2.hx:7: characters 17-18 : "Type+" is not a valid module name \ No newline at end of file +Macro2.hx:7: characters 17-18 : Module "" does not have a valid name. Module name must not be empty. +Macro2.hx:7: characters 17-18 : Module "0" does not have a valid name. "0" is not a valid module name. +Macro2.hx:7: characters 17-18 : Module "Type+" does not have a valid name. "Type+" is not a valid module name. \ No newline at end of file diff --git a/tests/misc/projects/Issue8258/compile-fail.hxml.stderr b/tests/misc/projects/Issue8258/compile-fail.hxml.stderr index c5ebcba6d776b217928af1c781f60dd4afe4ba6e..dbf9c4c4768c865af0ddc96e1410aa3910c1c820 100644 --- a/tests/misc/projects/Issue8258/compile-fail.hxml.stderr +++ b/tests/misc/projects/Issue8258/compile-fail.hxml.stderr @@ -1 +1 @@ -Main.hx:4: characters 2-14 : Duplicate abstract field declaration : Foobar.A \ No newline at end of file +Main.hx:4: characters 6-7 : Duplicate abstract field declaration : Foobar.A \ No newline at end of file diff --git a/tests/misc/projects/Issue8303/MainCatch.hx b/tests/misc/projects/Issue8303/MainCatch.hx index 89d7c6f8576d39ce7a82b3b6a3d1160185852870..bef7989a4d08621ae9b0b05c15ac87339e5cdf49 100644 --- a/tests/misc/projects/Issue8303/MainCatch.hx +++ b/tests/misc/projects/Issue8303/MainCatch.hx @@ -6,6 +6,8 @@ class MainCatch { static function test() { function log() { log(); + //prevent tail recursion elimination + return 0; } try { log(); diff --git a/tests/misc/projects/Issue8303/compile-fail.hxml b/tests/misc/projects/Issue8303/compile-fail.hxml index 234e999d46203b4765ed34dca21aa8e33c1a48e9..cde767e64db59e248a227b803294259fbcfdc48e 100644 --- a/tests/misc/projects/Issue8303/compile-fail.hxml +++ b/tests/misc/projects/Issue8303/compile-fail.hxml @@ -1,3 +1,3 @@ -main Main --D eval-call-stack-depth=5 +-D eval-call-stack-depth=20 --interp \ No newline at end of file diff --git a/tests/misc/projects/Issue8303/compile-fail.hxml.stderr b/tests/misc/projects/Issue8303/compile-fail.hxml.stderr index 596e6de327371337b0a63daa38d747680134bae6..00dd0661cfb61ec8f2305ed7e718a505053643dd 100644 --- a/tests/misc/projects/Issue8303/compile-fail.hxml.stderr +++ b/tests/misc/projects/Issue8303/compile-fail.hxml.stderr @@ -2,5 +2,20 @@ Uncaught exception Stack overflow Main.hx:1: character 1 : Called from here Main.hx:8: characters 4-9 : Called from here Main.hx:8: characters 4-9 : Called from here +Main.hx:8: characters 4-9 : Called from here +Main.hx:8: characters 4-9 : Called from here +Main.hx:8: characters 4-9 : Called from here +Main.hx:8: characters 4-9 : Called from here +Main.hx:8: characters 4-9 : Called from here +Main.hx:8: characters 4-9 : Called from here +Main.hx:8: characters 4-9 : Called from here +Main.hx:8: characters 4-9 : Called from here +Main.hx:8: characters 4-9 : Called from here +Main.hx:8: characters 4-9 : Called from here +Main.hx:8: characters 4-9 : Called from here +Main.hx:8: characters 4-9 : Called from here +Main.hx:8: characters 4-9 : Called from here +Main.hx:8: characters 4-9 : Called from here +Main.hx:8: characters 4-9 : Called from here Main.hx:10: characters 3-8 : Called from here -Main.hx:3: characters 3-9 : Called from here +Main.hx:3: characters 3-9 : Called from here \ No newline at end of file diff --git a/tests/misc/projects/Issue8303/compile.hxml b/tests/misc/projects/Issue8303/compile.hxml index cef811ef94be8ae512bf4d30efa50b9a80363f7a..743b04dcd8af9af4c78304a8949367ddb72a5d85 100644 --- a/tests/misc/projects/Issue8303/compile.hxml +++ b/tests/misc/projects/Issue8303/compile.hxml @@ -1,3 +1,3 @@ -main MainCatch --D eval-call-stack-depth=5 +-D eval-call-stack-depth=20 --interp \ No newline at end of file diff --git a/tests/misc/projects/Issue8750/Main2.hx b/tests/misc/projects/Issue8750/Main2.hx new file mode 100644 index 0000000000000000000000000000000000000000..87419ed04a113faf77bfec5d51f84aafa8cb0c13 --- /dev/null +++ b/tests/misc/projects/Issue8750/Main2.hx @@ -0,0 +1,18 @@ +class Main2 { + static function main () { + #if !macro + define(); + #end + } + + macro static public function define() { + haxe.macro.Context.defineModule("some.+", [{ + pos: (macro 0).pos, + pack: ["some"], + name: "+", + kind: TDClass(), + fields: [] + }]); + return macro {}; + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue8750/compile-fail.hxml b/tests/misc/projects/Issue8750/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..27d6e39ab72cf90b00703d0d1323b0c0e760514b --- /dev/null +++ b/tests/misc/projects/Issue8750/compile-fail.hxml @@ -0,0 +1 @@ +-main Main2 diff --git a/tests/misc/projects/Issue8750/compile-fail.hxml.stderr b/tests/misc/projects/Issue8750/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..66acbc9692ed30c018f1187f7e2b92489052fd59 --- /dev/null +++ b/tests/misc/projects/Issue8750/compile-fail.hxml.stderr @@ -0,0 +1 @@ +Main2.hx:10: characters 16-17 : Module "some.+" does not have a valid name. "+" is not a valid module name. \ No newline at end of file diff --git a/tests/misc/projects/Issue8819/Main.hx b/tests/misc/projects/Issue8819/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..33429a1183c393c0d424de718e62bc57c32c9a65 --- /dev/null +++ b/tests/misc/projects/Issue8819/Main.hx @@ -0,0 +1,7 @@ +class Main { + static function main() { + Type.allEnums(Foo); + } +} + +enum abstract Foo(String) {} \ No newline at end of file diff --git a/tests/misc/projects/Issue8819/compile-fail.hxml b/tests/misc/projects/Issue8819/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue8819/compile-fail.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue8819/compile-fail.hxml.stderr b/tests/misc/projects/Issue8819/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..d5a1122fa1ca7aef426acb72a5ffdb4eaac8eda9 --- /dev/null +++ b/tests/misc/projects/Issue8819/compile-fail.hxml.stderr @@ -0,0 +1,2 @@ +Main.hx:3: characters 17-20 : Abstract should be Enum> +Main.hx:3: characters 17-20 : For function argument 'e' \ No newline at end of file diff --git a/tests/misc/projects/Issue8828/Main1.hx b/tests/misc/projects/Issue8828/Main1.hx new file mode 100644 index 0000000000000000000000000000000000000000..9ba5630b3bf9235a0b3c0b33d8cbe3793911db42 --- /dev/null +++ b/tests/misc/projects/Issue8828/Main1.hx @@ -0,0 +1,3 @@ +enum abstract A(Int) { + extern var x = 1; +} \ No newline at end of file diff --git a/tests/misc/projects/Issue8828/Main2.hx b/tests/misc/projects/Issue8828/Main2.hx new file mode 100644 index 0000000000000000000000000000000000000000..9c56823334089210675643e9874a7f965b75757b --- /dev/null +++ b/tests/misc/projects/Issue8828/Main2.hx @@ -0,0 +1,3 @@ +enum abstract A(Int) { + public private var x = 1; +} \ No newline at end of file diff --git a/tests/misc/projects/Issue8828/Main3.hx b/tests/misc/projects/Issue8828/Main3.hx new file mode 100644 index 0000000000000000000000000000000000000000..72b585889bc4e7c1bacad2cd8ddbde499ecafe33 --- /dev/null +++ b/tests/misc/projects/Issue8828/Main3.hx @@ -0,0 +1,3 @@ +enum abstract A(Int) { + private public var x = 1; +} \ No newline at end of file diff --git a/tests/misc/projects/Issue8828/compile1-fail.hxml b/tests/misc/projects/Issue8828/compile1-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..742836a4c5cd04aab22c625cea2cfcfd52b2b8f0 --- /dev/null +++ b/tests/misc/projects/Issue8828/compile1-fail.hxml @@ -0,0 +1,2 @@ +-main Main1 +-js bin/test.js \ No newline at end of file diff --git a/tests/misc/projects/Issue8828/compile1-fail.hxml.stderr b/tests/misc/projects/Issue8828/compile1-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..5558e4f5f200807d2a0cde3fb663ab5b4cdcc962 --- /dev/null +++ b/tests/misc/projects/Issue8828/compile1-fail.hxml.stderr @@ -0,0 +1 @@ +Main1.hx:2: characters 2-8 : extern modifier is not allowed on enum abstract fields \ No newline at end of file diff --git a/tests/misc/projects/Issue8828/compile2-fail.hxml b/tests/misc/projects/Issue8828/compile2-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..c53921371e0ad41b4e8f692781ad4f6f84191d47 --- /dev/null +++ b/tests/misc/projects/Issue8828/compile2-fail.hxml @@ -0,0 +1,2 @@ +-main Main2 +-js bin/test.js \ No newline at end of file diff --git a/tests/misc/projects/Issue8828/compile2-fail.hxml.stderr b/tests/misc/projects/Issue8828/compile2-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..b30c52420515d0327aa4498931a5b7057532ca78 --- /dev/null +++ b/tests/misc/projects/Issue8828/compile2-fail.hxml.stderr @@ -0,0 +1,2 @@ +Main2.hx:2: characters 9-16 : Conflicting access modifier public +Main2.hx:2: characters 2-8 : Conflicts with this \ No newline at end of file diff --git a/tests/misc/projects/Issue8828/compile3-fail.hxml b/tests/misc/projects/Issue8828/compile3-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..9f71c0f23d9c6f17695fdf3470471164dd856f35 --- /dev/null +++ b/tests/misc/projects/Issue8828/compile3-fail.hxml @@ -0,0 +1,2 @@ +-main Main3 +-js bin/test.js \ No newline at end of file diff --git a/tests/misc/projects/Issue8828/compile3-fail.hxml.stderr b/tests/misc/projects/Issue8828/compile3-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..847f1700f19fe4293f238f6eb15473268f1b3dcd --- /dev/null +++ b/tests/misc/projects/Issue8828/compile3-fail.hxml.stderr @@ -0,0 +1,2 @@ +Main3.hx:2: characters 10-16 : Conflicting access modifier private +Main3.hx:2: characters 2-9 : Conflicts with this \ No newline at end of file diff --git a/tests/misc/projects/Issue8840/Main.hx b/tests/misc/projects/Issue8840/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..79960ed4634ad2f7d81c37fc9cc99a851691f7f5 --- /dev/null +++ b/tests/misc/projects/Issue8840/Main.hx @@ -0,0 +1,11 @@ +class Main { + static function main() {} +} + +abstract Abstr(String) { + @:to public static function staticTo():String + return ''; + + @:to public function instanceTo(a:Int):String + return ''; +} \ No newline at end of file diff --git a/tests/misc/projects/Issue8840/compile-fail.hxml b/tests/misc/projects/Issue8840/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue8840/compile-fail.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue8840/compile-fail.hxml.stderr b/tests/misc/projects/Issue8840/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..b1c10a4952a37dbacd00282a5ecd83bde395975e --- /dev/null +++ b/tests/misc/projects/Issue8840/compile-fail.hxml.stderr @@ -0,0 +1,2 @@ +Main.hx:6: lines 6-7 : static @:to method should have one argument +Main.hx:9: lines 9-10 : @:to method should have no arguments \ No newline at end of file diff --git a/tests/misc/projects/Issue8892/Main.hx b/tests/misc/projects/Issue8892/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..b70c391715a45c43d82bf01ef324f14f29fc533d --- /dev/null +++ b/tests/misc/projects/Issue8892/Main.hx @@ -0,0 +1,5 @@ +class Main { + static function main() { + js.Syntax.code('{0}'); + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue8892/compile-fail.hxml b/tests/misc/projects/Issue8892/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..58e535f906fd97cd59e26ce80ec13756b42b97f1 --- /dev/null +++ b/tests/misc/projects/Issue8892/compile-fail.hxml @@ -0,0 +1,2 @@ +-main Main +-js bin/test.js \ No newline at end of file diff --git a/tests/misc/projects/Issue8892/compile-fail.hxml.stderr b/tests/misc/projects/Issue8892/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..6c52e1935029f16e56f7cadff8379da38397deac --- /dev/null +++ b/tests/misc/projects/Issue8892/compile-fail.hxml.stderr @@ -0,0 +1 @@ +Main.hx:3: characters 19-22 : Out-of-bounds special parameter: 0 \ No newline at end of file diff --git a/tests/misc/projects/Issue8946/Main.hx b/tests/misc/projects/Issue8946/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..e2171c0a3a2753294b654dfeb44d44773a9ee4eb --- /dev/null +++ b/tests/misc/projects/Issue8946/Main.hx @@ -0,0 +1,7 @@ +class Main { + static function main() { + #if !EMPTY_FLAG + throw "Missing branch matching -D EMPTY_FLAG="; + #end + } +} diff --git a/tests/misc/projects/Issue8946/compile.hxml b/tests/misc/projects/Issue8946/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..bdc0e80d0e3df449ab4ff05074d6d7cfb2947cba --- /dev/null +++ b/tests/misc/projects/Issue8946/compile.hxml @@ -0,0 +1,2 @@ +-D EMPTY_FLAG= +--run Main diff --git a/tests/misc/projects/Issue9010/ChildFields-fail.hxml b/tests/misc/projects/Issue9010/ChildFields-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fb01f4fc343e971757e665462b6a91a77a3aef89 --- /dev/null +++ b/tests/misc/projects/Issue9010/ChildFields-fail.hxml @@ -0,0 +1 @@ +-main ChildFields \ No newline at end of file diff --git a/tests/misc/projects/Issue9010/ChildFields-fail.hxml.stderr b/tests/misc/projects/Issue9010/ChildFields-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..4a6e5350755618a293c80a32656d52467ed11c5b --- /dev/null +++ b/tests/misc/projects/Issue9010/ChildFields-fail.hxml.stderr @@ -0,0 +1,2 @@ +ChildFields.hx:4: characters 18-28 : Field noOverride should be declared with 'override' since it is inherited from superclass Parent +ChildFields.hx:7: characters 27-34 : Field inlined is inlined and cannot be overridden \ No newline at end of file diff --git a/tests/misc/projects/Issue9010/ChildFields.hx b/tests/misc/projects/Issue9010/ChildFields.hx new file mode 100644 index 0000000000000000000000000000000000000000..6c8e60e9d96df8b6f343335dea75bed7c3373616 --- /dev/null +++ b/tests/misc/projects/Issue9010/ChildFields.hx @@ -0,0 +1,19 @@ +class ChildFields extends Parent { + static function main() {} + + public function noOverride():String { + return null; + } + override public function inlined():String { + return null; + } +} + +class Parent { + public function noOverride():String { + return null; + } + public inline function inlined():String { + return null; + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9010/InterfaceFields-fail.hxml b/tests/misc/projects/Issue9010/InterfaceFields-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..27bc7e3184984df3afccc3e6b3958de9f8a59644 --- /dev/null +++ b/tests/misc/projects/Issue9010/InterfaceFields-fail.hxml @@ -0,0 +1 @@ +-main InterfaceFields \ No newline at end of file diff --git a/tests/misc/projects/Issue9010/InterfaceFields-fail.hxml.stderr b/tests/misc/projects/Issue9010/InterfaceFields-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..de2a7245810561422a6834eab40dd8afa77079bf --- /dev/null +++ b/tests/misc/projects/Issue9010/InterfaceFields-fail.hxml.stderr @@ -0,0 +1,3 @@ +InterfaceFields.hx:1: characters 7-22 : Field missing needed by IFace is missing +InterfaceFields.hx:4: characters 13-24 : Field wrongAccess has different property access than in IFace ((never,null) should be (default,null)) +InterfaceFields.hx:5: characters 18-27 : Field wrongKind has different property access than in IFace (method should be var) \ No newline at end of file diff --git a/tests/misc/projects/Issue9010/InterfaceFields.hx b/tests/misc/projects/Issue9010/InterfaceFields.hx new file mode 100644 index 0000000000000000000000000000000000000000..2a9baec1337a0e011d0e5091c57fc7f50bfa24e7 --- /dev/null +++ b/tests/misc/projects/Issue9010/InterfaceFields.hx @@ -0,0 +1,14 @@ +class InterfaceFields implements IFace { + static function main() {} + + public var wrongAccess(never,null):String; + public function wrongKind():String { + return null; + } +} + +interface IFace { + var missing:String; + var wrongAccess(default,null):String; + var wrongKind:String; +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9010/InvalidOverride-fail.hxml b/tests/misc/projects/Issue9010/InvalidOverride-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..d8ac18bf59eb3143453429d8faf4e39f36e2b20c --- /dev/null +++ b/tests/misc/projects/Issue9010/InvalidOverride-fail.hxml @@ -0,0 +1 @@ +-main InvalidOverride \ No newline at end of file diff --git a/tests/misc/projects/Issue9010/InvalidOverride-fail.hxml.stderr b/tests/misc/projects/Issue9010/InvalidOverride-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..9f8b231b42d864b3a5d5fe38f322f03c47121518 --- /dev/null +++ b/tests/misc/projects/Issue9010/InvalidOverride-fail.hxml.stderr @@ -0,0 +1,2 @@ +InvalidOverride.hx:4: characters 2-10 : Invalid accessor 'override' for variable field +InvalidOverride.hx:6: characters 20-24 : Field some is declared 'override' but doesn't override any field \ No newline at end of file diff --git a/tests/misc/projects/Issue9010/InvalidOverride.hx b/tests/misc/projects/Issue9010/InvalidOverride.hx new file mode 100644 index 0000000000000000000000000000000000000000..2d6b5bb692d47ded6594cb4fd0d42700c713bd52 --- /dev/null +++ b/tests/misc/projects/Issue9010/InvalidOverride.hx @@ -0,0 +1,11 @@ +class InvalidOverride extends Parent { + static function main() {} + + override var field:String; + + override function some():String { + return null; + } +} + +class Parent {} \ No newline at end of file diff --git a/tests/misc/projects/Issue9010/NativeMeta-fail.hxml b/tests/misc/projects/Issue9010/NativeMeta-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..6d23e9fc0109109976e33491e5e002be25f1224f --- /dev/null +++ b/tests/misc/projects/Issue9010/NativeMeta-fail.hxml @@ -0,0 +1 @@ +-main NativeMeta \ No newline at end of file diff --git a/tests/misc/projects/Issue9010/NativeMeta-fail.hxml.stderr b/tests/misc/projects/Issue9010/NativeMeta-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..65f3e9735fa1e0795422547809678a23b28381c7 --- /dev/null +++ b/tests/misc/projects/Issue9010/NativeMeta-fail.hxml.stderr @@ -0,0 +1,6 @@ +NativeMeta.hx:4: characters 11-24 : Field some has different @:native value than in superclass +NativeMeta.hx:16: characters 11-25 : Base field is defined here +NativeMeta.hx:1: lines 1-13 : Defined in this class +NativeMeta.hx:9: characters 11-25 : Field noNative has different @:native value than in superclass +NativeMeta.hx:20: characters 18-26 : Base field is defined here +NativeMeta.hx:1: lines 1-13 : Defined in this class \ No newline at end of file diff --git a/tests/misc/projects/Issue9010/NativeMeta.hx b/tests/misc/projects/Issue9010/NativeMeta.hx new file mode 100644 index 0000000000000000000000000000000000000000..4804b1fa9efeced80536f7fa07f7fdad09514119 --- /dev/null +++ b/tests/misc/projects/Issue9010/NativeMeta.hx @@ -0,0 +1,22 @@ +class Main extends Parent { + static function main() {} + + @:native('childNative') + override function some() { + super.some(); + } + + @:native('childNative2') + override function noNative() { + super.noNative(); + } +} + +class Parent { + @:native('parentNative') + public function some() { + } + + public function noNative() { + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9014/Main.hx b/tests/misc/projects/Issue9014/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..16c2dadfcd69db23c761be2129679647bd72ce15 --- /dev/null +++ b/tests/misc/projects/Issue9014/Main.hx @@ -0,0 +1,7 @@ +class Main extends Base { + static function main() {} + override static function foo():Void {} + dynamic inline function bar():Void {} +} + +class Base {} diff --git a/tests/misc/projects/Issue9014/compile-fail.hxml b/tests/misc/projects/Issue9014/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..e2a3d27a1903cc58c64892f2c3cacd367f3533ef --- /dev/null +++ b/tests/misc/projects/Issue9014/compile-fail.hxml @@ -0,0 +1,2 @@ +--main Main +--interp diff --git a/tests/misc/projects/Issue9014/compile-fail.hxml.stderr b/tests/misc/projects/Issue9014/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..2b25ed33ed99cc0663877e78c796e56f0a8203e1 --- /dev/null +++ b/tests/misc/projects/Issue9014/compile-fail.hxml.stderr @@ -0,0 +1,2 @@ +Main.hx:3: characters 2-40 : foo: 'override' is not allowed on 'static' functions +Main.hx:4: characters 2-39 : bar: 'inline' is not allowed on 'dynamic' functions diff --git a/tests/misc/projects/Issue9017/Main.hx b/tests/misc/projects/Issue9017/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..d8360ddfd55fe63940a747e98efe6cccee9dec1d --- /dev/null +++ b/tests/misc/projects/Issue9017/Main.hx @@ -0,0 +1,11 @@ +class Main { + static function main() { + var f:Foo = { field:1 }; + trace(f.field); + } +} + +@:structInit +interface Foo { + var field:Int; +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9017/compile-fail.hxml b/tests/misc/projects/Issue9017/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue9017/compile-fail.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue9017/compile-fail.hxml.stderr b/tests/misc/projects/Issue9017/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..a47acdb7cd238e6ba82354b4dea5984efe7c0b8c --- /dev/null +++ b/tests/misc/projects/Issue9017/compile-fail.hxml.stderr @@ -0,0 +1,3 @@ +Main.hx:8: characters 1-13 : @:structInit is not allowed on interfaces +Main.hx:9: lines 9-11 : Defined in this class +Main.hx:3: characters 15-26 : Foo does not have a constructor \ No newline at end of file diff --git a/tests/misc/projects/Issue9061/Main.hx b/tests/misc/projects/Issue9061/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..f8116eaaaa4dbe9cde69eb4699b6b8f2f8e31f29 --- /dev/null +++ b/tests/misc/projects/Issue9061/Main.hx @@ -0,0 +1,9 @@ +class Main { + static function main() { + + } + + static function main() { + + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9061/compile-fail.hxml b/tests/misc/projects/Issue9061/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue9061/compile-fail.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue9061/compile-fail.hxml.stderr b/tests/misc/projects/Issue9061/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..01d617aa900fe8c11e0b61161a374748e5afbccb --- /dev/null +++ b/tests/misc/projects/Issue9061/compile-fail.hxml.stderr @@ -0,0 +1 @@ +Main.hx:6: characters 18-22 : Duplicate class field declaration : Main.main \ No newline at end of file diff --git a/tests/misc/projects/Issue9064/Check.hx b/tests/misc/projects/Issue9064/Check.hx new file mode 100644 index 0000000000000000000000000000000000000000..102f5afa10df92f31df8d1ca5ade9bfe0e20e666 --- /dev/null +++ b/tests/misc/projects/Issue9064/Check.hx @@ -0,0 +1,27 @@ +import haxe.macro.Type; +import haxe.macro.Context; + +class Check { + static public function init() { + Context.onGenerate(function(types:Array) { + for(type in types) { + switch type { + case TInst(_.get() => cls, []) if(cls.name == 'Main'): + for(field in cls.statics.get()) { + if(field.name == 'testMeta') { + var pureCount = field.meta.extract(':pure').length; + if(pureCount != 1) { + Context.error('Main.testMeta is expected to have exactly one @:pure meta, got $pureCount', field.pos); + return; + } + //success + return; + } + } + case _: + } + } + Context.error('Main.testMeta not found', (macro {}).pos); + }); + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9064/Main.hx b/tests/misc/projects/Issue9064/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..916ac51b8893a442c68b2d91699324670465dbfc --- /dev/null +++ b/tests/misc/projects/Issue9064/Main.hx @@ -0,0 +1,6 @@ +class Main { + static function main() {} + + @:pure @:keep + static function testMeta() {} +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9064/compile.hxml b/tests/misc/projects/Issue9064/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..94209f3188aafd3e15927c93c81a487a03263473 --- /dev/null +++ b/tests/misc/projects/Issue9064/compile.hxml @@ -0,0 +1,4 @@ +-main Main +-D analyzer-optimize +--macro Check.init() +-js bin/test.js \ No newline at end of file diff --git a/tests/misc/projects/Issue9067/Main.hx b/tests/misc/projects/Issue9067/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..68e50b85b6a30d047d58bbcb199118d4efee2592 --- /dev/null +++ b/tests/misc/projects/Issue9067/Main.hx @@ -0,0 +1,27 @@ +class Main { + static function main() { + trace(Foo.make()); + } +} + +abstract Foo(Int) from Int { + public static function make():Foo { + var foo:Foo = 0; + foo.init(); + return foo; + } + + var a(never, set):Int; + var b(never, set):Int; + + function init():Foo { + a = 1; + return this; + } + + inline function set_a(v) + return b = v; + + inline function set_b(v) + return this = v; +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9067/compile-fail.hxml b/tests/misc/projects/Issue9067/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue9067/compile-fail.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue9067/compile-fail.hxml.stderr b/tests/misc/projects/Issue9067/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..7adac3ce57ae966efb89d35e92f68e6bf7856e31 --- /dev/null +++ b/tests/misc/projects/Issue9067/compile-fail.hxml.stderr @@ -0,0 +1 @@ +Main.hx:18: characters 3-8 : Abstract 'this' value can only be modified inside an inline function. 'set_a' modifies 'this' \ No newline at end of file diff --git a/tests/misc/projects/Issue9192/Main.hx b/tests/misc/projects/Issue9192/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..2650de85757c8390d93c5905c1db96555e5db658 --- /dev/null +++ b/tests/misc/projects/Issue9192/Main.hx @@ -0,0 +1,10 @@ +class Main { + static function main() { + A.field; + } +} + +@:deprecated +class A { + public static final field = 3; +} diff --git a/tests/misc/projects/Issue9192/compile.hxml b/tests/misc/projects/Issue9192/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue9192/compile.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue9192/compile.hxml.stderr b/tests/misc/projects/Issue9192/compile.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..bff3db891f6fe1cefeabfaaae84132c7e837388e --- /dev/null +++ b/tests/misc/projects/Issue9192/compile.hxml.stderr @@ -0,0 +1 @@ +Main.hx:3: characters 3-4 : Warning : Usage of this class is deprecated \ No newline at end of file diff --git a/tests/misc/projects/Issue9204/Main.hx b/tests/misc/projects/Issue9204/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..93bf104221dec70a91baa27b2f105c165ed06bb4 --- /dev/null +++ b/tests/misc/projects/Issue9204/Main.hx @@ -0,0 +1,20 @@ +class C { + @:deprecated + static inline final SOME = 1; + + static public function f(x:Int) { + switch (x) { + case SOME: + return 'hello'; + case _: + return 'world'; + } + } +} + +class Main { + static function main() { + if(C.f(1) != 'hello') throw 'Test C.f(1) failed'; + if(C.f(2) != 'world') throw 'Test C.f(2) failed'; + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9204/compile.hxml b/tests/misc/projects/Issue9204/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..c717a2877a53df954ea3d984474ca0fededfaab7 --- /dev/null +++ b/tests/misc/projects/Issue9204/compile.hxml @@ -0,0 +1,2 @@ +-main Main +--interp \ No newline at end of file diff --git a/tests/misc/projects/Issue9204/compile.hxml.stderr b/tests/misc/projects/Issue9204/compile.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..c0df8bc895d98bd7346d9a7b6e76c10d72d863c5 --- /dev/null +++ b/tests/misc/projects/Issue9204/compile.hxml.stderr @@ -0,0 +1 @@ +Main.hx:7: characters 9-13 : Warning : Usage of this field is deprecated \ No newline at end of file diff --git a/tests/misc/projects/Issue9226/Main.hx b/tests/misc/projects/Issue9226/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..afd0a0218253fe24d7def5742d839fd6aabd203b --- /dev/null +++ b/tests/misc/projects/Issue9226/Main.hx @@ -0,0 +1,7 @@ +class Main { + function new(a:Int) {} + + static function main() { + var f = Main.new.bind("not an int"); + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9226/compile-fail.hxml b/tests/misc/projects/Issue9226/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue9226/compile-fail.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue9226/compile-fail.hxml.stderr b/tests/misc/projects/Issue9226/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..4a3e7604bbe824f226043a63bb909836ef69f411 --- /dev/null +++ b/tests/misc/projects/Issue9226/compile-fail.hxml.stderr @@ -0,0 +1 @@ +Main.hx:5: characters 25-37 : String should be Int \ No newline at end of file diff --git a/tests/misc/projects/Issue9243/Main.hx b/tests/misc/projects/Issue9243/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..246a68a782b46434d680f43d2a11ab6ea995417a --- /dev/null +++ b/tests/misc/projects/Issue9243/Main.hx @@ -0,0 +1,5 @@ +private class Main { + static function main() { + trace("Test"); + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9243/compile-fail.hxml b/tests/misc/projects/Issue9243/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue9243/compile-fail.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue9243/compile-fail.hxml.stderr b/tests/misc/projects/Issue9243/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..60a43e14c137f964e0a91ceaf77081a8857fb911 --- /dev/null +++ b/tests/misc/projects/Issue9243/compile-fail.hxml.stderr @@ -0,0 +1 @@ +Cannot access private type Main in module Main \ No newline at end of file diff --git a/tests/misc/projects/Issue9245/Main.hx b/tests/misc/projects/Issue9245/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..50053f7628a91034e88fd1d6ebeb93f18370e748 --- /dev/null +++ b/tests/misc/projects/Issue9245/Main.hx @@ -0,0 +1,6 @@ +class Main { + static function main() { + var foo = haxe.Json.parse("{}"); + for (key => value in foo) {} + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9245/compile-fail.hxml b/tests/misc/projects/Issue9245/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue9245/compile-fail.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue9245/compile-fail.hxml.stderr b/tests/misc/projects/Issue9245/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..50522dc9d4ad13de2470e700a03bc1d0fcbd3566 --- /dev/null +++ b/tests/misc/projects/Issue9245/compile-fail.hxml.stderr @@ -0,0 +1 @@ +Main.hx:4: characters 24-27 : You can't iterate on a Dynamic value, please specify KeyValueIterator or KeyValueIterable \ No newline at end of file diff --git a/tests/misc/projects/Issue9286/Main.hx b/tests/misc/projects/Issue9286/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..52f036c722b4f5d471ba90a61332581656818779 --- /dev/null +++ b/tests/misc/projects/Issue9286/Main.hx @@ -0,0 +1,13 @@ +class Main { + public static function level2():Void { + level3(); + } + + public static function level3():Void { + throw "!"; + } + + static public function main() { + level2(); + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9286/compile-fail.hxml b/tests/misc/projects/Issue9286/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..c717a2877a53df954ea3d984474ca0fededfaab7 --- /dev/null +++ b/tests/misc/projects/Issue9286/compile-fail.hxml @@ -0,0 +1,2 @@ +-main Main +--interp \ No newline at end of file diff --git a/tests/misc/projects/Issue9286/compile-fail.hxml.stderr b/tests/misc/projects/Issue9286/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..8b4d8d93c0a75d218525d0b05658c363b93d32b8 --- /dev/null +++ b/tests/misc/projects/Issue9286/compile-fail.hxml.stderr @@ -0,0 +1,3 @@ +Main.hx:7: characters 3-8 : Uncaught exception ! +Main.hx:3: characters 3-11 : Called from here +Main.hx:11: characters 3-11 : Called from here \ No newline at end of file diff --git a/tests/misc/projects/Issue9294/Main.hx b/tests/misc/projects/Issue9294/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..1e6a48e0d5296f322900fc1a89868c161432128c --- /dev/null +++ b/tests/misc/projects/Issue9294/Main.hx @@ -0,0 +1,16 @@ +import haxe.macro.Context; + +class Main { + static function main() { + test(); + } + + macro static public function test() { + try { + Context.getType(""); + } catch(e:Dynamic) { + Context.error(Std.string(e), Context.currentPos()); + } + return macro {}; + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9294/compile-fail.hxml b/tests/misc/projects/Issue9294/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue9294/compile-fail.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue9294/compile-fail.hxml.stderr b/tests/misc/projects/Issue9294/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..9a36ef8ce6dc8bb12ba77694774e72b8ee8543ef --- /dev/null +++ b/tests/misc/projects/Issue9294/compile-fail.hxml.stderr @@ -0,0 +1 @@ +Main.hx:5: characters 3-9 : Empty module name is not allowed \ No newline at end of file diff --git a/tests/misc/projects/Issue9295/Main.hx b/tests/misc/projects/Issue9295/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..c7e8174260f504868c27328ee989eb8239300555 --- /dev/null +++ b/tests/misc/projects/Issue9295/Main.hx @@ -0,0 +1,15 @@ +abstract A(Int) from Int { + public var x(get,set):Int; + + function get_x() return this; + + inline function set_x(value) return this = value; + + public function modify() { + x += 3; + } +} + +class Main { + static function main() {} +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9295/compile-fail.hxml b/tests/misc/projects/Issue9295/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue9295/compile-fail.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue9295/compile-fail.hxml.stderr b/tests/misc/projects/Issue9295/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e43c76d9efba0a9c6a3079a17073e188d2bc7670 --- /dev/null +++ b/tests/misc/projects/Issue9295/compile-fail.hxml.stderr @@ -0,0 +1 @@ +Main.hx:9: characters 3-9 : Abstract 'this' value can only be modified inside an inline function. 'set_x' modifies 'this' \ No newline at end of file diff --git a/tests/misc/projects/Issue9296/Main.hx b/tests/misc/projects/Issue9296/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..c3910689cce5b193a0fb402c4d2d20f5febff726 --- /dev/null +++ b/tests/misc/projects/Issue9296/Main.hx @@ -0,0 +1,24 @@ +class Main { + static function main() { + var v = 1; + var success = false; + function next(b:Bool) { + run(v, bool(), function() { + if(b) next(!b) + else success = true; + }); + } + next(true); + if(!success) { + throw 'Test failed'; + } + } + + static function bool():Bool { + return true; + } + + static function run(v:Int, b:Bool, cb:()->Void) { + cb(); + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9296/compile.hxml b/tests/misc/projects/Issue9296/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..321ab1168991be63bd161bfc6e07e5e5999f6b9a --- /dev/null +++ b/tests/misc/projects/Issue9296/compile.hxml @@ -0,0 +1,3 @@ +-main Main +-js bin/test.js +--cmd node bin/test.js \ No newline at end of file diff --git a/tests/misc/projects/Issue9308/Main.hx b/tests/misc/projects/Issue9308/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..9682a35caebf52702838a9d837352aa4acc5f02f --- /dev/null +++ b/tests/misc/projects/Issue9308/Main.hx @@ -0,0 +1,30 @@ +enum E { + A; + B; +} + +class Main { + static var n:Int = 3; + static var e:Null = A; + + static function main() { + switch (e) { + case A: + // commenting this trace makes it work... + trace("hi"); + + for (i in 0...n) { + trace(i); + } + + case B: + for (i in 0...n) { + trace(i); + } + + // commenting this default removes the nullcheck for `e` + // and makes it work... + default: + } + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9308/compile.hxml b/tests/misc/projects/Issue9308/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..a0cee90600aa81de016e4b6d66ac0ce144503920 --- /dev/null +++ b/tests/misc/projects/Issue9308/compile.hxml @@ -0,0 +1,4 @@ +-main Main +-js bin/test.js +-D js-es=6 +--cmd node bin/test.js \ No newline at end of file diff --git a/tests/misc/projects/Issue9312/Main.hx b/tests/misc/projects/Issue9312/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..d70eebe120ec13f003cbf304e2ddc83e64dc340f --- /dev/null +++ b/tests/misc/projects/Issue9312/Main.hx @@ -0,0 +1,11 @@ +class Main { + static function main() { + var fn:(Array)->Void; + fn = function(a:Array):Void { + for(i in a) { + fn([i]); + } + } + fn([1,2,3]); + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9312/compile.hxml b/tests/misc/projects/Issue9312/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..4efafa31484f21d58d6c5de02c091da958da2e0e --- /dev/null +++ b/tests/misc/projects/Issue9312/compile.hxml @@ -0,0 +1,3 @@ +-main Main +-js bin/test.js +-D js-es=6 \ No newline at end of file diff --git a/tests/misc/projects/Issue9336/Main.hx b/tests/misc/projects/Issue9336/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..3f724bcb7a75af2f9a965791579d76cba31ee518 --- /dev/null +++ b/tests/misc/projects/Issue9336/Main.hx @@ -0,0 +1,22 @@ +import haxe.macro.Context; +import haxe.macro.PositionTools; + +class Main { + #if !macro + static function main(){ + test(); + } + #end + static macro function test() { + var pos = Context.makePosition({min: 20, max: 23, file: 'my_template.mtt' }); + var range = PositionTools.toLocation(pos).range; + if(range.start.line != range.end.line || range.end.line != 2) { + Context.fatalError('Invalid position', pos); + } + Context.parse('foo', pos); + if(range.start.line != range.end.line || range.end.line != 2) { + Context.fatalError('Invalid position after Context.parse', pos); + } + return macro null; + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9336/compile.hxml b/tests/misc/projects/Issue9336/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue9336/compile.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue9336/my_template.mtt b/tests/misc/projects/Issue9336/my_template.mtt new file mode 100644 index 0000000000000000000000000000000000000000..c0fb0ccef903e55f74a1a9bc2813b50d48564efb --- /dev/null +++ b/tests/misc/projects/Issue9336/my_template.mtt @@ -0,0 +1,2 @@ +
 
+::foo():: \ No newline at end of file diff --git a/tests/misc/projects/Issue9342/Macro.hx b/tests/misc/projects/Issue9342/Macro.hx new file mode 100644 index 0000000000000000000000000000000000000000..aaf53518824e15cba17d18f7ebf015e50e2157df --- /dev/null +++ b/tests/misc/projects/Issue9342/Macro.hx @@ -0,0 +1,15 @@ +import haxe.macro.Context; +import haxe.macro.Expr; + +class Macro { + static public macro function foo() { + var pos = Context.currentPos(); + return macro @:pos(pos) new Foo(); + } +#if macro + static function buildFoo() { + Context.warning('check pos', Context.currentPos()); + return Context.typeof(macro [1]); + } +#end +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9342/Main.hx b/tests/misc/projects/Issue9342/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..1ef2b66f5f08467ef676c95fc58b97fb0b93ac55 --- /dev/null +++ b/tests/misc/projects/Issue9342/Main.hx @@ -0,0 +1,8 @@ +class Main { + static function main() { + Macro.foo(); + } +} + +@:genericBuild(Macro.buildFoo()) +class Foo {} \ No newline at end of file diff --git a/tests/misc/projects/Issue9342/compile.hxml b/tests/misc/projects/Issue9342/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue9342/compile.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue9342/compile.hxml.stderr b/tests/misc/projects/Issue9342/compile.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..0fa28c1a82d1ad421b55f9d816aa37c5e09c4fe5 --- /dev/null +++ b/tests/misc/projects/Issue9342/compile.hxml.stderr @@ -0,0 +1 @@ +Main.hx:3: characters 3-14 : Warning : check pos \ No newline at end of file diff --git a/tests/misc/projects/Issue9347/Main.hx b/tests/misc/projects/Issue9347/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..c76739bd8a5b9a17a9ec0e5ba8875d80c2960efd --- /dev/null +++ b/tests/misc/projects/Issue9347/Main.hx @@ -0,0 +1,19 @@ +class Main { + static function main() { + (1:A1)['foo']; + (1:A2)['bar']; + (1:A2
)['baz']; + } +} + +abstract A1(Int) from Int { + @:op([]) static function get(instance: A1, key: String): String { + return '${instance}${key}'; + } +} + +abstract A2(Int) from Int { + @:op([]) static function get(instance: A2, key: String): String { + return '${instance}${key}'; + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9347/compile-fail.hxml b/tests/misc/projects/Issue9347/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue9347/compile-fail.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue9347/compile-fail.hxml.stderr b/tests/misc/projects/Issue9347/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..c83df983d3893c1df6aeaeacee0e8012a7ac1018 --- /dev/null +++ b/tests/misc/projects/Issue9347/compile-fail.hxml.stderr @@ -0,0 +1 @@ +Main.hx:5: characters 3-22 : No @:arrayAccess function for A2
accepts argument of String \ No newline at end of file diff --git a/tests/misc/projects/Issue9368/Main.hx b/tests/misc/projects/Issue9368/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..0b09ab236b1eb0633d7a1844ecfe186fcb77f3fa --- /dev/null +++ b/tests/misc/projects/Issue9368/Main.hx @@ -0,0 +1,5 @@ +class Main { + static function __init__() {} + static function __init__() {} + static function main() {} +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9368/compile-fail.hxml b/tests/misc/projects/Issue9368/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue9368/compile-fail.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue9368/compile-fail.hxml.stderr b/tests/misc/projects/Issue9368/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..bf0526fca8c24cdd2bffb20910601556110e3e02 --- /dev/null +++ b/tests/misc/projects/Issue9368/compile-fail.hxml.stderr @@ -0,0 +1 @@ +Main.hx:3: characters 18-26 : Duplicate class field declaration : Main.__init__ \ No newline at end of file diff --git a/tests/misc/projects/Issue9378/Main.hx b/tests/misc/projects/Issue9378/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..549626d274b775656380a95c5e4470c07a7a944d --- /dev/null +++ b/tests/misc/projects/Issue9378/Main.hx @@ -0,0 +1,15 @@ +class C { + public final x:Int; + public function new() { + x = 10; + } +} + +class Main { + function new() { + new C().x = 10; + } + + static function main() { + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9378/compile-fail.hxml b/tests/misc/projects/Issue9378/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue9378/compile-fail.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue9378/compile-fail.hxml.stderr b/tests/misc/projects/Issue9378/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..bd536e66ecdd963cf31dd873de485593cd6492f2 --- /dev/null +++ b/tests/misc/projects/Issue9378/compile-fail.hxml.stderr @@ -0,0 +1 @@ +Main.hx:10: characters 3-17 : Cannot access field or identifier x for writing \ No newline at end of file diff --git a/tests/misc/projects/Issue9389/Main.hx b/tests/misc/projects/Issue9389/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..8e68ceb2b43825b1fee8b031bcb7a3c8faa5d4ac --- /dev/null +++ b/tests/misc/projects/Issue9389/Main.hx @@ -0,0 +1,9 @@ +class Main { + static function main() { + f(123); + } + + static macro function f(e) { + throw new haxe.macro.Expr.Error("boop", e.pos); + } +} \ No newline at end of file diff --git a/tests/misc/projects/Issue9389/compile-fail.hxml b/tests/misc/projects/Issue9389/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..fcdb2c3f8e660623abdf6e845a4ee42927aa7163 --- /dev/null +++ b/tests/misc/projects/Issue9389/compile-fail.hxml @@ -0,0 +1 @@ +-main Main \ No newline at end of file diff --git a/tests/misc/projects/Issue9389/compile-fail.hxml.stderr b/tests/misc/projects/Issue9389/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..ccabc8d7eb6002afc0ca9b1f6e326d54c45ba814 --- /dev/null +++ b/tests/misc/projects/Issue9389/compile-fail.hxml.stderr @@ -0,0 +1 @@ +Main.hx:3: characters 5-8 : boop \ No newline at end of file diff --git a/tests/misc/projects/issue5002/compile-fail.hxml.stderr b/tests/misc/projects/issue5002/compile-fail.hxml.stderr index 1de0af27a49ad7a692634b4a5b717b0be2e3f9e9..94abf99404cae62fe154311de505ba11332e2833 100644 --- a/tests/misc/projects/issue5002/compile-fail.hxml.stderr +++ b/tests/misc/projects/issue5002/compile-fail.hxml.stderr @@ -1,4 +1,4 @@ -Main.hx:1: characters 1-8 : "0" is not a valid field name +Main.hx:1: characters 1-8 : "0" is not a valid field name. Main.hx:2: lines 2-4 : Defined in this class -Main.hx:1: characters 1-8 : "this" is not a valid field name +Main.hx:1: characters 1-8 : "this" is not a valid field name. Main.hx:2: lines 2-4 : Defined in this class \ No newline at end of file diff --git a/tests/misc/projects/issue5002/compile2-fail.hxml.stderr b/tests/misc/projects/issue5002/compile2-fail.hxml.stderr index c66dc08ca2e487327dd0d1ce0d396015b1fe1b1d..7d220a6350de2fe7452cdf36b208e66ace3cfd5f 100644 --- a/tests/misc/projects/issue5002/compile2-fail.hxml.stderr +++ b/tests/misc/projects/issue5002/compile2-fail.hxml.stderr @@ -1,18 +1,18 @@ -"0_variable" is not a valid variable name +"0_variable" is not a valid variable name. Main2.hx:6: characters 3-32 : Called from macro here -"var" is not a valid variable name +"var" is not a valid variable name. Main2.hx:7: characters 3-25 : Called from macro here -"new" is not a valid variable name +"new" is not a valid variable name. Main2.hx:8: characters 3-25 : Called from macro here -"foo \"\t\n" is not a valid variable name +"foo \"\t\n" is not a valid variable name. Main2.hx:9: characters 3-32 : Called from macro here -"0_catchVariable" is not a valid catch variable name +"0_catchVariable" is not a valid catch variable name. Main2.hx:10: characters 3-25 : Called from macro here -"0_function" is not a valid function name +"0_function" is not a valid function name. Main2.hx:11: characters 3-24 : Called from macro here -"0_argument" is not a valid function argument name +"0_argument" is not a valid function argument name. Main2.hx:12: characters 3-32 : Called from macro here Main2.hx:13: characters 3-27 : Pattern variables must be lower-case -Main2.hx:14: characters 3-23 : "0_forVariable" is not a valid for variable name -Main2.hx:15: characters 3-31 : "0_forVariableKey" is not a valid for variable name -Main2.hx:15: characters 3-31 : "0_forVariableValue" is not a valid for variable name \ No newline at end of file +Main2.hx:14: characters 3-23 : "0_forVariable" is not a valid for variable name. +Main2.hx:15: characters 3-31 : "0_forVariableKey" is not a valid for variable name. +Main2.hx:15: characters 3-31 : "0_forVariableValue" is not a valid for variable name. \ No newline at end of file diff --git a/tests/misc/projects/issue5002/compile3-fail.hxml.stderr b/tests/misc/projects/issue5002/compile3-fail.hxml.stderr index f48bd84f0d6cac898b1fbd5c36e3665ee3242e2b..4310e3252f3b8b9b7cf268267d0edee143d25181 100644 --- a/tests/misc/projects/issue5002/compile3-fail.hxml.stderr +++ b/tests/misc/projects/issue5002/compile3-fail.hxml.stderr @@ -1,6 +1,6 @@ -Main3.hx:9: characters 17-18 : Module name should start with an uppercase letter: "lowercase" -Main3.hx:9: characters 17-18 : "0_class" is not a valid module name -Main3.hx:9: characters 17-18 : "0_enum" is not a valid module name -Main3.hx:9: characters 17-18 : "0_struct" is not a valid module name -Main3.hx:9: characters 17-18 : "0_abstract_Impl_" is not a valid type name -Main3.hx:9: characters 17-18 : "0_abstract" is not a valid module name \ No newline at end of file +Main3.hx:9: characters 17-18 : Module "lowercase" does not have a valid name. Module name should start with an uppercase letter: "lowercase" +Main3.hx:9: characters 17-18 : Module "0_class" does not have a valid name. "0_class" is not a valid module name. +Main3.hx:9: characters 17-18 : Module "0_enum" does not have a valid name. "0_enum" is not a valid module name. +Main3.hx:9: characters 17-18 : Module "0_struct" does not have a valid name. "0_struct" is not a valid module name. +Main3.hx:9: characters 17-18 : "0_abstract_Impl_" is not a valid type name. +Main3.hx:9: characters 17-18 : Module "0_abstract" does not have a valid name. "0_abstract" is not a valid module name. \ No newline at end of file diff --git a/tests/misc/python/projects/Issue9256/Main.hx b/tests/misc/python/projects/Issue9256/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..8f31fdd9468d808136f697544373a4e1b8bbfefc --- /dev/null +++ b/tests/misc/python/projects/Issue9256/Main.hx @@ -0,0 +1,7 @@ +class Main { + public static function main(){ + python.Syntax.importModule("numpy"); + python.Syntax.importAs("pandas", "pd"); + python.Syntax.importFromAs("sklearn", "metrics", "metrics"); + } +} \ No newline at end of file diff --git a/tests/misc/python/projects/Issue9256/build.hxml b/tests/misc/python/projects/Issue9256/build.hxml new file mode 100644 index 0000000000000000000000000000000000000000..e69f70c8f00889717cd51155e89bc5eac204fc1d --- /dev/null +++ b/tests/misc/python/projects/Issue9256/build.hxml @@ -0,0 +1,2 @@ +-python bin/test.py +--main Main \ No newline at end of file diff --git a/tests/misc/python/pythonImport/native_python/__pycache__/__init__.cpython-36.pyc b/tests/misc/python/pythonImport/native_python/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index f2fd5f7775c8f4db3cb82d35b02591dec2c7db3b..0000000000000000000000000000000000000000 Binary files a/tests/misc/python/pythonImport/native_python/__pycache__/__init__.cpython-36.pyc and /dev/null differ diff --git a/tests/misc/python/pythonImport/native_python/__pycache__/__init__.pypy3-24.pyc b/tests/misc/python/pythonImport/native_python/__pycache__/__init__.pypy3-24.pyc deleted file mode 100644 index 2cb4929736ef11e212eac2d272c556f5b6b24bb3..0000000000000000000000000000000000000000 Binary files a/tests/misc/python/pythonImport/native_python/__pycache__/__init__.pypy3-24.pyc and /dev/null differ diff --git a/tests/misc/python/pythonImport/native_python/__pycache__/sample.cpython-36.pyc b/tests/misc/python/pythonImport/native_python/__pycache__/sample.cpython-36.pyc deleted file mode 100644 index 4bda2e449791bcd27c351cb2241787660d2ed892..0000000000000000000000000000000000000000 Binary files a/tests/misc/python/pythonImport/native_python/__pycache__/sample.cpython-36.pyc and /dev/null differ diff --git a/tests/misc/python/pythonImport/native_python/__pycache__/sample.pypy3-24.pyc b/tests/misc/python/pythonImport/native_python/__pycache__/sample.pypy3-24.pyc deleted file mode 100644 index 21cf2e262102fb5130f6e2d49030058862686f5f..0000000000000000000000000000000000000000 Binary files a/tests/misc/python/pythonImport/native_python/__pycache__/sample.pypy3-24.pyc and /dev/null differ diff --git a/tests/misc/resolution/projects/Issue9189/compile-fail.hxml b/tests/misc/resolution/projects/Issue9189/compile-fail.hxml new file mode 100644 index 0000000000000000000000000000000000000000..78c5c4faf63dae864bc42fec4ed71cca4b4cb8b6 --- /dev/null +++ b/tests/misc/resolution/projects/Issue9189/compile-fail.hxml @@ -0,0 +1 @@ +-main pack.Main diff --git a/tests/misc/resolution/projects/Issue9189/compile-fail.hxml.stderr b/tests/misc/resolution/projects/Issue9189/compile-fail.hxml.stderr new file mode 100644 index 0000000000000000000000000000000000000000..ba11591038bbc75f6fa0412bd389088bca9a1e7e --- /dev/null +++ b/tests/misc/resolution/projects/Issue9189/compile-fail.hxml.stderr @@ -0,0 +1 @@ +pack/Main.hx:8: characters 13-14 : Class has no field A \ No newline at end of file diff --git a/tests/misc/resolution/projects/Issue9189/otherPack/Mod.hx b/tests/misc/resolution/projects/Issue9189/otherPack/Mod.hx new file mode 100644 index 0000000000000000000000000000000000000000..f6486daf14efd221f8e6dc78a336d883813e1698 --- /dev/null +++ b/tests/misc/resolution/projects/Issue9189/otherPack/Mod.hx @@ -0,0 +1,5 @@ +package otherPack; + +class Mod { + public function new() {} +} diff --git a/tests/misc/resolution/projects/Issue9189/pack/Main.hx b/tests/misc/resolution/projects/Issue9189/pack/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..f907653c7034120e5ce5092669e51df2992f516c --- /dev/null +++ b/tests/misc/resolution/projects/Issue9189/pack/Main.hx @@ -0,0 +1,10 @@ +package pack; + +import otherPack.*; + +class Main { + static function main() { + trace(new Mod()); + trace(Mod.A); + } +} diff --git a/tests/misc/resolution/projects/Issue9189/pack/Mod.hx b/tests/misc/resolution/projects/Issue9189/pack/Mod.hx new file mode 100644 index 0000000000000000000000000000000000000000..3f8968ec5a15f804b8ee0afee8910ae7a98e3de6 --- /dev/null +++ b/tests/misc/resolution/projects/Issue9189/pack/Mod.hx @@ -0,0 +1,5 @@ +package pack; + +class Mod { + public static final A = 3; +} diff --git a/tests/misc/resolution/projects/Issue9367/Main.hx b/tests/misc/resolution/projects/Issue9367/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..506c46534683703b8587352fb8e898b4f490eb0b --- /dev/null +++ b/tests/misc/resolution/projects/Issue9367/Main.hx @@ -0,0 +1,12 @@ +import utest.Assert.equals; + +class Main extends utest.Test { + function test() { + equals("subtype1subtype2", pack.UsageNoImport.f()); + equals("field1subtype2", pack.UsageImport.f()); + } + + static function main() { + utest.UTest.run([new Main()]); + } +} diff --git a/tests/misc/resolution/projects/Issue9367/compile.hxml b/tests/misc/resolution/projects/Issue9367/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..f539ee6f3a8a8b6048079aaf3bbd28fd22dad67b --- /dev/null +++ b/tests/misc/resolution/projects/Issue9367/compile.hxml @@ -0,0 +1,4 @@ +-main Main +-lib utest +-js test.js +-cmd node test.js diff --git a/tests/misc/resolution/projects/Issue9367/pack/Mod1.hx b/tests/misc/resolution/projects/Issue9367/pack/Mod1.hx new file mode 100644 index 0000000000000000000000000000000000000000..6747734c46d9ade83d92740f430d9079009d2a2c --- /dev/null +++ b/tests/misc/resolution/projects/Issue9367/pack/Mod1.hx @@ -0,0 +1,9 @@ +package pack; + +class Mod1 { + public static final Mod1Sub = {field: "field1"}; +} + +class Mod1Sub { + public static final field = "subtype1"; +} diff --git a/tests/misc/resolution/projects/Issue9367/pack/Mod2.hx b/tests/misc/resolution/projects/Issue9367/pack/Mod2.hx new file mode 100644 index 0000000000000000000000000000000000000000..c4a35c819fc81357ff30376ecb84396d4f8e9a9c --- /dev/null +++ b/tests/misc/resolution/projects/Issue9367/pack/Mod2.hx @@ -0,0 +1,8 @@ +package pack; + +class Mod2 { +} + +class Mod2Sub { + public static final field = "subtype2"; +} diff --git a/tests/misc/resolution/projects/Issue9367/pack/UsageImport.hx b/tests/misc/resolution/projects/Issue9367/pack/UsageImport.hx new file mode 100644 index 0000000000000000000000000000000000000000..b88356362f02d6ceee95dd85ff6d0b14d1557558 --- /dev/null +++ b/tests/misc/resolution/projects/Issue9367/pack/UsageImport.hx @@ -0,0 +1,10 @@ +package pack; + +import pack.Mod1; +import pack.Mod2; + +class UsageImport { + public static function f() { + return Mod1.Mod1Sub.field + Mod2.Mod2Sub.field; + } +} diff --git a/tests/misc/resolution/projects/Issue9367/pack/UsageNoImport.hx b/tests/misc/resolution/projects/Issue9367/pack/UsageNoImport.hx new file mode 100644 index 0000000000000000000000000000000000000000..5d56b83696cca736fc2d3ceae03881eeb4266608 --- /dev/null +++ b/tests/misc/resolution/projects/Issue9367/pack/UsageNoImport.hx @@ -0,0 +1,10 @@ +package pack; + + + + +class UsageNoImport { + public static function f() { + return Mod1.Mod1Sub.field + Mod2.Mod2Sub.field; + } +} diff --git a/tests/misc/resolution/projects/spec/Imported.hx b/tests/misc/resolution/projects/spec/Imported.hx new file mode 100644 index 0000000000000000000000000000000000000000..bb6f4f6e722f5ce6915a3638c0c9e4351b40810b --- /dev/null +++ b/tests/misc/resolution/projects/spec/Imported.hx @@ -0,0 +1,11 @@ +import RootModWithStatic; +import pack.ModWithStatic; +import utest.Assert; + +class Imported extends utest.Test { + function test() { + Assert.equals("pack.ModWithStatic.TheStatic function", ModWithStatic.TheStatic()); + Assert.equals("RootModWithStatic.TheStatic function", RootModWithStatic.TheStatic()); + Assert.equals("pack.TheStatic", Type.getClassName(TheStatic)); + } +} diff --git a/tests/misc/resolution/projects/spec/Issue9150.hx b/tests/misc/resolution/projects/spec/Issue9150.hx new file mode 100644 index 0000000000000000000000000000000000000000..1c12cb59c75f125d057cd6834fde4332ea427c60 --- /dev/null +++ b/tests/misc/resolution/projects/spec/Issue9150.hx @@ -0,0 +1,7 @@ +import pack.Mod; + +class Issue9150 extends utest.Test { + function test() { + Macro.assert("pack.ModSubType"); + } +} diff --git a/tests/misc/resolution/projects/spec/Macro.hx b/tests/misc/resolution/projects/spec/Macro.hx new file mode 100644 index 0000000000000000000000000000000000000000..ff61964a30bb7473b2287607ef256fa331e290e9 --- /dev/null +++ b/tests/misc/resolution/projects/spec/Macro.hx @@ -0,0 +1,36 @@ +#if macro +import haxe.macro.Expr; +import haxe.macro.Context; +using haxe.macro.Tools; +#end + +class Macro { + #if macro + static function build():Array { + var dotPath = Context.getLocalClass().toString(); + return (macro class { + public final f = $v{dotPath}; + public function new() {} + public static function UpperCase() return $v{dotPath + ".UpperCase"}; + public static function lowerCase() return $v{dotPath + ".lowerCase"}; + }).fields; + } + #end + + public static macro function assert(path:String) { + var pos = Context.currentPos(); + var nameExpr = Context.parse("new " + path + "().f", pos); + var uCallExpr = Context.parse(path + ".UpperCase()", pos); + var lCallExpr = Context.parse(path + ".lowerCase()", pos); + var fullPath = Context.getType(path).toString(); + return macro @:pos(pos) { + utest.Assert.equals($v{fullPath}, $nameExpr); + utest.Assert.equals($v{fullPath + ".UpperCase"}, $uCallExpr); + utest.Assert.equals($v{fullPath + ".lowerCase"}, $lCallExpr); + }; + } + + public static macro function resolves(path:String) { + return try { Context.getType(path); macro true; } catch (_:Any) macro false; + } +} diff --git a/tests/misc/resolution/projects/spec/Main.hx b/tests/misc/resolution/projects/spec/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..7dd5bfd8649592f04299ee12758e44851905416a --- /dev/null +++ b/tests/misc/resolution/projects/spec/Main.hx @@ -0,0 +1,39 @@ +class Main extends utest.Test { + function testQualified() { + Macro.assert("pack.Mod"); + Macro.assert("pack.Mod.Mod"); + Macro.assert("pack.Mod.ModSubType"); + Macro.assert("pack.ModNoMain.ModNoMainSubType"); + Macro.assert("pack.ModNoValue.ModNoValueSubType"); + Macro.assert("pack.ModWithStatic.TheStatic"); + } + + function testQualifiedStd() { + Macro.assert("std.pack.Mod"); + Macro.assert("std.pack.Mod.Mod"); + Macro.assert("std.pack.Mod.ModSubType"); + Macro.assert("std.pack.ModNoMain.ModNoMainSubType"); + Macro.assert("std.pack.ModNoValue.ModNoValueSubType"); + Macro.assert("std.pack.ModWithStatic.TheStatic"); + } + + function testQualifiedStdShadowed() { + var pack = 1; + Macro.assert("std.pack.Mod"); + Macro.assert("std.pack.Mod.Mod"); + Macro.assert("std.pack.Mod.ModSubType"); + Macro.assert("std.pack.ModNoMain.ModNoMainSubType"); + Macro.assert("std.pack.ModNoValue.ModNoValueSubType"); + Macro.assert("std.pack.ModWithStatic.TheStatic"); + } + + static function main() { + utest.UTest.run([ + new Main(), + new pack.inner.Test(), + new Issue9150(), + new Wildcard(), + new Imported(), + ]); + } +} diff --git a/tests/misc/resolution/projects/spec/RootMod.hx b/tests/misc/resolution/projects/spec/RootMod.hx new file mode 100644 index 0000000000000000000000000000000000000000..af2d6b96e10c9add86d89c424be5b118cc5a26e7 --- /dev/null +++ b/tests/misc/resolution/projects/spec/RootMod.hx @@ -0,0 +1,2 @@ +@:build(Macro.build()) class RootMod {} +@:build(Macro.build()) class RootModSubType {} diff --git a/tests/misc/resolution/projects/spec/RootModNoMain.hx b/tests/misc/resolution/projects/spec/RootModNoMain.hx new file mode 100644 index 0000000000000000000000000000000000000000..27bed73d7f44c9772bd51ec893432dcc57090d8d --- /dev/null +++ b/tests/misc/resolution/projects/spec/RootModNoMain.hx @@ -0,0 +1 @@ +@:build(Macro.build()) class RootModNoMainSubType {} diff --git a/tests/misc/resolution/projects/spec/RootModNoValue.hx b/tests/misc/resolution/projects/spec/RootModNoValue.hx new file mode 100644 index 0000000000000000000000000000000000000000..d951ab0d8fbbf684decb027a178cf8438aaef288 --- /dev/null +++ b/tests/misc/resolution/projects/spec/RootModNoValue.hx @@ -0,0 +1,3 @@ +typedef RootModNoValue = {} + +@:build(Macro.build()) class RootModNoValueSubType {} diff --git a/tests/misc/resolution/projects/spec/RootModWithStatic.hx b/tests/misc/resolution/projects/spec/RootModWithStatic.hx new file mode 100644 index 0000000000000000000000000000000000000000..5eb059e5bfbbad7f3cb69230647d5e79c6d6b58b --- /dev/null +++ b/tests/misc/resolution/projects/spec/RootModWithStatic.hx @@ -0,0 +1,5 @@ +class RootModWithStatic { + public static function TheStatic() return "RootModWithStatic.TheStatic function"; +} + +@:build(Macro.build()) class TheStatic {} diff --git a/tests/misc/resolution/projects/spec/Wildcard.hx b/tests/misc/resolution/projects/spec/Wildcard.hx new file mode 100644 index 0000000000000000000000000000000000000000..e32ab1b0326a39d36ac270ae2f4975abc3a98f96 --- /dev/null +++ b/tests/misc/resolution/projects/spec/Wildcard.hx @@ -0,0 +1,16 @@ +import pack.inner.*; +import pack.shadow.*; + +import utest.Assert; + +class Wildcard extends utest.Test { + function test() { + Macro.assert("InnerMod"); + Macro.assert("InnerMod.InnerModSubType"); + Assert.isFalse(Macro.resolves("InnerModSubType")); + Assert.isFalse(Macro.resolves("InnerModNoMainSubType")); + Assert.isTrue(Macro.resolves("InnerModNoValue")); + Assert.isFalse(Macro.resolves("InnerModNoValueSubType")); + Assert.equals(42, Test.f()); + } +} diff --git a/tests/misc/resolution/projects/spec/compile.hxml b/tests/misc/resolution/projects/spec/compile.hxml new file mode 100644 index 0000000000000000000000000000000000000000..f539ee6f3a8a8b6048079aaf3bbd28fd22dad67b --- /dev/null +++ b/tests/misc/resolution/projects/spec/compile.hxml @@ -0,0 +1,4 @@ +-main Main +-lib utest +-js test.js +-cmd node test.js diff --git a/tests/misc/resolution/projects/spec/pack/Mod.hx b/tests/misc/resolution/projects/spec/pack/Mod.hx new file mode 100644 index 0000000000000000000000000000000000000000..ac54bc773f26cee9c1965da4d404de606688caf5 --- /dev/null +++ b/tests/misc/resolution/projects/spec/pack/Mod.hx @@ -0,0 +1,4 @@ +package pack; + +@:build(Macro.build()) class Mod {} +@:build(Macro.build()) class ModSubType {} diff --git a/tests/misc/resolution/projects/spec/pack/ModNoMain.hx b/tests/misc/resolution/projects/spec/pack/ModNoMain.hx new file mode 100644 index 0000000000000000000000000000000000000000..4392ccec801518b69a5b166a9057c9e7d7b2ab41 --- /dev/null +++ b/tests/misc/resolution/projects/spec/pack/ModNoMain.hx @@ -0,0 +1,3 @@ +package pack; + +@:build(Macro.build()) class ModNoMainSubType {} diff --git a/tests/misc/resolution/projects/spec/pack/ModNoValue.hx b/tests/misc/resolution/projects/spec/pack/ModNoValue.hx new file mode 100644 index 0000000000000000000000000000000000000000..bc0437b77357ab699aba59763880a40d714c99c1 --- /dev/null +++ b/tests/misc/resolution/projects/spec/pack/ModNoValue.hx @@ -0,0 +1,5 @@ +package pack; + +typedef ModNoValue = {} + +@:build(Macro.build()) class ModNoValueSubType {} diff --git a/tests/misc/resolution/projects/spec/pack/ModWithStatic.hx b/tests/misc/resolution/projects/spec/pack/ModWithStatic.hx new file mode 100644 index 0000000000000000000000000000000000000000..625ca782ad3203573df58bdc3608d364ab54c3eb --- /dev/null +++ b/tests/misc/resolution/projects/spec/pack/ModWithStatic.hx @@ -0,0 +1,8 @@ +package pack; + +class ModWithStatic { + public static function TheStatic() return "pack.ModWithStatic.TheStatic function"; +} + +@:build(Macro.build()) +class TheStatic {} diff --git a/tests/misc/resolution/projects/spec/pack/inner/InnerMod.hx b/tests/misc/resolution/projects/spec/pack/inner/InnerMod.hx new file mode 100644 index 0000000000000000000000000000000000000000..4bc98895954c060dc29fd12cd23877be75846a37 --- /dev/null +++ b/tests/misc/resolution/projects/spec/pack/inner/InnerMod.hx @@ -0,0 +1,4 @@ +package pack.inner; + +@:build(Macro.build()) class InnerMod {} +@:build(Macro.build()) class InnerModSubType {} diff --git a/tests/misc/resolution/projects/spec/pack/inner/InnerModNoMain.hx b/tests/misc/resolution/projects/spec/pack/inner/InnerModNoMain.hx new file mode 100644 index 0000000000000000000000000000000000000000..a05db3a36c1362e4bf23e93a01f76c229b45f83f --- /dev/null +++ b/tests/misc/resolution/projects/spec/pack/inner/InnerModNoMain.hx @@ -0,0 +1,3 @@ +package pack.inner; + +@:build(Macro.build()) class InnerModNoMainSubType {} diff --git a/tests/misc/resolution/projects/spec/pack/inner/InnerModNoValue.hx b/tests/misc/resolution/projects/spec/pack/inner/InnerModNoValue.hx new file mode 100644 index 0000000000000000000000000000000000000000..87619181e58ccff1583fa6b265847e889ac1db6f --- /dev/null +++ b/tests/misc/resolution/projects/spec/pack/inner/InnerModNoValue.hx @@ -0,0 +1,5 @@ +package pack.inner; + +typedef InnerModNoValue = {} + +@:build(Macro.build()) class InnerModNoValueSubType {} diff --git a/tests/misc/resolution/projects/spec/pack/inner/Test.hx b/tests/misc/resolution/projects/spec/pack/inner/Test.hx new file mode 100644 index 0000000000000000000000000000000000000000..0106199e72245d4647ac7c720c342ede06c7448e --- /dev/null +++ b/tests/misc/resolution/projects/spec/pack/inner/Test.hx @@ -0,0 +1,48 @@ +package pack.inner; + +class Test extends utest.Test { + function testUnqualifiedThisPack() { + Macro.assert("InnerMod"); + Macro.assert("InnerMod.InnerMod"); + Macro.assert("InnerMod.InnerModSubType"); + Macro.assert("InnerModNoMain.InnerModNoMainSubType"); + Macro.assert("InnerModNoValue.InnerModNoValueSubType"); + } + + function testUnqualifiedUpperPack() { + Macro.assert("Mod"); + Macro.assert("Mod.Mod"); + Macro.assert("Mod.ModSubType"); + Macro.assert("ModNoMain.ModNoMainSubType"); + Macro.assert("ModNoValue.ModNoValueSubType"); + Macro.assert("ModWithStatic.TheStatic"); + } + + function testUnqualifiedRootPack() { + Macro.assert("RootMod"); + Macro.assert("RootMod.RootMod"); + Macro.assert("RootMod.RootModSubType"); + Macro.assert("RootModNoMain.RootModNoMainSubType"); + Macro.assert("RootModNoValue.RootModNoValueSubType"); + Macro.assert("RootModWithStatic.TheStatic"); + } + + function testUnqualifiedRootPackStd() { + Macro.assert("std.RootMod"); + Macro.assert("std.RootMod.RootMod"); + Macro.assert("std.RootMod.RootModSubType"); + Macro.assert("std.RootModNoMain.RootModNoMainSubType"); + Macro.assert("std.RootModNoValue.RootModNoValueSubType"); + Macro.assert("std.RootModWithStatic.TheStatic"); + } + + function testUnqualifiedRootPackStdShadowed() { + var RootMod = 1; + Macro.assert("std.RootMod"); + Macro.assert("std.RootMod.RootMod"); + Macro.assert("std.RootMod.RootModSubType"); + Macro.assert("std.RootModNoMain.RootModNoMainSubType"); + Macro.assert("std.RootModNoValue.RootModNoValueSubType"); + Macro.assert("std.RootModWithStatic.TheStatic"); + } +} diff --git a/tests/misc/resolution/projects/spec/pack/shadow/Test.hx b/tests/misc/resolution/projects/spec/pack/shadow/Test.hx new file mode 100644 index 0000000000000000000000000000000000000000..d71fe6f4e5c2bcbffe0a92b03e996be688941980 --- /dev/null +++ b/tests/misc/resolution/projects/spec/pack/shadow/Test.hx @@ -0,0 +1,5 @@ +package pack.shadow; + +class Test { + public static function f() return 42; +} diff --git a/tests/misc/resolution/run.hxml b/tests/misc/resolution/run.hxml new file mode 100644 index 0000000000000000000000000000000000000000..ddd91b1b97cc9c16e2ff9dff562172bae4d471d2 --- /dev/null +++ b/tests/misc/resolution/run.hxml @@ -0,0 +1,2 @@ +-cp ../src +--run Main diff --git a/tests/misc/src/Main.hx b/tests/misc/src/Main.hx index 38621a80de66de19815ed2b979a1e011411c639f..92638c7e12a4ff11efba64234118d4339443ea76 100644 --- a/tests/misc/src/Main.hx +++ b/tests/misc/src/Main.hx @@ -7,19 +7,25 @@ using StringTools; typedef Result = { count:Int, - failures:Int + failures:Int, + summary:String } class Main { static public function main() { var result:Result = compileProjects(); Sys.println('Done running ${result.count} tests with ${result.failures} failures'); + if(result.count > 20 && result.failures > 0) { + Sys.println('SUMMARY:'); + Sys.println(result.summary); + } Sys.exit(result.failures); } static public function compileProjects():Result { var count = 0; var failures = 0; + var failuresSummary = []; var filter = Compiler.getDefine("MISC_TEST_FILTER"); var filterRegex = filter == null ? ~/.*/ : new EReg(filter, ""); function browse(dirPath) { @@ -39,10 +45,11 @@ class Main { Sys.println('Running haxe $path'); var expectFailure = file.endsWith("-fail.hxml"); var expectStderr = if (FileSystem.exists('$file.stderr')) prepareExpectedOutput(File.getContent('$file.stderr')) else null; - var success = runCommand("haxe", [file], expectFailure, expectStderr); + var result = runCommand("haxe", [file], expectFailure, expectStderr); ++count; - if (!success) { + if (!result.success) { failures++; + failuresSummary.push(path + '\n' + result.summary); } Sys.setCwd(old); } @@ -51,7 +58,8 @@ class Main { browse("projects"); return { count: count, - failures: failures + failures: failures, + summary: failuresSummary.join('\n') } } @@ -66,18 +74,21 @@ class Main { return new haxe.Template(s).execute(context, macros); } - static function normPath(_, p:String, properCase = false):String { + static function normPath(_, p:String):String { if (Sys.systemName() == "Windows") { // on windows, haxe returns lowercase paths with backslashes, drive letter uppercased p = p.substr(0, 1).toUpperCase() + p.substr(1); p = p.replace("/", "\\"); - if (!properCase) - p = p.toLowerCase(); } return p; } - static function runCommand(command:String, args:Array, expectFailure:Bool, expectStderr:String) { + static function runCommand(command:String, args:Array, expectFailure:Bool, expectStderr:String):{success:Bool, summary:String} { + var summary = []; + function println(msg:String) { + summary.push(msg); + Sys.println(msg); + } #if timeout switch Sys.systemName() { case 'Linux': @@ -94,13 +105,13 @@ class Main { var success = exit == 0; // 124 - exit code of linux `timeout` command in case it actually timed out if (exit == 124) { - Sys.println('Timeout. No response in ${Compiler.getDefine('timeout')} seconds.'); + println('Timeout. No response in ${Compiler.getDefine('timeout')} seconds.'); } var result = switch [success, expectFailure] { case [true, false]: true; case [true, true]: - Sys.println("Expected failure, but no failure occurred"); + println("Expected failure, but no failure occurred"); false; case [false, true]: true; @@ -111,19 +122,19 @@ class Main { } if (stdout.length > 0) { - Sys.println(stdout); + println(stdout.toString()); } if (result && expectStderr != null) { var stderr = proc.stderr.readAll().toString().replace("\r\n", "\n").trim(); if (stderr != expectStderr.trim()) { - Sys.println("Actual stderr output doesn't match the expected one"); - Sys.println('Expected:\n"$expectStderr"'); - Sys.println('Actual:\n"$stderr"'); + println("Actual stderr output doesn't match the expected one"); + println('Expected:\n"$expectStderr"'); + println('Actual:\n"$stderr"'); result = false; } } proc.close(); - return result; + return {success:result, summary:summary.join('\n')}; } } diff --git a/tests/nullsafety/src/Validator.hx b/tests/nullsafety/src/Validator.hx index 23d835b44dc82365690b1f08cf90d11aba23d595..eb7d11696d06fcc2d8a1d988547c31f5b9c356f1 100644 --- a/tests/nullsafety/src/Validator.hx +++ b/tests/nullsafety/src/Validator.hx @@ -23,7 +23,9 @@ class Validator { for(field in Context.getBuildFields()) { for(meta in field.meta) { if(meta.name == ':shouldFail') { - expectedErrors.push({symbol: field.name, pos:field.pos}); + var fieldPosInfos = Context.getPosInfos(field.pos); + fieldPosInfos.min = Context.getPosInfos(meta.pos).max + 1; + expectedErrors.push({symbol: field.name, pos:Context.makePosition(fieldPosInfos)}); break; } } diff --git a/tests/nullsafety/src/cases/TestStrict.hx b/tests/nullsafety/src/cases/TestStrict.hx index 8fc6578819d1d224343faaf2957bd575c3f3918a..89d5b0eaa3f913dc03d3ade131e1ac06d39f23ab 100644 --- a/tests/nullsafety/src/cases/TestStrict.hx +++ b/tests/nullsafety/src/cases/TestStrict.hx @@ -824,12 +824,34 @@ class TestStrict { a = b; } - function nonFinalField_shouldFail(o:{field:Null}) { + function nonFinalField_immediatelyAfterCheck_shouldPass(o:{field:Null}) { if(o.field != null) { + var notNullable:String = o.field; + } + } + + function nonFinalField_afterLocalAssignment_shouldPass(o:{field:Null}, b:{field:Null}) { + if(o.field != null) { + b = {field:null}; + var notNullable:String = o.field; + } + } + + function nonFinalField_afterFieldAssignment_shouldFail(o:{field:Null}, b:{o:{field:Null}}) { + if(o.field != null) { + b.o = {field:null}; shouldFail(var notNullable:String = o.field); } } + function nonFinalField_afterSomeCall_shouldFail(o:{field:Null}) { + if(o.field != null) { + someCall(); + shouldFail(var notNullable:String = o.field); + } + } + function someCall() {} + static function anonFinalNullableField_checkedForNull() { var o:{ final ?f:String; } = {}; if (o.f != null) { @@ -888,6 +910,16 @@ class TestStrict { } } + function safetyOffArgument_shouldPass(?a:String) { + staticSafetyOffArgument(a); + instanceSafetyOffArgument(a); + inline instanceSafetyOffArgument(a); + } + static function staticSafetyOffArgument(@:nullSafety(Off) b:Dynamic) {} + function instanceSafetyOffArgument(@:nullSafety(Off) b:Dynamic) { + return staticSafetyOffArgument(b); + } + static function issue8122_abstractOnTopOfNullable() { var x:NullFloat = null; var y:Float = x.val(); @@ -908,6 +940,9 @@ class TestStrict { trace("hi", x); trace("hi", shouldFail(x())); } + + @:shouldFail @:nullSafety(InvalidArgument) + static function invalidMetaArgument_shouldFail() {} } private class FinalNullableFields { diff --git a/tests/nullsafety/src/cases/TestStrictThreaded.hx b/tests/nullsafety/src/cases/TestStrictThreaded.hx new file mode 100644 index 0000000000000000000000000000000000000000..f5449adbbd94123f474935b450e39d766fe6dfcb --- /dev/null +++ b/tests/nullsafety/src/cases/TestStrictThreaded.hx @@ -0,0 +1,11 @@ +package cases; + +import Validator.shouldFail; + +class TestStrictThreaded { + function nonFinalField_immediatelyAfterCheck_shouldFail(o:{field:Null}) { + if(o.field != null) { + shouldFail(var notNullable:String = o.field); + } + } +} \ No newline at end of file diff --git a/tests/nullsafety/test.hxml b/tests/nullsafety/test.hxml index 5131c11c4fe8271d641adba8ee2b0cb4ca2e6329..9780163dec403681487996029454a35b9628ae53 100644 --- a/tests/nullsafety/test.hxml +++ b/tests/nullsafety/test.hxml @@ -1,10 +1,12 @@ -cp src -D analyzer-optimize cases.TestStrict +cases.TestStrictThreaded cases.TestLoose cases.TestSafeFieldInUnsafeClass cases.TestAbstract ---macro nullSafety('cases.TestStrict', Strict) --macro nullSafety('cases.TestLoose', Loose) +--macro nullSafety('cases.TestStrict', Strict) +--macro nullSafety('cases.TestStrictThreaded', StrictThreaded) --macro Validator.register() \ No newline at end of file diff --git a/tests/optimization/run.hxml b/tests/optimization/run.hxml index 2195f94f3398bb2ae60631d4350b0fd8741e791c..0734d83f1e240c815a8bd9b5805c31aa62eda9ea 100644 --- a/tests/optimization/run.hxml +++ b/tests/optimization/run.hxml @@ -11,10 +11,15 @@ -D analyzer-check-null --interp +--next +--main TestTreBehavior +--interp + --next -js testopt.js --macro Macro.register('Test') --macro Macro.register('TestJs') --macro Macro.register('TestLocalDce') +--macro Macro.register('TestTreGeneration') --macro Macro.register('issues') --dce std \ No newline at end of file diff --git a/tests/optimization/src/Test.hx b/tests/optimization/src/Test.hx index f1f52bc7da7f70a1e83fdaf296a6ea501b0a9f83..6b2a2c3222ed713a7d2b1f964f06c43095a1ce76 100644 --- a/tests/optimization/src/Test.hx +++ b/tests/optimization/src/Test.hx @@ -8,6 +8,25 @@ class InlineCtor { } } +class Collection { + public var amount:Int; + public inline function new(amount:Int) this.amount = amount; + public inline function count() return amount; + public inline function iterator() return new CollectionIterator(this); +} + +class CollectionIterator { + final set:Collection; + var current:Int = 0; + public inline function new(set:Collection) this.set = set; + public inline function hasNext() return current++ < set.amount; + public inline function next() return (null:V); +} + +typedef Countable = { + function count():Int; +} + enum abstract MyEnum(String) to String { var A = "a"; } @@ -85,6 +104,45 @@ class Test { b.x = a; } + @:js(' + var v_amount = 10; + var a = 10; + ') + static function testInlineCtor_passedToInlineMethodAsAnonConstraint() { + var a = count(new Collection(10)); + } + static inline function count(v:T) { + return v.count(); + } + + @:js(' + var _g_set_amount = 10; + var _g_current = 0; + while(_g_current++ < 10) { + var i = null; + } + ') + static function testIterator_passedToInlineMethodAsAnonConstraint() { + iterIterator(new Collection(10).iterator()); + } + static inline function iterIterator>(it:T) { + for(i in it) {} + } + + @:js(' + var _g_set_amount = 10; + var _g_current = 0; + while(_g_current++ < 10) { + var i = null; + } + ') + static function testIterable_passedToInlineMethodAsAnonConstraint() { + iterIterable(new Collection(10)); + } + static inline function iterIterable>(it:T) { + for(i in it) {} + } + @:js(' var x_foo = 1; var x_bar = 2; @@ -102,9 +160,9 @@ class Test { @:js('var x = { "oh-my" : "god"};') static function testStructureInlineInvalidField() { - var x = { - "oh-my": "god" - }; + var x = { + "oh-my": "god" + }; } @:js(' diff --git a/tests/optimization/src/TestBase.hx b/tests/optimization/src/TestBase.hx index 176cf657d3e9f39fd7711b63108f150533d5bddf..5bf73de61201fbba593d33f306b3f48a234f136d 100644 --- a/tests/optimization/src/TestBase.hx +++ b/tests/optimization/src/TestBase.hx @@ -18,5 +18,11 @@ class TestBase { } } + function fail(?msg:String, ?p:haxe.PosInfos) { + ++numTests; + ++numFailures; + haxe.Log.trace(msg != null ? msg : 'Forced failure', p); + } + function setup() { } } \ No newline at end of file diff --git a/tests/optimization/src/TestBaseMacro.hx b/tests/optimization/src/TestBaseMacro.hx index e8deb5959d87c40359e324c7842db11f2968c65b..ba99bbe5c29d44c7f86318493cfea3fdea8f51ac 100644 --- a/tests/optimization/src/TestBaseMacro.hx +++ b/tests/optimization/src/TestBaseMacro.hx @@ -19,7 +19,12 @@ class TestBaseMacro { acc.push(macro $i{field.name}()); } } - acc.push(macro trace("Done " +numTests+ " tests (" +numFailures+ " failures)")); + acc.push(macro { + trace("Done " +numTests+ " tests (" +numFailures+ " failures)"); + if(numFailures > 0) { + Sys.exit(1); + } + }); Context.onGenerate(check); return macro $b{acc}; } diff --git a/tests/optimization/src/TestJs.hx b/tests/optimization/src/TestJs.hx index 52cc8449e5ab6545817bbb59c69607916537ec43..96fb1dc663f5d9c53a81082e07692b9430a014ff 100644 --- a/tests/optimization/src/TestJs.hx +++ b/tests/optimization/src/TestJs.hx @@ -62,7 +62,7 @@ class TestJs { return v + v2; } - @:js("var a = [];var tmp;try {tmp = a[0];} catch( e ) {((e) instanceof js__$Boot_HaxeError);tmp = null;}tmp;") + @:js("var a = [];var tmp;try {tmp = a[0];} catch( _g ) {tmp = null;}tmp;") @:analyzer(no_local_dce) static function testInlineWithComplexExpr() { var a = []; @@ -73,7 +73,7 @@ class TestJs { return try a[i] catch (e:Dynamic) null; } - @:js("var a_v_0_b = 1;a_v_0_b;") + @:js("var a_v_0_b = 1;") @:analyzer(no_const_propagation, no_local_dce) static function testDeepMatchingWithoutClosures() { var a = {v: [{b: 1}]}; @@ -167,27 +167,27 @@ class TestJs { var vRand = new Inl(Math.random()); } - @:js("try {throw new js__$Boot_HaxeError(false);} catch( e ) {}") + @:js("try {throw haxe_Exception.thrown(false);} catch( _g ) {}") static function testNoHaxeErrorUnwrappingWhenNotRequired() { try throw false catch (e:Dynamic) {} } - @:js('try {throw new js__$Boot_HaxeError(false);} catch( e ) {TestJs.use(((e) instanceof js__$Boot_HaxeError) ? e.val : e);}') + @:js('try {throw haxe_Exception.thrown(false);} catch( _g ) {TestJs.use(haxe_Exception.caught(_g).unwrap());}') static function testHaxeErrorUnwrappingWhenUsed() { try throw false catch (e:Dynamic) use(e); } - @:js('try {throw new js__$Boot_HaxeError(false);} catch( e ) {if(typeof(((e) instanceof js__$Boot_HaxeError) ? e.val : e) != "boolean") {throw e;}}') + @:js('try {throw haxe_Exception.thrown(false);} catch( _g ) {if(typeof(haxe_Exception.caught(_g).unwrap()) != "boolean") {throw _g;}}') static function testHaxeErrorUnwrappingWhenTypeChecked() { try throw false catch (e:Bool) {}; } - @:js('try {throw new js__$Boot_HaxeError(false);} catch( e ) {if(typeof(((e) instanceof js__$Boot_HaxeError) ? e.val : e) == "boolean") {TestJs.use(e);} else {throw e;}}') + @:js('try {throw haxe_Exception.thrown(false);} catch( _g ) {if(typeof(haxe_Exception.caught(_g).unwrap()) == "boolean") {TestJs.use(_g);} else {throw _g;}}') static function testGetOriginalException() { try throw false catch (e:Bool) use(js.Lib.getOriginalException()); } - @:js('try {throw new js__$Boot_HaxeError(false);} catch( e ) {if(typeof(((e) instanceof js__$Boot_HaxeError) ? e.val : e) == "boolean") {throw e;} else {throw e;}}') + @:js('try {throw haxe_Exception.thrown(false);} catch( _g ) {if(typeof(haxe_Exception.caught(_g).unwrap()) == "boolean") {throw _g;} else {throw _g;}}') static function testRethrow() { try throw false catch (e:Bool) js.Lib.rethrow(); } @@ -249,8 +249,8 @@ class TestJs { } @:js(' - var map = new haxe_ds_StringMap(); - if(__map_reserved["some"] != null) {map.setReserved("some",2);} else {map.h["some"] = 2;} + var map_h = Object.create(null); + map_h["some"] = 2; TestJs.use(2); ') static function testIssue4731() { @@ -362,7 +362,7 @@ class TestJs { @:js(' TestJs.getInt(); if(TestJs.getInt() != 0) { - throw new js__$Boot_HaxeError("meh"); + throw haxe_Exception.thrown("meh"); } ') static function testIfInvert() { @@ -432,8 +432,8 @@ class TestJs { @:js(' var d1 = TestJs.call(1,2); var d11 = TestJs.call(TestJs.call(3,4),d1); - var d12 = TestJs.call(5,6); - TestJs.call(TestJs.call(TestJs.call(7,8),d12),d11); + var d1 = TestJs.call(5,6); + TestJs.call(TestJs.call(TestJs.call(7,8),d1),d11); ') static function testInlineRebuilding7() { inlineCall(inlineCall(call(1, 2), call(3, 4)), inlineCall(call(5, 6), call(7, 8))); @@ -442,8 +442,8 @@ class TestJs { @:js(' var d1 = TestJs.call(1,2); var d11 = TestJs.call(TestJs.intField,d1); - var d12 = TestJs.intField; - TestJs.call(TestJs.call(TestJs.call(5,6),d12),d11); + var d1 = TestJs.intField; + TestJs.call(TestJs.call(TestJs.call(5,6),d1),d11); ') static function testInlineRebuilding8() { inlineCall(inlineCall(call(1, 2), intField), inlineCall(intField, call(5, 6))); @@ -527,11 +527,11 @@ class TestJs { @:js(' var tmp = "foo"; Extern.test(tmp); - var tmp1 = "bar"; - Extern.test(tmp1); + var tmp = "bar"; + Extern.test(tmp); var closure = Extern.test; - var tmp2 = "baz"; - closure(tmp2); + var tmp = "baz"; + closure(tmp); ') static function testAsVar() { Extern.test("foo"); @@ -552,6 +552,105 @@ class TestJs { static function testIssue8751() { (2:Issue8751Int) * 3; } + + @:js('var v = "hi";TestJs.use(typeof(v) == "string" ? v : null);') + static function testStdIsOptimizationSurvivesCast() { + var value = "hi"; + use(as(value, String)); + } + + static inline function as(v:Dynamic, c:Class):Null { + return if (Std.isOfType(v, c)) v else null; + } + + @:js('var f = function(x) {TestJs.use(x);};f(10);') + static function testVarSelfAssignmentRemoved() { + inline function g() return 0; + function f(x:Int) { + x = x + g(); + use(x); + } + + f(10); + } + + @:js('var f = function(x) {while(true) TestJs.use(x);};f(10);') + static inline function testNoRedundantContinue() { + inline function g() return true; + function f(x:Int) { + while (true) { + TestJs.use(x); + if (g()) continue; + } + } + f(10); + } + + @:js(' + var x = function() {return true;}; + var f = function(b) { + if(x()) {b = true;} + TestJs.use(b); + }; + f(false); + ') + static function testIssue9239_noDoubleNegation() { + function x() return true; + function f(b:Bool) { + b = x() || b; + TestJs.use(b); + } + f(false); + } + + @:js('var a = !(!null);TestJs.use(a);') + static function testIssue9239_dubleNegation_notOptimizedForNullBool() { + inline function processNullBool(v:Null):Bool { + return !!v; + } + var a = processNullBool(null); + TestJs.use(a); + } + + @:js(' + var produce = function(producer) {return null;}; + produce(function(obj) {obj.id = 2;}); + ') + static function testIssue9181_arrowFunction_infersVoidReturn() { + function produce(producer: T -> Void): T { + return null; + } + var result = produce((obj) -> { + obj.id = 2; + }); + } + + @:js(' + var voidFunc = function() {}; + TestJs.use(function() {voidFunc();}); + TestJs.use(function() {voidFunc();}); + ') + static function testIssue6420_voidFunction_noRedundantReturn() { + function voidFunc() {} + TestJs.use(function() return voidFunc()); + TestJs.use(() -> voidFunc()); + } + + @:js(' + var x = 1; + var f = function(y) { + return new Issue9227(x,y); + }; + f(3); + ') + static function testIssue9227_bind_lessClosures() { + var f = Issue9227.new.bind(1); + f(3); + } +} + +class Issue9227 { + public function new(x:Int, y:Int) {} } extern class Extern { diff --git a/tests/optimization/src/TestLocalDce.hx b/tests/optimization/src/TestLocalDce.hx index d4afd9df478191b3c1c46bac36b6655e569f8991..4f8021ba69425432766e44261ed7d68d939fc84f 100644 --- a/tests/optimization/src/TestLocalDce.hx +++ b/tests/optimization/src/TestLocalDce.hx @@ -161,7 +161,6 @@ class TestLocalDce { var i = _g1[_g]; ++_g; s += i * 2; - continue; } TestJs.use(s); ') @@ -176,9 +175,9 @@ class TestLocalDce { @:js(' var s = TestLocalDce.keep(1); - var _g1 = [0,3,4]; - while(0 < _g1.length) { - var i = _g1[0]; + var _g = [0,3,4]; + while(0 < _g.length) { + var i = _g[0]; s += i * 2; break; } diff --git a/tests/optimization/src/TestTreBehavior.hx b/tests/optimization/src/TestTreBehavior.hx new file mode 100644 index 0000000000000000000000000000000000000000..0057d2cd92faf225877962c34299829835d48756 --- /dev/null +++ b/tests/optimization/src/TestTreBehavior.hx @@ -0,0 +1,68 @@ +package ; + +class TestTreBehavior extends TestBase { + + static function main() { + new TestTreBehavior(); + } + + public function new() { + super(); + TestBaseMacro.run(); + } + + function testClosureCapturedArgs() { + var steps = []; + + function loop(a:Int):Int { + steps.push(() -> a); + --a; + return a <= 0 ? 0 : loop(a - 1); + } + loop(5); + + var actual = steps.map(fn -> fn()); + switch actual { + case [4, 2, 0]: + case _: assertEquals(actual, [4, 2, 0]); + } + } + + function testOverriddenMethod() { + var parent = new Parent(); + var child = new Child(); + + assertEquals(2, parent.rec(2)); + assertEquals(5, child.rec(2)); + } + + function testSelfModifyingFields() { + assertEquals(1, selfModifyingMethod()); + assertEquals(2, selfModifyingVar()); + } + + static dynamic function selfModifyingMethod():Int { + selfModifyingMethod = () -> 1; + return selfModifyingMethod(); + } + + static var selfModifyingVar:()->Int = function() { + selfModifyingVar = () -> 2; + return selfModifyingVar(); + } +} + +private class Parent { + public function new() {} + + public function rec(n:Int, cnt:Int = 0):Int { + if(n <= 0) return cnt; + return rec(n - 1, cnt + 1); + } +} + +private class Child extends Parent { + override public function rec(n:Int, cnt:Int = 0):Int { + return super.rec(n, cnt + 1); + } +} \ No newline at end of file diff --git a/tests/optimization/src/TestTreGeneration.hx b/tests/optimization/src/TestTreGeneration.hx new file mode 100644 index 0000000000000000000000000000000000000000..6fa83e109831f774070b6f6c9e02fb4a907cfafa --- /dev/null +++ b/tests/optimization/src/TestTreGeneration.hx @@ -0,0 +1,157 @@ +class TestTreGeneration { + @:js(' + if(b == null) { + b = 10; + } + while(true) { + if(Std.random(2) == 0) { + var _gtmp = a; + a = b + a; + b = _gtmp; + s += "?"; + continue; + } + if(s == null) { + return a; + } else { + return b; + } + } + ') + static function testStaticMethod(a:Int, b:Int = 10, ?s:String):Int { + if(Std.random(2) == 0) { + return testStaticMethod(b + a, a, s + '?'); + } + return s == null ? a : b; + } + + @:js(' + if(b == null) { + b = 10; + } + while(true) { + if(Std.random(2) == 0) { + var _gtmp1 = a; + a = b + a; + b = _gtmp1; + s += "?"; + continue; + } + if(s == null) { + return a; + } else { + return b; + } + } + ') + function testInstanceMethod(a:Int, b:Int = 10, ?s:String):Int { + if(Std.random(2) == 0) { + return testInstanceMethod(b + a, a, s + '?'); + } + return s == null ? a : b; + } + + @:js(' + var local = null; + local = function(a,b,s) { + if(b == null) { + b = 10; + } + while(true) { + if(Std.random(2) == 0) { + var _gtmp = a; + a = b + a; + b = _gtmp; + s += "?"; + continue; + } + if(s == null) { + return a; + } else { + return b; + } + } + }; + local(1,2); + ') + static function testLocalNamedFunction() { + function local(a:Int, b:Int = 10, ?s:String):Int { + if(Std.random(2) == 0) { + return local(b + a, a, s + '?'); + } + return s == null ? a : b; + } + local(1, 2); + } + + @:js(' + var _g = 0; + var _g1 = Std.random(10); + while(_g < _g1) { + ++_g; + if(Std.random(2) == 0) { + return TestTreGeneration.testTailRecursionInsideLoop(); + } + } + return Std.random(10); + ') + static function testTailRecursionInsideLoop():Int { + for(i in 0...Std.random(10)) { + if(Std.random(2) == 0) { + return testTailRecursionInsideLoop(); + } + } + return Std.random(10); + } + + @:js(' + while(true) { + if(Std.random(2) == 0) { + a -= 1; + continue; + } + if(a < 10) { + a += 1; + continue; + } + return; + } + ') + static function testVoid(a:Int):Void { + if(Std.random(2) == 0) { + testVoid(a - 1); + return; + } + if(a < 10) { + testVoid(a + 1); + } + } + + @:js(' + while(true) { + try { + if(n <= 0) { + throw haxe_Exception.thrown("exit"); + } + return TestTreGeneration.testTryCancelsTre(n - 1); + } catch( _g ) { + if(n == 0) { + n -= 1; + continue; + } + } + return 0; + } + ') + static function testTryCancelsTre(n:Int):Int { + try { + if(n <= 0) throw 'exit'; + return testTryCancelsTre(n - 1); + } catch(e:Dynamic) { + if(n == 0) { + return testTryCancelsTre(n - 1); + } + } + return 0; + } +} \ No newline at end of file diff --git a/tests/optimization/src/issues/Issue3524.hx b/tests/optimization/src/issues/Issue3524.hx index c312463c009f884b1d492ceef9c2f7e91561079b..c38487dbe796e949995e29151cbde5928d4babf4 100644 --- a/tests/optimization/src/issues/Issue3524.hx +++ b/tests/optimization/src/issues/Issue3524.hx @@ -4,20 +4,26 @@ typedef List = { v : Int, next : List }; class Issue3524 { @:js(' - var l1 = { v : 0, next : null}; - var l2 = { v : 1, next : null}; - l1.v - l2.v; + var l1_v; + var l1_next; + l1_v = 0; + l1_next = null; + var l2_v; + var l2_next; + l2_v = 1; + l2_next = null; + l1_v - l2_v; ') @:analyzer(ignore) - static function main() { + static function main() { var l1 = { v: 0, next: null }; var l2 = { v: 1, next: null }; apply(cmp, l1, l2); - } + } static inline function cmp(a:List, b:List) { - return a.v - b.v; - } + return a.v - b.v; + } static inline function apply(f:List -> List -> Int, l1:List, l2:List) { f(l1, l2); diff --git a/tests/optimization/src/issues/Issue4690.hx b/tests/optimization/src/issues/Issue4690.hx index 34889830b490ec6565003235d6673dda043e0b5c..940002fd9911894c9f7873706483868a40537682 100644 --- a/tests/optimization/src/issues/Issue4690.hx +++ b/tests/optimization/src/issues/Issue4690.hx @@ -35,7 +35,12 @@ class Issue4690 { TestJs.use("Child.new: Before super"); TestJs.use("Parent.new: Before assign"); c_x = 1; - c_y = "" + 2; + var c_y1 = false; + if(c_y1) { + c_y = "null"; + } else { + c_y = "" + 2; + } TestJs.use("Parent.new: After assign"); TestJs.use("Child.new: After super"); c_z = 3; diff --git a/tests/optimization/src/issues/Issue5745.hx b/tests/optimization/src/issues/Issue5745.hx index 92ffb6928b2f960ac5218d228a5c8c1d0e809ff2..c4046ee4803899ef547a3be3621030652d9b7de5 100644 --- a/tests/optimization/src/issues/Issue5745.hx +++ b/tests/optimization/src/issues/Issue5745.hx @@ -4,9 +4,8 @@ import TestJs.use; class Issue5745 { @:js(' - var fn = "filename"; - var v = cat(fn); - runProgram.apply(undefined, ["rm",fn]); + var v = cat("filename"); + runProgram.apply(undefined, ["rm","filename"]); TestJs.use(v); ') static function test() { @@ -19,9 +18,9 @@ class Issue5745 { class Shell { public inline static function runProgram(args:Array):Int { - return untyped __js__('runProgram.apply(undefined, {0})', args); + return js.Syntax.code('runProgram.apply(undefined, {0})', args); } public inline static function cat(v:String):String { - return untyped __js__('cat({0})', v); + return js.Syntax.code('cat({0})', v); } } \ No newline at end of file diff --git a/tests/optimization/src/issues/Issue6296.hx b/tests/optimization/src/issues/Issue6296.hx deleted file mode 100644 index 7aa5d41d4cd9ec387c36f00e0cc77edb54ea33f7..0000000000000000000000000000000000000000 --- a/tests/optimization/src/issues/Issue6296.hx +++ /dev/null @@ -1,17 +0,0 @@ -package issues; - -class Issue6296 { - @:js(' - var a1 = []; - if(a1.push != null) { - a1.push(1); - }' - ) - @:analyzer(no_local_dce) - static function f(a, b) { - var a = []; - if (a.push != null) { - a.push(1); - } - } -} \ No newline at end of file diff --git a/tests/optimization/src/issues/Issue6297.hx b/tests/optimization/src/issues/Issue6297.hx new file mode 100644 index 0000000000000000000000000000000000000000..e1630d1ba9722063b0865bff4a874c14a41e037b --- /dev/null +++ b/tests/optimization/src/issues/Issue6297.hx @@ -0,0 +1,20 @@ +package issues; + +class Issue6297 { + @:js(" + issues_Issue6297.use(a.test == null); + issues_Issue6297.use(a.test != null); + issues_Issue6297.use(null == a.test); + issues_Issue6297.use(null != a.test); + ") + @:analyzer(no_local_dce) + static function f(a:{function test():Void;}) { + use(a.test == null); + use(a.test != null); + use(null == a.test); + use(null != a.test); + } + + @:pure(false) + static function use(e:Dynamic) {} +} \ No newline at end of file diff --git a/tests/optimization/src/issues/Issue6302.hx b/tests/optimization/src/issues/Issue6302.hx index 0c683f0f8305e1a726f8e25cd8343fb82ca205bb..4f305ad1c98d4c7aa1b8cd97e711fc86150a7f2e 100644 --- a/tests/optimization/src/issues/Issue6302.hx +++ b/tests/optimization/src/issues/Issue6302.hx @@ -1,9 +1,15 @@ package issues; class Issue6302 { - @:js('a = b && a;') + @:js('a = b && c;') @:analyzer(no_local_dce) - static function f(a, b) { + static function f1(a, b, c) { + a = b && c; + } + + @:js('if(!b) {a = false;}') + @:analyzer(no_local_dce) + static function f2(a, b) { a = b && a; } } \ No newline at end of file diff --git a/tests/optimization/src/issues/Issue6715.hx b/tests/optimization/src/issues/Issue6715.hx index 7cb0fc0ab7453b2f11ecb15a2dc011d17d59c51d..8604011e543851599500e3de8c1a5261f0602e45 100644 --- a/tests/optimization/src/issues/Issue6715.hx +++ b/tests/optimization/src/issues/Issue6715.hx @@ -9,12 +9,12 @@ class Issue6715 { issues_Issue6715.x = f; issues_Issue6715.x = f; issues_Issue6715.x = f; - var x1 = 1; - x1 = 2; - var x2 = 1; - x2 = 2; - var x3 = 1; - x3 = 2; + var x = 1; + x = 2; + var x = 1; + x = 2; + var x = 1; + x = 2; ') @:analyzer(no_local_dce) static public function test1() { @@ -24,10 +24,10 @@ class Issue6715 { @:js(' var x = 1; x = 2; - var x1 = 1; - x1 = 2; - var x2 = 1; - x2 = 2; + var x = 1; + x = 2; + var x = 1; + x = 2; ') @:analyzer(no_local_dce) static public function test2() { diff --git a/tests/optimization/src/issues/Issue7113.hx b/tests/optimization/src/issues/Issue7113.hx index 083830371e29eff7a30df239d9fb7549c9681eae..47503f86073ea805c54b7cea00b3129a67de8b53 100644 --- a/tests/optimization/src/issues/Issue7113.hx +++ b/tests/optimization/src/issues/Issue7113.hx @@ -5,7 +5,7 @@ private class MyType<@:const T> { public function new() { } public inline function constGenericInlineWtf() { - untyped __js__('console.log({0})', T); + js.Syntax.code('console.log({0})', T); } } diff --git a/tests/runci/TestTarget.hx b/tests/runci/TestTarget.hx index b2d90f4810ee876da04360e4173a3f3bb6676a0b..ade86653a9f3e9ede0301a111be7c8ef3f6d2f3f 100644 --- a/tests/runci/TestTarget.hx +++ b/tests/runci/TestTarget.hx @@ -10,7 +10,6 @@ enum abstract TestTarget(String) from String { var Cpp = "cpp"; var Cppia = "cppia"; var Flash9 = "flash9"; - var As3 = "as3"; var Java = "java"; var Jvm = "jvm"; var Cs = "cs"; diff --git a/tests/runci/targets/As3.hx b/tests/runci/targets/As3.hx deleted file mode 100644 index c16bc7744dbe15542e7a40d42f1e360057c9ccec..0000000000000000000000000000000000000000 --- a/tests/runci/targets/As3.hx +++ /dev/null @@ -1,15 +0,0 @@ -package runci.targets; - -import runci.System.*; - -class As3 { - static public function run(args:Array) { - runci.targets.Flash.setupFlashPlayerDebugger(); - runci.targets.Flash.setupFlexSdk(); - - runCommand("haxe", ["compile-as3.hxml", "-D", "fdb"].concat(args)); - var success = runci.targets.Flash.runFlash("bin/unit9_as3.swf"); - if (!success) - fail(); - } -} \ No newline at end of file diff --git a/tests/runci/targets/Flash.hx b/tests/runci/targets/Flash.hx index 752e5587c3e34cb467e03db16b7780de262271b3..55dfc73ff331241f9e0ec974b081a3c0edbe64dd 100644 --- a/tests/runci/targets/Flash.hx +++ b/tests/runci/targets/Flash.hx @@ -144,6 +144,8 @@ class Flash { break; } } + traceProcess.kill(); + traceProcess.close(); Sys.command("cat", [flashlogPath]); return success; } diff --git a/tests/runci/targets/Lua.hx b/tests/runci/targets/Lua.hx index 2202bc65d81b636880bc3e82a29a44aac95540d2..8fd6db2603ef56e95cd26c3aedc716794a33f24c 100644 --- a/tests/runci/targets/Lua.hx +++ b/tests/runci/targets/Lua.hx @@ -7,6 +7,9 @@ import haxe.io.*; using StringTools; class Lua { + static var miscLuaDir(get,never):String; + static inline function get_miscLuaDir() return miscDir + 'lua/'; + static public function getLuaDependencies(){ switch (systemName){ case "Linux": @@ -62,7 +65,7 @@ class Lua { // Note: don't use a user config // runCommand("luarocks", ["config", "--user-config"], false, true); - installLib("haxe-deps", "0.0.1-1"); + installLib("haxe-deps", "0.0.1-2"); changeDirectory(unitDir); runCommand("haxe", ["compile-lua.hxml"].concat(args)); @@ -74,6 +77,9 @@ class Lua { changeDirectory(miscDir + "luaDeadCode/stringReflection"); runCommand("haxe", ["compile.hxml"]); + + changeDirectory(miscLuaDir); + runCommand("haxe", ["run.hxml"]); } } } diff --git a/tests/runci/targets/Macro.hx b/tests/runci/targets/Macro.hx index c9984630af8cf82737e284b0ec74eb22441ff886..3ce14801a1290645ac42fd3492e73bb28d3d2ecc 100644 --- a/tests/runci/targets/Macro.hx +++ b/tests/runci/targets/Macro.hx @@ -24,6 +24,9 @@ class Macro { changeDirectory(miscDir); runCommand("haxe", ["compile.hxml"]); + changeDirectory(miscDir + "resolution"); + runCommand("haxe", ["run.hxml"]); + changeDirectory(sysDir); runCommand("haxe", ["compile-macro.hxml"].concat(args)); diff --git a/tests/runci/targets/Python.hx b/tests/runci/targets/Python.hx index a4465eddf8d84dd20da76357a0bd52eafe1ba983..5cb49afb348a29de44843bbb346de1d3e3dbc43d 100644 --- a/tests/runci/targets/Python.hx +++ b/tests/runci/targets/Python.hx @@ -21,7 +21,7 @@ class Python { if (commandSucceed(pypy, ["-V"])) { infoMsg('pypy3 has already been installed.'); } else { - var pypyVersion = "pypy3-2.4.0-linux64"; + var pypyVersion = "pypy3.6-v7.3.0-linux64"; var file = '${pypyVersion}.tar.bz2'; if(!FileSystem.exists(file)) { runCommand("wget", ["-nv", 'https://bitbucket.org/pypy/pypy/downloads/$file'], true); diff --git a/tests/server/.vscode/settings.json b/tests/server/.vscode/settings.json index 9f0eb0d8dc19bf43f9d1f24d832e2502f76fdaeb..41760e5e363f52973dbb51585bbea33312407ded 100644 --- a/tests/server/.vscode/settings.json +++ b/tests/server/.vscode/settings.json @@ -1,6 +1,6 @@ { "haxe.diagnosticsPathFilter": "${workspaceRoot}/src", - "editor.formatOnSave": true, + // "editor.formatOnSave": true, "haxeTestExplorer.testCommand": [ "${haxe}", "build.hxml", diff --git a/tests/server/build.hxml b/tests/server/build.hxml index 8529f804cb1d4a66999af32fda37f9e56dbb392f..e06a6c87fce81139c25a70fa5beb365f549d5fed 100644 --- a/tests/server/build.hxml +++ b/tests/server/build.hxml @@ -4,4 +4,5 @@ -js test.js -lib hxnodejs -lib utest --lib haxeserver \ No newline at end of file +-lib haxeserver +-D analyzer-optimize \ No newline at end of file diff --git a/tests/server/src/AsyncMacro.hx b/tests/server/src/AsyncMacro.hx deleted file mode 100644 index 94ba91b13903aa07c3569042b5befe249ea37af9..0000000000000000000000000000000000000000 --- a/tests/server/src/AsyncMacro.hx +++ /dev/null @@ -1,53 +0,0 @@ -import haxe.macro.Expr; -import haxe.macro.Context; - -using StringTools; - -class AsyncMacro { - static public macro function build():Array { - var fields = Context.getBuildFields(); - for (field in fields) { - if (!field.name.startsWith("test")) { - continue; - } - switch (field.kind) { - case FFun(f): - f.args.push({ - name: "async", - type: macro:utest.Async - }); - switch (f.expr.expr) { - case EBlock(el): - el.push(macro @:pos(f.expr.pos) async.done()); - f.expr = transformHaxeCalls(el); - case _: - Context.error("Block expression expected", f.expr.pos); - } - case _: - } - } - return fields; - } - - static function transformHaxeCalls(el:Array) { - var e0 = el.shift(); - return if (el.length == 0) { - e0; - } else switch (e0) { - case macro runHaxe($a{args}): - var e = transformHaxeCalls(el); - args.push(macro() -> $e); - macro runHaxe($a{args}); - case macro runHaxeJson($a{args}): - var e = transformHaxeCalls(el); - args.push(macro() -> $e); - macro runHaxeJson($a{args}); - case macro complete($a{args}): - var e = transformHaxeCalls(el); - args.push(macro function(response, markers) $e); - macro complete($a{args}); - case _: - macro {$e0; ${transformHaxeCalls(el)}}; - } - } -} diff --git a/tests/server/src/DisplayTestCase.hx b/tests/server/src/DisplayTestCase.hx new file mode 100644 index 0000000000000000000000000000000000000000..d1197323d3ce37627132816a82e0dad37b46bc75 --- /dev/null +++ b/tests/server/src/DisplayTestCase.hx @@ -0,0 +1,48 @@ +import haxe.display.Position; +import haxe.Exception; +import utils.Markers; +import haxe.display.FsPath; + +/** + Display test should have a snippet with `{-N-}` markers + in the doc block. + The snippet will be automatically parsed. +**/ +class DisplayTestCase extends TestCase { + /** The snippet with markers removed */ + var source(get,never):String; + /** A file created for the snippet */ + final file = new FsPath("Main.hx"); + /** Data extracted from the snippet */ + var markers(get, never):Markers; + @:noCompletion var _markers:Null; + + inline function get_markers():Markers + return switch _markers { + case null: throw new Exception('Markers are not initialized'); + case m: m; + } + + inline function get_source():String + return markers.source; + + /** + * Returns an offset of the n-th marker. + * Amount of characters from the beginning of the parsed document excluding markers. + */ + public function offset(n:Int):Int + return markers.offset(n); + + /** + * Returns a position of n-th marker. + * Line number and character number from the beginning of the line. + */ + public function pos(n:Int):Position + return markers.pos(n); + + /** + * Returns a range between positions of `startMarker` and `endMarker` + */ + public function range(startMarker:Int, endMarker:Int):Range + return markers.range(startMarker, endMarker); +} diff --git a/tests/server/src/DisplayTests.hx b/tests/server/src/DisplayTests.hx deleted file mode 100644 index 879d1d28a500f5bd176f95cbd4e0994f089c7edb..0000000000000000000000000000000000000000 --- a/tests/server/src/DisplayTests.hx +++ /dev/null @@ -1,248 +0,0 @@ -import haxe.display.Protocol; -import haxe.PosInfos; -import haxe.display.Server; -import utest.Assert; -import utest.Assert.*; -import haxe.display.Display; -import haxe.display.FsPath; - -@:timeout(5000) -// TODO: somebody has to clean this up -class DisplayTests extends HaxeServerTestCase { - function testIssue7305() { - var content = 'class Main { - static public function main() { - new Map{-1-} - } -}'; - var transform = Marker.extractMarkers(content); - vfs.putContent("Main.hx", transform.source); - runHaxeJson([], DisplayMethods.Completion, { - file: new FsPath("Main.hx"), - offset: transform.markers[1], - wasAutoTriggered: true - }); - var result = parseCompletion(); - assertHasCompletion(result, item -> switch (item.kind) { - case Type: item.args.path.pack.length == 0 && item.args.path.typeName == "Map"; - case _: false; - }); - } - - function testIssue7317() { - var content = 'class Main { - public static function main() { - var obj = {}; - obj.{-1-} - } -}'; - var transform = Marker.extractMarkers(content); - vfs.putContent("Main.hx", transform.source); - runHaxeJson([], DisplayMethods.Completion, { - file: new FsPath("Main.hx"), - offset: transform.markers[1], - wasAutoTriggered: true - }); - var result = parseCompletion(); - Assert.equals("obj", result.result.mode.args.item.args.name); - } - - function testIssue8061() { - var content = 'class Main { - static function main() { - new sys.io.Process({-1-}) - } -}'; - var transform = Marker.extractMarkers(content); - vfs.putContent("Main.hx", transform.source); - runHaxeJson([], DisplayMethods.SignatureHelp, { - file: new FsPath("Main.hx"), - offset: transform.markers[1], - wasAutoTriggered: true - }); - var result = parseSignatureHelp(); - Assert.isTrue(result.result.signatures[0].documentation != null); - } - - function testIssue8194() { - var content = 'class Main { - static function main() { - switch ("p") { - case "p"{-1-} - "foo"; - } - } -}'; - var transform = Marker.extractMarkers(content); - vfs.putContent("Main.hx", transform.source); - runHaxeJson([], DisplayMethods.Completion, { - file: new FsPath("Main.hx"), - offset: transform.markers[1], - wasAutoTriggered: true - }); - var result = parseCompletion(); - Assert.equals(null, result.result); - } - - function testIssue8381() { - var content = 'class Main { - static function main() { - var f:Foo; - f.f{-1-}oo(); - f.bar; - } -} - -typedef Foo = { - /** Test **/ - function foo():Void; - - /** Test **/ - var bar:Int; -}'; - - var transform = Marker.extractMarkers(content); - vfs.putContent("Main.hx", transform.source); - runHaxeJson([], DisplayMethods.Hover, { - file: new FsPath("Main.hx"), - offset: transform.markers[1] - }); - var result = parseHover(); - Assert.equals(DisplayItemKind.ClassField, result.result.item.kind); - } - - function testIssue8438() { - var content = 'class Main { - static function main() { - " ".char{-1-} - } -}'; - var transform = Marker.extractMarkers(content); - vfs.putContent("Main.hx", transform.source); - runHaxeJson([], DisplayMethods.Completion, { - file: new FsPath("Main.hx"), - offset: transform.markers[1], - wasAutoTriggered: true - }); - var result = parseCompletion(); - Assert.equals(6, result.result.replaceRange.start.character); - Assert.equals(10, result.result.replaceRange.end.character); - } - - function testIssue8602() { - var content = "class Main { - static function main() { - haxe.ds.{-1-} - } -}"; - var transform = Marker.extractMarkers(content); - vfs.putContent("Main.hx", transform.source); - runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("Main.hx"), offset: transform.markers[1], wasAutoTriggered: true}); - var result = parseCompletion(); - Assert.equals(Toplevel, result.result.mode.kind); - } - - function testIssue8644() { - vfs.putContent("HelloJvm.hx", getTemplate("HelloJvm.hx")); - var args = ["-cp", ".", "--interp"]; - runHaxeJson(args, ServerMethods.ReadClassPaths, null); - runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("HelloJvm.hx"), offset: 55, wasAutoTriggered: false}); - var completion = parseCompletion(); - assertHasNoCompletion(completion, module -> switch (module.kind) { - case Type: module.args.path.typeName == "Jvm"; - case _: false; - }); - } - - function testIssue8651() { - var content = "class Main { static function main() { {-1-}buffer{-2-} } }"; - vfs.putContent("Main.hx", content); - var transform = Marker.extractMarkers(content); - vfs.putContent("Main.hx", transform.source); - runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("Main.hx"), offset: transform.markers[2], wasAutoTriggered: true}); - var result = parseCompletion(); - var r = result.result; - Assert.equals("buffer", r.filterString); - Assert.equals(transform.markers[1], r.replaceRange.start.character); - Assert.equals(transform.markers[2], r.replaceRange.end.character); - } - - function testIssue8657() { - var content = "class Main { static function main() { var x:{-1-}stream{-2-} } }"; - vfs.putContent("Main.hx", content); - var transform = Marker.extractMarkers(content); - vfs.putContent("Main.hx", transform.source); - runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("Main.hx"), offset: transform.markers[2], wasAutoTriggered: true}); - var result = parseCompletion(); - var r = result.result; - Assert.equals("stream", r.filterString); - Assert.equals(transform.markers[1], r.replaceRange.start.character); - Assert.equals(transform.markers[2], r.replaceRange.end.character); - } - - function testIssue8659() { - var content = "class Main extends {-1-}StreamTokenizer{-2-} { }"; - vfs.putContent("Main.hx", content); - var transform = Marker.extractMarkers(content); - vfs.putContent("Main.hx", transform.source); - runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("Main.hx"), offset: transform.markers[2], wasAutoTriggered: true}); - var result = parseCompletion(); - var r = result.result; - Assert.equals("StreamTokenizer", r.filterString); - Assert.equals(transform.markers[1], r.replaceRange.start.character); - Assert.equals(transform.markers[2], r.replaceRange.end.character); - } - - function testIssue8666() { - vfs.putContent("cp1/HelloWorld.hx", getTemplate("HelloWorld.hx")); - vfs.putContent("cp2/MyClass.hx", "class MyClass { }"); - var args = ["-cp", "cp1", "--interp"]; - runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false}); - var completion = parseCompletion(); - assertHasNoCompletion(completion, module -> switch (module.kind) { - case Type: module.args.path.typeName == "MyClass"; - case _: false; - }); - runHaxeJson(args.concat(["-cp", "cp2"]), DisplayMethods.Completion, {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false}); - var completion = parseCompletion(); - assertHasCompletion(completion, module -> switch (module.kind) { - case Type: module.args.path.typeName == "MyClass"; - case _: false; - }); - } - - function testIssue8666_lib() { - vfs.putContent("cp1/HelloWorld.hx", getTemplate("HelloWorld.hx")); - vfs.putContent("cp2/MyClass.hx", "class MyClass { }"); - var args = ["-cp", "cp1", "--interp"]; - runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false}); - var completion = parseCompletion(); - assertHasNoCompletion(completion, module -> switch (module.kind) { - case Type: module.args.path.typeName == "MyClass"; - case _: false; - }); - runHaxeJson(args.concat(["-cp", "cp2", "-D", "imalibrary"]), DisplayMethods.Completion, - {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false}); - var completion = parseCompletion(); - assertHasCompletion(completion, module -> switch (module.kind) { - case Type: module.args.path.typeName == "MyClass"; - case _: false; - }); - } - - function testIssue8732() { - var content = "class Main { static function main() { var ident = \"foo\"; {-1-}i{-2-}dent.{-3-} } }"; - vfs.putContent("Main.hx", content); - var transform = Marker.extractMarkers(content); - vfs.putContent("Main.hx", transform.source); - runHaxeJson([], Methods.Initialize, {maxCompletionItems: 50}); - runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("Main.hx"), offset: transform.markers[2], wasAutoTriggered: true}); - runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("Main.hx"), offset: transform.markers[3], wasAutoTriggered: true}); - runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("Main.hx"), offset: transform.markers[1], wasAutoTriggered: true}); - var result = parseCompletion(); - assertHasNoCompletion(result, item -> switch (item.kind) { - case ClassField: item.args.field.name == "charAt"; - case _: false; - }); - } -} diff --git a/tests/server/src/Main.hx b/tests/server/src/Main.hx index 2cb6c52347a133c076ec824903c2c7e8fcf61476..e35a4cafcbe06112012eab275e7d7ff78da45560 100644 --- a/tests/server/src/Main.hx +++ b/tests/server/src/Main.hx @@ -1,273 +1,16 @@ -import haxe.display.Display; -import haxe.display.FsPath; -import haxe.display.Server; -import utest.Assert; - -using StringTools; -using Lambda; - -@:timeout(10000) -class ServerTests extends HaxeServerTestCase { - function testNoModification() { - vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx")); - var args = ["-main", "HelloWorld.hx", "--no-output", "-js", "no.js"]; - runHaxe(args); - runHaxe(args); - assertReuse("HelloWorld"); - runHaxe(args); - assertReuse("HelloWorld"); - } - - function testModification() { - vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx")); - var args = ["-main", "HelloWorld.hx", "--no-output", "-js", "no.js"]; - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("HelloWorld.hx")}); - runHaxe(args); - assertSkipping("HelloWorld"); - // assertNotCacheModified("HelloWorld"); - } - - function testDependency() { - vfs.putContent("WithDependency.hx", getTemplate("WithDependency.hx")); - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - var args = ["-main", "WithDependency.hx", "--no-output", "-js", "no.js"]; - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); - runHaxe(args); - assertSkipping("WithDependency", "Dependency"); - // assertNotCacheModified("Dependency"); - runHaxe(args); - assertReuse("Dependency"); - assertReuse("WithDependency"); - } - - function testMacro() { - vfs.putContent("MacroMain.hx", getTemplate("MacroMain.hx")); - vfs.putContent("Macro.hx", getTemplate("Macro.hx")); - var args = ["-main", "MacroMain.hx", "--no-output", "-js", "no.js"]; - runHaxe(args); - assertHasPrint("1"); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("MacroMain.hx")}); - runHaxe(args); - assertHasPrint("1"); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Macro.hx")}); - runHaxe(args); - assertHasPrint("1"); - vfs.putContent("Macro.hx", getTemplate("Macro.hx").replace("1", "2")); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Macro.hx")}); - runHaxe(args); - assertHasPrint("2"); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("MacroMain.hx")}); - runHaxe(args); - assertHasPrint("2"); - } - - function testDceEmpty() { - vfs.putContent("Empty.hx", getTemplate("Empty.hx")); - var args = ["-main", "Empty", "--no-output", "-java", "java"]; - runHaxe(args); - runHaxeJson(args, cast "typer/compiledTypes" /* TODO */, {}); - assertHasField("", "Type", "enumIndex", true); - } - - function testBuildMacro() { - vfs.putContent("BuildMacro.hx", getTemplate("BuildMacro.hx")); - vfs.putContent("BuiltClass.hx", getTemplate("BuiltClass.hx")); - var args = ["-main", "BuiltClass.hx", "--interp"]; - runHaxe(args); - runHaxe(args); - assertReuse("BuiltClass"); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("BuildMacro.hx")}); - runHaxe(args); - // assertNotCacheModified("BuildMacro"); - assertSkipping("BuiltClass", "BuildMacro"); - assertSkipping("BuildMacro"); - } - - function testBrokenSyntaxDiagnostics() { - vfs.putContent("BrokenSyntax.hx", getTemplate("BrokenSyntax.hx")); - vfs.putContent("Empty.hx", getTemplate("Empty.hx")); - var args = ["-main", "BrokenSyntax.hx", "--interp", "--no-output"]; - runHaxe(args); - assertErrorMessage("Expected }"); - runHaxe(args.concat(["--display", "Empty.hx@0@diagnostics"])); - runHaxe(args); - assertErrorMessage("Expected }"); - } - - function testGlobalBuildMacro_subsequentCompilations() { - vfs.putContent("GlobalBuildMacro.hx", getTemplate("GlobalBuildMacro.hx")); - var args = ["--macro", "GlobalBuildMacro.use()", "--run", "GlobalBuildMacro"]; - runHaxe(args); - runHaxe(args); - assertSuccess(); - } - - - #if false // @see https://github.com/HaxeFoundation/haxe/issues/8596#issuecomment-518815594 - function testDisplayModuleRecache() { - vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx")); - var args = ["--main", "HelloWorld", "--interp"]; - runHaxe(args); - runHaxe(args); - assertReuse("HelloWorld"); - - var args2 = ["--main", "HelloWorld", "--interp", "--display", "HelloWorld.hx@64@type"]; - runHaxe(args2); - - runHaxe(args); - assertReuse("HelloWorld"); - - // make sure we still invalidate if the file does change - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("HelloWorld.hx")}); - runHaxe(args2); - - runHaxe(args); - assertSkipping("HelloWorld"); - } - #end - - #if false // @see https://github.com/HaxeFoundation/haxe/issues/8596#issuecomment-518815594 - function testMutuallyDependent() { - vfs.putContent("MutuallyDependent1.hx", getTemplate("MutuallyDependent1.hx")); - vfs.putContent("MutuallyDependent2.hx", getTemplate("MutuallyDependent2.hx")); - - var args = ["MutuallyDependent1", "MutuallyDependent2"]; - runHaxe(args); - - args = args.concat(["--display", "MutuallyDependent1.hx@44@type"]); - runHaxe(args); - assertSuccess(); - } - #end - - function testSyntaxCache() { - vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx")); - runHaxeJson(["-cp", "."], ServerMethods.ReadClassPaths, null); - vfs.putContent("Empty.hx", ""); - runHaxeJson([], ServerMethods.ModuleCreated, {file: new FsPath("Empty.hx")}); - vfs.putContent("Empty.hx", getTemplate("Empty.hx")); - runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("HelloWorld.hx"), offset: 75, wasAutoTriggered: false}); - var completion = parseCompletion(); - assertHasCompletion(completion, module -> switch (module.kind) { - case Type: module.args.path.typeName == "HelloWorld"; - case _: false; - }); - assertHasCompletion(completion, module -> switch (module.kind) { - case Type: module.args.path.typeName == "Empty"; - case _: false; - }); - // check removal - vfs.putContent("Empty.hx", ""); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Empty.hx")}); - runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("HelloWorld.hx"), offset: 75, wasAutoTriggered: false}); - var completion = parseCompletion(); - assertHasCompletion(completion, module -> switch (module.kind) { - case Type: module.args.path.typeName == "HelloWorld"; - case _: false; - }); - assertHasNoCompletion(completion, module -> switch (module.kind) { - case Type: module.args.path.typeName == "Empty"; - case _: false; - }); - } - - function testSyntaxCache2() { - vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx")); - var args = ["-cp", ".", "--interp"]; - runHaxeJson(args, ServerMethods.ReadClassPaths, null); - vfs.putContent("Empty.hx", getTemplate("Empty.hx")); - runHaxeJson([] /* No args here because file watchers don't generally know */, ServerMethods.ModuleCreated, {file: new FsPath("Empty.hx")}); - runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("HelloWorld.hx"), offset: 75, wasAutoTriggered: false}); - var completion = parseCompletion(); - assertHasCompletion(completion, module -> switch (module.kind) { - case Type: module.args.path.typeName == "Empty"; - case _: false; - }); - } - - function testVectorInliner() { - vfs.putContent("Vector.hx", getTemplate("Vector.hx")); - vfs.putContent("VectorInliner.hx", getTemplate("VectorInliner.hx")); - var args = ["-main", "VectorInliner", "--interp"]; - runHaxe(args); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("VectorInliner.hx")}); - runHaxeJson(args, cast "typer/compiledTypes" /* TODO */, {}); - var type = getStoredType("", "VectorInliner"); - function moreHack(s:String) { - return ~/[\r\n\t]/g.replace(s, ""); - } - utest.Assert.equals("function() {_Vector.Vector_Impl_.toIntVector(null);}", moreHack(type.args.statics[0].expr.testHack)); // lmao - } - - // See https://github.com/HaxeFoundation/haxe/issues/8368#issuecomment-525379060 - #if false - function testXRedefinedFromX() { - vfs.putContent("Main.hx", getTemplate("issues/Issue8368/Main.hx")); - vfs.putContent("MyMacro.hx", getTemplate("issues/Issue8368/MyMacro.hx")); - vfs.putContent("Type1.hx", getTemplate("issues/Issue8368/Type1.hx")); - vfs.putContent("Type2.hx", getTemplate("issues/Issue8368/Type2.hx")); - var args = ["-main", "Main", "--macro", "define('whatever')"]; - runHaxe(args); - runHaxe(args); - assertSuccess(); - } - #end - - function testMacroStaticsReset() { - vfs.putContent("Main.hx", getTemplate("issues/Issue8631/Main.hx")); - vfs.putContent("Init.hx", getTemplate("issues/Issue8631/Init.hx")); - vfs.putContent("Macro.hx", getTemplate("issues/Issue8631/Macro.hx")); - var hxml = ["-main", "Main", "--macro", "Init.callMacro()", "--interp"]; - runHaxe(hxml); - runHaxe(hxml); - var counter = vfs.getContent("counter.txt"); - utest.Assert.equals('2', counter); - } - - function testIssue8738() { - vfs.putContent("Base.hx", getTemplate("issues/Issue8738/Base.hx")); - vfs.putContent("Main.hx", getTemplate("issues/Issue8738/Main1.hx")); - var args = ["-main", "Main", "--interp"]; - runHaxe(args); - assertSuccess(); - vfs.putContent("Main.hx", getTemplate("issues/Issue8738/Main2.hx")); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); - runHaxe(args); - assertErrorMessage("Cannot force inline-call to test because it is overridden"); - vfs.putContent("Main.hx", getTemplate("issues/Issue8738/Main3.hx")); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); - runHaxe(args); - assertSuccess(); - } - - function testIssue8748() { - vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); - vfs.putContent("WithDependency.hx", getTemplate("WithDependency.hx")); - vfs.putContent("res/dep.dep", ""); - var args = [ - "-main", - "WithDependency", - "--interp", - "--macro", - "haxe.macro.Context.registerModuleDependency(\"Dependency\", \"res/dep.dep\")" - ]; - runHaxeJson(args, ServerMethods.Configure, {noModuleChecks: true}); - runHaxe(args); - runHaxeJson(args, DisplayMethods.Hover, {file: new FsPath("WithDependency.hx"), offset: 65}); - assertReuse("Dependency"); - runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("res/dep.dep")}); - runHaxeJson(args, DisplayMethods.Hover, {file: new FsPath("WithDependency.hx"), offset: 65}); - // check messages manually because module file contains awkward absolute path - var r = ~/skipping Dependency\(.*dep.dep\)/; - Assert.isTrue(messages.exists(message -> r.match(message))); - } -} +import utest.ui.Report; +import utest.Runner; +import utils.Vfs; class Main { static public function main() { Vfs.removeDir("test/cases"); - utest.UTest.run([new ServerTests(), new DisplayTests(), new ReplaceRanges()]); + + var runner = new Runner(); + runner.addCases('cases'); + var report = Report.create(runner); + report.displayHeader = AlwaysShowHeader; + report.displaySuccessResults = NeverShowSuccessResults; + runner.run(); } -} +} \ No newline at end of file diff --git a/tests/server/src/HaxeServerTestCase.hx b/tests/server/src/TestCase.hx similarity index 85% rename from tests/server/src/HaxeServerTestCase.hx rename to tests/server/src/TestCase.hx index 9172c91272e716b9ad547d9f316c8ab65c260073..327aaf8cf8b04a474dc0acfe6e2cdf065ed219ef 100644 --- a/tests/server/src/HaxeServerTestCase.hx +++ b/tests/server/src/TestCase.hx @@ -1,3 +1,5 @@ +import haxe.Exception; +import haxe.display.Position; import haxeserver.HaxeServerRequestResult; import haxe.display.JsonModuleTypes; import haxe.display.Display; @@ -7,12 +9,13 @@ import haxeserver.process.HaxeServerProcessNode; import haxeserver.HaxeServerAsync; import utest.Assert; import utest.ITest; +import utils.Vfs; using StringTools; using Lambda; -@:autoBuild(AsyncMacro.build()) -class HaxeServerTestCase implements ITest { +@:autoBuild(utils.macro.BuildHub.build()) +class TestCase implements ITest { var server:HaxeServerAsync; var vfs:Vfs; var testDir:String; @@ -120,6 +123,19 @@ class HaxeServerTestCase implements ITest { return Json.parse(lastResult.stderr).result; } + function parseGotoDefinition():GotoTypeDefinitionResult { + return Json.parse(lastResult.stderr).result; + } + + function parseGotoDefinitionLocations():Array { + switch parseGotoDefinition().result { + case null: + throw new Exception('No result for GotoDefinition found'); + case result: + return result; + } + } + function assertSuccess(?p:haxe.PosInfos) { Assert.isTrue(0 == errorMessages.length, p); } @@ -186,4 +202,16 @@ class HaxeServerTestCase implements ITest { } Assert.pass(); } + + function strType(t:JsonType):String { + var path = t.args.path; + var params = t.args.params; + var parts = path.pack.concat([path.typeName]); + var s = parts.join('.'); + if (params.length == 0) { + return s; + } + var sParams = params.map(strType).join('.'); + return '$s<$sParams>'; + } } diff --git a/tests/server/src/ReplaceRanges.hx b/tests/server/src/cases/ReplaceRanges.hx similarity index 99% rename from tests/server/src/ReplaceRanges.hx rename to tests/server/src/cases/ReplaceRanges.hx index 62b2d877ca4b08c5fb45604353a26cc25e7e51be..17b6bb4b646be3dd1225cdefdf575e2518ba18a1 100644 --- a/tests/server/src/ReplaceRanges.hx +++ b/tests/server/src/cases/ReplaceRanges.hx @@ -1,3 +1,5 @@ +package cases; + import haxe.PosInfos; import haxe.display.FsPath; import haxe.display.Display; @@ -5,7 +7,7 @@ import utest.Assert.*; @:timeout(5000) // TODO: somebody has to clean this up -class ReplaceRanges extends HaxeServerTestCase { +class ReplaceRanges extends TestCase { function complete(content:String, markerIndex:Int, cb:(response:CompletionResponse, markers:Map) -> Void) { var transform = Marker.extractMarkers(content); vfs.putContent("Main.hx", transform.source); diff --git a/tests/server/src/cases/ServerTests.hx b/tests/server/src/cases/ServerTests.hx new file mode 100644 index 0000000000000000000000000000000000000000..9497017fb2eb75ac9292ff94b699544e664044a3 --- /dev/null +++ b/tests/server/src/cases/ServerTests.hx @@ -0,0 +1,240 @@ +package cases; + +import haxe.display.Display; +import haxe.display.FsPath; +import haxe.display.Server; +import utest.Assert; + +using StringTools; +using Lambda; + +@:timeout(10000) +class ServerTests extends TestCase { + function testNoModification() { + vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx")); + var args = ["-main", "HelloWorld.hx", "--no-output", "-js", "no.js"]; + runHaxe(args); + runHaxe(args); + assertReuse("HelloWorld"); + runHaxe(args); + assertReuse("HelloWorld"); + } + + function testModification() { + vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx")); + var args = ["-main", "HelloWorld.hx", "--no-output", "-js", "no.js"]; + runHaxe(args); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("HelloWorld.hx")}); + runHaxe(args); + assertSkipping("HelloWorld"); + // assertNotCacheModified("HelloWorld"); + } + + function testDependency() { + vfs.putContent("WithDependency.hx", getTemplate("WithDependency.hx")); + vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); + var args = ["-main", "WithDependency.hx", "--no-output", "-js", "no.js"]; + runHaxe(args); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Dependency.hx")}); + runHaxe(args); + assertSkipping("WithDependency", "Dependency"); + // assertNotCacheModified("Dependency"); + runHaxe(args); + assertReuse("Dependency"); + assertReuse("WithDependency"); + } + + function testMacro() { + vfs.putContent("MacroMain.hx", getTemplate("MacroMain.hx")); + vfs.putContent("Macro.hx", getTemplate("Macro.hx")); + var args = ["-main", "MacroMain.hx", "--no-output", "-js", "no.js"]; + runHaxe(args); + assertHasPrint("1"); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("MacroMain.hx")}); + runHaxe(args); + assertHasPrint("1"); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Macro.hx")}); + runHaxe(args); + assertHasPrint("1"); + vfs.putContent("Macro.hx", getTemplate("Macro.hx").replace("1", "2")); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Macro.hx")}); + runHaxe(args); + assertHasPrint("2"); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("MacroMain.hx")}); + runHaxe(args); + assertHasPrint("2"); + } + + function testDceEmpty() { + vfs.putContent("Empty.hx", getTemplate("Empty.hx")); + var args = ["-main", "Empty", "--no-output", "-java", "java"]; + runHaxe(args); + runHaxeJson(args, cast "typer/compiledTypes" /* TODO */, {}); + assertHasField("", "Type", "enumIndex", true); + } + + function testBuildMacro() { + vfs.putContent("BuildMacro.hx", getTemplate("BuildMacro.hx")); + vfs.putContent("BuiltClass.hx", getTemplate("BuiltClass.hx")); + var args = ["-main", "BuiltClass.hx", "--interp"]; + runHaxe(args); + runHaxe(args); + assertReuse("BuiltClass"); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("BuildMacro.hx")}); + runHaxe(args); + // assertNotCacheModified("BuildMacro"); + assertSkipping("BuiltClass", "BuildMacro"); + assertSkipping("BuildMacro"); + } + + function testBrokenSyntaxDiagnostics() { + vfs.putContent("BrokenSyntax.hx", getTemplate("BrokenSyntax.hx")); + vfs.putContent("Empty.hx", getTemplate("Empty.hx")); + var args = ["-main", "BrokenSyntax.hx", "--interp", "--no-output"]; + runHaxe(args); + assertErrorMessage("Expected }"); + runHaxe(args.concat(["--display", "Empty.hx@0@diagnostics"])); + runHaxe(args); + assertErrorMessage("Expected }"); + } + + function testGlobalBuildMacro_subsequentCompilations() { + vfs.putContent("GlobalBuildMacro.hx", getTemplate("GlobalBuildMacro.hx")); + var args = ["--macro", "GlobalBuildMacro.use()", "--run", "GlobalBuildMacro"]; + runHaxe(args); + runHaxe(args); + assertSuccess(); + } + + #if false // @see https://github.com/HaxeFoundation/haxe/issues/8596#issuecomment-518815594 + function testDisplayModuleRecache() { + vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx")); + var args = ["--main", "HelloWorld", "--interp"]; + runHaxe(args); + runHaxe(args); + assertReuse("HelloWorld"); + + var args2 = ["--main", "HelloWorld", "--interp", "--display", "HelloWorld.hx@64@type"]; + runHaxe(args2); + + runHaxe(args); + assertReuse("HelloWorld"); + + // make sure we still invalidate if the file does change + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("HelloWorld.hx")}); + runHaxe(args2); + + runHaxe(args); + assertSkipping("HelloWorld"); + } + #end + + #if false // @see https://github.com/HaxeFoundation/haxe/issues/8596#issuecomment-518815594 + function testMutuallyDependent() { + vfs.putContent("MutuallyDependent1.hx", getTemplate("MutuallyDependent1.hx")); + vfs.putContent("MutuallyDependent2.hx", getTemplate("MutuallyDependent2.hx")); + + var args = ["MutuallyDependent1", "MutuallyDependent2"]; + runHaxe(args); + + args = args.concat(["--display", "MutuallyDependent1.hx@44@type"]); + runHaxe(args); + assertSuccess(); + } + #end + + function testSyntaxCache() { + vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx")); + runHaxeJson(["-cp", "."], ServerMethods.ReadClassPaths, null); + vfs.putContent("Empty.hx", ""); + runHaxeJson([], ServerMethods.ModuleCreated, {file: new FsPath("Empty.hx")}); + vfs.putContent("Empty.hx", getTemplate("Empty.hx")); + runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("HelloWorld.hx"), offset: 75, wasAutoTriggered: false}); + var completion = parseCompletion(); + assertHasCompletion(completion, module -> switch (module.kind) { + case Type: module.args.path.typeName == "HelloWorld"; + case _: false; + }); + assertHasCompletion(completion, module -> switch (module.kind) { + case Type: module.args.path.typeName == "Empty"; + case _: false; + }); + // check removal + vfs.putContent("Empty.hx", ""); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Empty.hx")}); + runHaxeJson([], DisplayMethods.Completion, {file: new FsPath("HelloWorld.hx"), offset: 75, wasAutoTriggered: false}); + var completion = parseCompletion(); + assertHasCompletion(completion, module -> switch (module.kind) { + case Type: module.args.path.typeName == "HelloWorld"; + case _: false; + }); + assertHasNoCompletion(completion, module -> switch (module.kind) { + case Type: module.args.path.typeName == "Empty"; + case _: false; + }); + } + + function testSyntaxCache2() { + vfs.putContent("HelloWorld.hx", getTemplate("HelloWorld.hx")); + var args = ["-cp", ".", "--interp"]; + runHaxeJson(args, ServerMethods.ReadClassPaths, null); + vfs.putContent("Empty.hx", getTemplate("Empty.hx")); + runHaxeJson([] /* No args here because file watchers don't generally know */, ServerMethods.ModuleCreated, {file: new FsPath("Empty.hx")}); + runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("HelloWorld.hx"), offset: 75, wasAutoTriggered: false}); + var completion = parseCompletion(); + assertHasCompletion(completion, module -> switch (module.kind) { + case Type: module.args.path.typeName == "Empty"; + case _: false; + }); + } + + function testVectorInliner() { + vfs.putContent("Vector.hx", getTemplate("Vector.hx")); + vfs.putContent("VectorInliner.hx", getTemplate("VectorInliner.hx")); + var args = ["-main", "VectorInliner", "--interp"]; + runHaxe(args); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("VectorInliner.hx")}); + runHaxeJson(args, cast "typer/compiledTypes" /* TODO */, {}); + var type = getStoredType("", "VectorInliner"); + function moreHack(s:String) { + return ~/[\r\n\t]/g.replace(s, ""); + } + utest.Assert.equals("function() {_Vector.Vector_Impl_.toIntVector(null);}", moreHack(type.args.statics[0].expr.testHack)); // lmao + } + + // See https://github.com/HaxeFoundation/haxe/issues/8368#issuecomment-525379060 + #if false + function testXRedefinedFromX() { + vfs.putContent("Main.hx", getTemplate("issues/Issue8368/Main.hx")); + vfs.putContent("MyMacro.hx", getTemplate("issues/Issue8368/MyMacro.hx")); + vfs.putContent("Type1.hx", getTemplate("issues/Issue8368/Type1.hx")); + vfs.putContent("Type2.hx", getTemplate("issues/Issue8368/Type2.hx")); + var args = ["-main", "Main", "--macro", "define('whatever')"]; + runHaxe(args); + runHaxe(args); + assertSuccess(); + } + #end + + function testMacroStaticsReset() { + vfs.putContent("Main.hx", getTemplate("issues/Issue8631/Main.hx")); + vfs.putContent("Init.hx", getTemplate("issues/Issue8631/Init.hx")); + vfs.putContent("Macro.hx", getTemplate("issues/Issue8631/Macro.hx")); + var hxml = ["-main", "Main", "--macro", "Init.callMacro()", "--interp"]; + runHaxe(hxml); + runHaxe(hxml); + var counter = vfs.getContent("counter.txt"); + utest.Assert.equals('2', counter); + } + + // function testIssue8616() { + // vfs.putContent("Main.hx", getTemplate("issues/Issue8616/Main.hx")); + // vfs.putContent("A.hx", getTemplate("issues/Issue8616/A.hx")); + // var args = ["-main", "Main", "-js", "out.js"]; + // runHaxe(args); + // runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); + // runHaxe(args); + // var content = sys.io.File.getContent(haxe.io.Path.join([testDir, "out.js"])); + // Assert.isTrue(content.indexOf("this1.use(v1)") != -1); + // } +} diff --git a/tests/server/src/cases/display/issues/Issue7262.hx b/tests/server/src/cases/display/issues/Issue7262.hx new file mode 100644 index 0000000000000000000000000000000000000000..b6f4e8fff4efa0eb5b6e8fc41f4c0556e9aecf75 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue7262.hx @@ -0,0 +1,20 @@ +package cases.display.issues; + +class Issue7262 extends DisplayTestCase { + /** + class Main { + static public function main() { + var x:haxe.extern.EitherType Void> = {-1-} + } + } + **/ + function test(_) { + runHaxeJson([], DisplayMethods.Completion, { + file: file, + offset: offset(1), + wasAutoTriggered: true + }); + var result = parseCompletion().result; + Assert.equals("TAnonymous", result.mode.args.expectedTypeFollowed.args.params[0].kind); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue7305.hx b/tests/server/src/cases/display/issues/Issue7305.hx new file mode 100644 index 0000000000000000000000000000000000000000..4d8d3b64819ce2f431f7568d3a2d02cf9e3979c6 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue7305.hx @@ -0,0 +1,23 @@ +package cases.display.issues; + +class Issue7305 extends DisplayTestCase { + /** + class Main { + static public function main() { + new Map{-1-} + } + } + **/ + function test(_) { + runHaxeJson([], DisplayMethods.Completion, { + file: file, + offset: offset(1), + wasAutoTriggered: true + }); + var result = parseCompletion(); + assertHasCompletion(result, item -> switch (item.kind) { + case Type: item.args.path.pack.length == 0 && item.args.path.typeName == "Map"; + case _: false; + }); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue7317.hx b/tests/server/src/cases/display/issues/Issue7317.hx new file mode 100644 index 0000000000000000000000000000000000000000..636988f0f0d961c28d1606b185ae5f424ea99c83 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue7317.hx @@ -0,0 +1,21 @@ +package cases.display.issues; + +class Issue7317 extends DisplayTestCase { + /** + class Main { + public static function main() { + var obj = {}; + obj.{-1-} + } + } + **/ + function test(_) { + runHaxeJson([], DisplayMethods.Completion, { + file: file, + offset: offset(1), + wasAutoTriggered: true + }); + var result = parseCompletion(); + Assert.equals("obj", result.result.mode.args.item.args.name); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue7754.hx b/tests/server/src/cases/display/issues/Issue7754.hx new file mode 100644 index 0000000000000000000000000000000000000000..812e7c031f385090e765f2cb543812524b45b364 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue7754.hx @@ -0,0 +1,27 @@ +package cases.display.issues; + +class Issue7754 extends DisplayTestCase { + /** + class Main { + static function main() { + Foo.foo({-1-}); + } + } + extern class Foo { + @:overload(function(?s:String):Void {}) + static function foo(?i:Int):Void; + } + **/ + function test(_) { + runHaxeJson([], DisplayMethods.SignatureHelp, { + file: file, + offset: offset(1), + wasAutoTriggered: true + }); + var result = parseSignatureHelp(); + var sigs = result.result.signatures; + Assert.equals(2, sigs.length); + Assert.equals('Null', strType(sigs[0].args[0].t)); + Assert.equals('Null', strType(sigs[1].args[0].t)); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue7923.hx b/tests/server/src/cases/display/issues/Issue7923.hx new file mode 100644 index 0000000000000000000000000000000000000000..368e080fd8bc57399d23b2cbfd4d6c75bbe79dd3 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue7923.hx @@ -0,0 +1,20 @@ +package cases.display.issues; + +class Issue7923 extends DisplayTestCase { + function test(_) { + vfs.putContent("TreeItem.hx", getTemplate("issues/Issue7923/TreeItem.hx")); + var content = getTemplate("issues/Issue7923/Main.hx"); + var transform = Marker.extractMarkers(content); + vfs.putContent("Main.hx", transform.source); + runHaxeJson([], DisplayMethods.Completion, { + file: new FsPath("Main.hx"), + offset: transform.markers[1], + wasAutoTriggered: true + }); + var result = parseCompletion(); + assertHasCompletion(result, item -> switch (item.kind) { + case EnumAbstractField: item.args.field.name == "Collapsed"; + case _: false; + }); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue8061.hx b/tests/server/src/cases/display/issues/Issue8061.hx new file mode 100644 index 0000000000000000000000000000000000000000..1f1d5c68f76d632c44fce4373803af7348c6e76a --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue8061.hx @@ -0,0 +1,20 @@ +package cases.display.issues; + +class Issue8061 extends DisplayTestCase { + /** + class Main { + static function main() { + new sys.io.Process({-1-}) + } + } + **/ + function test(_) { + runHaxeJson([], DisplayMethods.SignatureHelp, { + file: file, + offset: offset(1), + wasAutoTriggered: true + }); + var result = parseSignatureHelp(); + Assert.isTrue(result.result.signatures[0].documentation != null); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue8194.hx b/tests/server/src/cases/display/issues/Issue8194.hx new file mode 100644 index 0000000000000000000000000000000000000000..4f9a4c9fa65149ff8c9bfc337311a119f269c654 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue8194.hx @@ -0,0 +1,23 @@ +package cases.display.issues; + +class Issue8194 extends DisplayTestCase { + /** + class Main { + static function main() { + switch ("p") { + case "p"{-1-} + "foo"; + } + } + } + **/ + function test(_) { + runHaxeJson([], DisplayMethods.Completion, { + file: file, + offset: offset(1), + wasAutoTriggered: true + }); + var result = parseCompletion(); + Assert.equals(null, result.result); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue8381.hx b/tests/server/src/cases/display/issues/Issue8381.hx new file mode 100644 index 0000000000000000000000000000000000000000..6192ff213682dd8c55ae3671bc8672190f888251 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue8381.hx @@ -0,0 +1,27 @@ +package cases.display.issues; + +class Issue8381 extends DisplayTestCase { + /** + class Main { + static function main() { + var f:Foo; + f.f{-1-}oo(); + f.bar; + } + } + + typedef Foo = { + function foo():Void; + + var bar:Int; + } + **/ + function test(_) { + runHaxeJson([], DisplayMethods.Hover, { + file: file, + offset: offset(1) + }); + var result = parseHover(); + Assert.equals(DisplayItemKind.ClassField, result.result.item.kind); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue8438.hx b/tests/server/src/cases/display/issues/Issue8438.hx new file mode 100644 index 0000000000000000000000000000000000000000..b05cd25d126857f9d357bd3e1a3c6267005e3315 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue8438.hx @@ -0,0 +1,19 @@ +package cases.display.issues; + +class Issue8438 extends DisplayTestCase { + /**class Main { + static function main() { + " ".char{-1-} + } +}**/ + function test(_) { + runHaxeJson([], DisplayMethods.Completion, { + file: file, + offset: offset(1), + wasAutoTriggered: true + }); + var result = parseCompletion(); + Assert.equals(6, result.result.replaceRange.start.character); + Assert.equals(10, result.result.replaceRange.end.character); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue8602.hx b/tests/server/src/cases/display/issues/Issue8602.hx new file mode 100644 index 0000000000000000000000000000000000000000..572254b607d1c7d1629d83f03a74c99da639d3ce --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue8602.hx @@ -0,0 +1,16 @@ +package cases.display.issues; + +class Issue8602 extends DisplayTestCase { + /** + class Main { + static function main() { + haxe.ds.{-1-} + } + } + **/ + function test(_) { + runHaxeJson([], DisplayMethods.Completion, {file: file, offset: offset(1), wasAutoTriggered: true}); + var result = parseCompletion(); + Assert.equals(Toplevel, result.result.mode.kind); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue8644.hx b/tests/server/src/cases/display/issues/Issue8644.hx new file mode 100644 index 0000000000000000000000000000000000000000..e613b60a35f2dd987df73dadba3ecfd4d0f1e373 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue8644.hx @@ -0,0 +1,17 @@ +package cases.display.issues; + +import haxe.display.Server.ServerMethods; + +class Issue8644 extends DisplayTestCase { + function test(_) { + vfs.putContent("HelloJvm.hx", getTemplate("HelloJvm.hx")); + var args = ["-cp", ".", "--interp"]; + runHaxeJson(args, ServerMethods.ReadClassPaths, null); + runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("HelloJvm.hx"), offset: 55, wasAutoTriggered: false}); + var completion = parseCompletion(); + assertHasNoCompletion(completion, module -> switch (module.kind) { + case Type: module.args.path.typeName == "Jvm"; + case _: false; + }); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue8651.hx b/tests/server/src/cases/display/issues/Issue8651.hx new file mode 100644 index 0000000000000000000000000000000000000000..db3dcd984814c27fd61209880c293eed1f043995 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue8651.hx @@ -0,0 +1,13 @@ +package cases.display.issues; + +class Issue8651 extends DisplayTestCase { + /**class Main { static function main() { {-1-}buffer{-2-} } }**/ + function test(_) { + runHaxeJson([], DisplayMethods.Completion, {file: file, offset: offset(2), wasAutoTriggered: true}); + var result = parseCompletion(); + var r = result.result; + Assert.equals("buffer", r.filterString); + Assert.equals(offset(1), r.replaceRange.start.character); + Assert.equals(offset(2), r.replaceRange.end.character); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue8657.hx b/tests/server/src/cases/display/issues/Issue8657.hx new file mode 100644 index 0000000000000000000000000000000000000000..c35e7383ad513918ef1b6fc5cf5b3027d762369f --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue8657.hx @@ -0,0 +1,13 @@ +package cases.display.issues; + +class Issue8657 extends DisplayTestCase { + /**class Main { static function main() { var x:{-1-}stream{-2-} } }**/ + function test(_) { + runHaxeJson([], DisplayMethods.Completion, {file: file, offset: offset(2), wasAutoTriggered: true}); + var result = parseCompletion(); + var r = result.result; + Assert.equals("stream", r.filterString); + Assert.equals(offset(1), r.replaceRange.start.character); + Assert.equals(offset(2), r.replaceRange.end.character); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue8659.hx b/tests/server/src/cases/display/issues/Issue8659.hx new file mode 100644 index 0000000000000000000000000000000000000000..5d85bf38f7e8b687086928f71677033a0c5e4f0c --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue8659.hx @@ -0,0 +1,13 @@ +package cases.display.issues; + +class Issue8659 extends DisplayTestCase { + /**class Main extends {-1-}StreamTokenizer{-2-} { }**/ + function test(_) { + runHaxeJson([], DisplayMethods.Completion, {file: file, offset: offset(2), wasAutoTriggered: true}); + var result = parseCompletion(); + var r = result.result; + Assert.equals("StreamTokenizer", r.filterString); + Assert.equals(offset(1), r.replaceRange.start.character); + Assert.equals(offset(2), r.replaceRange.end.character); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue8666.hx b/tests/server/src/cases/display/issues/Issue8666.hx new file mode 100644 index 0000000000000000000000000000000000000000..1b93aeee4083cd99fc9245ef1e716357c7e43380 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue8666.hx @@ -0,0 +1,40 @@ +package cases.display.issues; + +class Issue8666 extends DisplayTestCase { + function test(_) { + vfs.putContent("cp1/HelloWorld.hx", getTemplate("HelloWorld.hx")); + vfs.putContent("cp2/MyClass.hx", "class MyClass { }"); + var args = ["-cp", "cp1", "--interp"]; + runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false}); + var completion = parseCompletion(); + assertHasNoCompletion(completion, module -> switch (module.kind) { + case Type: module.args.path.typeName == "MyClass"; + case _: false; + }); + runHaxeJson(args.concat(["-cp", "cp2"]), DisplayMethods.Completion, {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false}); + var completion = parseCompletion(); + assertHasCompletion(completion, module -> switch (module.kind) { + case Type: module.args.path.typeName == "MyClass"; + case _: false; + }); + } + + function testLib(_) { + vfs.putContent("cp1/HelloWorld.hx", getTemplate("HelloWorld.hx")); + vfs.putContent("cp2/MyClass.hx", "class MyClass { }"); + var args = ["-cp", "cp1", "--interp"]; + runHaxeJson(args, DisplayMethods.Completion, {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false}); + var completion = parseCompletion(); + assertHasNoCompletion(completion, module -> switch (module.kind) { + case Type: module.args.path.typeName == "MyClass"; + case _: false; + }); + runHaxeJson(args.concat(["-cp", "cp2", "-D", "imalibrary"]), DisplayMethods.Completion, + {file: new FsPath("cp1/HelloWorld.hx"), offset: 75, wasAutoTriggered: false}); + var completion = parseCompletion(); + assertHasCompletion(completion, module -> switch (module.kind) { + case Type: module.args.path.typeName == "MyClass"; + case _: false; + }); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue8732.hx b/tests/server/src/cases/display/issues/Issue8732.hx new file mode 100644 index 0000000000000000000000000000000000000000..37d9fd70269fd214b473825c0010b3809c7494c6 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue8732.hx @@ -0,0 +1,20 @@ +package cases.display.issues; + +import haxe.display.Protocol; + +class Issue8732 extends DisplayTestCase { + /** + class Main { static function main() { var ident = "foo"; {-1-}i{-2-}dent.{-3-} } } + **/ + function test(_) { + runHaxeJson([], Methods.Initialize, {maxCompletionItems: 50}); + runHaxeJson([], DisplayMethods.Completion, {file: file, offset: offset(2), wasAutoTriggered: true}); + runHaxeJson([], DisplayMethods.Completion, {file: file, offset: offset(3), wasAutoTriggered: true}); + runHaxeJson([], DisplayMethods.Completion, {file: file, offset: offset(1), wasAutoTriggered: true}); + var result = parseCompletion(); + assertHasNoCompletion(result, item -> switch (item.kind) { + case ClassField: item.args.field.name == "charAt"; + case _: false; + }); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue8805.hx b/tests/server/src/cases/display/issues/Issue8805.hx new file mode 100644 index 0000000000000000000000000000000000000000..91bbaf3746de9568391f4d110e5cae09fcf3f5a6 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue8805.hx @@ -0,0 +1,15 @@ +package cases.display.issues; + +class Issue8805 extends DisplayTestCase { + function testIssue8805_gotoAbstractPropertyWithInlineGetter(_) { + vfs.putContent("Main.hx", getTemplate("issues/Issue8805/Main.hx")); + var args = ["-main", "Main"]; + runHaxeJson(args, DisplayMethods.GotoDefinition, {file: file, offset: 56}); + var result = parseGotoDefinition(); + if (result.result.length == 0) { + Assert.fail('display/definition failed'); + } else { + Assert.same({"start": {"line": 7, "character": 12}, "end": {"line": 7, "character": 15}}, result.result[0].range); + } + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue8991.hx b/tests/server/src/cases/display/issues/Issue8991.hx new file mode 100644 index 0000000000000000000000000000000000000000..8908c554814f7ac08a28123d90a7df90ce1e5c14 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue8991.hx @@ -0,0 +1,26 @@ +package cases.display.issues; + +import haxe.display.Server; + +class Issue8991 extends DisplayTestCase { + function test(_) { + var mainHx = 'class Main { + static function main() { + C.inst{-1-}ance; + } +}'; + var cHx = 'class C { + public static var instance:Int; +}'; + var mainHx = Marker.extractMarkers(mainHx); + vfs.putContent("Main.hx", mainHx.source); + vfs.putContent("C.hx", cHx); + + runHaxe(["--no-output", "-main", "Main"]); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("C.hx")}); + runHaxeJson([], DisplayMethods.Hover, {file: file, offset: mainHx.markers[1]}); + + var result = parseHover().result; + Assert.equals(DisplayItemKind.ClassField, result.item.kind); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue8992.hx b/tests/server/src/cases/display/issues/Issue8992.hx new file mode 100644 index 0000000000000000000000000000000000000000..2ee74b9b9f46e4945951cb9583300e65649b363e --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue8992.hx @@ -0,0 +1,19 @@ +package cases.display.issues; + +import haxe.display.Protocol; + +class Issue8992 extends DisplayTestCase { + /** + class Main { + static func{-1-}tion main() { + } + } + **/ + function test(_) { + runHaxe(["--no-output", "-main", "Main"]); + runHaxeJson([], DisplayMethods.Hover, {file: file, offset: offset(1)}); + + var result = parseHover().result; + Assert.isNull(result); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue9012.hx b/tests/server/src/cases/display/issues/Issue9012.hx new file mode 100644 index 0000000000000000000000000000000000000000..cf449d92ec3d179bd4cd1a803ef3502eef5000a4 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue9012.hx @@ -0,0 +1,17 @@ +package cases.display.issues; + +class Issue9012 extends DisplayTestCase { + function test(_) { + vfs.putContent("Some.hx", "class Some { public static function func():String return 'hello'; }"); + + var content = "import Some.func; class Main { static function main() { fu{-1-}nc(); } }"; + var transform = Marker.extractMarkers(content); + vfs.putContent("Main.hx", transform.source); + + runHaxe(["--no-output", "-main", "Main"]); // commenting this makes it work + runHaxeJson([], DisplayMethods.Hover, {file: file, offset: transform.markers[1]}); + var result = parseHover().result; + + Assert.equals(DisplayItemKind.ClassField, result.item.kind); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue9039.hx b/tests/server/src/cases/display/issues/Issue9039.hx new file mode 100644 index 0000000000000000000000000000000000000000..3ee191259930bad818b68fe8321069792e0061b3 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue9039.hx @@ -0,0 +1,27 @@ +package cases.display.issues; + +class Issue9039 extends DisplayTestCase { + function test(_) { + vfs.putContent("I.hx", "interface I { var prop(get,never):Int; }"); + vfs.putContent("Main.hx", "class Main { static function main() { var i:I = null; } }"); + + runHaxe(["--no-output", "-main", "Main"]); + + var content = "class Main { static function main() { var i:I = null; i.{-1-} } }"; + var transform = Marker.extractMarkers(content); + + vfs.putContent("Main.hx", transform.source); + runHaxeJson([], DisplayMethods.Completion, { + file: file, + offset: transform.markers[1], + wasAutoTriggered: true + }); + + assertHasNoCompletion(parseCompletion(), function(item) { + return switch item.kind { + case ClassField: item.args.field.name == "get_prop"; + case _: false; + } + }); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue9044.hx b/tests/server/src/cases/display/issues/Issue9044.hx new file mode 100644 index 0000000000000000000000000000000000000000..142e25761dca2f847467530e220e9d15d2e10810 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue9044.hx @@ -0,0 +1,55 @@ +package cases.display.issues; + +class Issue9044 extends DisplayTestCase { + /** + class Child extends Base { + public function new() {} + + override function f{-1-}unc() { + super.{-2-}func{-3-}(); + } + } + + class GrandChild extends Child { + override function func() { + super.{-5-}func{-6-}(); + } + } + + class Base { + public function func() {} + } + + class Main { + static function main() { + var c = new Child(); + c.{-8-}func{-9-}(); + var base:Base = c; + base.{-10-}func{-11-}(); + var g = new GrandChild(); + g.{-12-}func{-13-}(); + } + } + **/ + function test(_) { + runHaxeJson([], DisplayMethods.FindReferences, { + file: file, + offset: offset(1), + contents: source, + kind: WithBaseAndDescendants + }); + var result = parseGotoDefinitionLocations(); + var expectedRanges = [range(2, 3), range(5, 6), range(8, 9), range(10, 11), range(12, 13)]; + Assert.same(expectedRanges, result.map(l -> l.range)); + + runHaxeJson([], DisplayMethods.FindReferences, { + file: file, + offset: offset(1), + contents: source, + kind: WithDescendants + }); + var result = parseGotoDefinitionLocations(); + var expectedRanges = [range(5, 6), range(8, 9), range(12, 13)]; + Assert.same(expectedRanges, result.map(l -> l.range)); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue9047.hx b/tests/server/src/cases/display/issues/Issue9047.hx new file mode 100644 index 0000000000000000000000000000000000000000..3e810c3c0297170abdb685574870679b5351932f --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue9047.hx @@ -0,0 +1,17 @@ +package cases.display.issues; + +class Issue9047 extends DisplayTestCase { + /** + interface Main { var field(never,s{-1-}et):Int; } + **/ + function test(_) { + var args = ["Main", "-js", "main.js"]; + function parseGotoDefintion():GotoDefinitionResult { + return haxe.Json.parse(lastResult.stderr).result; + } + runHaxeJson(args, DisplayMethods.FindReferences, {file: file, offset: offset(1), contents: source}); + Assert.same([], parseGotoDefintion().result); + runHaxeJson(args, DisplayMethods.FindReferences, {file: file, offset: offset(1), contents: source}); + Assert.same([], parseGotoDefintion().result); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue9082.hx b/tests/server/src/cases/display/issues/Issue9082.hx new file mode 100644 index 0000000000000000000000000000000000000000..3a1bf4d2fb1540a563c7e4c935e642879878d52a --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue9082.hx @@ -0,0 +1,31 @@ +package cases.display.issues; + +import haxe.display.Server; +import haxe.display.Protocol; + +class Issue9082 extends DisplayTestCase { + function test(_) { + var args = ["-cp", ".", "--interp"]; + + vfs.putContent("org/Thing.hx", "package org; class Thing {}"); + vfs.putContent("AThing.hx", "class AThing {}"); + vfs.putContent("ThingB.hx", "class ThingB {}"); + runHaxeJson(args, Methods.Initialize, {maxCompletionItems: 2}); + runHaxeJson(args, ServerMethods.ReadClassPaths, null); + + var markers = Markers.parse("class C extends Thing{-1-}"); + vfs.putContent("C.hx", markers.source); + runHaxeJson(args, DisplayMethods.Completion, { + file: new FsPath("C.hx"), + offset: markers.offset(1), + wasAutoTriggered: true + }); + var result = parseCompletion(); + assertHasCompletion(result, function(item) { + return switch item { + case {kind: Type, args: {path: {pack: ["org"], typeName: "Thing"}}}: true; + case _: false; + } + }); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue9087.hx b/tests/server/src/cases/display/issues/Issue9087.hx new file mode 100644 index 0000000000000000000000000000000000000000..0317c6358346e3c0b8bb93bda09f6fbd3ec3ad8e --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue9087.hx @@ -0,0 +1,29 @@ +package cases.display.issues; + +class Issue9087 extends DisplayTestCase { + function test(_) { + var content = getTemplate("issues/Issue9087/A.hx"); + var markers = Markers.parse(content); + vfs.putContent("A.hx", markers.source); + var args = ["A", "-js", "main.js"]; + function parseGotoDefintion():GotoDefinitionResult { + return haxe.Json.parse(lastResult.stderr).result; + } + runHaxeJson(args, DisplayMethods.GotoImplementation, {file: new FsPath("A.hx"), offset: markers.offset(1), contents: markers.source}); + var result = parseGotoDefintion().result; + // TODO: We should use the markers, but I forgot how to get lines and characters from offsets + // Also That Assert.same doesn't work + Assert.equals(9, result[0].range.start.line); + Assert.equals(19, result[0].range.start.character); + Assert.equals(9, result[0].range.end.line); + Assert.equals(23, result[0].range.end.character); + // Assert.same([ + // { + // range: { + // start: {line: 9, character: 1}, + // end: {line: 11, character: 2} + // } + // } + // ], result); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue9115.hx b/tests/server/src/cases/display/issues/Issue9115.hx new file mode 100644 index 0000000000000000000000000000000000000000..5f0492ea9a4ecdaef3c301cb3acfc1a58b1eff08 --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue9115.hx @@ -0,0 +1,16 @@ +package cases.display.issues; + +class Issue9115 extends DisplayTestCase { + function test(_) { + var content = getTemplate("issues/Issue9115/A.hx"); + var markers = Markers.parse(content); + vfs.putContent("A.hx", markers.source); + runHaxe(["--no-output", "A"]); + runHaxeJson([], DisplayMethods.Hover, { + file: new FsPath("A.hx"), + offset: markers.offset(1) + }); + var result = parseHover(); + Assert.equals("A", result.result.item.type.args.path.typeName /* lol */); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/display/issues/Issue9159.hx b/tests/server/src/cases/display/issues/Issue9159.hx new file mode 100644 index 0000000000000000000000000000000000000000..5e54fb27f0fe34dc480c5da349d6af8779bb45ec --- /dev/null +++ b/tests/server/src/cases/display/issues/Issue9159.hx @@ -0,0 +1,44 @@ +package cases.display.issues; + +class Issue9159 extends DisplayTestCase { + /** + @:structInit + class CustomConstructor { + public var nope1:String; + public function new(x:Int = 0) {} + public function nope2() {} + } + + @:structInit + class AutoConstructor { + public var y:Float; + public function nope() {} + } + + class Main { + static function main() { + var a:CustomConstructor = {-1-}{}; + var b:AutoConstructor = {-2-}{}; + } + } + **/ + function test(_) { + runHaxeJson([], DisplayMethods.Completion, { + file: file, + offset: offset(1), + wasAutoTriggered: true + }); + var result = parseCompletion().result; + Assert.equals(1, result.items.length); + Assert.equals('x', result.items[0].args.field.name); + + runHaxeJson([], DisplayMethods.Completion, { + file: file, + offset: offset(2), + wasAutoTriggered: true + }); + var result = parseCompletion().result; + Assert.equals(1, result.items.length); + Assert.equals('y', result.items[0].args.field.name); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/issues/Issue8738.hx b/tests/server/src/cases/issues/Issue8738.hx new file mode 100644 index 0000000000000000000000000000000000000000..5c851995911e3d855cf990f199b909ab935595a1 --- /dev/null +++ b/tests/server/src/cases/issues/Issue8738.hx @@ -0,0 +1,19 @@ +package cases.issues; + +class Issue8738 extends TestCase { + function test(_) { + vfs.putContent("Base.hx", getTemplate("issues/Issue8738/Base.hx")); + vfs.putContent("Main.hx", getTemplate("issues/Issue8738/Main1.hx")); + var args = ["-main", "Main", "--interp"]; + runHaxe(args); + assertSuccess(); + vfs.putContent("Main.hx", getTemplate("issues/Issue8738/Main2.hx")); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); + runHaxe(args); + assertErrorMessage("Cannot force inline-call to test because it is overridden"); + vfs.putContent("Main.hx", getTemplate("issues/Issue8738/Main3.hx")); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Main.hx")}); + runHaxe(args); + assertSuccess(); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/issues/Issue8748.hx b/tests/server/src/cases/issues/Issue8748.hx new file mode 100644 index 0000000000000000000000000000000000000000..900dff728e3661355df6372c24124602c1a58d73 --- /dev/null +++ b/tests/server/src/cases/issues/Issue8748.hx @@ -0,0 +1,25 @@ +package cases.issues; + +class Issue8748 extends TestCase { + function test(_) { + vfs.putContent("Dependency.hx", getTemplate("Dependency.hx")); + vfs.putContent("WithDependency.hx", getTemplate("WithDependency.hx")); + vfs.putContent("res/dep.dep", ""); + var args = [ + "-main", + "WithDependency", + "--interp", + "--macro", + "haxe.macro.Context.registerModuleDependency(\"Dependency\", \"res/dep.dep\")" + ]; + runHaxeJson(args, ServerMethods.Configure, {noModuleChecks: true}); + runHaxe(args); + runHaxeJson(args, DisplayMethods.Hover, {file: new FsPath("WithDependency.hx"), offset: 65}); + assertReuse("Dependency"); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("res/dep.dep")}); + runHaxeJson(args, DisplayMethods.Hover, {file: new FsPath("WithDependency.hx"), offset: 65}); + // check messages manually because module file contains awkward absolute path + var r = ~/skipping Dependency\(.*dep.dep\)/; + Assert.isTrue(messages.exists(message -> r.match(message))); + } +} \ No newline at end of file diff --git a/tests/server/src/cases/issues/Issue9029.hx b/tests/server/src/cases/issues/Issue9029.hx new file mode 100644 index 0000000000000000000000000000000000000000..aa7158af3568f96c607fc754fe5f6d6f9d725836 --- /dev/null +++ b/tests/server/src/cases/issues/Issue9029.hx @@ -0,0 +1,15 @@ +package cases.issues; + +class Issue9029 extends TestCase { + function testIssue9029_analyzer_preventPurityOnOverridden(_) { + vfs.putContent("Main.hx", getTemplate("issues/Issue9029/Main.hx")); + vfs.putContent("Game.hx", getTemplate("issues/Issue9029/Game.hx")); + vfs.putContent("Screen.hx", getTemplate("issues/Issue9029/Screen.hx")); + var args = ["-main", "Main", "-D", "analyzer-optimize", "--interp"]; + runHaxe(args); + vfs.putContent("Game.hx", getTemplate("issues/Issue9029/Game.hx.modified")); + runHaxeJson([], ServerMethods.Invalidate, {file: new FsPath("Game.hx")}); + runHaxe(args); + assertSuccess(); + } +} \ No newline at end of file diff --git a/tests/server/src/import.hx b/tests/server/src/import.hx new file mode 100644 index 0000000000000000000000000000000000000000..fb938e012456d1e764cc52883976db5e0cf3127b --- /dev/null +++ b/tests/server/src/import.hx @@ -0,0 +1,10 @@ +package cases.display; + +import haxe.display.Display; +import haxe.display.FsPath; +import haxe.display.Server; +import utest.Assert; +import utils.Markers; + +using Lambda; +using StringTools; \ No newline at end of file diff --git a/tests/server/src/utils/Markers.hx b/tests/server/src/utils/Markers.hx new file mode 100644 index 0000000000000000000000000000000000000000..0f54827c70ae8e50100cfa41cdad87d7c6d3a0c0 --- /dev/null +++ b/tests/server/src/utils/Markers.hx @@ -0,0 +1,88 @@ +package utils; + +import haxe.Exception; +import haxe.display.Position; + +/** + * Parses a document with markers. + * Marker format: `{-N-}`, where `N` is an integer number. + */ +class Markers { + /** Parsed document with all markers removed. */ + public final source:String; + + final offsets:Array; + final positions:Array; + + static public function parse(doc:String):Markers { + var positions = []; + var offsets = []; + var line = 0; + var lastNewLinePos = 0; + var markersLengthSum = 0; + var markersLengthSinceNewLine = 0; + var source = ~/{-(\d+)-}|\n/g.map(doc, function(r) { + var p = r.matchedPos(); + var replacement = switch r.matched(0) { + case '\n': + line++; + lastNewLinePos = p.pos; + markersLengthSinceNewLine = 0; + '\n'; + case _: + var name = r.matched(1); + switch Std.parseInt(name) { + case null: + throw new Exception('Invalid marker name: {-$name-}'); + case n: + offsets[n] = p.pos - markersLengthSum; + var character = p.pos - (lastNewLinePos + 1) - markersLengthSinceNewLine; + positions[n] = {line: line, character: character}; + } + markersLengthSum += p.len; + markersLengthSinceNewLine += p.len; + ""; + } + return replacement; + }); + return new Markers(source, offsets, positions); + } + + function new(source:String, offsets:Array, positions:Array) { + this.source = source; + this.offsets = offsets; + this.positions = positions; + } + + /** + * Returns an offset of the n-th marker. + * Amount of characters from the beginning of the parsed document excluding markers. + */ + public function offset(n:Int):Int { + return switch offsets[n] { + case null: throw new Exception('Marker {-$n-} not found'); + case pos: pos; + } + } + + /** + * Returns a position of n-th marker. + * Line number and character number from the beginning of the line. + */ + public function pos(n:Int):Position { + return switch positions[n] { + case null: throw new Exception('Marker {-$n-} not found'); + case pos: pos; + } + } + + /** + * Returns a range between positions of `startMarker` and `endMarker` + */ + public function range(startMarker:Int, endMarker:Int):Range { + return { + start: pos(startMarker), + end: pos(endMarker) + } + } +} diff --git a/tests/server/src/Vfs.hx b/tests/server/src/utils/Vfs.hx similarity index 99% rename from tests/server/src/Vfs.hx rename to tests/server/src/utils/Vfs.hx index 439090185d2ac31fc5a050f32640b563f5ff5f6e..1f59bee5cafe03b15f1a2056afeccdb4c38b57ba 100644 --- a/tests/server/src/Vfs.hx +++ b/tests/server/src/utils/Vfs.hx @@ -1,3 +1,5 @@ +package utils; + import js.node.Fs; import sys.FileSystem; import haxe.io.Path; diff --git a/tests/server/src/utils/macro/BuildHub.macro.hx b/tests/server/src/utils/macro/BuildHub.macro.hx new file mode 100644 index 0000000000000000000000000000000000000000..47729c879b07c8fc3b6f843e88fea6f782cf655b --- /dev/null +++ b/tests/server/src/utils/macro/BuildHub.macro.hx @@ -0,0 +1,31 @@ +package utils.macro; + +import haxe.macro.Context; +import haxe.macro.Expr; +import haxe.macro.Type; + +class BuildHub { + macro static public function build():Array { + var fields = Context.getBuildFields(); + + switch Context.getLocalClass() { + case null: + case _.get() => cls: + if(isDisplayTest(cls)) { + fields = DisplayTestBuilder.build(fields); + } + } + + return TestBuilder.build(fields); + } + + static function isDisplayTest(cls:ClassType):Bool { + if(cls.pack.length == 0 && cls.name == "DisplayTestCase") { + return true; + } + return switch cls.superClass { + case null: false; + case _.t.get() => cls: isDisplayTest(cls); + } + } +} \ No newline at end of file diff --git a/tests/server/src/utils/macro/DisplayTestBuilder.macro.hx b/tests/server/src/utils/macro/DisplayTestBuilder.macro.hx new file mode 100644 index 0000000000000000000000000000000000000000..69d3c89bff925a0e90cd653b57a398777b61a9d9 --- /dev/null +++ b/tests/server/src/utils/macro/DisplayTestBuilder.macro.hx @@ -0,0 +1,58 @@ +package utils.macro; + +import haxe.macro.Context; +import haxe.macro.Expr; +import haxe.Exception; + +using StringTools; + +private class BuilderException extends Exception { + override function toString():String { + return message; + } +} + +class DisplayTestBuilder { + static public function build(fields:Array):Array { + for (field in fields) { + if (field.name.startsWith('test')) { + try { + patchExpr(field); + } catch (e) { + Context.error('Failed to build display test: $e', field.pos); + } + } + } + return fields; + } + + static function patchExpr(field:Field) { + switch field.kind { + case FFun(fn): + switch fn.expr { + case null: + case { expr:EBlock(exprs) }: + exprs.unshift(generateInit(field)); + case e: + fn.expr = macro { + ${generateInit(field)}; + $e; + } + } + case _: + } + } + + static function generateInit(field:Field):Expr { + return switch field.doc { + case null: + macro async.setTimeout(5000); + case src: + macro { + async.setTimeout(5000); + _markers = utils.Markers.parse($v{src}); + vfs.putContent("Main.hx", markers.source); + } + } + } +} diff --git a/tests/server/src/utils/macro/TestBuilder.macro.hx b/tests/server/src/utils/macro/TestBuilder.macro.hx new file mode 100644 index 0000000000000000000000000000000000000000..744c9efa6de460fcdd178fcf1ce263a611ca2290 --- /dev/null +++ b/tests/server/src/utils/macro/TestBuilder.macro.hx @@ -0,0 +1,73 @@ +package utils.macro; + +import haxe.macro.Expr; +import haxe.macro.Context; + +using StringTools; + +class TestBuilder { + static public function build(fields:Array):Array { + for (field in fields) { + if (!field.name.startsWith("test")) { + continue; + } + switch (field.kind) { + case FFun(f): + var asyncName = switch f.args { + case []: + var name = "async"; + f.args.push({ + name: name, + type: macro:utest.Async + }); + name; + case [arg]: + if(arg.name == "_") { + arg.name = "async"; + arg.type = macro:utest.Async; + } + arg.name; + case _: + Context.fatalError('Unexpected amount of test arguments', field.pos); + ""; + } + switch (f.expr.expr) { + case EBlock(el): + var posInfos = Context.getPosInfos(f.expr.pos); + var pos = Context.makePosition({min: posInfos.max, max: posInfos.max, file: posInfos.file}); + el.push(macro @:pos(pos) $i{asyncName}.done()); + f.expr = macro { + $i{asyncName}.setTimeout(10000); + ${transformHaxeCalls(el)}; + } + case _: + Context.error("Block expression expected", f.expr.pos); + } + case _: + } + } + return fields; + } + + static function transformHaxeCalls(el:Array) { + var e0 = el.shift(); + return if (el.length == 0) { + e0; + } else switch (e0) { + case macro runHaxe($a{args}): + var e = transformHaxeCalls(el); + args.push(macro() -> $e); + macro @:pos(e0.pos) runHaxe($a{args}); + case macro runHaxeJson($a{args}): + var e = transformHaxeCalls(el); + args.push(macro() -> $e); + macro @:pos(e0.pos) runHaxeJson($a{args}); + case macro complete($a{args}): + var e = transformHaxeCalls(el); + args.push(macro function(response, markers) $e); + macro @:pos(e0.pos) complete($a{args}); + case _: + macro {$e0; ${transformHaxeCalls(el)}}; + } + } +} diff --git a/tests/server/test/templates/issues/Issue7923/Main.hx b/tests/server/test/templates/issues/Issue7923/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..94424c9502063c337344544097564cd82cb7e67f --- /dev/null +++ b/tests/server/test/templates/issues/Issue7923/Main.hx @@ -0,0 +1,6 @@ +class Main { + static function main() { + var treeItem:TreeItem; + treeItem.collapsibleState = {-1-} + } +} \ No newline at end of file diff --git a/tests/server/test/templates/issues/Issue7923/TreeItem.hx b/tests/server/test/templates/issues/Issue7923/TreeItem.hx new file mode 100644 index 0000000000000000000000000000000000000000..c421dfe3c522a13bb1de7a398d7cdcae74c693b3 --- /dev/null +++ b/tests/server/test/templates/issues/Issue7923/TreeItem.hx @@ -0,0 +1,7 @@ +class TreeItem { + public var collapsibleState:Null; +} + +enum abstract TreeItemCollapsibleState(Int) { + var Collapsed; +} diff --git a/tests/server/test/templates/issues/Issue8616/A.hx b/tests/server/test/templates/issues/Issue8616/A.hx new file mode 100644 index 0000000000000000000000000000000000000000..b18c2fcc9bffcb689c0866b0afa1d0de1019d59c --- /dev/null +++ b/tests/server/test/templates/issues/Issue8616/A.hx @@ -0,0 +1,13 @@ +abstract A(C) { + public inline function f(v:Int) + this.f(v); +} + +class C { + public inline function f(v:Int) { + use(v); + use(v); + } + + function use(v:Int) {} +} diff --git a/tests/server/test/templates/issues/Issue8616/Main.hx b/tests/server/test/templates/issues/Issue8616/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..39fff55d6657ec2b90a61785b7f0a1ab1948a89d --- /dev/null +++ b/tests/server/test/templates/issues/Issue8616/Main.hx @@ -0,0 +1,9 @@ +class Main { + static var a:A; + static var v:Int; + + static function main() { + a.f(v); + a.f(v); + } +} diff --git a/tests/server/test/templates/issues/Issue8805/Main.hx b/tests/server/test/templates/issues/Issue8805/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..f3912209cf57ed47112fb11c7bc65e1b23516703 --- /dev/null +++ b/tests/server/test/templates/issues/Issue8805/Main.hx @@ -0,0 +1,13 @@ +class Main { + static function main() { + (null : Foo).bar; + } +} + +abstract Foo(String) from String { + public var bar(get, never):String; + + inline function get_bar() { + return this; + } +} \ No newline at end of file diff --git a/tests/server/test/templates/issues/Issue9029/Game.hx b/tests/server/test/templates/issues/Issue9029/Game.hx new file mode 100644 index 0000000000000000000000000000000000000000..beb1f380eeacfde1601eefde230050cccdff3f2d --- /dev/null +++ b/tests/server/test/templates/issues/Issue9029/Game.hx @@ -0,0 +1,5 @@ +class Game extends Screen { + override function onStart() { + // trace(123); + } +} \ No newline at end of file diff --git a/tests/server/test/templates/issues/Issue9029/Game.hx.modified b/tests/server/test/templates/issues/Issue9029/Game.hx.modified new file mode 100644 index 0000000000000000000000000000000000000000..c6076cc95adf260f0f3d7846aa8480c5b8c416c2 --- /dev/null +++ b/tests/server/test/templates/issues/Issue9029/Game.hx.modified @@ -0,0 +1,5 @@ +class Game extends Screen { + override function onStart() { + trace(123); + } +} \ No newline at end of file diff --git a/tests/server/test/templates/issues/Issue9029/Main.hx b/tests/server/test/templates/issues/Issue9029/Main.hx new file mode 100644 index 0000000000000000000000000000000000000000..b6e54f7a1e5a7001845120018ec9ab871d6eee21 --- /dev/null +++ b/tests/server/test/templates/issues/Issue9029/Main.hx @@ -0,0 +1,5 @@ +class Main { + static function main() { + final game = new Game(); + } +} \ No newline at end of file diff --git a/tests/server/test/templates/issues/Issue9029/Screen.hx b/tests/server/test/templates/issues/Issue9029/Screen.hx new file mode 100644 index 0000000000000000000000000000000000000000..0144fdd8e0d9e0eae385a899cc5a748b072b9636 --- /dev/null +++ b/tests/server/test/templates/issues/Issue9029/Screen.hx @@ -0,0 +1,7 @@ +class Screen { + public function new() { + onStart(); + } + + function onStart():Void {} +} \ No newline at end of file diff --git a/tests/server/test/templates/issues/Issue9087/A.hx b/tests/server/test/templates/issues/Issue9087/A.hx new file mode 100644 index 0000000000000000000000000000000000000000..4532046eccf29655705d83a05a056c52c1fbdd7c --- /dev/null +++ b/tests/server/test/templates/issues/Issue9087/A.hx @@ -0,0 +1,13 @@ +class A { + public function new() { + in{-1-}it(); // "go to implementation" from the call site currently yields nothing + } + + function init() {} +} + +class B extends A { + override function {-2-}init{-3-}() { + super.init(); + } +} diff --git a/tests/server/test/templates/issues/Issue9115/A.hx b/tests/server/test/templates/issues/Issue9115/A.hx new file mode 100644 index 0000000000000000000000000000000000000000..51141b31cb965f563c8cc3434b466fc02092b44d --- /dev/null +++ b/tests/server/test/templates/issues/Issue9115/A.hx @@ -0,0 +1,11 @@ +enum abstract A(String) { + var A1; + var A2; + + function f() { + var {-1-}a:A = cast this; // hovering `a` will print Dynamic + switch (a) { + // no exhaustiveness check + } + } +} diff --git a/tests/sys/compile-each.hxml b/tests/sys/compile-each.hxml index c0c25df4b063129d621de3244421860266b8c970..608fc6b8b546bde8bafbf1ec7fd8dbad54f5f0f0 100644 --- a/tests/sys/compile-each.hxml +++ b/tests/sys/compile-each.hxml @@ -8,4 +8,5 @@ -D source-header='' --debug -lib utest --p src \ No newline at end of file +-p src +compile-fs.hxml diff --git a/tests/sys/compile-fs.hxml b/tests/sys/compile-fs.hxml new file mode 100644 index 0000000000000000000000000000000000000000..f7551fb0ed820cfab9e7b8a5363c79281e4544b3 --- /dev/null +++ b/tests/sys/compile-fs.hxml @@ -0,0 +1,4 @@ +# comment the following line to disable testing the filesystem with invalid +# Unicode codepoints; these will not work on APFS + +-D TEST_INVALID_UNICODE_FS diff --git a/tests/sys/compile-lua.hxml b/tests/sys/compile-lua.hxml index 04c84edac5340962e16dfa8c73d5f25555a0479f..c7bb1ef52dec25d05c23d4b10316d8570332877e 100644 --- a/tests/sys/compile-lua.hxml +++ b/tests/sys/compile-lua.hxml @@ -16,4 +16,4 @@ compile-each.hxml --next compile-each.hxml --main UtilityProcess --lua bin/lua/UtilityProcess.lua \ No newline at end of file +-lua bin/lua/UtilityProcess.lua diff --git a/tests/sys/genTestRes.py b/tests/sys/genTestRes.py index 3c590dcaea54f80798b34cb52e0e872af4383293..9f921fbb01136c859b05b4e12e11f117b679034f 100755 --- a/tests/sys/genTestRes.py +++ b/tests/sys/genTestRes.py @@ -4,8 +4,18 @@ # The test vector printf'ed into data.bin, as well as the names in filenames() # should correspond exactly to the sequences in UnicodeSequences.valid. +# Run with: +# python3 genTestRes.py +# Or: +# python3 genTestRes.py TEST_INVALID_UNICODE_FS +# The latter will attempt to create filenames which contain invalid Unicode +# codepoints; this does not work on some filesystems, e.g. APFS. + import os import shutil +import sys + +MODE = " ".join(sys.argv[1:]) TESTDIR = "test-res" @@ -17,19 +27,19 @@ os.mkdir(TESTDIR) # Unicode test vectors allUnicode = [ - [0x01], + [0x01], # will not work on NTFS [0x7F], [0xC2, 0x80], [0xDF, 0xBF], [0xE0, 0xA0, 0x80], - [0xED, 0x9F, 0xBF], + [0xED, 0x9F, 0xBF], # will not work on APFS [0xEE, 0x80, 0x80], [0xEF, 0xBF, 0xBD], [0xF0, 0x90, 0x80, 0x80], - [0xF0, 0x9F, 0xBF, 0xBF], - [0xF3, 0xBF, 0xBF, 0xBF], + [0xF0, 0x9F, 0xBF, 0xBF], # will not work on APFS + [0xF3, 0xBF, 0xBF, 0xBF], # will not work on APFS [0xF4, 0x80, 0x80, 0x80], - [0xF4, 0x8F, 0xBF, 0xBF], + [0xF4, 0x8F, 0xBF, 0xBF], # will not work on APFS [0xF0, 0x9F, 0x98, 0x82, 0xF0, 0x9F, 0x98, 0x84, 0xF0, 0x9F, 0x98, 0x99], [0xC8, 0xA7], [0xE4, 0xB8, 0xAD, 0xE6, 0x96, 0x87, 0xEF, 0xBC, 0x8C, 0xE3, 0x81, 0xAB, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x93, 0xE3, 0x81, 0x94] @@ -43,6 +53,13 @@ allFilenames = allStrings[:] if os.name == "nt": allFilenames.remove(bytes([0x01]).decode("utf-8")) +# on APFS (macOS 10.13+), filenames must consist of valid Unicode codepoints +if MODE != "TEST_INVALID_UNICODE_FS": + allFilenames.remove(bytes([0xED, 0x9F, 0xBF]).decode("utf-8")) + allFilenames.remove(bytes([0xF0, 0x9F, 0xBF, 0xBF]).decode("utf-8")) + allFilenames.remove(bytes([0xF3, 0xBF, 0xBF, 0xBF]).decode("utf-8")) + allFilenames.remove(bytes([0xF4, 0x8F, 0xBF, 0xBF]).decode("utf-8")) + allBinary = b"" for data in allUnicode: allBinary += bytes(data) + b"\n" diff --git a/tests/sys/src/TestFileSystem.hx b/tests/sys/src/TestFileSystem.hx index 1332d8bd4d12e985c3f96305c1d22ba8e0e912ca..fa411f850f727b04097e4a7a4975b9fc5a1f286a 100644 --- a/tests/sys/src/TestFileSystem.hx +++ b/tests/sys/src/TestFileSystem.hx @@ -146,8 +146,6 @@ class TestFileSystem extends utest.Test { // on windows, haxe returns lowercase paths with backslashes, drive letter uppercased p = p.substr(0, 1).toUpperCase() + p.substr(1); p = p.replace("/", "\\"); - if (!properCase) - p = p.toLowerCase(); } return p; } diff --git a/tests/sys/src/TestUnicode.hx b/tests/sys/src/TestUnicode.hx index 561c49fd92d2b48b6c9e76589c8b6bea4796b6e5..00ed2829efd7cd305fc3533b32a7d7484fa6ad76 100644 --- a/tests/sys/src/TestUnicode.hx +++ b/tests/sys/src/TestUnicode.hx @@ -58,7 +58,7 @@ class TestUnicode extends utest.Test { ]; // list of expected filenames in sub-directories - static var names:Array = (Sys.systemName() == "Windows" ? UnicodeSequences.valid.slice(1) : UnicodeSequences.valid); + static var names:Array = UnicodeSequences.validFilenames; // extra files only present in the root test-res directory static var namesRoot = names.concat([ @@ -132,7 +132,11 @@ class TestUnicode extends utest.Test { function setupClass() { FileSystem.createDirectory("temp-unicode"); + #if TEST_INVALID_UNICODE_FS + Sys.command("python3", ["genTestRes.py", "TEST_INVALID_UNICODE_FS"]); + #else Sys.command("python3", ["genTestRes.py"]); + #end } function teardownClass() { @@ -326,10 +330,8 @@ class TestUnicode extends utest.Test { #if (hl || cpp) if (Sys.systemName() != "Windows") { #end // HL and C++ temporarily disabled (#8379) // putEnv + getEnv assertUEquals(runUtility(["putEnv", "HAXE_TEST", '$i', mode, "getEnv", "HAXE_TEST"]).stdout, str + endLine); -#if !lua // Lua disabled temporarily (#8216) // putEnv + environment assertUEquals(runUtility(["putEnv", "HAXE_TEST", '$i', mode, "environment", "HAXE_TEST"]).stdout, str + endLine); -#end #if (hl || cpp) } #end // HL and C++ temporarily disabled (#8379) #end }); diff --git a/tests/sys/src/UnicodeSequences.hx b/tests/sys/src/UnicodeSequences.hx index 17db479f5710b48fe56284c747a3d11793c59cb3..e8c62f6a8300ca87409b8816451cefca6f8b0c9f 100644 --- a/tests/sys/src/UnicodeSequences.hx +++ b/tests/sys/src/UnicodeSequences.hx @@ -39,6 +39,19 @@ class UnicodeSequences { .concat([Only([0x1F602, 0x1F604, 0x1F619])]) // important (non-BMP) emoji .concat(normal); + public static var validFilenames:Array = { + var valid = valid.copy(); + if (Sys.systemName() == "Windows") valid = valid.filter(f -> !f.match(Only([0x0001]))); + #if !(TEST_INVALID_UNICODE_FS) + valid = valid.filter(f -> + !f.match(Only([0xD7FF])) + && !f.match(Only([0x1FFFF])) + && !f.match(Only([0xFFFFF])) + && !f.match(Only([0x10FFFF]))); + #end + valid; + }; + public static var validBytes = haxe.io.Bytes.ofHex( "010A" + "7F0A" + @@ -76,12 +89,6 @@ class UnicodeSequences { "\u0227\n" + "\u4E2D\u6587\uFF0C\u306B\u307B\u3093\u3054\n"; - // invalid sequences - public static var invalid:Array = [ - Only([0xFFFE]), - Only([0xFFFF]) - ]; - // utility methods public static function unicodeCodepoints(str:String):Array { diff --git a/tests/threads/src/Main.hx b/tests/threads/src/Main.hx index 30b43ad5961192c27bc2ce61052ebbf5dd583984..5c1efd44fcccb8863751c103dc2b9580d580857c 100644 --- a/tests/threads/src/Main.hx +++ b/tests/threads/src/Main.hx @@ -5,6 +5,8 @@ class Main { static function main() { var runner = new Runner(); runner.addCases("cases"); + runner.onTestStart.add(test -> Sys.println("[START] " + test.fixture.target)); + runner.onTestComplete.add(test -> Sys.println("[STOP] " + test.fixture.target)); var report = Report.create(runner); report.displayHeader = AlwaysShowHeader; report.displaySuccessResults = NeverShowSuccessResults; diff --git a/tests/threads/src/cases/DequeBrackets.hx b/tests/threads/src/cases/DequeBrackets.hx index 3ad2f3d1c5bf7f0b485bcbd2fb34224a4b34f376..3871f1be30da5bc63d197bbb395f382fc11d41c8 100644 --- a/tests/threads/src/cases/DequeBrackets.hx +++ b/tests/threads/src/cases/DequeBrackets.hx @@ -15,7 +15,6 @@ class DequeBrackets implements ITest { @:timeout(2000) public function test(async:utest.Async) { Thread.create(() -> { - Sys.println("Running DequeBrackets"); var deque = new Deque(); var dequeMutex = new Mutex(); function add(open:String, close:String) { diff --git a/tests/threads/src/cases/Issue8063.hx b/tests/threads/src/cases/Issue8063.hx index 974d951d0191ea8ab4be6ddbd950f237a0c86b5f..b81b8d467b28e2c772078fc38ca897aab3c44b6f 100644 --- a/tests/threads/src/cases/Issue8063.hx +++ b/tests/threads/src/cases/Issue8063.hx @@ -9,7 +9,6 @@ class Issue8063 implements ITest { @:timeout(5000) function test(async:Async) { - Sys.println("Running Issue8063"); Assert.isTrue(Thread.current() == Thread.current()); Thread.create(() -> { Assert.isTrue(Thread.current() == Thread.current()); diff --git a/tests/threads/src/cases/TestThreads.hx b/tests/threads/src/cases/TestThreads.hx index 66e3741e052940f7c08f1af2fdf04dbb7dceecfb..962279af9663fbcae36442d52a4d0d1fb2c637a4 100644 --- a/tests/threads/src/cases/TestThreads.hx +++ b/tests/threads/src/cases/TestThreads.hx @@ -17,7 +17,6 @@ class TestThreads implements utest.ITest private function doTestSort() { - Sys.println("Running TestThreads"); var ts = new ThreadSort(); #if java ts.maxVal *= 10; diff --git a/tests/threads/src/cases/WeirdTreeSum.hx b/tests/threads/src/cases/WeirdTreeSum.hx index e437a06cfc704016387ba854c8e3ac0554e9fd3d..4b7aab2c0c04d420eb598dc552d018f748dc7f68 100644 --- a/tests/threads/src/cases/WeirdTreeSum.hx +++ b/tests/threads/src/cases/WeirdTreeSum.hx @@ -60,7 +60,6 @@ class WeirdTreeSum implements utest.ITest { @:timeout(2000) public function test(async:utest.Async) { Thread.create(() -> { - Sys.println("Running WeirdTreeSum"); var fileContent = File.getContent("res/tree1.txt"); var buf = new StringBuf(); buf.add("(1)\n"); diff --git a/tests/unit/compile-as3.hxml b/tests/unit/compile-as3.hxml deleted file mode 100644 index 0c2337a23ce336bf1daba7c4eb05cfc58100fc42..0000000000000000000000000000000000000000 --- a/tests/unit/compile-as3.hxml +++ /dev/null @@ -1,9 +0,0 @@ --cmd compc -output native_swf/lib.swc -include-sources native_swf/ - ---next - -compile-each.hxml ---main unit.TestMain --as3 bin/as3 --swf-lib native_swf/lib.swc --cmd mxmlc -include-libraries=native_swf/lib.swc -static-link-runtime-shared-libraries=true -debug bin/as3/__main__.as --output bin/unit9_as3.swf diff --git a/tests/unit/compile.hxml b/tests/unit/compile.hxml index c9645219cd241189711f43bbcd07b3d619098f62..33c128e4d9f53bdb0ab07aabcca00fe911331970 100644 --- a/tests/unit/compile.hxml +++ b/tests/unit/compile.hxml @@ -20,7 +20,6 @@ compile-java-runner.hxml --next compile-lua.hxml --next compile-neko.hxml --next compile-php.hxml ---next compile-as3.hxml --next compile-cpp.hxml --next compile-java.hxml --next compile-cs.hxml diff --git a/tests/unit/native_swf/ParentCtorWithDefaultStringArgument.as b/tests/unit/native_swf/ParentCtorWithDefaultStringArgument.as new file mode 100644 index 0000000000000000000000000000000000000000..5b60e34ad0ae93c52f8c0ae0b69cce1087b34270 --- /dev/null +++ b/tests/unit/native_swf/ParentCtorWithDefaultStringArgument.as @@ -0,0 +1,8 @@ +package { + public class ParentCtorWithDefaultStringArgument { + public var strField:String; + public function ParentCtorWithDefaultStringArgument(str:String = "hello") { + strField = str; + } + } +} \ No newline at end of file diff --git a/tests/unit/src/RunCastGenerator.hx b/tests/unit/src/RunCastGenerator.hx new file mode 100644 index 0000000000000000000000000000000000000000..fc08fac35f296bceb7081186de7e19971b7e510d --- /dev/null +++ b/tests/unit/src/RunCastGenerator.hx @@ -0,0 +1,106 @@ +import sys.io.File; +import haxe.macro.Expr; +import haxe.macro.Printer; + +class RunCastGenerator { + static function main() { + Sys.println("Starting cast generation..."); + var td = macro class TestNumericCasts extends unit.Test {}; + var intTypes = [macro:Int8, macro:Int16, macro:Int32, macro:Int64]; + var floatTypes = [macro:Float32, macro:Float64]; + var boxedIntTypes = [macro:Null, macro:Null, macro:Null, macro:Null]; + var boxedFloatTypes = [macro:Null, macro:Null]; + var allTypes = intTypes.concat(floatTypes).concat(boxedIntTypes).concat(boxedFloatTypes); + function getInfo(c:ComplexType) { + return switch (c) { + case macro:Int8: {nullable: false, floatable: false, name: "Int8"}; + case macro:Int16: {nullable: false, floatable: false, name: "Int16"}; + case macro:Int32: {nullable: false, floatable: false, name: "Int32"}; + case macro:Int64: {nullable: false, floatable: false, name: "Int64"}; + case macro:Float32: {nullable: false, floatable: true, name: "Float32"}; + case macro:Float64: {nullable: false, floatable: true, name: "Float64"}; + case macro:Null: {nullable: true, floatable: false, name: "BoxedInt8"}; + case macro:Null: {nullable: true, floatable: false, name: "BoxedInt16"}; + case macro:Null: {nullable: true, floatable: false, name: "BoxedInt32"}; + case macro:Null: {nullable: true, floatable: false, name: "BoxedInt64"}; + case macro:Null: {nullable: true, floatable: true, name: "BoxedFloat32"}; + case macro:Null: {nullable: true, floatable: true, name: "BoxedFloat64"}; + case _: throw false; + } + } + var tests = []; + for (typeFrom in allTypes) { + for (typeTo in allTypes) { + if (typeFrom == typeTo) { + continue; + } + var infoFrom = getInfo(typeFrom); + var infoTo = getInfo(typeTo); + var name = infoFrom.name + "_" + infoTo.name; + var dynamicName = "Dynamic" + name; + var fields = (macro class C { + static function $name(v : $typeFrom):$typeTo return cast v; + static function $dynamicName(v : $typeFrom):$typeTo { + var x:Dynamic = v; + return x; + } + }).fields; + td.fields.push(fields[0]); + td.fields.push(fields[1]); + function generateCalls(name:String) { + tests.push(macro deq(0, $i{name}(0))); + tests.push(macro deq(1, $i{name}(1))); + if (infoFrom.floatable) { + tests.push(macro deq(0., $i{name}(0.))); + tests.push(macro deq(1., $i{name}(1.))); + } + if (infoFrom.nullable) { + if (infoTo.nullable) { + tests.push(macro deq(null, $i{name}(null))); + } else { + tests.push(macro deq(CastHelper.nullOr0, $i{name}(null))); + } + } + } + generateCalls(name); + generateCalls(dynamicName); + } + } + td.fields = td.fields.concat((macro class C { + public function test() { + $b{tests}; + } + + function deq(expected:Dynamic, actual:Dynamic, ?p:haxe.PosInfos) { + eq(expected, actual, p); + } + }).fields); + var printer = new Printer(); + var buffer = new StringBuf(); + function line(content:String) { + buffer.add(content); + buffer.addChar("\n".code); + } + line("// This file is auto-generated from RunCastGenerator.hx - do not edit!"); + line("package unit;"); + line("#if java"); + line("import java.StdTypes;"); + line("private typedef Int32 = Int;"); + line("private typedef Float32 = Single;"); + line("private typedef Float64 = Float;"); + line("#else"); + line("private typedef Int8 = Int;"); + line("private typedef Int16 = Int;"); + line("private typedef Int32 = Int;"); + line("private typedef Int64 = Int;"); + line("private typedef Float32 = Float;"); + line("private typedef Float64 = Float;"); + line("#end"); + line("private class CastHelper {"); + line("\tstatic public var nullOr0 = #if target.static 0 #else null #end;"); + line("}"); + line(printer.printTypeDefinition(td)); + File.saveContent("src/unit/TestNumericCasts.hx", buffer.toString()); + Sys.println('Done with cast generation! " Generated ${td.fields.length} functions and ${tests.length} tests.'); + } +} diff --git a/tests/unit/src/misc/Issue9394Class.hx b/tests/unit/src/misc/Issue9394Class.hx new file mode 100644 index 0000000000000000000000000000000000000000..f6fd1abfcc5cfee700612f7a228d2610b6383b4d --- /dev/null +++ b/tests/unit/src/misc/Issue9394Class.hx @@ -0,0 +1,5 @@ +package misc; + +class Issue9394Class { + @:pure(false) static public function test() {} +} \ No newline at end of file diff --git a/tests/unit/src/unit/HelperMacros.hx b/tests/unit/src/unit/HelperMacros.hx index e0caed2c68f156da1639e42c205943498387697b..c349a33b312a6a371c7d5eb75408e9e076117002 100644 --- a/tests/unit/src/unit/HelperMacros.hx +++ b/tests/unit/src/unit/HelperMacros.hx @@ -75,7 +75,7 @@ class HelperMacros { var result = try { typeof(e); "no error"; - } catch (e:Dynamic) Std.string(e.message); + } catch (e:haxe.Exception) Std.string(e.message); return macro $v{result}; } diff --git a/tests/unit/src/unit/MyClass.hx b/tests/unit/src/unit/MyClass.hx index cfd71626dd4b9ed7079606094ec7b36c3c0c8af3..514d123edb2e50a5e04a16a5b342ce443cf24946 100644 --- a/tests/unit/src/unit/MyClass.hx +++ b/tests/unit/src/unit/MyClass.hx @@ -11,7 +11,7 @@ interface IMyChild extends IMyParent {} class MyClass { - #if as3 public #end var val : Int; + var val : Int; public var ref : MyClass; public var intValue : Int; @@ -46,11 +46,10 @@ class MyChild1 extends MyParent implements IMyChild { override function b() return 21; function c() return 19; } -#if !as3 + class MyChild2 extends MyParent { public function test1(mc1:MyChild1) return mc1.b(); } -#end interface I1 { } class Base { public var s:String; public function new() { } } @@ -290,11 +289,7 @@ class InlineCastB extends InlineCastA { public function new() { } public inline function test() : InlineCastB { - #if as3 - return cast (self(), InlineCastB); - #else return cast self(); - #end } public function quote() { diff --git a/tests/unit/src/unit/MySubClass.hx b/tests/unit/src/unit/MySubClass.hx index 3393035218583694e16f330b721e2a0432c5a5d9..76ff0d989af9b36a8d24b555eb2841df017a6bd3 100644 --- a/tests/unit/src/unit/MySubClass.hx +++ b/tests/unit/src/unit/MySubClass.hx @@ -6,6 +6,6 @@ class MySubClass extends MyClass { return val * 2; } - @:keep #if as3 public #end static var XXX = 3; + @:keep static var XXX = 3; } \ No newline at end of file diff --git a/tests/unit/src/unit/Test.hx b/tests/unit/src/unit/Test.hx index fbe6bcfd9a7c9194880ca28ec1f7c3cc19969c81..04b04ac50742dda9c79cb710a06ddd83d66f21df 100644 --- a/tests/unit/src/unit/Test.hx +++ b/tests/unit/src/unit/Test.hx @@ -10,9 +10,6 @@ import cpp.link.StaticZlib; #end @:keepSub -#if as3 -@:publicFields -#end class Test implements utest.ITest { public function new() { @@ -63,18 +60,18 @@ class Test implements utest.ITest { } function hf(c:Class, n:String, ?pos:haxe.PosInfos) { - t(Lambda.has(Type.getInstanceFields(c), n)); + t(Lambda.has(Type.getInstanceFields(c), n), pos); } function nhf(c:Class, n:String, ?pos:haxe.PosInfos) { - f(Lambda.has(Type.getInstanceFields(c), n)); + f(Lambda.has(Type.getInstanceFields(c), n), pos); } function hsf(c:Class , n:String, ?pos:haxe.PosInfos) { - t(Lambda.has(Type.getClassFields(c), n)); + t(Lambda.has(Type.getClassFields(c), n), pos); } function nhsf(c:Class , n:String, ?pos:haxe.PosInfos) { - f(Lambda.has(Type.getClassFields(c), n)); + f(Lambda.has(Type.getClassFields(c), n), pos); } } diff --git a/tests/unit/src/unit/TestArrowFunctions.hx b/tests/unit/src/unit/TestArrowFunctions.hx index e6151213232f6fc95ed395281c16fc8b31173b8c..6c8e859c3602ef4c067fcc1fae28319792a34b73 100644 --- a/tests/unit/src/unit/TestArrowFunctions.hx +++ b/tests/unit/src/unit/TestArrowFunctions.hx @@ -34,8 +34,6 @@ class TestArrowFunctions extends Test { var maybe : Void -> Bool; - #if !as3 - function testSyntax(){ maybe = () -> Math.random() > 0.5; @@ -145,5 +143,4 @@ class TestArrowFunctions extends Test { obj = { f : a -> a + a }; } - #end } diff --git a/tests/unit/src/unit/TestBasetypes.hx b/tests/unit/src/unit/TestBasetypes.hx index b1f7abfa69eb51af828cb2c441e8330abc3a6122..f7be0942defc42b837f9ca85bf562bd7076ef38a 100644 --- a/tests/unit/src/unit/TestBasetypes.hx +++ b/tests/unit/src/unit/TestBasetypes.hx @@ -182,7 +182,7 @@ class TestBasetypes extends Test { eq( Std.int( 2147483647.001), 0x7FFFFFFF ); - #if (flash && !as3) + #if flash eq( Math.floor( -10000000000.7), 0xABF41BFF); eq( Math.ceil( -10000000000.7), 0xABF41C00); eq( Math.round( -10000000000.7), 0xABF41BFF); @@ -279,13 +279,12 @@ class TestBasetypes extends Test { function testObjectKeyword() { // new is a keyword in Haxe var l = { "new": "test" }; - var prefix = #if as3 "_" #else "" #end; - eq(Reflect.field(l, prefix + "new"), "test"); + eq(Reflect.field(l, "new"), "test"); // const is a keyword on some platforms but not in Haxe // check that with can still access it normally var o = { const : 6 } eq(o.const, 6); - eq(Reflect.field(o, prefix+"const"), 6); + eq(Reflect.field(o, "const"), 6); } function testFormat() { @@ -306,7 +305,7 @@ class TestBasetypes extends Test { function testAbstract() { var a = new MyAbstract(33); - t( Std.is(a, Int) ); + t( Std.isOfType(a, Int) ); eq( a.toInt(), 33 ); var b = a; a.incr(); @@ -318,26 +317,26 @@ class TestBasetypes extends Test { var s = "Abstract casting ::t::"; // var from var tpl:unit.MyAbstract.TemplateWrap = s; - t(Std.is(tpl, haxe.Template)); - t(Std.is(tpl.get(), haxe.Template)); + t(Std.isOfType(tpl, haxe.Template)); + t(Std.isOfType(tpl.get(), haxe.Template)); eq(tpl.get().execute( { t:"works!" } ), "Abstract casting works!"); //var to var str:String = tpl; - t(Std.is(str, String)); + t(Std.isOfType(str, String)); eq(str, "Abstract casting really works!"); // assign from var tpl:unit.MyAbstract.TemplateWrap; tpl = s; - t(Std.is(tpl, haxe.Template)); - t(Std.is(tpl.get(), haxe.Template)); + t(Std.isOfType(tpl, haxe.Template)); + t(Std.isOfType(tpl.get(), haxe.Template)); eq(tpl.get().execute( { t:"works!" } ), "Abstract casting works!"); //assign to var str:String; str = tpl; - t(Std.is(str, String)); + t(Std.isOfType(str, String)); eq(str, "Abstract casting really works!"); // call arg from diff --git a/tests/unit/src/unit/TestExceptions.hx b/tests/unit/src/unit/TestExceptions.hx new file mode 100644 index 0000000000000000000000000000000000000000..91dde25cadaad9a73703518c32cb223bb644057f --- /dev/null +++ b/tests/unit/src/unit/TestExceptions.hx @@ -0,0 +1,348 @@ +package unit; + +import haxe.Exception; +import haxe.ValueException; +import haxe.CallStack; +import utest.Assert; +import unit.HelperMacros; + +private enum EnumError { + EError; +} + +private abstract AbstrString(String) from String {} +private abstract AbstrException(CustomHaxeException) from CustomHaxeException {} + +private class CustomHaxeException extends Exception {} + +#if php +private class CustomNativeException extends php.Exception {} +#elseif js +private class CustomNativeException extends js.lib.Error {} +#elseif flash +private class CustomNativeException extends flash.errors.Error {} +#elseif java +private class CustomNativeException extends java.lang.RuntimeException {} +#elseif cs +private class CustomNativeException extends cs.system.Exception {} +#elseif python +private class CustomNativeException extends python.Exceptions.Exception {} +#elseif (lua || eval || neko || hl || cpp) +private class CustomNativeException { public function new(m:String) {} } +#end + +#if java +private class NativeExceptionBase extends java.lang.RuntimeException {} +private class NativeExceptionChild extends NativeExceptionBase {} +private class NativeExceptionOther extends java.lang.RuntimeException {} +#end + +private class NoConstructorValueException extends ValueException {} + +private class WithConstructorValueException extends ValueException { + public function new(value:Any, ?previous:Exception, ?native:Any) { + super(value, previous, native); + } +} + +private typedef ItemData = {?file:String, ?line:Int, ?method:String} + +class TestExceptions extends Test { + /** Had to move to instance var because of https://github.com/HaxeFoundation/haxe/issues/9174 */ + var rethrown:Bool = false; + + public function testWildCardCatch() { + try { + throw 123; + } catch(e:Dynamic) { + eq(123, e); + } + + try { + throw 123; + } catch(e:Exception) { + eq('123', e.message); + t(Std.isOfType(e, ValueException)); + } + } + + public function testWildCardCatch_rethrow() { + var thrown = new CustomHaxeException(''); + rethrown = false; + try { + try { + throw thrown; + } catch(e:Exception) { + rethrown = true; + throw e; + } + } catch(e:CustomHaxeException) { + eq(thrown, e); + t(rethrown); + } + + var thrown = new CustomNativeException(''); + rethrown = false; + try { + try { + throw thrown; + } catch(e:Exception) { + rethrown = true; + throw e; + } + } catch(e:CustomNativeException) { + eq(thrown, e); + t(rethrown); + } + } + + public function testSpecificCatch_propagatesUnrelatedExceptions() { + var propagated = false; + try { + try { + throw new ValueException('hello'); + } catch(e:CustomHaxeException) { + assert(); + } + assert(); + } catch(e:ValueException) { + propagated = true; + } + t(propagated); + } + + public function testCatchAbstract() { + var a:AbstrString = 'hello'; + try { + throw a; + } catch(e:AbstrString) { + eq(a, e); + } + + var a:AbstrException = new CustomHaxeException(''); + try { + throw a; + } catch(e:AbstrException) { + eq(a, e); + } + } + + public function testValueException() { + try { + throw 123; + } catch(e:ValueException) { + eq(123, e.value); + } + try { + throw 123; + } catch(e:Int) { + eq(123, e); + } + + try { + throw EError; + } catch(e:ValueException) { + eq('EError', e.message); + } + try { + throw EError; + } catch(e:EnumError) { + eq(EError, e); + } + + try { + throw 'string'; + } catch(e:ValueException) { + eq('string', e.value); + } + try { + throw 'string'; + } catch(e:String) { + eq('string', e); + } + } + + public function testCustomNativeException() { + var thrown = new CustomNativeException(''); + rethrown = false; + try { + try { + throw thrown; + } catch(e:CustomNativeException) { + eq(thrown, e); + rethrown = true; + throw e; + } + } catch(e:CustomNativeException) { + eq(thrown, e); + t(rethrown); + } + } + + public function testCustomNativeException_thrownAsDynamic() { + var thrown:Any = new CustomNativeException(''); + rethrown = false; + try { + try { + throw thrown; + } catch(e:CustomNativeException) { + eq(thrown, e); + rethrown = true; + throw e; + } + } catch(e:CustomNativeException) { + eq(thrown, e); + t(rethrown); + } + } + + public function testCustomHaxeException() { + var thrown = new CustomHaxeException(''); + rethrown = false; + try { + try { + throw thrown; + } catch(e:CustomHaxeException) { + eq(thrown, e); + rethrown = true; + throw e; + } + } catch(e:CustomHaxeException) { + eq(thrown, e); + t(rethrown); + } + } + + public function testCustomHaxeException_thrownAsDynamic() { + var thrown:Any = new CustomHaxeException(''); + rethrown = false; + try { + try { + throw thrown; + } catch(e:CustomHaxeException) { + eq(thrown, e); + rethrown = true; + throw e; + } + } catch(e:CustomHaxeException) { + eq(thrown, e); + t(rethrown); + } + } + + public function testExceptionStack() { + var data = [ + '_without_ throws' => stacksWithoutThrowLevel1(), + '_with_ throws' => stacksWithThrowLevel1() + ]; + for(label => stacks in data) { + Assert.isTrue(stacks.length > 1, '$label: wrong stacks.length'); + var expected = null; + var lineShift = 0; + for(s in stacks) { + if(expected == null) { + expected = stackItemData(s[0]); + } else { + var actual = stackItemData(s[0]); + if(expected.line != actual.line) { + if(lineShift == 0) { + lineShift = actual.line - expected.line; + } + expected.line += lineShift; + } + Assert.same(expected, actual, '$label: $expected is expected, but got $actual'); + } + } + } + } + + function stacksWithoutThrowLevel1() { + return stacksWithoutThrowLevel2(); + } + + function stacksWithoutThrowLevel2():Array { + var result:Array = []; + // It's critical for `testExceptionStack` test to keep the following lines + // order with no additional code in between. + result.push(CallStack.callStack()); + result.push(new Exception('').stack); + result.push(new ValueException('').stack); + result.push(new WithConstructorValueException('').stack); + result.push(new NoConstructorValueException('').stack); + result.push(@:privateAccess (Exception.thrown(''):Exception).stack); + return result; + } + + function stacksWithThrowLevel1() { + return stacksWithThrowLevel2(); + } + + function stacksWithThrowLevel2():Array { + var result:Array = []; + // It's critical for `testExceptionStack` test to keep the following lines + // order with no additional code in between. + result.push(try throw new Exception('') catch(e:Exception) e.stack); + result.push(try throw new ValueException('') catch(e:Exception) e.stack); + result.push(try throw new WithConstructorValueException('') catch(e:Exception) e.stack); + result.push(try throw new NoConstructorValueException('') catch(e:Exception) e.stack); + result.push(try throw @:privateAccess (Exception.thrown(''):Exception) catch(e:Exception) e.stack); + return result; + } + + function stackItemData(item:StackItem):ItemData { + var result:ItemData = {}; + switch item { + case FilePos(s, f, l, _): + result.file = f; + result.line = l; + switch s { + case Method(_, m): result.method = m; + case _: + } + case _: + } + return result; + } + + function testCatch_noTypeHint() { + try { + throw new Exception('Terrible error'); + } catch(e) { + Assert.notNull(Std.downcast(e, Exception)); + } + + HelperMacros.parseAndPrint('try { } catch(e) { }'); + eq('haxe.Exception', HelperMacros.typeString(try throw new Exception('') catch(e) e)); + } + +#if java + function testCatchChain() { + eq("caught NativeExceptionChild: msg", raise(() -> throw new NativeExceptionChild("msg"))); + eq("caught NativeExceptionBase: msg", raise(() -> throw new NativeExceptionBase("msg"))); + eq("caught String: msg", raise(() -> throw "msg")); + eq("caught NativeExceptionOther: msg", raise(() -> throw new NativeExceptionOther("msg"))); + eq("caught Int: 12", raise(() -> throw 12)); + eq("caught Throwable: 12.1", raise(() -> throw 12.1)); + eq("caught Throwable: false", raise(() -> throw false)); + eq("caught Throwable: msg", raise(() -> throw new java.lang.Exception("msg"))); + } + + function raise(f:Void -> String) { + return try { + f(); + } catch(e:NativeExceptionChild) { + 'caught NativeExceptionChild: ${e.getMessage()}'; + } catch(e:NativeExceptionBase) { + 'caught NativeExceptionBase: ${e.getMessage()}'; + } catch(e:String) { + 'caught String: $e'; + } catch(e:NativeExceptionOther) { + 'caught NativeExceptionOther: ${e.getMessage()}'; + } catch(e:Int) { + 'caught Int: $e'; + } catch(e:java.lang.Throwable) { + 'caught Throwable: ${e.getMessage()}'; + } + } +#end +} \ No newline at end of file diff --git a/tests/unit/src/unit/TestHashMap.hx b/tests/unit/src/unit/TestHashMap.hx new file mode 100644 index 0000000000000000000000000000000000000000..6207454ad712d6c8ee49451e1bfb7f4c125ba611 --- /dev/null +++ b/tests/unit/src/unit/TestHashMap.hx @@ -0,0 +1,46 @@ +package unit; + +import haxe.ds.HashMap; + +class TestHashMap extends Test { + function test() { + var grid = new HashMap(); + grid[new Point(0, 0)] = "a"; + grid[new Point(0, 1)] = "b"; + grid[new Point(1, 0)] = "c"; + grid[new Point(1, 1)] = "d"; + + eq("c", grid[new Point(1, 0)]); + + var asserts = 0; + for (p => s in grid) { + t(p.equals(switch s { + case "a": new Point(0, 0); + case "b": new Point(0, 1); + case "c": new Point(1, 0); + case "d": new Point(1, 1); + case v: throw 'unknown value $v'; + })); + asserts++; + } + eq(4, asserts); + } +} + +private class Point { + public final x:Int; + public final y:Int; + + public function new(x, y) { + this.x = x; + this.y = y; + } + + public function equals(point:Point):Bool { + return x == point.x && y == point.y; + } + + public function hashCode():Int { + return x + 10000 * y; + } +} diff --git a/tests/unit/src/unit/TestInterface.hx b/tests/unit/src/unit/TestInterface.hx index 5a905836cc519faebcbd06f5864b444f7730ea16..07869af4462f0825b701ab30fe7cc46a9313a5c8 100644 --- a/tests/unit/src/unit/TestInterface.hx +++ b/tests/unit/src/unit/TestInterface.hx @@ -63,11 +63,11 @@ class TestInterface extends Test { var p = new Point(1.3,5); var px : IX = p; var py : IY = p; - t( Std.is(p, Point) ); - t( Std.is(p, IX) ); - t( Std.is(p, IY) ); - f( Std.is(p, IEmpty) ); - f( Std.is(p, IX2) ); + t( Std.isOfType(p, Point) ); + t( Std.isOfType(p, IX) ); + t( Std.isOfType(p, IY) ); + f( Std.isOfType(p, IEmpty) ); + f( Std.isOfType(p, IX2) ); t( px == p ); t( py == p ); diff --git a/tests/unit/src/unit/TestMacro.hx b/tests/unit/src/unit/TestMacro.hx index b9cb915c28ca5a38ca7242b3a06df2df70951279..4caf14dfdd3c722d36212cdd696e5b2e6dc42343 100644 --- a/tests/unit/src/unit/TestMacro.hx +++ b/tests/unit/src/unit/TestMacro.hx @@ -63,8 +63,50 @@ class TestMacro extends Test { parseAndPrint("var a:() -> A"); parseAndPrint("var a:() -> (() -> A)"); parseAndPrint("var a:(x:(y:Y) -> Z) -> A"); - // special case with 1 argument - parseAndPrint("var a:X -> Y"); - parseAndPrint("var a:(X) -> Y"); + // local functions + parseAndPrint('a -> b'); + parseAndPrint('(a:Int) -> b'); + parseAndPrint('(a, b) -> c'); + parseAndPrint('function(a) return b'); + parseAndPrint('function named(a) return b'); + + var p = new haxe.macro.Printer(); + // special handling of single arguments (don't add parentheses) + // types + eq(p.printComplexType(macro :X -> Y), "X -> Y"); + eq(p.printComplexType(macro :(X) -> Y), "(X) -> Y"); + eq(p.printComplexType(macro :((X)) -> Y), "((X)) -> Y"); + eq(p.printComplexType(macro :?X -> Y), "?X -> Y"); + eq(p.printComplexType(macro :(?X) -> Y), "(?X) -> Y"); + // named + eq( + // see issue #9353 + p.printComplexType( TFunction( [ TOptional( TNamed('a', macro :Int) ) ], macro :Int) ), + "(?a:Int) -> Int" + ); + // function returning function + eq( + // see issue #9385 + p.printComplexType( TFunction( [], TFunction([], macro :Int)) ), + "() -> (() -> Int)" + ); + eq(p.printComplexType(macro :(a:X) -> Y), "(a:X) -> Y"); + eq(p.printComplexType(macro :(?a:X) -> Y), "(?a:X) -> Y"); + eq(p.printComplexType(macro :((?a:X)) -> Y), "((?a:X)) -> Y"); + // multiple arguments are always wrapped with parentheses + eq(p.printComplexType(macro :(X, Y) -> Z), "(X, Y) -> Z"); + eq(p.printComplexType(macro :X -> Y -> Z), "(X, Y) -> Z"); + eq(p.printComplexType(macro :(X -> Y) -> Z), "(X -> Y) -> Z"); + + // access order, see #9349 + eq( + p.printField({ + name: 'x', + pos: null, + kind: FVar(macro :Any, null), + access: [AFinal, AStatic] + }), + 'static final x : Any' + ); } } \ No newline at end of file diff --git a/tests/unit/src/unit/TestMain.hx b/tests/unit/src/unit/TestMain.hx index 3994549147e11c3f89fbf66b730aefccda0d27c6..8d1eaa86ecee456792f11bb1442cbf05d40e094c 100644 --- a/tests/unit/src/unit/TestMain.hx +++ b/tests/unit/src/unit/TestMain.hx @@ -50,6 +50,7 @@ class TestMain { var classes = [ new TestOps(), new TestBasetypes(), + new TestExceptions(), new TestBytes(), new TestIO(), new TestLocals(), @@ -71,6 +72,8 @@ class TestMain { new TestCasts(), new TestSyntaxModule(), new TestNull(), + new TestNumericCasts(), + new TestHashMap(), #if (!no_http && (!azure || !(php && Windows))) new TestHttp(), #end @@ -100,7 +103,7 @@ class TestMain { #end new TestInterface(), new TestNaN(), - #if ((dce == "full") && !interp && !as3) + #if ((dce == "full") && !interp) new TestDCE(), #end new TestMapComprehension(), diff --git a/tests/unit/src/unit/TestMatch.hx b/tests/unit/src/unit/TestMatch.hx index 9700d32422a383c0c315b7d7a1d9a3ca71c57035..00bae746e2a77f5c71887ef0deb51329558c0103 100644 --- a/tests/unit/src/unit/TestMatch.hx +++ b/tests/unit/src/unit/TestMatch.hx @@ -534,7 +534,7 @@ class TestMatch extends Test { eq(3, check(3)); eq(4, check(4)); - function is(pred : T -> Bool) return function (x : T) { + function isTrue(pred : T -> Bool) return function (x : T) { return pred(x)?Some(x):None; } @@ -549,7 +549,7 @@ class TestMatch extends Test { return switch(i) { case [x]: 1; case isPair(_) => Some({ a : a, b : b }) if (a < 0): 42; - case isPair(_) => Some({ a : is(even)(_) => Some(a), b : b }) : a+b; + case isPair(_) => Some({ a : isTrue(even)(_) => Some(a), b : b }) : a+b; case isPair(_) => Some({ a : isNot(even)(_) => Some(a), b : b }) : a*b; case testArgs(1, "foo", _) => "[99,98,97]": 99; case var arr: 3; diff --git a/tests/unit/src/unit/TestMeta.hx b/tests/unit/src/unit/TestMeta.hx index 32d5cd87a64e0cfe4c14b63ac034b89afc360c09..5e5ed18e305a6f0f3b6bd41fc6d8fe34ffe4018b 100644 --- a/tests/unit/src/unit/TestMeta.hx +++ b/tests/unit/src/unit/TestMeta.hx @@ -40,7 +40,7 @@ import unit.HelperMacros.getMeta; var m = haxe.rtti.Meta.getFields(TestMeta); eq( fields(m), "_" ); - eq( fields(m._), #if as3 "_"+#end "new" ); + eq( fields(m._), "new" ); var m = haxe.rtti.Meta.getStatics(TestMeta); eq( fields(m), "foo" ); diff --git a/tests/unit/src/unit/TestMisc.hx b/tests/unit/src/unit/TestMisc.hx index 26585931da1638d8e592688176ecf7c5362052ad..3836c577a1f04b3fad6b892064db646e33ffd636 100644 --- a/tests/unit/src/unit/TestMisc.hx +++ b/tests/unit/src/unit/TestMisc.hx @@ -449,11 +449,9 @@ class TestMisc extends Test { eq( x, 1 ); eq( arr[0].v, 4 ); - #if !as3 x = 0; eq( arr[x++].v += 3, 7 ); eq( arr[0].v, 7 ); - #end x = 0; var arr:Dynamic = [{ v : 3 }]; @@ -461,11 +459,9 @@ class TestMisc extends Test { eq( x, 1 ); eq( arr[0].v, 4 ); - #if !as3 x = 0; eq( arr[x++].v += 3, 7 ); eq( arr[0].v, 7 ); - #end } function testInitOrder() { diff --git a/tests/unit/src/unit/TestNumericCasts.hx b/tests/unit/src/unit/TestNumericCasts.hx new file mode 100644 index 0000000000000000000000000000000000000000..5a53fde0e6f472e8f25df4cf6b2ebeb1f1012793 --- /dev/null +++ b/tests/unit/src/unit/TestNumericCasts.hx @@ -0,0 +1,1523 @@ +// This file is auto-generated from RunCastGenerator.hx - do not edit! +package unit; +#if java +import java.StdTypes; +private typedef Int32 = Int; +private typedef Float32 = Single; +private typedef Float64 = Float; +#else +private typedef Int8 = Int; +private typedef Int16 = Int; +private typedef Int32 = Int; +private typedef Int64 = Int; +private typedef Float32 = Float; +private typedef Float64 = Float; +#end +private class CastHelper { + static public var nullOr0 = #if target.static 0 #else null #end; +} +class TestNumericCasts extends unit.Test { + static function Int8_Int16(v:Int8):Int16 return cast v; + static function DynamicInt8_Int16(v:Int8):Int16 { + var x:Dynamic = v; + return x; + } + static function Int8_Int32(v:Int8):Int32 return cast v; + static function DynamicInt8_Int32(v:Int8):Int32 { + var x:Dynamic = v; + return x; + } + static function Int8_Int64(v:Int8):Int64 return cast v; + static function DynamicInt8_Int64(v:Int8):Int64 { + var x:Dynamic = v; + return x; + } + static function Int8_Float32(v:Int8):Float32 return cast v; + static function DynamicInt8_Float32(v:Int8):Float32 { + var x:Dynamic = v; + return x; + } + static function Int8_Float64(v:Int8):Float64 return cast v; + static function DynamicInt8_Float64(v:Int8):Float64 { + var x:Dynamic = v; + return x; + } + static function Int8_BoxedInt8(v:Int8):Null return cast v; + static function DynamicInt8_BoxedInt8(v:Int8):Null { + var x:Dynamic = v; + return x; + } + static function Int8_BoxedInt16(v:Int8):Null return cast v; + static function DynamicInt8_BoxedInt16(v:Int8):Null { + var x:Dynamic = v; + return x; + } + static function Int8_BoxedInt32(v:Int8):Null return cast v; + static function DynamicInt8_BoxedInt32(v:Int8):Null { + var x:Dynamic = v; + return x; + } + static function Int8_BoxedInt64(v:Int8):Null return cast v; + static function DynamicInt8_BoxedInt64(v:Int8):Null { + var x:Dynamic = v; + return x; + } + static function Int8_BoxedFloat32(v:Int8):Null return cast v; + static function DynamicInt8_BoxedFloat32(v:Int8):Null { + var x:Dynamic = v; + return x; + } + static function Int8_BoxedFloat64(v:Int8):Null return cast v; + static function DynamicInt8_BoxedFloat64(v:Int8):Null { + var x:Dynamic = v; + return x; + } + static function Int16_Int8(v:Int16):Int8 return cast v; + static function DynamicInt16_Int8(v:Int16):Int8 { + var x:Dynamic = v; + return x; + } + static function Int16_Int32(v:Int16):Int32 return cast v; + static function DynamicInt16_Int32(v:Int16):Int32 { + var x:Dynamic = v; + return x; + } + static function Int16_Int64(v:Int16):Int64 return cast v; + static function DynamicInt16_Int64(v:Int16):Int64 { + var x:Dynamic = v; + return x; + } + static function Int16_Float32(v:Int16):Float32 return cast v; + static function DynamicInt16_Float32(v:Int16):Float32 { + var x:Dynamic = v; + return x; + } + static function Int16_Float64(v:Int16):Float64 return cast v; + static function DynamicInt16_Float64(v:Int16):Float64 { + var x:Dynamic = v; + return x; + } + static function Int16_BoxedInt8(v:Int16):Null return cast v; + static function DynamicInt16_BoxedInt8(v:Int16):Null { + var x:Dynamic = v; + return x; + } + static function Int16_BoxedInt16(v:Int16):Null return cast v; + static function DynamicInt16_BoxedInt16(v:Int16):Null { + var x:Dynamic = v; + return x; + } + static function Int16_BoxedInt32(v:Int16):Null return cast v; + static function DynamicInt16_BoxedInt32(v:Int16):Null { + var x:Dynamic = v; + return x; + } + static function Int16_BoxedInt64(v:Int16):Null return cast v; + static function DynamicInt16_BoxedInt64(v:Int16):Null { + var x:Dynamic = v; + return x; + } + static function Int16_BoxedFloat32(v:Int16):Null return cast v; + static function DynamicInt16_BoxedFloat32(v:Int16):Null { + var x:Dynamic = v; + return x; + } + static function Int16_BoxedFloat64(v:Int16):Null return cast v; + static function DynamicInt16_BoxedFloat64(v:Int16):Null { + var x:Dynamic = v; + return x; + } + static function Int32_Int8(v:Int32):Int8 return cast v; + static function DynamicInt32_Int8(v:Int32):Int8 { + var x:Dynamic = v; + return x; + } + static function Int32_Int16(v:Int32):Int16 return cast v; + static function DynamicInt32_Int16(v:Int32):Int16 { + var x:Dynamic = v; + return x; + } + static function Int32_Int64(v:Int32):Int64 return cast v; + static function DynamicInt32_Int64(v:Int32):Int64 { + var x:Dynamic = v; + return x; + } + static function Int32_Float32(v:Int32):Float32 return cast v; + static function DynamicInt32_Float32(v:Int32):Float32 { + var x:Dynamic = v; + return x; + } + static function Int32_Float64(v:Int32):Float64 return cast v; + static function DynamicInt32_Float64(v:Int32):Float64 { + var x:Dynamic = v; + return x; + } + static function Int32_BoxedInt8(v:Int32):Null return cast v; + static function DynamicInt32_BoxedInt8(v:Int32):Null { + var x:Dynamic = v; + return x; + } + static function Int32_BoxedInt16(v:Int32):Null return cast v; + static function DynamicInt32_BoxedInt16(v:Int32):Null { + var x:Dynamic = v; + return x; + } + static function Int32_BoxedInt32(v:Int32):Null return cast v; + static function DynamicInt32_BoxedInt32(v:Int32):Null { + var x:Dynamic = v; + return x; + } + static function Int32_BoxedInt64(v:Int32):Null return cast v; + static function DynamicInt32_BoxedInt64(v:Int32):Null { + var x:Dynamic = v; + return x; + } + static function Int32_BoxedFloat32(v:Int32):Null return cast v; + static function DynamicInt32_BoxedFloat32(v:Int32):Null { + var x:Dynamic = v; + return x; + } + static function Int32_BoxedFloat64(v:Int32):Null return cast v; + static function DynamicInt32_BoxedFloat64(v:Int32):Null { + var x:Dynamic = v; + return x; + } + static function Int64_Int8(v:Int64):Int8 return cast v; + static function DynamicInt64_Int8(v:Int64):Int8 { + var x:Dynamic = v; + return x; + } + static function Int64_Int16(v:Int64):Int16 return cast v; + static function DynamicInt64_Int16(v:Int64):Int16 { + var x:Dynamic = v; + return x; + } + static function Int64_Int32(v:Int64):Int32 return cast v; + static function DynamicInt64_Int32(v:Int64):Int32 { + var x:Dynamic = v; + return x; + } + static function Int64_Float32(v:Int64):Float32 return cast v; + static function DynamicInt64_Float32(v:Int64):Float32 { + var x:Dynamic = v; + return x; + } + static function Int64_Float64(v:Int64):Float64 return cast v; + static function DynamicInt64_Float64(v:Int64):Float64 { + var x:Dynamic = v; + return x; + } + static function Int64_BoxedInt8(v:Int64):Null return cast v; + static function DynamicInt64_BoxedInt8(v:Int64):Null { + var x:Dynamic = v; + return x; + } + static function Int64_BoxedInt16(v:Int64):Null return cast v; + static function DynamicInt64_BoxedInt16(v:Int64):Null { + var x:Dynamic = v; + return x; + } + static function Int64_BoxedInt32(v:Int64):Null return cast v; + static function DynamicInt64_BoxedInt32(v:Int64):Null { + var x:Dynamic = v; + return x; + } + static function Int64_BoxedInt64(v:Int64):Null return cast v; + static function DynamicInt64_BoxedInt64(v:Int64):Null { + var x:Dynamic = v; + return x; + } + static function Int64_BoxedFloat32(v:Int64):Null return cast v; + static function DynamicInt64_BoxedFloat32(v:Int64):Null { + var x:Dynamic = v; + return x; + } + static function Int64_BoxedFloat64(v:Int64):Null return cast v; + static function DynamicInt64_BoxedFloat64(v:Int64):Null { + var x:Dynamic = v; + return x; + } + static function Float32_Int8(v:Float32):Int8 return cast v; + static function DynamicFloat32_Int8(v:Float32):Int8 { + var x:Dynamic = v; + return x; + } + static function Float32_Int16(v:Float32):Int16 return cast v; + static function DynamicFloat32_Int16(v:Float32):Int16 { + var x:Dynamic = v; + return x; + } + static function Float32_Int32(v:Float32):Int32 return cast v; + static function DynamicFloat32_Int32(v:Float32):Int32 { + var x:Dynamic = v; + return x; + } + static function Float32_Int64(v:Float32):Int64 return cast v; + static function DynamicFloat32_Int64(v:Float32):Int64 { + var x:Dynamic = v; + return x; + } + static function Float32_Float64(v:Float32):Float64 return cast v; + static function DynamicFloat32_Float64(v:Float32):Float64 { + var x:Dynamic = v; + return x; + } + static function Float32_BoxedInt8(v:Float32):Null return cast v; + static function DynamicFloat32_BoxedInt8(v:Float32):Null { + var x:Dynamic = v; + return x; + } + static function Float32_BoxedInt16(v:Float32):Null return cast v; + static function DynamicFloat32_BoxedInt16(v:Float32):Null { + var x:Dynamic = v; + return x; + } + static function Float32_BoxedInt32(v:Float32):Null return cast v; + static function DynamicFloat32_BoxedInt32(v:Float32):Null { + var x:Dynamic = v; + return x; + } + static function Float32_BoxedInt64(v:Float32):Null return cast v; + static function DynamicFloat32_BoxedInt64(v:Float32):Null { + var x:Dynamic = v; + return x; + } + static function Float32_BoxedFloat32(v:Float32):Null return cast v; + static function DynamicFloat32_BoxedFloat32(v:Float32):Null { + var x:Dynamic = v; + return x; + } + static function Float32_BoxedFloat64(v:Float32):Null return cast v; + static function DynamicFloat32_BoxedFloat64(v:Float32):Null { + var x:Dynamic = v; + return x; + } + static function Float64_Int8(v:Float64):Int8 return cast v; + static function DynamicFloat64_Int8(v:Float64):Int8 { + var x:Dynamic = v; + return x; + } + static function Float64_Int16(v:Float64):Int16 return cast v; + static function DynamicFloat64_Int16(v:Float64):Int16 { + var x:Dynamic = v; + return x; + } + static function Float64_Int32(v:Float64):Int32 return cast v; + static function DynamicFloat64_Int32(v:Float64):Int32 { + var x:Dynamic = v; + return x; + } + static function Float64_Int64(v:Float64):Int64 return cast v; + static function DynamicFloat64_Int64(v:Float64):Int64 { + var x:Dynamic = v; + return x; + } + static function Float64_Float32(v:Float64):Float32 return cast v; + static function DynamicFloat64_Float32(v:Float64):Float32 { + var x:Dynamic = v; + return x; + } + static function Float64_BoxedInt8(v:Float64):Null return cast v; + static function DynamicFloat64_BoxedInt8(v:Float64):Null { + var x:Dynamic = v; + return x; + } + static function Float64_BoxedInt16(v:Float64):Null return cast v; + static function DynamicFloat64_BoxedInt16(v:Float64):Null { + var x:Dynamic = v; + return x; + } + static function Float64_BoxedInt32(v:Float64):Null return cast v; + static function DynamicFloat64_BoxedInt32(v:Float64):Null { + var x:Dynamic = v; + return x; + } + static function Float64_BoxedInt64(v:Float64):Null return cast v; + static function DynamicFloat64_BoxedInt64(v:Float64):Null { + var x:Dynamic = v; + return x; + } + static function Float64_BoxedFloat32(v:Float64):Null return cast v; + static function DynamicFloat64_BoxedFloat32(v:Float64):Null { + var x:Dynamic = v; + return x; + } + static function Float64_BoxedFloat64(v:Float64):Null return cast v; + static function DynamicFloat64_BoxedFloat64(v:Float64):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt8_Int8(v:Null):Int8 return cast v; + static function DynamicBoxedInt8_Int8(v:Null):Int8 { + var x:Dynamic = v; + return x; + } + static function BoxedInt8_Int16(v:Null):Int16 return cast v; + static function DynamicBoxedInt8_Int16(v:Null):Int16 { + var x:Dynamic = v; + return x; + } + static function BoxedInt8_Int32(v:Null):Int32 return cast v; + static function DynamicBoxedInt8_Int32(v:Null):Int32 { + var x:Dynamic = v; + return x; + } + static function BoxedInt8_Int64(v:Null):Int64 return cast v; + static function DynamicBoxedInt8_Int64(v:Null):Int64 { + var x:Dynamic = v; + return x; + } + static function BoxedInt8_Float32(v:Null):Float32 return cast v; + static function DynamicBoxedInt8_Float32(v:Null):Float32 { + var x:Dynamic = v; + return x; + } + static function BoxedInt8_Float64(v:Null):Float64 return cast v; + static function DynamicBoxedInt8_Float64(v:Null):Float64 { + var x:Dynamic = v; + return x; + } + static function BoxedInt8_BoxedInt16(v:Null):Null return cast v; + static function DynamicBoxedInt8_BoxedInt16(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt8_BoxedInt32(v:Null):Null return cast v; + static function DynamicBoxedInt8_BoxedInt32(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt8_BoxedInt64(v:Null):Null return cast v; + static function DynamicBoxedInt8_BoxedInt64(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt8_BoxedFloat32(v:Null):Null return cast v; + static function DynamicBoxedInt8_BoxedFloat32(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt8_BoxedFloat64(v:Null):Null return cast v; + static function DynamicBoxedInt8_BoxedFloat64(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt16_Int8(v:Null):Int8 return cast v; + static function DynamicBoxedInt16_Int8(v:Null):Int8 { + var x:Dynamic = v; + return x; + } + static function BoxedInt16_Int16(v:Null):Int16 return cast v; + static function DynamicBoxedInt16_Int16(v:Null):Int16 { + var x:Dynamic = v; + return x; + } + static function BoxedInt16_Int32(v:Null):Int32 return cast v; + static function DynamicBoxedInt16_Int32(v:Null):Int32 { + var x:Dynamic = v; + return x; + } + static function BoxedInt16_Int64(v:Null):Int64 return cast v; + static function DynamicBoxedInt16_Int64(v:Null):Int64 { + var x:Dynamic = v; + return x; + } + static function BoxedInt16_Float32(v:Null):Float32 return cast v; + static function DynamicBoxedInt16_Float32(v:Null):Float32 { + var x:Dynamic = v; + return x; + } + static function BoxedInt16_Float64(v:Null):Float64 return cast v; + static function DynamicBoxedInt16_Float64(v:Null):Float64 { + var x:Dynamic = v; + return x; + } + static function BoxedInt16_BoxedInt8(v:Null):Null return cast v; + static function DynamicBoxedInt16_BoxedInt8(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt16_BoxedInt32(v:Null):Null return cast v; + static function DynamicBoxedInt16_BoxedInt32(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt16_BoxedInt64(v:Null):Null return cast v; + static function DynamicBoxedInt16_BoxedInt64(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt16_BoxedFloat32(v:Null):Null return cast v; + static function DynamicBoxedInt16_BoxedFloat32(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt16_BoxedFloat64(v:Null):Null return cast v; + static function DynamicBoxedInt16_BoxedFloat64(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt32_Int8(v:Null):Int8 return cast v; + static function DynamicBoxedInt32_Int8(v:Null):Int8 { + var x:Dynamic = v; + return x; + } + static function BoxedInt32_Int16(v:Null):Int16 return cast v; + static function DynamicBoxedInt32_Int16(v:Null):Int16 { + var x:Dynamic = v; + return x; + } + static function BoxedInt32_Int32(v:Null):Int32 return cast v; + static function DynamicBoxedInt32_Int32(v:Null):Int32 { + var x:Dynamic = v; + return x; + } + static function BoxedInt32_Int64(v:Null):Int64 return cast v; + static function DynamicBoxedInt32_Int64(v:Null):Int64 { + var x:Dynamic = v; + return x; + } + static function BoxedInt32_Float32(v:Null):Float32 return cast v; + static function DynamicBoxedInt32_Float32(v:Null):Float32 { + var x:Dynamic = v; + return x; + } + static function BoxedInt32_Float64(v:Null):Float64 return cast v; + static function DynamicBoxedInt32_Float64(v:Null):Float64 { + var x:Dynamic = v; + return x; + } + static function BoxedInt32_BoxedInt8(v:Null):Null return cast v; + static function DynamicBoxedInt32_BoxedInt8(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt32_BoxedInt16(v:Null):Null return cast v; + static function DynamicBoxedInt32_BoxedInt16(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt32_BoxedInt64(v:Null):Null return cast v; + static function DynamicBoxedInt32_BoxedInt64(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt32_BoxedFloat32(v:Null):Null return cast v; + static function DynamicBoxedInt32_BoxedFloat32(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt32_BoxedFloat64(v:Null):Null return cast v; + static function DynamicBoxedInt32_BoxedFloat64(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt64_Int8(v:Null):Int8 return cast v; + static function DynamicBoxedInt64_Int8(v:Null):Int8 { + var x:Dynamic = v; + return x; + } + static function BoxedInt64_Int16(v:Null):Int16 return cast v; + static function DynamicBoxedInt64_Int16(v:Null):Int16 { + var x:Dynamic = v; + return x; + } + static function BoxedInt64_Int32(v:Null):Int32 return cast v; + static function DynamicBoxedInt64_Int32(v:Null):Int32 { + var x:Dynamic = v; + return x; + } + static function BoxedInt64_Int64(v:Null):Int64 return cast v; + static function DynamicBoxedInt64_Int64(v:Null):Int64 { + var x:Dynamic = v; + return x; + } + static function BoxedInt64_Float32(v:Null):Float32 return cast v; + static function DynamicBoxedInt64_Float32(v:Null):Float32 { + var x:Dynamic = v; + return x; + } + static function BoxedInt64_Float64(v:Null):Float64 return cast v; + static function DynamicBoxedInt64_Float64(v:Null):Float64 { + var x:Dynamic = v; + return x; + } + static function BoxedInt64_BoxedInt8(v:Null):Null return cast v; + static function DynamicBoxedInt64_BoxedInt8(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt64_BoxedInt16(v:Null):Null return cast v; + static function DynamicBoxedInt64_BoxedInt16(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt64_BoxedInt32(v:Null):Null return cast v; + static function DynamicBoxedInt64_BoxedInt32(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt64_BoxedFloat32(v:Null):Null return cast v; + static function DynamicBoxedInt64_BoxedFloat32(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedInt64_BoxedFloat64(v:Null):Null return cast v; + static function DynamicBoxedInt64_BoxedFloat64(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedFloat32_Int8(v:Null):Int8 return cast v; + static function DynamicBoxedFloat32_Int8(v:Null):Int8 { + var x:Dynamic = v; + return x; + } + static function BoxedFloat32_Int16(v:Null):Int16 return cast v; + static function DynamicBoxedFloat32_Int16(v:Null):Int16 { + var x:Dynamic = v; + return x; + } + static function BoxedFloat32_Int32(v:Null):Int32 return cast v; + static function DynamicBoxedFloat32_Int32(v:Null):Int32 { + var x:Dynamic = v; + return x; + } + static function BoxedFloat32_Int64(v:Null):Int64 return cast v; + static function DynamicBoxedFloat32_Int64(v:Null):Int64 { + var x:Dynamic = v; + return x; + } + static function BoxedFloat32_Float32(v:Null):Float32 return cast v; + static function DynamicBoxedFloat32_Float32(v:Null):Float32 { + var x:Dynamic = v; + return x; + } + static function BoxedFloat32_Float64(v:Null):Float64 return cast v; + static function DynamicBoxedFloat32_Float64(v:Null):Float64 { + var x:Dynamic = v; + return x; + } + static function BoxedFloat32_BoxedInt8(v:Null):Null return cast v; + static function DynamicBoxedFloat32_BoxedInt8(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedFloat32_BoxedInt16(v:Null):Null return cast v; + static function DynamicBoxedFloat32_BoxedInt16(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedFloat32_BoxedInt32(v:Null):Null return cast v; + static function DynamicBoxedFloat32_BoxedInt32(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedFloat32_BoxedInt64(v:Null):Null return cast v; + static function DynamicBoxedFloat32_BoxedInt64(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedFloat32_BoxedFloat64(v:Null):Null return cast v; + static function DynamicBoxedFloat32_BoxedFloat64(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedFloat64_Int8(v:Null):Int8 return cast v; + static function DynamicBoxedFloat64_Int8(v:Null):Int8 { + var x:Dynamic = v; + return x; + } + static function BoxedFloat64_Int16(v:Null):Int16 return cast v; + static function DynamicBoxedFloat64_Int16(v:Null):Int16 { + var x:Dynamic = v; + return x; + } + static function BoxedFloat64_Int32(v:Null):Int32 return cast v; + static function DynamicBoxedFloat64_Int32(v:Null):Int32 { + var x:Dynamic = v; + return x; + } + static function BoxedFloat64_Int64(v:Null):Int64 return cast v; + static function DynamicBoxedFloat64_Int64(v:Null):Int64 { + var x:Dynamic = v; + return x; + } + static function BoxedFloat64_Float32(v:Null):Float32 return cast v; + static function DynamicBoxedFloat64_Float32(v:Null):Float32 { + var x:Dynamic = v; + return x; + } + static function BoxedFloat64_Float64(v:Null):Float64 return cast v; + static function DynamicBoxedFloat64_Float64(v:Null):Float64 { + var x:Dynamic = v; + return x; + } + static function BoxedFloat64_BoxedInt8(v:Null):Null return cast v; + static function DynamicBoxedFloat64_BoxedInt8(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedFloat64_BoxedInt16(v:Null):Null return cast v; + static function DynamicBoxedFloat64_BoxedInt16(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedFloat64_BoxedInt32(v:Null):Null return cast v; + static function DynamicBoxedFloat64_BoxedInt32(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedFloat64_BoxedInt64(v:Null):Null return cast v; + static function DynamicBoxedFloat64_BoxedInt64(v:Null):Null { + var x:Dynamic = v; + return x; + } + static function BoxedFloat64_BoxedFloat32(v:Null):Null return cast v; + static function DynamicBoxedFloat64_BoxedFloat32(v:Null):Null { + var x:Dynamic = v; + return x; + } + public function test() { + { + deq(0, Int8_Int16(0)); + deq(1, Int8_Int16(1)); + deq(0, DynamicInt8_Int16(0)); + deq(1, DynamicInt8_Int16(1)); + deq(0, Int8_Int32(0)); + deq(1, Int8_Int32(1)); + deq(0, DynamicInt8_Int32(0)); + deq(1, DynamicInt8_Int32(1)); + deq(0, Int8_Int64(0)); + deq(1, Int8_Int64(1)); + deq(0, DynamicInt8_Int64(0)); + deq(1, DynamicInt8_Int64(1)); + deq(0, Int8_Float32(0)); + deq(1, Int8_Float32(1)); + deq(0, DynamicInt8_Float32(0)); + deq(1, DynamicInt8_Float32(1)); + deq(0, Int8_Float64(0)); + deq(1, Int8_Float64(1)); + deq(0, DynamicInt8_Float64(0)); + deq(1, DynamicInt8_Float64(1)); + deq(0, Int8_BoxedInt8(0)); + deq(1, Int8_BoxedInt8(1)); + deq(0, DynamicInt8_BoxedInt8(0)); + deq(1, DynamicInt8_BoxedInt8(1)); + deq(0, Int8_BoxedInt16(0)); + deq(1, Int8_BoxedInt16(1)); + deq(0, DynamicInt8_BoxedInt16(0)); + deq(1, DynamicInt8_BoxedInt16(1)); + deq(0, Int8_BoxedInt32(0)); + deq(1, Int8_BoxedInt32(1)); + deq(0, DynamicInt8_BoxedInt32(0)); + deq(1, DynamicInt8_BoxedInt32(1)); + deq(0, Int8_BoxedInt64(0)); + deq(1, Int8_BoxedInt64(1)); + deq(0, DynamicInt8_BoxedInt64(0)); + deq(1, DynamicInt8_BoxedInt64(1)); + deq(0, Int8_BoxedFloat32(0)); + deq(1, Int8_BoxedFloat32(1)); + deq(0, DynamicInt8_BoxedFloat32(0)); + deq(1, DynamicInt8_BoxedFloat32(1)); + deq(0, Int8_BoxedFloat64(0)); + deq(1, Int8_BoxedFloat64(1)); + deq(0, DynamicInt8_BoxedFloat64(0)); + deq(1, DynamicInt8_BoxedFloat64(1)); + deq(0, Int16_Int8(0)); + deq(1, Int16_Int8(1)); + deq(0, DynamicInt16_Int8(0)); + deq(1, DynamicInt16_Int8(1)); + deq(0, Int16_Int32(0)); + deq(1, Int16_Int32(1)); + deq(0, DynamicInt16_Int32(0)); + deq(1, DynamicInt16_Int32(1)); + deq(0, Int16_Int64(0)); + deq(1, Int16_Int64(1)); + deq(0, DynamicInt16_Int64(0)); + deq(1, DynamicInt16_Int64(1)); + deq(0, Int16_Float32(0)); + deq(1, Int16_Float32(1)); + deq(0, DynamicInt16_Float32(0)); + deq(1, DynamicInt16_Float32(1)); + deq(0, Int16_Float64(0)); + deq(1, Int16_Float64(1)); + deq(0, DynamicInt16_Float64(0)); + deq(1, DynamicInt16_Float64(1)); + deq(0, Int16_BoxedInt8(0)); + deq(1, Int16_BoxedInt8(1)); + deq(0, DynamicInt16_BoxedInt8(0)); + deq(1, DynamicInt16_BoxedInt8(1)); + deq(0, Int16_BoxedInt16(0)); + deq(1, Int16_BoxedInt16(1)); + deq(0, DynamicInt16_BoxedInt16(0)); + deq(1, DynamicInt16_BoxedInt16(1)); + deq(0, Int16_BoxedInt32(0)); + deq(1, Int16_BoxedInt32(1)); + deq(0, DynamicInt16_BoxedInt32(0)); + deq(1, DynamicInt16_BoxedInt32(1)); + deq(0, Int16_BoxedInt64(0)); + deq(1, Int16_BoxedInt64(1)); + deq(0, DynamicInt16_BoxedInt64(0)); + deq(1, DynamicInt16_BoxedInt64(1)); + deq(0, Int16_BoxedFloat32(0)); + deq(1, Int16_BoxedFloat32(1)); + deq(0, DynamicInt16_BoxedFloat32(0)); + deq(1, DynamicInt16_BoxedFloat32(1)); + deq(0, Int16_BoxedFloat64(0)); + deq(1, Int16_BoxedFloat64(1)); + deq(0, DynamicInt16_BoxedFloat64(0)); + deq(1, DynamicInt16_BoxedFloat64(1)); + deq(0, Int32_Int8(0)); + deq(1, Int32_Int8(1)); + deq(0, DynamicInt32_Int8(0)); + deq(1, DynamicInt32_Int8(1)); + deq(0, Int32_Int16(0)); + deq(1, Int32_Int16(1)); + deq(0, DynamicInt32_Int16(0)); + deq(1, DynamicInt32_Int16(1)); + deq(0, Int32_Int64(0)); + deq(1, Int32_Int64(1)); + deq(0, DynamicInt32_Int64(0)); + deq(1, DynamicInt32_Int64(1)); + deq(0, Int32_Float32(0)); + deq(1, Int32_Float32(1)); + deq(0, DynamicInt32_Float32(0)); + deq(1, DynamicInt32_Float32(1)); + deq(0, Int32_Float64(0)); + deq(1, Int32_Float64(1)); + deq(0, DynamicInt32_Float64(0)); + deq(1, DynamicInt32_Float64(1)); + deq(0, Int32_BoxedInt8(0)); + deq(1, Int32_BoxedInt8(1)); + deq(0, DynamicInt32_BoxedInt8(0)); + deq(1, DynamicInt32_BoxedInt8(1)); + deq(0, Int32_BoxedInt16(0)); + deq(1, Int32_BoxedInt16(1)); + deq(0, DynamicInt32_BoxedInt16(0)); + deq(1, DynamicInt32_BoxedInt16(1)); + deq(0, Int32_BoxedInt32(0)); + deq(1, Int32_BoxedInt32(1)); + deq(0, DynamicInt32_BoxedInt32(0)); + deq(1, DynamicInt32_BoxedInt32(1)); + deq(0, Int32_BoxedInt64(0)); + deq(1, Int32_BoxedInt64(1)); + deq(0, DynamicInt32_BoxedInt64(0)); + deq(1, DynamicInt32_BoxedInt64(1)); + deq(0, Int32_BoxedFloat32(0)); + deq(1, Int32_BoxedFloat32(1)); + deq(0, DynamicInt32_BoxedFloat32(0)); + deq(1, DynamicInt32_BoxedFloat32(1)); + deq(0, Int32_BoxedFloat64(0)); + deq(1, Int32_BoxedFloat64(1)); + deq(0, DynamicInt32_BoxedFloat64(0)); + deq(1, DynamicInt32_BoxedFloat64(1)); + deq(0, Int64_Int8(0)); + deq(1, Int64_Int8(1)); + deq(0, DynamicInt64_Int8(0)); + deq(1, DynamicInt64_Int8(1)); + deq(0, Int64_Int16(0)); + deq(1, Int64_Int16(1)); + deq(0, DynamicInt64_Int16(0)); + deq(1, DynamicInt64_Int16(1)); + deq(0, Int64_Int32(0)); + deq(1, Int64_Int32(1)); + deq(0, DynamicInt64_Int32(0)); + deq(1, DynamicInt64_Int32(1)); + deq(0, Int64_Float32(0)); + deq(1, Int64_Float32(1)); + deq(0, DynamicInt64_Float32(0)); + deq(1, DynamicInt64_Float32(1)); + deq(0, Int64_Float64(0)); + deq(1, Int64_Float64(1)); + deq(0, DynamicInt64_Float64(0)); + deq(1, DynamicInt64_Float64(1)); + deq(0, Int64_BoxedInt8(0)); + deq(1, Int64_BoxedInt8(1)); + deq(0, DynamicInt64_BoxedInt8(0)); + deq(1, DynamicInt64_BoxedInt8(1)); + deq(0, Int64_BoxedInt16(0)); + deq(1, Int64_BoxedInt16(1)); + deq(0, DynamicInt64_BoxedInt16(0)); + deq(1, DynamicInt64_BoxedInt16(1)); + deq(0, Int64_BoxedInt32(0)); + deq(1, Int64_BoxedInt32(1)); + deq(0, DynamicInt64_BoxedInt32(0)); + deq(1, DynamicInt64_BoxedInt32(1)); + deq(0, Int64_BoxedInt64(0)); + deq(1, Int64_BoxedInt64(1)); + deq(0, DynamicInt64_BoxedInt64(0)); + deq(1, DynamicInt64_BoxedInt64(1)); + deq(0, Int64_BoxedFloat32(0)); + deq(1, Int64_BoxedFloat32(1)); + deq(0, DynamicInt64_BoxedFloat32(0)); + deq(1, DynamicInt64_BoxedFloat32(1)); + deq(0, Int64_BoxedFloat64(0)); + deq(1, Int64_BoxedFloat64(1)); + deq(0, DynamicInt64_BoxedFloat64(0)); + deq(1, DynamicInt64_BoxedFloat64(1)); + deq(0, Float32_Int8(0)); + deq(1, Float32_Int8(1)); + deq(0., Float32_Int8(0.)); + deq(1., Float32_Int8(1.)); + deq(0, DynamicFloat32_Int8(0)); + deq(1, DynamicFloat32_Int8(1)); + deq(0., DynamicFloat32_Int8(0.)); + deq(1., DynamicFloat32_Int8(1.)); + deq(0, Float32_Int16(0)); + deq(1, Float32_Int16(1)); + deq(0., Float32_Int16(0.)); + deq(1., Float32_Int16(1.)); + deq(0, DynamicFloat32_Int16(0)); + deq(1, DynamicFloat32_Int16(1)); + deq(0., DynamicFloat32_Int16(0.)); + deq(1., DynamicFloat32_Int16(1.)); + deq(0, Float32_Int32(0)); + deq(1, Float32_Int32(1)); + deq(0., Float32_Int32(0.)); + deq(1., Float32_Int32(1.)); + deq(0, DynamicFloat32_Int32(0)); + deq(1, DynamicFloat32_Int32(1)); + deq(0., DynamicFloat32_Int32(0.)); + deq(1., DynamicFloat32_Int32(1.)); + deq(0, Float32_Int64(0)); + deq(1, Float32_Int64(1)); + deq(0., Float32_Int64(0.)); + deq(1., Float32_Int64(1.)); + deq(0, DynamicFloat32_Int64(0)); + deq(1, DynamicFloat32_Int64(1)); + deq(0., DynamicFloat32_Int64(0.)); + deq(1., DynamicFloat32_Int64(1.)); + deq(0, Float32_Float64(0)); + deq(1, Float32_Float64(1)); + deq(0., Float32_Float64(0.)); + deq(1., Float32_Float64(1.)); + deq(0, DynamicFloat32_Float64(0)); + deq(1, DynamicFloat32_Float64(1)); + deq(0., DynamicFloat32_Float64(0.)); + deq(1., DynamicFloat32_Float64(1.)); + deq(0, Float32_BoxedInt8(0)); + deq(1, Float32_BoxedInt8(1)); + deq(0., Float32_BoxedInt8(0.)); + deq(1., Float32_BoxedInt8(1.)); + deq(0, DynamicFloat32_BoxedInt8(0)); + deq(1, DynamicFloat32_BoxedInt8(1)); + deq(0., DynamicFloat32_BoxedInt8(0.)); + deq(1., DynamicFloat32_BoxedInt8(1.)); + deq(0, Float32_BoxedInt16(0)); + deq(1, Float32_BoxedInt16(1)); + deq(0., Float32_BoxedInt16(0.)); + deq(1., Float32_BoxedInt16(1.)); + deq(0, DynamicFloat32_BoxedInt16(0)); + deq(1, DynamicFloat32_BoxedInt16(1)); + deq(0., DynamicFloat32_BoxedInt16(0.)); + deq(1., DynamicFloat32_BoxedInt16(1.)); + deq(0, Float32_BoxedInt32(0)); + deq(1, Float32_BoxedInt32(1)); + deq(0., Float32_BoxedInt32(0.)); + deq(1., Float32_BoxedInt32(1.)); + deq(0, DynamicFloat32_BoxedInt32(0)); + deq(1, DynamicFloat32_BoxedInt32(1)); + deq(0., DynamicFloat32_BoxedInt32(0.)); + deq(1., DynamicFloat32_BoxedInt32(1.)); + deq(0, Float32_BoxedInt64(0)); + deq(1, Float32_BoxedInt64(1)); + deq(0., Float32_BoxedInt64(0.)); + deq(1., Float32_BoxedInt64(1.)); + deq(0, DynamicFloat32_BoxedInt64(0)); + deq(1, DynamicFloat32_BoxedInt64(1)); + deq(0., DynamicFloat32_BoxedInt64(0.)); + deq(1., DynamicFloat32_BoxedInt64(1.)); + deq(0, Float32_BoxedFloat32(0)); + deq(1, Float32_BoxedFloat32(1)); + deq(0., Float32_BoxedFloat32(0.)); + deq(1., Float32_BoxedFloat32(1.)); + deq(0, DynamicFloat32_BoxedFloat32(0)); + deq(1, DynamicFloat32_BoxedFloat32(1)); + deq(0., DynamicFloat32_BoxedFloat32(0.)); + deq(1., DynamicFloat32_BoxedFloat32(1.)); + deq(0, Float32_BoxedFloat64(0)); + deq(1, Float32_BoxedFloat64(1)); + deq(0., Float32_BoxedFloat64(0.)); + deq(1., Float32_BoxedFloat64(1.)); + deq(0, DynamicFloat32_BoxedFloat64(0)); + deq(1, DynamicFloat32_BoxedFloat64(1)); + deq(0., DynamicFloat32_BoxedFloat64(0.)); + deq(1., DynamicFloat32_BoxedFloat64(1.)); + deq(0, Float64_Int8(0)); + deq(1, Float64_Int8(1)); + deq(0., Float64_Int8(0.)); + deq(1., Float64_Int8(1.)); + deq(0, DynamicFloat64_Int8(0)); + deq(1, DynamicFloat64_Int8(1)); + deq(0., DynamicFloat64_Int8(0.)); + deq(1., DynamicFloat64_Int8(1.)); + deq(0, Float64_Int16(0)); + deq(1, Float64_Int16(1)); + deq(0., Float64_Int16(0.)); + deq(1., Float64_Int16(1.)); + deq(0, DynamicFloat64_Int16(0)); + deq(1, DynamicFloat64_Int16(1)); + deq(0., DynamicFloat64_Int16(0.)); + deq(1., DynamicFloat64_Int16(1.)); + deq(0, Float64_Int32(0)); + deq(1, Float64_Int32(1)); + deq(0., Float64_Int32(0.)); + deq(1., Float64_Int32(1.)); + deq(0, DynamicFloat64_Int32(0)); + deq(1, DynamicFloat64_Int32(1)); + deq(0., DynamicFloat64_Int32(0.)); + deq(1., DynamicFloat64_Int32(1.)); + deq(0, Float64_Int64(0)); + deq(1, Float64_Int64(1)); + deq(0., Float64_Int64(0.)); + deq(1., Float64_Int64(1.)); + deq(0, DynamicFloat64_Int64(0)); + deq(1, DynamicFloat64_Int64(1)); + deq(0., DynamicFloat64_Int64(0.)); + deq(1., DynamicFloat64_Int64(1.)); + deq(0, Float64_Float32(0)); + deq(1, Float64_Float32(1)); + deq(0., Float64_Float32(0.)); + deq(1., Float64_Float32(1.)); + deq(0, DynamicFloat64_Float32(0)); + deq(1, DynamicFloat64_Float32(1)); + deq(0., DynamicFloat64_Float32(0.)); + deq(1., DynamicFloat64_Float32(1.)); + deq(0, Float64_BoxedInt8(0)); + deq(1, Float64_BoxedInt8(1)); + deq(0., Float64_BoxedInt8(0.)); + deq(1., Float64_BoxedInt8(1.)); + deq(0, DynamicFloat64_BoxedInt8(0)); + deq(1, DynamicFloat64_BoxedInt8(1)); + deq(0., DynamicFloat64_BoxedInt8(0.)); + deq(1., DynamicFloat64_BoxedInt8(1.)); + deq(0, Float64_BoxedInt16(0)); + deq(1, Float64_BoxedInt16(1)); + deq(0., Float64_BoxedInt16(0.)); + deq(1., Float64_BoxedInt16(1.)); + deq(0, DynamicFloat64_BoxedInt16(0)); + deq(1, DynamicFloat64_BoxedInt16(1)); + deq(0., DynamicFloat64_BoxedInt16(0.)); + deq(1., DynamicFloat64_BoxedInt16(1.)); + deq(0, Float64_BoxedInt32(0)); + deq(1, Float64_BoxedInt32(1)); + deq(0., Float64_BoxedInt32(0.)); + deq(1., Float64_BoxedInt32(1.)); + deq(0, DynamicFloat64_BoxedInt32(0)); + deq(1, DynamicFloat64_BoxedInt32(1)); + deq(0., DynamicFloat64_BoxedInt32(0.)); + deq(1., DynamicFloat64_BoxedInt32(1.)); + deq(0, Float64_BoxedInt64(0)); + deq(1, Float64_BoxedInt64(1)); + deq(0., Float64_BoxedInt64(0.)); + deq(1., Float64_BoxedInt64(1.)); + deq(0, DynamicFloat64_BoxedInt64(0)); + deq(1, DynamicFloat64_BoxedInt64(1)); + deq(0., DynamicFloat64_BoxedInt64(0.)); + deq(1., DynamicFloat64_BoxedInt64(1.)); + deq(0, Float64_BoxedFloat32(0)); + deq(1, Float64_BoxedFloat32(1)); + deq(0., Float64_BoxedFloat32(0.)); + deq(1., Float64_BoxedFloat32(1.)); + deq(0, DynamicFloat64_BoxedFloat32(0)); + deq(1, DynamicFloat64_BoxedFloat32(1)); + deq(0., DynamicFloat64_BoxedFloat32(0.)); + deq(1., DynamicFloat64_BoxedFloat32(1.)); + deq(0, Float64_BoxedFloat64(0)); + deq(1, Float64_BoxedFloat64(1)); + deq(0., Float64_BoxedFloat64(0.)); + deq(1., Float64_BoxedFloat64(1.)); + deq(0, DynamicFloat64_BoxedFloat64(0)); + deq(1, DynamicFloat64_BoxedFloat64(1)); + deq(0., DynamicFloat64_BoxedFloat64(0.)); + deq(1., DynamicFloat64_BoxedFloat64(1.)); + deq(0, BoxedInt8_Int8(0)); + deq(1, BoxedInt8_Int8(1)); + deq(CastHelper.nullOr0, BoxedInt8_Int8(null)); + deq(0, DynamicBoxedInt8_Int8(0)); + deq(1, DynamicBoxedInt8_Int8(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt8_Int8(null)); + deq(0, BoxedInt8_Int16(0)); + deq(1, BoxedInt8_Int16(1)); + deq(CastHelper.nullOr0, BoxedInt8_Int16(null)); + deq(0, DynamicBoxedInt8_Int16(0)); + deq(1, DynamicBoxedInt8_Int16(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt8_Int16(null)); + deq(0, BoxedInt8_Int32(0)); + deq(1, BoxedInt8_Int32(1)); + deq(CastHelper.nullOr0, BoxedInt8_Int32(null)); + deq(0, DynamicBoxedInt8_Int32(0)); + deq(1, DynamicBoxedInt8_Int32(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt8_Int32(null)); + deq(0, BoxedInt8_Int64(0)); + deq(1, BoxedInt8_Int64(1)); + deq(CastHelper.nullOr0, BoxedInt8_Int64(null)); + deq(0, DynamicBoxedInt8_Int64(0)); + deq(1, DynamicBoxedInt8_Int64(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt8_Int64(null)); + deq(0, BoxedInt8_Float32(0)); + deq(1, BoxedInt8_Float32(1)); + deq(CastHelper.nullOr0, BoxedInt8_Float32(null)); + deq(0, DynamicBoxedInt8_Float32(0)); + deq(1, DynamicBoxedInt8_Float32(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt8_Float32(null)); + deq(0, BoxedInt8_Float64(0)); + deq(1, BoxedInt8_Float64(1)); + deq(CastHelper.nullOr0, BoxedInt8_Float64(null)); + deq(0, DynamicBoxedInt8_Float64(0)); + deq(1, DynamicBoxedInt8_Float64(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt8_Float64(null)); + deq(0, BoxedInt8_BoxedInt16(0)); + deq(1, BoxedInt8_BoxedInt16(1)); + deq(null, BoxedInt8_BoxedInt16(null)); + deq(0, DynamicBoxedInt8_BoxedInt16(0)); + deq(1, DynamicBoxedInt8_BoxedInt16(1)); + deq(null, DynamicBoxedInt8_BoxedInt16(null)); + deq(0, BoxedInt8_BoxedInt32(0)); + deq(1, BoxedInt8_BoxedInt32(1)); + deq(null, BoxedInt8_BoxedInt32(null)); + deq(0, DynamicBoxedInt8_BoxedInt32(0)); + deq(1, DynamicBoxedInt8_BoxedInt32(1)); + deq(null, DynamicBoxedInt8_BoxedInt32(null)); + deq(0, BoxedInt8_BoxedInt64(0)); + deq(1, BoxedInt8_BoxedInt64(1)); + deq(null, BoxedInt8_BoxedInt64(null)); + deq(0, DynamicBoxedInt8_BoxedInt64(0)); + deq(1, DynamicBoxedInt8_BoxedInt64(1)); + deq(null, DynamicBoxedInt8_BoxedInt64(null)); + deq(0, BoxedInt8_BoxedFloat32(0)); + deq(1, BoxedInt8_BoxedFloat32(1)); + deq(null, BoxedInt8_BoxedFloat32(null)); + deq(0, DynamicBoxedInt8_BoxedFloat32(0)); + deq(1, DynamicBoxedInt8_BoxedFloat32(1)); + deq(null, DynamicBoxedInt8_BoxedFloat32(null)); + deq(0, BoxedInt8_BoxedFloat64(0)); + deq(1, BoxedInt8_BoxedFloat64(1)); + deq(null, BoxedInt8_BoxedFloat64(null)); + deq(0, DynamicBoxedInt8_BoxedFloat64(0)); + deq(1, DynamicBoxedInt8_BoxedFloat64(1)); + deq(null, DynamicBoxedInt8_BoxedFloat64(null)); + deq(0, BoxedInt16_Int8(0)); + deq(1, BoxedInt16_Int8(1)); + deq(CastHelper.nullOr0, BoxedInt16_Int8(null)); + deq(0, DynamicBoxedInt16_Int8(0)); + deq(1, DynamicBoxedInt16_Int8(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt16_Int8(null)); + deq(0, BoxedInt16_Int16(0)); + deq(1, BoxedInt16_Int16(1)); + deq(CastHelper.nullOr0, BoxedInt16_Int16(null)); + deq(0, DynamicBoxedInt16_Int16(0)); + deq(1, DynamicBoxedInt16_Int16(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt16_Int16(null)); + deq(0, BoxedInt16_Int32(0)); + deq(1, BoxedInt16_Int32(1)); + deq(CastHelper.nullOr0, BoxedInt16_Int32(null)); + deq(0, DynamicBoxedInt16_Int32(0)); + deq(1, DynamicBoxedInt16_Int32(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt16_Int32(null)); + deq(0, BoxedInt16_Int64(0)); + deq(1, BoxedInt16_Int64(1)); + deq(CastHelper.nullOr0, BoxedInt16_Int64(null)); + deq(0, DynamicBoxedInt16_Int64(0)); + deq(1, DynamicBoxedInt16_Int64(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt16_Int64(null)); + deq(0, BoxedInt16_Float32(0)); + deq(1, BoxedInt16_Float32(1)); + deq(CastHelper.nullOr0, BoxedInt16_Float32(null)); + deq(0, DynamicBoxedInt16_Float32(0)); + deq(1, DynamicBoxedInt16_Float32(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt16_Float32(null)); + deq(0, BoxedInt16_Float64(0)); + deq(1, BoxedInt16_Float64(1)); + deq(CastHelper.nullOr0, BoxedInt16_Float64(null)); + deq(0, DynamicBoxedInt16_Float64(0)); + deq(1, DynamicBoxedInt16_Float64(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt16_Float64(null)); + deq(0, BoxedInt16_BoxedInt8(0)); + deq(1, BoxedInt16_BoxedInt8(1)); + deq(null, BoxedInt16_BoxedInt8(null)); + deq(0, DynamicBoxedInt16_BoxedInt8(0)); + deq(1, DynamicBoxedInt16_BoxedInt8(1)); + deq(null, DynamicBoxedInt16_BoxedInt8(null)); + deq(0, BoxedInt16_BoxedInt32(0)); + deq(1, BoxedInt16_BoxedInt32(1)); + deq(null, BoxedInt16_BoxedInt32(null)); + deq(0, DynamicBoxedInt16_BoxedInt32(0)); + deq(1, DynamicBoxedInt16_BoxedInt32(1)); + deq(null, DynamicBoxedInt16_BoxedInt32(null)); + deq(0, BoxedInt16_BoxedInt64(0)); + deq(1, BoxedInt16_BoxedInt64(1)); + deq(null, BoxedInt16_BoxedInt64(null)); + deq(0, DynamicBoxedInt16_BoxedInt64(0)); + deq(1, DynamicBoxedInt16_BoxedInt64(1)); + deq(null, DynamicBoxedInt16_BoxedInt64(null)); + deq(0, BoxedInt16_BoxedFloat32(0)); + deq(1, BoxedInt16_BoxedFloat32(1)); + deq(null, BoxedInt16_BoxedFloat32(null)); + deq(0, DynamicBoxedInt16_BoxedFloat32(0)); + deq(1, DynamicBoxedInt16_BoxedFloat32(1)); + deq(null, DynamicBoxedInt16_BoxedFloat32(null)); + deq(0, BoxedInt16_BoxedFloat64(0)); + deq(1, BoxedInt16_BoxedFloat64(1)); + deq(null, BoxedInt16_BoxedFloat64(null)); + deq(0, DynamicBoxedInt16_BoxedFloat64(0)); + deq(1, DynamicBoxedInt16_BoxedFloat64(1)); + deq(null, DynamicBoxedInt16_BoxedFloat64(null)); + deq(0, BoxedInt32_Int8(0)); + deq(1, BoxedInt32_Int8(1)); + deq(CastHelper.nullOr0, BoxedInt32_Int8(null)); + deq(0, DynamicBoxedInt32_Int8(0)); + deq(1, DynamicBoxedInt32_Int8(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt32_Int8(null)); + deq(0, BoxedInt32_Int16(0)); + deq(1, BoxedInt32_Int16(1)); + deq(CastHelper.nullOr0, BoxedInt32_Int16(null)); + deq(0, DynamicBoxedInt32_Int16(0)); + deq(1, DynamicBoxedInt32_Int16(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt32_Int16(null)); + deq(0, BoxedInt32_Int32(0)); + deq(1, BoxedInt32_Int32(1)); + deq(CastHelper.nullOr0, BoxedInt32_Int32(null)); + deq(0, DynamicBoxedInt32_Int32(0)); + deq(1, DynamicBoxedInt32_Int32(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt32_Int32(null)); + deq(0, BoxedInt32_Int64(0)); + deq(1, BoxedInt32_Int64(1)); + deq(CastHelper.nullOr0, BoxedInt32_Int64(null)); + deq(0, DynamicBoxedInt32_Int64(0)); + deq(1, DynamicBoxedInt32_Int64(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt32_Int64(null)); + deq(0, BoxedInt32_Float32(0)); + deq(1, BoxedInt32_Float32(1)); + deq(CastHelper.nullOr0, BoxedInt32_Float32(null)); + deq(0, DynamicBoxedInt32_Float32(0)); + deq(1, DynamicBoxedInt32_Float32(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt32_Float32(null)); + deq(0, BoxedInt32_Float64(0)); + deq(1, BoxedInt32_Float64(1)); + deq(CastHelper.nullOr0, BoxedInt32_Float64(null)); + deq(0, DynamicBoxedInt32_Float64(0)); + deq(1, DynamicBoxedInt32_Float64(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt32_Float64(null)); + deq(0, BoxedInt32_BoxedInt8(0)); + deq(1, BoxedInt32_BoxedInt8(1)); + deq(null, BoxedInt32_BoxedInt8(null)); + deq(0, DynamicBoxedInt32_BoxedInt8(0)); + deq(1, DynamicBoxedInt32_BoxedInt8(1)); + deq(null, DynamicBoxedInt32_BoxedInt8(null)); + deq(0, BoxedInt32_BoxedInt16(0)); + deq(1, BoxedInt32_BoxedInt16(1)); + deq(null, BoxedInt32_BoxedInt16(null)); + deq(0, DynamicBoxedInt32_BoxedInt16(0)); + deq(1, DynamicBoxedInt32_BoxedInt16(1)); + deq(null, DynamicBoxedInt32_BoxedInt16(null)); + deq(0, BoxedInt32_BoxedInt64(0)); + deq(1, BoxedInt32_BoxedInt64(1)); + deq(null, BoxedInt32_BoxedInt64(null)); + deq(0, DynamicBoxedInt32_BoxedInt64(0)); + deq(1, DynamicBoxedInt32_BoxedInt64(1)); + deq(null, DynamicBoxedInt32_BoxedInt64(null)); + deq(0, BoxedInt32_BoxedFloat32(0)); + deq(1, BoxedInt32_BoxedFloat32(1)); + deq(null, BoxedInt32_BoxedFloat32(null)); + deq(0, DynamicBoxedInt32_BoxedFloat32(0)); + deq(1, DynamicBoxedInt32_BoxedFloat32(1)); + deq(null, DynamicBoxedInt32_BoxedFloat32(null)); + deq(0, BoxedInt32_BoxedFloat64(0)); + deq(1, BoxedInt32_BoxedFloat64(1)); + deq(null, BoxedInt32_BoxedFloat64(null)); + deq(0, DynamicBoxedInt32_BoxedFloat64(0)); + deq(1, DynamicBoxedInt32_BoxedFloat64(1)); + deq(null, DynamicBoxedInt32_BoxedFloat64(null)); + deq(0, BoxedInt64_Int8(0)); + deq(1, BoxedInt64_Int8(1)); + deq(CastHelper.nullOr0, BoxedInt64_Int8(null)); + deq(0, DynamicBoxedInt64_Int8(0)); + deq(1, DynamicBoxedInt64_Int8(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt64_Int8(null)); + deq(0, BoxedInt64_Int16(0)); + deq(1, BoxedInt64_Int16(1)); + deq(CastHelper.nullOr0, BoxedInt64_Int16(null)); + deq(0, DynamicBoxedInt64_Int16(0)); + deq(1, DynamicBoxedInt64_Int16(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt64_Int16(null)); + deq(0, BoxedInt64_Int32(0)); + deq(1, BoxedInt64_Int32(1)); + deq(CastHelper.nullOr0, BoxedInt64_Int32(null)); + deq(0, DynamicBoxedInt64_Int32(0)); + deq(1, DynamicBoxedInt64_Int32(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt64_Int32(null)); + deq(0, BoxedInt64_Int64(0)); + deq(1, BoxedInt64_Int64(1)); + deq(CastHelper.nullOr0, BoxedInt64_Int64(null)); + deq(0, DynamicBoxedInt64_Int64(0)); + deq(1, DynamicBoxedInt64_Int64(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt64_Int64(null)); + deq(0, BoxedInt64_Float32(0)); + deq(1, BoxedInt64_Float32(1)); + deq(CastHelper.nullOr0, BoxedInt64_Float32(null)); + deq(0, DynamicBoxedInt64_Float32(0)); + deq(1, DynamicBoxedInt64_Float32(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt64_Float32(null)); + deq(0, BoxedInt64_Float64(0)); + deq(1, BoxedInt64_Float64(1)); + deq(CastHelper.nullOr0, BoxedInt64_Float64(null)); + deq(0, DynamicBoxedInt64_Float64(0)); + deq(1, DynamicBoxedInt64_Float64(1)); + deq(CastHelper.nullOr0, DynamicBoxedInt64_Float64(null)); + deq(0, BoxedInt64_BoxedInt8(0)); + deq(1, BoxedInt64_BoxedInt8(1)); + deq(null, BoxedInt64_BoxedInt8(null)); + deq(0, DynamicBoxedInt64_BoxedInt8(0)); + deq(1, DynamicBoxedInt64_BoxedInt8(1)); + deq(null, DynamicBoxedInt64_BoxedInt8(null)); + deq(0, BoxedInt64_BoxedInt16(0)); + deq(1, BoxedInt64_BoxedInt16(1)); + deq(null, BoxedInt64_BoxedInt16(null)); + deq(0, DynamicBoxedInt64_BoxedInt16(0)); + deq(1, DynamicBoxedInt64_BoxedInt16(1)); + deq(null, DynamicBoxedInt64_BoxedInt16(null)); + deq(0, BoxedInt64_BoxedInt32(0)); + deq(1, BoxedInt64_BoxedInt32(1)); + deq(null, BoxedInt64_BoxedInt32(null)); + deq(0, DynamicBoxedInt64_BoxedInt32(0)); + deq(1, DynamicBoxedInt64_BoxedInt32(1)); + deq(null, DynamicBoxedInt64_BoxedInt32(null)); + deq(0, BoxedInt64_BoxedFloat32(0)); + deq(1, BoxedInt64_BoxedFloat32(1)); + deq(null, BoxedInt64_BoxedFloat32(null)); + deq(0, DynamicBoxedInt64_BoxedFloat32(0)); + deq(1, DynamicBoxedInt64_BoxedFloat32(1)); + deq(null, DynamicBoxedInt64_BoxedFloat32(null)); + deq(0, BoxedInt64_BoxedFloat64(0)); + deq(1, BoxedInt64_BoxedFloat64(1)); + deq(null, BoxedInt64_BoxedFloat64(null)); + deq(0, DynamicBoxedInt64_BoxedFloat64(0)); + deq(1, DynamicBoxedInt64_BoxedFloat64(1)); + deq(null, DynamicBoxedInt64_BoxedFloat64(null)); + deq(0, BoxedFloat32_Int8(0)); + deq(1, BoxedFloat32_Int8(1)); + deq(0., BoxedFloat32_Int8(0.)); + deq(1., BoxedFloat32_Int8(1.)); + deq(CastHelper.nullOr0, BoxedFloat32_Int8(null)); + deq(0, DynamicBoxedFloat32_Int8(0)); + deq(1, DynamicBoxedFloat32_Int8(1)); + deq(0., DynamicBoxedFloat32_Int8(0.)); + deq(1., DynamicBoxedFloat32_Int8(1.)); + deq(CastHelper.nullOr0, DynamicBoxedFloat32_Int8(null)); + deq(0, BoxedFloat32_Int16(0)); + deq(1, BoxedFloat32_Int16(1)); + deq(0., BoxedFloat32_Int16(0.)); + deq(1., BoxedFloat32_Int16(1.)); + deq(CastHelper.nullOr0, BoxedFloat32_Int16(null)); + deq(0, DynamicBoxedFloat32_Int16(0)); + deq(1, DynamicBoxedFloat32_Int16(1)); + deq(0., DynamicBoxedFloat32_Int16(0.)); + deq(1., DynamicBoxedFloat32_Int16(1.)); + deq(CastHelper.nullOr0, DynamicBoxedFloat32_Int16(null)); + deq(0, BoxedFloat32_Int32(0)); + deq(1, BoxedFloat32_Int32(1)); + deq(0., BoxedFloat32_Int32(0.)); + deq(1., BoxedFloat32_Int32(1.)); + deq(CastHelper.nullOr0, BoxedFloat32_Int32(null)); + deq(0, DynamicBoxedFloat32_Int32(0)); + deq(1, DynamicBoxedFloat32_Int32(1)); + deq(0., DynamicBoxedFloat32_Int32(0.)); + deq(1., DynamicBoxedFloat32_Int32(1.)); + deq(CastHelper.nullOr0, DynamicBoxedFloat32_Int32(null)); + deq(0, BoxedFloat32_Int64(0)); + deq(1, BoxedFloat32_Int64(1)); + deq(0., BoxedFloat32_Int64(0.)); + deq(1., BoxedFloat32_Int64(1.)); + deq(CastHelper.nullOr0, BoxedFloat32_Int64(null)); + deq(0, DynamicBoxedFloat32_Int64(0)); + deq(1, DynamicBoxedFloat32_Int64(1)); + deq(0., DynamicBoxedFloat32_Int64(0.)); + deq(1., DynamicBoxedFloat32_Int64(1.)); + deq(CastHelper.nullOr0, DynamicBoxedFloat32_Int64(null)); + deq(0, BoxedFloat32_Float32(0)); + deq(1, BoxedFloat32_Float32(1)); + deq(0., BoxedFloat32_Float32(0.)); + deq(1., BoxedFloat32_Float32(1.)); + deq(CastHelper.nullOr0, BoxedFloat32_Float32(null)); + deq(0, DynamicBoxedFloat32_Float32(0)); + deq(1, DynamicBoxedFloat32_Float32(1)); + deq(0., DynamicBoxedFloat32_Float32(0.)); + deq(1., DynamicBoxedFloat32_Float32(1.)); + deq(CastHelper.nullOr0, DynamicBoxedFloat32_Float32(null)); + deq(0, BoxedFloat32_Float64(0)); + deq(1, BoxedFloat32_Float64(1)); + deq(0., BoxedFloat32_Float64(0.)); + deq(1., BoxedFloat32_Float64(1.)); + deq(CastHelper.nullOr0, BoxedFloat32_Float64(null)); + deq(0, DynamicBoxedFloat32_Float64(0)); + deq(1, DynamicBoxedFloat32_Float64(1)); + deq(0., DynamicBoxedFloat32_Float64(0.)); + deq(1., DynamicBoxedFloat32_Float64(1.)); + deq(CastHelper.nullOr0, DynamicBoxedFloat32_Float64(null)); + deq(0, BoxedFloat32_BoxedInt8(0)); + deq(1, BoxedFloat32_BoxedInt8(1)); + deq(0., BoxedFloat32_BoxedInt8(0.)); + deq(1., BoxedFloat32_BoxedInt8(1.)); + deq(null, BoxedFloat32_BoxedInt8(null)); + deq(0, DynamicBoxedFloat32_BoxedInt8(0)); + deq(1, DynamicBoxedFloat32_BoxedInt8(1)); + deq(0., DynamicBoxedFloat32_BoxedInt8(0.)); + deq(1., DynamicBoxedFloat32_BoxedInt8(1.)); + deq(null, DynamicBoxedFloat32_BoxedInt8(null)); + deq(0, BoxedFloat32_BoxedInt16(0)); + deq(1, BoxedFloat32_BoxedInt16(1)); + deq(0., BoxedFloat32_BoxedInt16(0.)); + deq(1., BoxedFloat32_BoxedInt16(1.)); + deq(null, BoxedFloat32_BoxedInt16(null)); + deq(0, DynamicBoxedFloat32_BoxedInt16(0)); + deq(1, DynamicBoxedFloat32_BoxedInt16(1)); + deq(0., DynamicBoxedFloat32_BoxedInt16(0.)); + deq(1., DynamicBoxedFloat32_BoxedInt16(1.)); + deq(null, DynamicBoxedFloat32_BoxedInt16(null)); + deq(0, BoxedFloat32_BoxedInt32(0)); + deq(1, BoxedFloat32_BoxedInt32(1)); + deq(0., BoxedFloat32_BoxedInt32(0.)); + deq(1., BoxedFloat32_BoxedInt32(1.)); + deq(null, BoxedFloat32_BoxedInt32(null)); + deq(0, DynamicBoxedFloat32_BoxedInt32(0)); + deq(1, DynamicBoxedFloat32_BoxedInt32(1)); + deq(0., DynamicBoxedFloat32_BoxedInt32(0.)); + deq(1., DynamicBoxedFloat32_BoxedInt32(1.)); + deq(null, DynamicBoxedFloat32_BoxedInt32(null)); + deq(0, BoxedFloat32_BoxedInt64(0)); + deq(1, BoxedFloat32_BoxedInt64(1)); + deq(0., BoxedFloat32_BoxedInt64(0.)); + deq(1., BoxedFloat32_BoxedInt64(1.)); + deq(null, BoxedFloat32_BoxedInt64(null)); + deq(0, DynamicBoxedFloat32_BoxedInt64(0)); + deq(1, DynamicBoxedFloat32_BoxedInt64(1)); + deq(0., DynamicBoxedFloat32_BoxedInt64(0.)); + deq(1., DynamicBoxedFloat32_BoxedInt64(1.)); + deq(null, DynamicBoxedFloat32_BoxedInt64(null)); + deq(0, BoxedFloat32_BoxedFloat64(0)); + deq(1, BoxedFloat32_BoxedFloat64(1)); + deq(0., BoxedFloat32_BoxedFloat64(0.)); + deq(1., BoxedFloat32_BoxedFloat64(1.)); + deq(null, BoxedFloat32_BoxedFloat64(null)); + deq(0, DynamicBoxedFloat32_BoxedFloat64(0)); + deq(1, DynamicBoxedFloat32_BoxedFloat64(1)); + deq(0., DynamicBoxedFloat32_BoxedFloat64(0.)); + deq(1., DynamicBoxedFloat32_BoxedFloat64(1.)); + deq(null, DynamicBoxedFloat32_BoxedFloat64(null)); + deq(0, BoxedFloat64_Int8(0)); + deq(1, BoxedFloat64_Int8(1)); + deq(0., BoxedFloat64_Int8(0.)); + deq(1., BoxedFloat64_Int8(1.)); + deq(CastHelper.nullOr0, BoxedFloat64_Int8(null)); + deq(0, DynamicBoxedFloat64_Int8(0)); + deq(1, DynamicBoxedFloat64_Int8(1)); + deq(0., DynamicBoxedFloat64_Int8(0.)); + deq(1., DynamicBoxedFloat64_Int8(1.)); + deq(CastHelper.nullOr0, DynamicBoxedFloat64_Int8(null)); + deq(0, BoxedFloat64_Int16(0)); + deq(1, BoxedFloat64_Int16(1)); + deq(0., BoxedFloat64_Int16(0.)); + deq(1., BoxedFloat64_Int16(1.)); + deq(CastHelper.nullOr0, BoxedFloat64_Int16(null)); + deq(0, DynamicBoxedFloat64_Int16(0)); + deq(1, DynamicBoxedFloat64_Int16(1)); + deq(0., DynamicBoxedFloat64_Int16(0.)); + deq(1., DynamicBoxedFloat64_Int16(1.)); + deq(CastHelper.nullOr0, DynamicBoxedFloat64_Int16(null)); + deq(0, BoxedFloat64_Int32(0)); + deq(1, BoxedFloat64_Int32(1)); + deq(0., BoxedFloat64_Int32(0.)); + deq(1., BoxedFloat64_Int32(1.)); + deq(CastHelper.nullOr0, BoxedFloat64_Int32(null)); + deq(0, DynamicBoxedFloat64_Int32(0)); + deq(1, DynamicBoxedFloat64_Int32(1)); + deq(0., DynamicBoxedFloat64_Int32(0.)); + deq(1., DynamicBoxedFloat64_Int32(1.)); + deq(CastHelper.nullOr0, DynamicBoxedFloat64_Int32(null)); + deq(0, BoxedFloat64_Int64(0)); + deq(1, BoxedFloat64_Int64(1)); + deq(0., BoxedFloat64_Int64(0.)); + deq(1., BoxedFloat64_Int64(1.)); + deq(CastHelper.nullOr0, BoxedFloat64_Int64(null)); + deq(0, DynamicBoxedFloat64_Int64(0)); + deq(1, DynamicBoxedFloat64_Int64(1)); + deq(0., DynamicBoxedFloat64_Int64(0.)); + deq(1., DynamicBoxedFloat64_Int64(1.)); + deq(CastHelper.nullOr0, DynamicBoxedFloat64_Int64(null)); + deq(0, BoxedFloat64_Float32(0)); + deq(1, BoxedFloat64_Float32(1)); + deq(0., BoxedFloat64_Float32(0.)); + deq(1., BoxedFloat64_Float32(1.)); + deq(CastHelper.nullOr0, BoxedFloat64_Float32(null)); + deq(0, DynamicBoxedFloat64_Float32(0)); + deq(1, DynamicBoxedFloat64_Float32(1)); + deq(0., DynamicBoxedFloat64_Float32(0.)); + deq(1., DynamicBoxedFloat64_Float32(1.)); + deq(CastHelper.nullOr0, DynamicBoxedFloat64_Float32(null)); + deq(0, BoxedFloat64_Float64(0)); + deq(1, BoxedFloat64_Float64(1)); + deq(0., BoxedFloat64_Float64(0.)); + deq(1., BoxedFloat64_Float64(1.)); + deq(CastHelper.nullOr0, BoxedFloat64_Float64(null)); + deq(0, DynamicBoxedFloat64_Float64(0)); + deq(1, DynamicBoxedFloat64_Float64(1)); + deq(0., DynamicBoxedFloat64_Float64(0.)); + deq(1., DynamicBoxedFloat64_Float64(1.)); + deq(CastHelper.nullOr0, DynamicBoxedFloat64_Float64(null)); + deq(0, BoxedFloat64_BoxedInt8(0)); + deq(1, BoxedFloat64_BoxedInt8(1)); + deq(0., BoxedFloat64_BoxedInt8(0.)); + deq(1., BoxedFloat64_BoxedInt8(1.)); + deq(null, BoxedFloat64_BoxedInt8(null)); + deq(0, DynamicBoxedFloat64_BoxedInt8(0)); + deq(1, DynamicBoxedFloat64_BoxedInt8(1)); + deq(0., DynamicBoxedFloat64_BoxedInt8(0.)); + deq(1., DynamicBoxedFloat64_BoxedInt8(1.)); + deq(null, DynamicBoxedFloat64_BoxedInt8(null)); + deq(0, BoxedFloat64_BoxedInt16(0)); + deq(1, BoxedFloat64_BoxedInt16(1)); + deq(0., BoxedFloat64_BoxedInt16(0.)); + deq(1., BoxedFloat64_BoxedInt16(1.)); + deq(null, BoxedFloat64_BoxedInt16(null)); + deq(0, DynamicBoxedFloat64_BoxedInt16(0)); + deq(1, DynamicBoxedFloat64_BoxedInt16(1)); + deq(0., DynamicBoxedFloat64_BoxedInt16(0.)); + deq(1., DynamicBoxedFloat64_BoxedInt16(1.)); + deq(null, DynamicBoxedFloat64_BoxedInt16(null)); + deq(0, BoxedFloat64_BoxedInt32(0)); + deq(1, BoxedFloat64_BoxedInt32(1)); + deq(0., BoxedFloat64_BoxedInt32(0.)); + deq(1., BoxedFloat64_BoxedInt32(1.)); + deq(null, BoxedFloat64_BoxedInt32(null)); + deq(0, DynamicBoxedFloat64_BoxedInt32(0)); + deq(1, DynamicBoxedFloat64_BoxedInt32(1)); + deq(0., DynamicBoxedFloat64_BoxedInt32(0.)); + deq(1., DynamicBoxedFloat64_BoxedInt32(1.)); + deq(null, DynamicBoxedFloat64_BoxedInt32(null)); + deq(0, BoxedFloat64_BoxedInt64(0)); + deq(1, BoxedFloat64_BoxedInt64(1)); + deq(0., BoxedFloat64_BoxedInt64(0.)); + deq(1., BoxedFloat64_BoxedInt64(1.)); + deq(null, BoxedFloat64_BoxedInt64(null)); + deq(0, DynamicBoxedFloat64_BoxedInt64(0)); + deq(1, DynamicBoxedFloat64_BoxedInt64(1)); + deq(0., DynamicBoxedFloat64_BoxedInt64(0.)); + deq(1., DynamicBoxedFloat64_BoxedInt64(1.)); + deq(null, DynamicBoxedFloat64_BoxedInt64(null)); + deq(0, BoxedFloat64_BoxedFloat32(0)); + deq(1, BoxedFloat64_BoxedFloat32(1)); + deq(0., BoxedFloat64_BoxedFloat32(0.)); + deq(1., BoxedFloat64_BoxedFloat32(1.)); + deq(null, BoxedFloat64_BoxedFloat32(null)); + deq(0, DynamicBoxedFloat64_BoxedFloat32(0)); + deq(1, DynamicBoxedFloat64_BoxedFloat32(1)); + deq(0., DynamicBoxedFloat64_BoxedFloat32(0.)); + deq(1., DynamicBoxedFloat64_BoxedFloat32(1.)); + deq(null, DynamicBoxedFloat64_BoxedFloat32(null)); + }; + } + function deq(expected:Dynamic, actual:Dynamic, ?p:haxe.PosInfos) { + eq(expected, actual, p); + } +} diff --git a/tests/unit/src/unit/TestReflect.hx b/tests/unit/src/unit/TestReflect.hx index 60778d190477f0b472062b2f518e7bd6a9d696f9..3455291e4acb47212379bf96ab638cee89eb33d5 100644 --- a/tests/unit/src/unit/TestReflect.hx +++ b/tests/unit/src/unit/TestReflect.hx @@ -77,12 +77,7 @@ class TestReflect extends Test { } static inline function u2( s : String, s2 ) : String { - #if as3 - return s + "." +s2; - #else - // this causes a null pointer exception on as3 for whatever reason return u(s) + "." + u(s2); - #end } static var TNAMES = [ @@ -111,44 +106,44 @@ class TestReflect extends Test { } public function testIs() { - is(0,Int,Float); - is(1,Int,Float); - is(-1,Int,Float); - is(2.0,Int,Float); - is(1.2,Float); - is(1e10,Float); - is(-1e10,Float); - is(Math.NaN,Float); - is(Math.POSITIVE_INFINITY,Float); - is(Math.NEGATIVE_INFINITY,Float); - is(true,Bool); - is(false,Bool); - is("Hello",String); - is("123",String); - is("false",String); - is("",String); - is([],Array); - is([1, 2], Array); - is([1.1, 2.2], Array); - is(["a", "b"], Array); - is((["a",2]:Array),Array); - is(new List(),List); - is(new haxe.ds.StringMap(),haxe.ds.StringMap); - is(new MyClass(0),MyClass); - is(new MySubClass(0),MyClass,MySubClass); - is(MyEnum.A,MyEnum); - is(MyEnum.C(0,""),MyEnum); - is(Date.now(),Date); - is({ x : 0 },null); - is(function() { },null); - is(MyClass,Class); - is(MyEnum,Enum); + isTrue(0,Int,Float); + isTrue(1,Int,Float); + isTrue(-1,Int,Float); + isTrue(2.0,Int,Float); + isTrue(1.2,Float); + isTrue(1e10,Float); + isTrue(-1e10,Float); + isTrue(Math.NaN,Float); + isTrue(Math.POSITIVE_INFINITY,Float); + isTrue(Math.NEGATIVE_INFINITY,Float); + isTrue(true,Bool); + isTrue(false,Bool); + isTrue("Hello",String); + isTrue("123",String); + isTrue("false",String); + isTrue("",String); + isTrue([],Array); + isTrue([1, 2], Array); + isTrue([1.1, 2.2], Array); + isTrue(["a", "b"], Array); + isTrue((["a",2]:Array),Array); + isTrue(new List(),List); + isTrue(new haxe.ds.StringMap(),haxe.ds.StringMap); + isTrue(new MyClass(0),MyClass); + isTrue(new MySubClass(0),MyClass,MySubClass); + isTrue(MyEnum.A,MyEnum); + isTrue(MyEnum.C(0,""),MyEnum); + isTrue(Date.now(),Date); + isTrue({ x : 0 },null); + isTrue(function() { },null); + isTrue(MyClass,Class); + isTrue(MyEnum,Enum); } - function is( v : Dynamic, t1 : Dynamic, ?t2 : Dynamic, ?pos : haxe.PosInfos ){ + function isTrue( v : Dynamic, t1 : Dynamic, ?t2 : Dynamic, ?pos : haxe.PosInfos ){ for( i in 0...TYPES.length ) { var c : Dynamic = TYPES[i]; - eq( Std.is(v,c), c != null && (c == t1 || c == t2) || (c == Dynamic), pos ); + eq( Std.isOfType(v,c), c != null && (c == t1 || c == t2) || (c == Dynamic), pos ); } t( (v is Dynamic), pos ); } diff --git a/tests/unit/src/unit/TestSyntaxModule.hx b/tests/unit/src/unit/TestSyntaxModule.hx index 734830a3b5f83914f9c5b496928e804873a37772..0098822c15ce4e30bc8ca80900a4c124d82146c8 100644 --- a/tests/unit/src/unit/TestSyntaxModule.hx +++ b/tests/unit/src/unit/TestSyntaxModule.hx @@ -39,15 +39,22 @@ class TestSyntaxModule extends Test { #elseif python "unit__TestSyntaxModule_Construct"; #end var a:Construct = Syntax.construct(className, 10); - t(Std.is(a, Construct)); + t(Std.isOfType(a, Construct)); eq(10, a.value); var b = Syntax.construct(Construct, 10); - t(Std.is(b, Construct)); + t(Std.isOfType(b, Construct)); eq(10, b.value); } #end #end + +#if js + function testPlainCode() { + var s = Syntax.plainCode('"{0}"'); + eq('{0}', s); + } +#end } private class Construct { diff --git a/tests/unit/src/unit/TestType.hx b/tests/unit/src/unit/TestType.hx index 69de09f038178d45b5b3b38bb972750a06424413..8add5cd279063259b215c4c355ef2b80c95e80c5 100644 --- a/tests/unit/src/unit/TestType.hx +++ b/tests/unit/src/unit/TestType.hx @@ -35,9 +35,6 @@ class TestType extends Test { fl.sort(Reflect.compare); eq( fl.join("|"), fields.join("|") ); - // AS3 generator will create native properties - #if !as3 - // x should not be listed since it's not a variable var fl = Type.getInstanceFields(VarProps); var fields = ["get_x","get_y","set_x","set_y","set_z","y","z"]; @@ -49,8 +46,6 @@ class TestType extends Test { var fields = ["SY", "get_SX", "get_SY", "set_SX", "set_SY"]; fl.sort(Reflect.compare); eq( fl.join("|"), fields.join("|")); - - #end } public function testEnumEq() { @@ -99,11 +94,8 @@ class TestType extends Test { var c = new MyClass.MyChild1(); eq(12, c.a()); - // TODO: this is also a problem - #if !as3 var mc2 = new MyChild2(); eq(21, mc2.test1(new MyChild1())); - #end } function testUnifyMin() { @@ -306,8 +298,8 @@ class TestType extends Test { var c = new Cov2(); typedAs(c.covariant(), c1); - t(Std.is(c.covariant(), Child1)); - t(Std.is(cast(c, Cov1).covariant(), Child1)); + t(Std.isOfType(c.covariant(), Child1)); + t(Std.isOfType(cast(c, Cov1).covariant(), Child1)); // base class reference var br:Cov1 = c; @@ -779,8 +771,7 @@ class TestType extends Test { eq(mr["hhh"], 2); eq(v, "hhhh"); - // note for later: As3 compilation fails if the function name is removed - mr["101"] = function n(x) return 9 + x; + mr["101"] = function(x) return 9 + x; eq(mr["101"](1), 10); } diff --git a/tests/unit/src/unit/hxcpp_issues/Issue9194.hx b/tests/unit/src/unit/hxcpp_issues/Issue9194.hx new file mode 100644 index 0000000000000000000000000000000000000000..84d50d635626291cbb47733a565bec1184c99b1d --- /dev/null +++ b/tests/unit/src/unit/hxcpp_issues/Issue9194.hx @@ -0,0 +1,24 @@ +package unit.hxcpp_issues; + + +class Issue9194 extends Test { + + @:analyzer(no_optimize) + function test() { + #if cpp + // will fail during C++ compile + var buffer: cpp.RawPointer = null; + var floatBuffer: cpp.RawPointer = cast buffer; + // generates incorrect: float* floatBuffer = buffer + // the lack of native casting means the compiler throws an error here + + var buffer: cpp.Star = null; + var floatBuffer: cpp.Star = cast buffer; + // generates correct: float* floatBuffer = ( (float*) buffer ) + #end + + // empty test to keep the test-runner happy + t(true); + } + +} diff --git a/tests/unit/src/unit/issues/Issue3226.hx b/tests/unit/src/unit/issues/Issue3226.hx index 3893b26c159123f43dc7f018fe7261e635c0b0a6..cab1fd514d2c9e172f9a8e275260f70bb6fb9ddf 100644 --- a/tests/unit/src/unit/issues/Issue3226.hx +++ b/tests/unit/src/unit/issues/Issue3226.hx @@ -5,7 +5,7 @@ class Issue3226 extends Test { function testJs() { var a = 1; var v = 2; - untyped __js__("{0} = {0} + {1}", a, v); + a = js.Syntax.code("{0} + {1}", a, v); eq(3, a); } #elseif (cpp && !cppia) diff --git a/tests/unit/src/unit/issues/Issue3846.hx b/tests/unit/src/unit/issues/Issue3846.hx deleted file mode 100644 index 9b81c5394d8e3ad37594deef154d9eb2845adac3..0000000000000000000000000000000000000000 --- a/tests/unit/src/unit/issues/Issue3846.hx +++ /dev/null @@ -1,29 +0,0 @@ -package unit.issues; - -// they don't allow this insanity -#if (!java && !cs) - -private class Extern { - - @:keep - static public function mytest(a:Dynamic) { - return a; - } - - @:overload( function (a:Int):Dynamic {}) - extern - inline public static function test(a:String):Dynamic { - return mytest(a); - } -} - -#end - -class Issue3846 extends Test { - #if (!java && !cs) - function test() { - eq("coucou", Extern.test("coucou")); - eq(1, Extern.test(1)); - } - #end -} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue4014.hx b/tests/unit/src/unit/issues/Issue4014.hx index 7330bf22770a19f8ba4154ccfb124616f722e6af..a711f88abc6e131e97f169b57483bdd6d1d15b72 100644 --- a/tests/unit/src/unit/issues/Issue4014.hx +++ b/tests/unit/src/unit/issues/Issue4014.hx @@ -1,4 +1,5 @@ package unit.issues; + import haxe.Int64; class Issue4014 extends Test @@ -7,11 +8,11 @@ class Issue4014 extends Test { var d = Int64.make(1,1); var dyn:Dynamic = d; - t(Int64.is(dyn)); + t(Int64.isInt64(dyn)); d = dyn; eq(d.high,1); eq(d.low,1); dyn = {}; - f(Int64.is(dyn)); + f(Int64.isInt64(dyn)); } } diff --git a/tests/unit/src/unit/issues/Issue4085.hx b/tests/unit/src/unit/issues/Issue4085.hx index bc2736b6a0e756320674fa796cfc4d9e828c2449..38d2f811d622cd6af63c3dc215b9a30b84a0ed38 100644 --- a/tests/unit/src/unit/issues/Issue4085.hx +++ b/tests/unit/src/unit/issues/Issue4085.hx @@ -3,9 +3,8 @@ package unit.issues; class Issue4085 extends Test { #if js function test() { - function throwError() throw "hello, world"; var msg = null; - untyped __js__("try { throwError(); } catch (e) { msg = e.message; }"); + js.Syntax.code("try { ({0})(); } catch (e) { ({1})(e); }", () -> throw "hello, world", e -> msg = e.message); eq(msg, "hello, world"); } #end diff --git a/tests/unit/src/unit/issues/Issue4285.hx b/tests/unit/src/unit/issues/Issue4285.hx index 4c1fa2341266473ddcffdc5d177f33631ea31620..084a3edb00898af2db6f02a89fc7a5c84514c63f 100644 --- a/tests/unit/src/unit/issues/Issue4285.hx +++ b/tests/unit/src/unit/issues/Issue4285.hx @@ -7,6 +7,6 @@ class Issue4285 extends Test { } static function myIs(d:Dynamic, t:Dynamic) { - return Std.is(d, t); + return Std.isOfType(d, t); } } \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue4644.hx b/tests/unit/src/unit/issues/Issue4644.hx index 7f707640e75b52d45e016d3e955333862be5e6bb..29050aee6191dcaf8257d4807cadfafe775ba45b 100644 --- a/tests/unit/src/unit/issues/Issue4644.hx +++ b/tests/unit/src/unit/issues/Issue4644.hx @@ -1,25 +1,25 @@ package unit.issues; class Issue4644 extends Test { +#if js + function test() { - #if js - var isHaxeError; - untyped __js__( + var isHaxeError = true; + js.Syntax.code( "try {{ - {0}; + ({0})(); }} catch (e) {{ - {1} = (e instanceof {2}); + ({1})(e instanceof {2}); }}", - throw (new js.lib.Error() : Dynamic), - isHaxeError, + () -> throw (new js.lib.Error():Dynamic), + b -> isHaxeError = b, #if js_unflatten - __js__("js._Boot.HaxeError") + js.Syntax.code("haxe.Exception") #else - __js__("js__$Boot_HaxeError") + js.Syntax.code("haxe_Exception") #end ); f(isHaxeError); - #end - noAssert(); } +#end } diff --git a/tests/unit/src/unit/issues/Issue4862.hx b/tests/unit/src/unit/issues/Issue4862.hx index 58db957f4328338f3283b303841a5497eab8bccb..03323c1b2712999aedb3717c9afbc2ba1ac10638 100644 --- a/tests/unit/src/unit/issues/Issue4862.hx +++ b/tests/unit/src/unit/issues/Issue4862.hx @@ -7,7 +7,7 @@ private extern enum abstract HttpStatus(Int) to Int { var NotFound; static function __init__():Void { - untyped __js__("var __issue4862__http_status = {Ok: 200, NotFound: 404};"); + js.Syntax.code("var __issue4862__http_status = {Ok: 200, NotFound: 404};"); } } #end diff --git a/tests/unit/src/unit/issues/Issue4962.hx b/tests/unit/src/unit/issues/Issue4962.hx index 56540129a104d152caff2295cb0c94bc8fb676ef..af6893310a2f79cdcd610d53a593c6613b7b2ba1 100644 --- a/tests/unit/src/unit/issues/Issue4962.hx +++ b/tests/unit/src/unit/issues/Issue4962.hx @@ -8,8 +8,8 @@ private class C { class Issue4962 extends Test { function test() { var int:Dynamic = Int; - f(Std.is(new C(), int)); + f(Std.isOfType(new C(), int)); - f(Std.is(new C(), Int)); + f(Std.isOfType(new C(), Int)); } } diff --git a/tests/unit/src/unit/issues/Issue4973.hx b/tests/unit/src/unit/issues/Issue4973.hx index b5a91de7534cfafbc57c2a8c768093a677230d74..78bd39e8ac99eaf37dff9ff2725419fb5be0cada 100644 --- a/tests/unit/src/unit/issues/Issue4973.hx +++ b/tests/unit/src/unit/issues/Issue4973.hx @@ -8,8 +8,8 @@ class Issue4973 extends Test { #if php function test() { try sys.io.File.getContent("not-existant") - catch(exc:Exception) t(Std.is(exc, Exception)) - catch(exc:Dynamic) t(Std.is(exc, Exception)); + catch(exc:Exception) t(Std.isOfType(exc, Exception)) + catch(exc:Dynamic) t(Std.isOfType(exc, Exception)); } #end } diff --git a/tests/unit/src/unit/issues/Issue4986.hx b/tests/unit/src/unit/issues/Issue4986.hx index da899559ddaae2f6552c7a94d29020d927f41c9f..a35a76164328de31c14da576e9459a94134123c8 100644 --- a/tests/unit/src/unit/issues/Issue4986.hx +++ b/tests/unit/src/unit/issues/Issue4986.hx @@ -4,7 +4,11 @@ class Issue4986 extends Test { function test() { try { var v = new haxe.ds.Vector>(1); + #if cppia //see https://github.com/HaxeFoundation/haxe/issues/9261 + v[0].length; + #else foo(v[0].length); + #end } catch (e:Dynamic) {} noAssert(); } diff --git a/tests/unit/src/unit/issues/Issue4988.hx b/tests/unit/src/unit/issues/Issue4988.hx index 4bcbc610bb42a2115afed0190b0cb62e90acea21..8210081fa15ad3577edd7d4e0fb698ddf3e53af1 100644 --- a/tests/unit/src/unit/issues/Issue4988.hx +++ b/tests/unit/src/unit/issues/Issue4988.hx @@ -9,7 +9,7 @@ class Issue4988 extends Test { try { var d:{i:Null} = null; value = (d.i > 0); - #if !(lua || as3) + #if !lua (null:Dynamic).nonExistent(); null.nonExistent(); #end diff --git a/tests/unit/src/unit/issues/Issue5011.hx b/tests/unit/src/unit/issues/Issue5011.hx new file mode 100644 index 0000000000000000000000000000000000000000..875b8e34f787c2541b39016e43655e9ddf9d36d9 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue5011.hx @@ -0,0 +1,21 @@ +package unit.issues; + +private enum E { + A; + B(n:Int); +} + +class Issue5011 extends unit.Test { + var e:E; + var n(get,never):Null; + + function get_n() return switch (e) { + case A: null; + case B(n): n; + } + + function test() { + e = B(12); + eq(12, get_n()); + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue5025.hx b/tests/unit/src/unit/issues/Issue5025.hx index 77514699ef3e192d22e0eca8f4cf2ae641390593..61870cfccd6931dd4323b1a39a3ccadb6b878e36 100644 --- a/tests/unit/src/unit/issues/Issue5025.hx +++ b/tests/unit/src/unit/issues/Issue5025.hx @@ -6,7 +6,7 @@ class Issue5025 extends Test { } function shouldCompile() { - #if !(java || cs || as3 || lua) + #if !(java || cs || lua) try { switch (null) { case Value(i): diff --git a/tests/unit/src/unit/issues/Issue5039.hx b/tests/unit/src/unit/issues/Issue5039.hx index 8fc3f340b16f5cb6cb9df57df2a8c6a2a1e2772a..831ae5793de7be3aae30e23150a414a0c91a6cd0 100644 --- a/tests/unit/src/unit/issues/Issue5039.hx +++ b/tests/unit/src/unit/issues/Issue5039.hx @@ -42,10 +42,8 @@ class Issue5039 extends Test { f(getterCalled); f(setterCalled); - t(Std.is(@:bypassAccessor c, C)); - #if !as3 // because as3 generates underlying field as protected, we cannot access it from outside :-/ + t(Std.isOfType(@:bypassAccessor c, C)); eq(42, @:bypassAccessor (@:bypassAccessor c).prop); eq(42, @:bypassAccessor @:bypassAccessor c.prop); - #end } } diff --git a/tests/unit/src/unit/issues/Issue5168.hx b/tests/unit/src/unit/issues/Issue5168.hx index e95570770fc769807c03ffaff111d0688a81a110..979c7ef9e974a811c4aa0fdd1192e875ac43a325 100644 --- a/tests/unit/src/unit/issues/Issue5168.hx +++ b/tests/unit/src/unit/issues/Issue5168.hx @@ -2,7 +2,7 @@ package unit.issues; class Issue5168 extends unit.Test { function test() { - f(Std.is("hello", Issue5168)); - f(Std.is(1, String)); + f(Std.isOfType("hello", Issue5168)); + f(Std.isOfType(1, String)); } } \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue5351.hx b/tests/unit/src/unit/issues/Issue5351.hx index 1f2ef72b886b2546bfe0d6d298e1fb1fbfe9a606..43b5a4cfb6efca08fb26e2eb806b76e2eb258d6a 100644 --- a/tests/unit/src/unit/issues/Issue5351.hx +++ b/tests/unit/src/unit/issues/Issue5351.hx @@ -2,7 +2,6 @@ package unit.issues; import scripthost.Issue5351; class Issue5351 extends Test { -#if !as3 public function test() { var t3:Issue5351_2 = Type.createInstance(Type.resolveClass('unit.issues.Issue5351_3'), []); eq(t3.doTest1(), 'doTest1 override'); @@ -28,7 +27,6 @@ class Issue5351 extends Test { eq(t3.doTest4(), 'doTest4'); } -#end } @:keep class Issue5351_3 extends Issue5351_2 { diff --git a/tests/unit/src/unit/issues/Issue5466.hx b/tests/unit/src/unit/issues/Issue5466.hx index 1b677b2e4e08f8a495949c3f89e8f1ca63e4f192..89bd8618153c746be371be6a9759ed85328f41ab 100644 --- a/tests/unit/src/unit/issues/Issue5466.hx +++ b/tests/unit/src/unit/issues/Issue5466.hx @@ -3,7 +3,7 @@ package unit.issues; class Issue5466 extends Test { function test() { var test:Base = (Math.random() > 0.5) ? new A() : new B(); - t(Std.is(test, A) || Std.is(test, B)); + t(Std.isOfType(test, A) || Std.isOfType(test, B)); } } diff --git a/tests/unit/src/unit/issues/Issue5486.hx b/tests/unit/src/unit/issues/Issue5486.hx index 05ea00555e51beaeb7b062dff5f096ca7486303e..d8c8f2238da29454627975238aa8db6cc1de48e3 100644 --- a/tests/unit/src/unit/issues/Issue5486.hx +++ b/tests/unit/src/unit/issues/Issue5486.hx @@ -23,7 +23,7 @@ class Issue5486 extends unit.Test { } static function broken(?input:Dynamic):Option{ - if(Std.is(input, Int)){ + if(Std.isOfType(input, Int)){ return Some(input); } else { return None; diff --git a/tests/unit/src/unit/issues/Issue5565.hx b/tests/unit/src/unit/issues/Issue5565.hx index 925649848ef4a4170832ffb760b2ae6b373a7c1e..31d6cb8ec75f64b72d6318d56cea222e519863ae 100644 --- a/tests/unit/src/unit/issues/Issue5565.hx +++ b/tests/unit/src/unit/issues/Issue5565.hx @@ -3,7 +3,7 @@ package unit.issues; class Issue5565 extends Test { #if php function test() { - t(Std.is(php.Syntax.arrayDecl(), php.NativeArray)); + t(Std.isOfType(php.Syntax.arrayDecl(), php.NativeArray)); } #end } \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue5862.hx b/tests/unit/src/unit/issues/Issue5862.hx index d8d07df97f9a7752c488058146fa08478e378f9b..1ff8e731372fdb62489520dd760c16d2446f2770 100644 --- a/tests/unit/src/unit/issues/Issue5862.hx +++ b/tests/unit/src/unit/issues/Issue5862.hx @@ -26,10 +26,12 @@ class Issue5862 extends Test { smap.set("v3", "val3"); smap.set("v3", "changed_val3"); + #if !jvm var v:Vector = cast @:privateAccess smap.vals; for (i in 0...v.length) { t(v[i] != "val3"); - } + } + #end var omap = new ObjectMap<{}, String>(); omap.set(imap, "val1"); @@ -73,10 +75,12 @@ class Issue5862 extends Test { smap.set("v3", "changed_val3"); smap.set("v2", "changed_val2"); + #if !jvm var v:Vector = cast @:privateAccess smap.vals; for (i in 0...v.length) { t(v[i] != "val2"); - } + } + #end var omap = new ObjectMap<{}, String>(); omap.set(imap, "val1"); diff --git a/tests/unit/src/unit/issues/Issue5973.hx b/tests/unit/src/unit/issues/Issue5973.hx index 889ea257f4c0681df12d90207675c19044fc7615..1f4bc0aa5c3feb72dfd84b61c3633bf53e209c45 100644 --- a/tests/unit/src/unit/issues/Issue5973.hx +++ b/tests/unit/src/unit/issues/Issue5973.hx @@ -4,12 +4,12 @@ class Issue5973 extends Test{ var foo = new Issue5973Foo(); var bar = new Issue5973Bar(); var foobar = new Issue5973FooBar(); - t(Std.is(foo , Issue5973IFoo)); - f(Std.is(foo , Issue5973IBar)); - f(Std.is(bar , Issue5973IFoo)); - t(Std.is(bar , Issue5973IBar)); - t(Std.is(foobar , Issue5973IFoo)); - t(Std.is(foobar , Issue5973IBar)); + t(Std.isOfType(foo , Issue5973IFoo)); + f(Std.isOfType(foo , Issue5973IBar)); + f(Std.isOfType(bar , Issue5973IFoo)); + t(Std.isOfType(bar , Issue5973IBar)); + t(Std.isOfType(foobar , Issue5973IFoo)); + t(Std.isOfType(foobar , Issue5973IBar)); } } diff --git a/tests/unit/src/unit/issues/Issue6059.hx b/tests/unit/src/unit/issues/Issue6059.hx index 431cdea694205847d73a5ff08a098ea8c7632e24..c895b794faa086f7a099e8b3468584291dfe6675 100644 --- a/tests/unit/src/unit/issues/Issue6059.hx +++ b/tests/unit/src/unit/issues/Issue6059.hx @@ -1,14 +1,12 @@ package unit.issues; class Issue6059 extends Test { -#if !as3 // See #6891 public static inline function foo (name : B, ?id : B, data : Array) : Void { } public static function test () : Void { Issue6059.foo ("", []); // -> stackoverflow Issue6059.foo ("", null, []); // ok } -#end } private abstract A (String) { diff --git a/tests/unit/src/unit/issues/Issue6195.hx b/tests/unit/src/unit/issues/Issue6195.hx new file mode 100644 index 0000000000000000000000000000000000000000..daffd344d797a9f6af56d0d11f78bbe18e676255 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue6195.hx @@ -0,0 +1,14 @@ +package unit.issues; + +class Issue6195 extends unit.Test { + var field(get,default):Int = 1; + function get_field():Int { + return field + 1; + } + + function test() { + eq(2, field); + field = 10; + eq(11, field); + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue6208.hx b/tests/unit/src/unit/issues/Issue6208.hx index 726343e61d33159816f1af1ad310790972629fee..c9bc9b7388bc1a1e8f5c6fa45fe41d40bfe8347d 100644 --- a/tests/unit/src/unit/issues/Issue6208.hx +++ b/tests/unit/src/unit/issues/Issue6208.hx @@ -4,8 +4,8 @@ package unit.issues; class Issue6208 extends unit.Test implements IBase implements IChild { function test() { - t(Std.is(this, IChild)); - t(Std.is(this, IBase)); + t(Std.isOfType(this, IChild)); + t(Std.isOfType(this, IBase)); } public function base() {} diff --git a/tests/unit/src/unit/issues/Issue6290.hx b/tests/unit/src/unit/issues/Issue6290.hx index 2877926f1466c1abe83a0a299ce94de439ca9340..4dc578ac20278cee933d05fc183c85542c156e31 100644 --- a/tests/unit/src/unit/issues/Issue6290.hx +++ b/tests/unit/src/unit/issues/Issue6290.hx @@ -13,7 +13,7 @@ private class TakeParent { private class TakeChild extends TakeParent { public function new(child:Child) { super(child); - if (!Std.is(child, Child)) throw 'wtf?'; + if (!Std.isOfType(child, Child)) throw 'wtf?'; } } diff --git a/tests/unit/src/unit/issues/Issue6325.hx b/tests/unit/src/unit/issues/Issue6325.hx index 763983cc86002ad126e13b7b740fe68fa0b468e6..927a6ff60bc2ad1d98d328cf3b990bd7f3d28fc8 100644 --- a/tests/unit/src/unit/issues/Issue6325.hx +++ b/tests/unit/src/unit/issues/Issue6325.hx @@ -1,7 +1,7 @@ package unit.issues; class Issue6325 extends Test { -#if (!hl && !flash && !cpp && !as3) +#if (!hl && !flash && !cpp) public function test() { var base = new Base(); base.someInt = 42; diff --git a/tests/unit/src/unit/issues/Issue6448.hx b/tests/unit/src/unit/issues/Issue6448.hx index 4781a882eeba9b12e9f2c9e8ed0f1cc6cf1cab88..61413aa898e1c949eaf2edde58a0256d7c2fe86d 100644 --- a/tests/unit/src/unit/issues/Issue6448.hx +++ b/tests/unit/src/unit/issues/Issue6448.hx @@ -13,7 +13,7 @@ private extern class Lib { static function returnTrue():Bool; static function __init__():Void { - untyped __js__("function ___hx_returnTrue() { return true; }"); + js.Syntax.code("function ___hx_returnTrue() { return true; }"); } } #end diff --git a/tests/unit/src/unit/issues/Issue6449.hx b/tests/unit/src/unit/issues/Issue6449.hx index 3a543949180ebf91273f28b6a7a4c8e7f081b86b..047c2b7564942148ae37bf790a606f88dbbab1f3 100644 --- a/tests/unit/src/unit/issues/Issue6449.hx +++ b/tests/unit/src/unit/issues/Issue6449.hx @@ -8,7 +8,7 @@ class Issue6449 extends unit.Test { } static function doTest(isNaN:Float):Bool { - return untyped __js__("isNaN")(isNaN); + return js.Syntax.code("isNaN")(isNaN); } #end } \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue6801.hx b/tests/unit/src/unit/issues/Issue6801.hx index bf1fd6fac7c19330a21bf05e8d6d100a5c61e235..a963c0667946dd1886e9b1203952cba484cde3c7 100644 --- a/tests/unit/src/unit/issues/Issue6801.hx +++ b/tests/unit/src/unit/issues/Issue6801.hx @@ -4,7 +4,6 @@ import haxe.Json; import haxe.format.JsonPrinter; class Issue6801 extends unit.Test { -#if !as3 function test() { var o = new Child(); var json = haxe.format.JsonPrinter.print(o); @@ -17,19 +16,18 @@ class Issue6801 extends unit.Test { eq(expected.p, actual.p); eq(expected.p2, actual.p2); } -#end } @:keep private class Parent { - public var p:Int = 1; + public var p:Int = 1; public function new() {} } @:keep private class Child extends Parent{ var c:String = 'hello'; - + public var prop(get,set):Int; function get_prop() return 0; function set_prop(v) return v; diff --git a/tests/unit/src/unit/issues/Issue6838.hx b/tests/unit/src/unit/issues/Issue6838.hx index 636ffd8d1e5721efa01d4663896cbf0f1ef3da24..6c6714f8e007c0d4fc66f28161f73f6f8e118e72 100644 --- a/tests/unit/src/unit/issues/Issue6838.hx +++ b/tests/unit/src/unit/issues/Issue6838.hx @@ -3,7 +3,7 @@ package unit.issues; class Issue6838 extends unit.Test { function test() { var o = new Object(); - eq('unit.issues._Issue6838.Object', Type.getClassName(Type.getClass(o))); + eq(#if jvm "unit.issues.Issue6838$Object" #else 'unit.issues._Issue6838.Object' #end, Type.getClassName(Type.getClass(o))); } } diff --git a/tests/unit/src/unit/issues/Issue6848.hx b/tests/unit/src/unit/issues/Issue6848.hx index f10d4ae50b695ab98ea0504144a99964a00799ae..43c6a167e061fbfa73da8a6709056355a9542347 100644 --- a/tests/unit/src/unit/issues/Issue6848.hx +++ b/tests/unit/src/unit/issues/Issue6848.hx @@ -4,7 +4,7 @@ class Issue6848 extends unit.Test { #if php function test() { var e = Type.createInstance(php.Exception, ['hello']); - t(Std.is(e, php.Exception)); + t(Std.isOfType(e, php.Exception)); eq('hello', e.getMessage()); } #end diff --git a/tests/unit/src/unit/issues/Issue6880.hx b/tests/unit/src/unit/issues/Issue6880.hx new file mode 100644 index 0000000000000000000000000000000000000000..39c88b7499151b7967aa0ba18ebbf6082c3b496d --- /dev/null +++ b/tests/unit/src/unit/issues/Issue6880.hx @@ -0,0 +1,19 @@ +package unit.issues; + +private enum abstract JsonTypeKind(String) { + var TMono; +} + +class Issue6880 extends unit.Test { + function test() { + var u:Null = null; + eq('null', '$u'); + } +} + +private abstract AInt(Int) from Int { + public inline function toString() { + var result = this + 100; + return '$result'; + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue6942.hx b/tests/unit/src/unit/issues/Issue6942.hx index 306d23fd7479608d8279357b6848b264019e71bd..eb3c59b56f709b4b0786dba3c53405f30bda0e14 100644 --- a/tests/unit/src/unit/issues/Issue6942.hx +++ b/tests/unit/src/unit/issues/Issue6942.hx @@ -9,7 +9,7 @@ class Issue6942 extends unit.Test { eq(2, 1 - IntEnum); //these targets have actual UInt type at runtime - #if (flash || cs || as3) + #if (flash || cs) eq(-4294967295, -UIntEnum); eq(2, 1 - UIntEnum); #else diff --git a/tests/unit/src/unit/issues/Issue7115.hx b/tests/unit/src/unit/issues/Issue7115.hx index 8c9c5b90a6d5444a34ac28436a820d095abb30cb..5f9f48eef1397a721356bda7b161993d1988ac52 100644 --- a/tests/unit/src/unit/issues/Issue7115.hx +++ b/tests/unit/src/unit/issues/Issue7115.hx @@ -4,15 +4,15 @@ private interface Interface { } class Issue7115 extends unit.Test { function testIs() { - f(Std.is(getNull(), Int)); - f(Std.is(getNull(), Float)); - f(Std.is(getNull(), Bool)); - f(Std.is(getNull(), String)); - f(Std.is(getNull(), Issue7115)); - f(Std.is(getNull(), haxe.ds.Option)); - f(Std.is(getNull(), Dynamic)); - f(Std.is(getNull(), null)); - f(Std.is(getNull(), Interface)); + f(Std.isOfType(getNull(), Int)); + f(Std.isOfType(getNull(), Float)); + f(Std.isOfType(getNull(), Bool)); + f(Std.isOfType(getNull(), String)); + f(Std.isOfType(getNull(), Issue7115)); + f(Std.isOfType(getNull(), haxe.ds.Option)); + f(Std.isOfType(getNull(), Dynamic)); + f(Std.isOfType(getNull(), null)); + f(Std.isOfType(getNull(), Interface)); } function testCast() { diff --git a/tests/unit/src/unit/issues/Issue7428.hx b/tests/unit/src/unit/issues/Issue7428.hx new file mode 100644 index 0000000000000000000000000000000000000000..39f871fc641d98d5d02178da706f2081b465b6d6 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue7428.hx @@ -0,0 +1,20 @@ +package unit.issues; + +class Issue7428 extends unit.Test { + function test() { + eq(null, getIntOrNull()); + } + + @:pure(false) + static function getIntOrNull():Null { + return execute(function():Null { + return null; + }); + } + + @:pure(false) + static function execute(callback:Void->T):T { + var result = callback(); + return result; + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue7985.hx b/tests/unit/src/unit/issues/Issue7985.hx new file mode 100644 index 0000000000000000000000000000000000000000..b155a8b753c15b2c3ba3d91d95a1f5116ae86fe8 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue7985.hx @@ -0,0 +1,19 @@ +package unit.issues; + +class Issue7985 extends unit.Test { + function test() { + gen((null:Rec)); + (null:Gen); + noAssert(); + } + + @:generic + static function gen(v:T) {} +} + +@:generic +private class Gen {} + +private typedef Rec = { + field:Rec +} diff --git a/tests/unit/src/unit/issues/Issue8075.hx b/tests/unit/src/unit/issues/Issue8075.hx index e8a3ddc0e863e759286ec13e9cfdeed589f41ffe..cf5440af99c5035e66fc5da96e768c6f40b12c95 100644 --- a/tests/unit/src/unit/issues/Issue8075.hx +++ b/tests/unit/src/unit/issues/Issue8075.hx @@ -1,7 +1,6 @@ package unit.issues; class Issue8075 extends unit.Test { -#if !as3 function test() { var expect = #if static 0 #else null #end; var a = []; @@ -10,5 +9,4 @@ class Issue8075 extends unit.Test { a[2] = 2; eq(expect, a[0]); } -#end } \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue8227.hx b/tests/unit/src/unit/issues/Issue8227.hx index a30e96bb0eb6ffb87ba4f0e148f8ddc518f690b3..f896ccd994bae2688f615f78e6e54e30fe890471 100644 --- a/tests/unit/src/unit/issues/Issue8227.hx +++ b/tests/unit/src/unit/issues/Issue8227.hx @@ -1,7 +1,7 @@ package unit.issues; class Issue8227 extends unit.Test { - #if (flash && !as3) + #if flash function test() { var ns = new NsCls(); eq(ns.ns1v, 1); @@ -17,7 +17,7 @@ class Issue8227 extends unit.Test { #end } -#if (flash && !as3) +#if flash @:access(unit.Test) private class Child extends NsCls { public function new(test:unit.Test) { diff --git a/tests/unit/src/unit/issues/Issue8241.hx b/tests/unit/src/unit/issues/Issue8241.hx index 4fa01298150119ffd260d4e4981d9a0f801fa730..340704835e7ec1565ab455464d8cb388e5fa15c1 100644 --- a/tests/unit/src/unit/issues/Issue8241.hx +++ b/tests/unit/src/unit/issues/Issue8241.hx @@ -1,6 +1,6 @@ package unit.issues; -#if (flash && !as3) +#if flash private class PropClassChild extends PropClass { override function get_x():Int { return super.get_x() + 1; @@ -28,7 +28,7 @@ private class HaxePropIfaceImpl extends PropClass implements HaxePropIface {} #end class Issue8241 extends unit.Test { - #if (flash && !as3) + #if flash function test() { var p = new PropClass(); eq(42, p.x); diff --git a/tests/unit/src/unit/issues/Issue8248.hx b/tests/unit/src/unit/issues/Issue8248.hx index 467dea80ad9baac1b60e58a9190225eb8133b784..c671fb84c4615f109efeaafdab68d4af006921df 100644 --- a/tests/unit/src/unit/issues/Issue8248.hx +++ b/tests/unit/src/unit/issues/Issue8248.hx @@ -1,6 +1,6 @@ package unit.issues; -#if (flash && !as3) +#if flash private class NoProtected {} private class Base extends NoProtected { @@ -30,7 +30,7 @@ private class ExternGrandChild extends ExternChild { #end class Issue8248 extends unit.Test { - #if (flash && !as3) + #if flash function test() { eq(new GrandChild().x, 2); eq(new ExternGrandChild().getF(), "bye"); diff --git a/tests/unit/src/unit/issues/Issue8493.hx b/tests/unit/src/unit/issues/Issue8493.hx index d8e0dad7f63bd492961f40c7dc64efda820b17fa..b13fc8d7390ce23ad8176b766a6b87c24b7855f6 100644 --- a/tests/unit/src/unit/issues/Issue8493.hx +++ b/tests/unit/src/unit/issues/Issue8493.hx @@ -10,11 +10,11 @@ class Issue8493 extends unit.Test { static var typeRef = (Vector.typeReference() : Class>>>); function test() { - t(Std.is(v, (Vector.typeReference() : Class>>>))); + t(Std.isOfType(v, (Vector.typeReference() : Class>>>))); t(Std.downcast(v, (Vector.typeReference() : Class>>>)) == v); t(flash.Lib.as(v, (Vector.typeReference() : Class>>>)) == v); - t(Std.is(v, typeRef)); + t(Std.isOfType(v, typeRef)); t(Std.downcast(v, typeRef) == v); t(flash.Lib.as(v, typeRef) == v); } diff --git a/tests/unit/src/unit/issues/Issue8543.hx b/tests/unit/src/unit/issues/Issue8543.hx new file mode 100644 index 0000000000000000000000000000000000000000..5dd185d0326686048370f3e750b4faf8aeef35b0 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue8543.hx @@ -0,0 +1,9 @@ +package unit.issues; + +import unit.issues.misc.issue8543.hx.Sample; + +class Issue8543 extends unit.Test { + function test() { + eq('hello', Sample.test()); + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue8549.hx b/tests/unit/src/unit/issues/Issue8549.hx index 8ea32c0d27f26668ef14e88475d9de9b77365de2..8e09e1e849dba1fa53ca404e0111be7457543c9b 100644 --- a/tests/unit/src/unit/issues/Issue8549.hx +++ b/tests/unit/src/unit/issues/Issue8549.hx @@ -5,7 +5,7 @@ class Issue8549 extends unit.Test { function test() { // can be used as a Vector type param, for type checking :-/ var v = new flash.Vector(); - t(Std.is(v, (flash.Vector.typeReference() : Class>))); + t(Std.isOfType(v, (flash.Vector.typeReference() : Class>))); // also assignable from/to stuff, similar to Any, just in case... var v:flash.AnyType = 10; diff --git a/tests/unit/src/unit/issues/Issue8716.hx b/tests/unit/src/unit/issues/Issue8716.hx index 6ca723947d09e8adef17eb091ae21476ee934daa..317ce3dd3922b7a969742cf6b04697ac617d2def 100644 --- a/tests/unit/src/unit/issues/Issue8716.hx +++ b/tests/unit/src/unit/issues/Issue8716.hx @@ -7,8 +7,15 @@ private enum abstract JsonTypeKind(String) { class Issue8716 extends unit.Test { #if !static function test() { - var u:UInt = null; + var u:AInt = null; eq('null', '$u'); } #end +} + +private abstract AInt(Int) from Int { + public inline function toString() { + var result = this + 100; + return '$result'; + } } \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue8717.hx b/tests/unit/src/unit/issues/Issue8717.hx new file mode 100644 index 0000000000000000000000000000000000000000..961810186ca7b6e383f6bfd84d23070d01f053ec --- /dev/null +++ b/tests/unit/src/unit/issues/Issue8717.hx @@ -0,0 +1,8 @@ +package unit.issues; + +class Issue8717 extends Test { + function test() { + var instance = Type.createInstance(unit.issues.misc.Issue8717Foo, []); + t(Std.isOfType(instance, unit.issues.misc.Issue8717Foo)); + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue8778.hx b/tests/unit/src/unit/issues/Issue8778.hx new file mode 100644 index 0000000000000000000000000000000000000000..aaa73d4329a20301a5058c943f429118bfc3078b --- /dev/null +++ b/tests/unit/src/unit/issues/Issue8778.hx @@ -0,0 +1,13 @@ +package unit.issues; + +class Issue8778 extends unit.Test { + function test() { + eq("haxe.macro.Position", runMacro("foo")); + } + + macro static function runMacro(e:haxe.macro.Expr) { + var c = Type.getClass(e.pos); + var fields = Type.getInstanceFields(c); + return macro $v{Type.getClassName(c)}; + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue8849.hx b/tests/unit/src/unit/issues/Issue8849.hx new file mode 100644 index 0000000000000000000000000000000000000000..dbd10542c93141ce48941024dd8a62c0ff639424 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue8849.hx @@ -0,0 +1,10 @@ +package unit.issues; + +class Issue8849 extends unit.Test { + static var a:Int = -1; + + function test() { + eq(-1, a | -1); + eq(-1, a & -1); + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue8876.hx b/tests/unit/src/unit/issues/Issue8876.hx new file mode 100644 index 0000000000000000000000000000000000000000..10299bb82c6c059054864943f7127cf751896e05 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue8876.hx @@ -0,0 +1,15 @@ +package unit.issues; + +class Issue8876 extends Test { + function test() { + var foo:Person = {fullName: 'John Smith'}; + eq('John', foo.firstName); + } +} + +@:structInit +private class Person { + public var fullName:String; + public var firstName(get, never):String; + function get_firstName():String return fullName.split(' ')[0]; +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue8930.hx b/tests/unit/src/unit/issues/Issue8930.hx new file mode 100644 index 0000000000000000000000000000000000000000..e65303423b0330a565c99a4c4adf89eff1f52156 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue8930.hx @@ -0,0 +1,36 @@ +package unit.issues; + +class Issue8930 extends Test { + var v:Bar = {x:10}; + + function test() { + eq(11, ++v.x); + eq(11, v.x); + eq(11, v.x++); + eq(12, v.x); + + eq(11, --v.x); + eq(11, v.x); + eq(11, v.x--); + eq(10, v.x); + + var cnt = 0; + function sideEffect() { + cnt++; + return v; + } + ++sideEffect().x; + sideEffect().x++; + eq(2, cnt); + } +} + +private typedef Foo = { + x: Int +} + +private abstract Bar(Foo) from Foo to Foo { + public var x(get, set):Int; + public inline function get_x() return this.x; + public inline function set_x(value) return this.x = value; +} diff --git a/tests/unit/src/unit/issues/Issue8986.hx b/tests/unit/src/unit/issues/Issue8986.hx new file mode 100644 index 0000000000000000000000000000000000000000..7df83d959991dd296b5687f587a23087d83ad411 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue8986.hx @@ -0,0 +1,13 @@ +package unit.issues; + +class Issue8986 extends unit.Test { + function test() { + try invoke(null) + catch(_:Dynamic) {} + noAssert(); + } + + static inline function invoke(f:(item:Int)->Void) { + f(1); + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9040.hx b/tests/unit/src/unit/issues/Issue9040.hx new file mode 100644 index 0000000000000000000000000000000000000000..9f992a802328a8555b59a8c7398dc9c27719bea7 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9040.hx @@ -0,0 +1,8 @@ +package unit.issues; + +class Issue9040 extends unit.Test { + static var to:Int = 10; + function test() { + aeq([0, 2, 3, 4, 6, 8, 9], [for (i in 0...10) if(i % 2 == 0) i else if(i % 3 == 0) i]); + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9046.hx b/tests/unit/src/unit/issues/Issue9046.hx new file mode 100644 index 0000000000000000000000000000000000000000..eda0d47d2a42a9fa908ccd752821fd5b842cb662 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9046.hx @@ -0,0 +1,25 @@ +package unit.issues; + +class Issue9046 extends unit.Test { + function test() { + var a = Utils9046.flatten('hello'); + aeq(['hello'], a); + + //check multiple calls with the same type params + var a = Utils9046.flatten('hello'); + aeq(['hello'], a); + + //Check it gets a separate module. + //This test should not rely on a generated module name, + //but I don't know how to check it without the name. + t(null != Type.resolveClass('unit.issues.Utils9046_flatten_String')); + } +} + +@:genericClassPerMethod +class Utils9046 { + @:pure(false) + @:generic public static function flatten(i:T):Array { + return [i]; + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9057.hx b/tests/unit/src/unit/issues/Issue9057.hx new file mode 100644 index 0000000000000000000000000000000000000000..c1da93d2238bfca1d07ecfe4aad6f840b0eb6471 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9057.hx @@ -0,0 +1,21 @@ +package unit.issues; + +class Issue9057 extends unit.Test { + function test() { + var foo:Foo = 0; + + switch foo { + case v if(v): + noAssert(); + return; + case v: + } + assert(); + } +} + +private abstract Foo(Int) from Int to Int { + @:to + public function toBool():Bool + return true; +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9060.hx b/tests/unit/src/unit/issues/Issue9060.hx new file mode 100644 index 0000000000000000000000000000000000000000..c22a540915fb9ee75e94c6485ad1bf9afef8850c --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9060.hx @@ -0,0 +1,39 @@ +package unit.issues; + +import unit.Test; + +class Issue9060 extends Test { + function test() { + var i64 = new Int64(new Impl()); + eq("helloworld", i64.prefixDecrement()); + } +} + +private class Impl { + public inline function new() {} +} + +private abstract Int64(Impl) from Impl { + static public var MIN(get, never):Int64; + + static function get_MIN():Int64 { + return new Int64(new Impl()); + } + + public function new(value:Impl) { + this = value; + } + + inline function equal(b:Int64):Bool { + return this != null; + } + + inline public function prefixDecrement() { + var s = ""; + if (MIN.equal(new Int64(this))) { + s += "hello"; + } + s += "world"; + return s; + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9102.hx b/tests/unit/src/unit/issues/Issue9102.hx new file mode 100644 index 0000000000000000000000000000000000000000..634c04749ad3041476103d867b7fcf29d9985e04 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9102.hx @@ -0,0 +1,12 @@ +package unit.issues; + +import haxe.ds.ReadOnlyArray; + +using Lambda; + +class Issue9102 extends unit.Test { + function test() { + var a:ReadOnlyArray = [1, 2, 3]; + t(a.exists(i -> i == 1)); + } +} diff --git a/tests/unit/src/unit/issues/Issue9147.hx b/tests/unit/src/unit/issues/Issue9147.hx new file mode 100644 index 0000000000000000000000000000000000000000..bac83114b77e1256334d59caae8b99bf893228f3 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9147.hx @@ -0,0 +1,12 @@ +package unit.issues; + +import unit.Test; + +class Issue9147 extends Test { + public function test() { + var result = unit.issues.misc.Issue9147Macro.typeAndReplaceTypes((null:{a:Bool,b:Int}), 'String'); + aeq(['Bool', 'Int'], result.foundTypes); + eq('{a:String,b:String}', result.mappedAnon); + } + +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9149.hx b/tests/unit/src/unit/issues/Issue9149.hx new file mode 100644 index 0000000000000000000000000000000000000000..c9c6857276b261a45f98c15d620c7fa1f90e28af --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9149.hx @@ -0,0 +1,15 @@ +package unit.issues; + +import unit.Test; + +class Issue9149 extends Test { + public function test() { + eq(-3, new Bleh<-3>().say()); + } +} + +@:generic +private class Bleh<@:const Root> { + public function new() { } + public function say() return Root; +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9177.hx b/tests/unit/src/unit/issues/Issue9177.hx new file mode 100644 index 0000000000000000000000000000000000000000..c9a5f0b44cb6edf24f097c0bcf7eb93733b7bcd2 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9177.hx @@ -0,0 +1,20 @@ +package unit.issues; + +import unit.Test; + +class Issue9177 extends Test { + public function test() { + eq(123, ({}:C).x); + eq("hi", ({}:C).y); + } +} + +@:structInit +private class C { + public var x:Int; + public var y:String; + public function new(x:Int = 123, y:String = "hi") { + this.x = x; + this.y = y; + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9200.hx b/tests/unit/src/unit/issues/Issue9200.hx new file mode 100644 index 0000000000000000000000000000000000000000..66600d18b376dff4c91a697235adc9927d911f9e --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9200.hx @@ -0,0 +1,14 @@ +package unit.issues; + +private enum Foo { + Bar(i:Int); +} + +class Issue9200 extends unit.Test { + public function test () { + switch Bar(4) { + case null: + case Bar(s): eq(4, s); + } + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9202.hx b/tests/unit/src/unit/issues/Issue9202.hx new file mode 100644 index 0000000000000000000000000000000000000000..8e28199b521f8da76dc656a4a9b96bcfc0937067 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9202.hx @@ -0,0 +1,14 @@ +package unit.issues; + +class Issue9202 extends unit.Test { + public function test() { + var path = getDotPath(); + eq("hi", path.first); + } + + static function getDotPath() { + return {first: "hi"} + } +} + +private typedef Separated = {first:T} diff --git a/tests/unit/src/unit/issues/Issue9217.hx b/tests/unit/src/unit/issues/Issue9217.hx new file mode 100644 index 0000000000000000000000000000000000000000..06fbacbaec365f806fe8e70bfbd25aa5b05ccc5f --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9217.hx @@ -0,0 +1,43 @@ +package unit.issues; + +import unit.Test; + +class Issue9217 extends Test { + #if (!java || jvm) // doesn't work on genjava + function test() { + eq("default", switch(Ea) { + case "FB": "FB"; + case _: "default"; + }); + + eq("FB", switch(FB) { + case "FB": "FB"; + case _: "default"; + }); + + eq("FB", switch(FB) { + case "FB": "FB"; + case "Ea": "Ea"; + case _: "default"; + }); + + eq("Ea", switch(Ea) { + case "FB": "FB"; + case "Ea": "Ea"; + case _: "default"; + }); + + eq("FB | Ea", switch(Ea) { + case "FB" | "Ea": "FB | Ea"; + case _: "default"; + }); + + var d:Dynamic = this; + eq("Ea", d.Ea); + eq("FB", d.FB); + } + + var Ea = "Ea"; + var FB = "FB"; + #end +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9218.hx b/tests/unit/src/unit/issues/Issue9218.hx new file mode 100644 index 0000000000000000000000000000000000000000..d6d7ffdb81f9845c5d6b2add705c938ee3bd8a29 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9218.hx @@ -0,0 +1,19 @@ +package unit.issues; + +import unit.Test; + +class Issue9218 extends Test { + public function test() { + eq(-1, format(0)); + } + + static function format(w:Null) { + if (whatever) { + w--; + } + return w; + } + + + static var whatever = true; +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9219.hx b/tests/unit/src/unit/issues/Issue9219.hx new file mode 100644 index 0000000000000000000000000000000000000000..6128608a3be7ab82b0d574e822caf02a86e1f5e7 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9219.hx @@ -0,0 +1,30 @@ +package unit.issues; + +import unit.Test; + +private class NotMain implements Hashable { + public function new() { } +} + +class Issue9219 extends Test { + public function test() { + var hs:Set = new HashSet(); + t(hs.remove(new NotMain())); + } +} + +private interface Hashable {} + +private interface Collection { + function remove(val:T):Bool; +} + +private interface Set extends Collection {} + +private class HashSet implements Set { + public function new() {} + + public function remove(val:T):Bool { + return true; + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9220.hx b/tests/unit/src/unit/issues/Issue9220.hx new file mode 100644 index 0000000000000000000000000000000000000000..bfaf5bd15ab4fd26a6c4a26531504ea5a43c98b1 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9220.hx @@ -0,0 +1,11 @@ +package unit.issues; + +import unit.Test; + +class Issue9220 extends Test { + #if java + public function test() { + eq("12.200", java.NativeString.format(java.util.Locale.US, '%.3f', 12.2)); + } + #end +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9232.hx b/tests/unit/src/unit/issues/Issue9232.hx new file mode 100644 index 0000000000000000000000000000000000000000..7e823b0cec305be87829017220ec2c3e6eb0ddf9 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9232.hx @@ -0,0 +1,13 @@ +package unit.issues; + +import unit.Test; + +class Issue9232 extends Test { + public function test() { + eq(1, doubleIntDiv(9, 3)); + } + + static function doubleIntDiv(a:Int, b:Int):Int { + return Std.int(Std.int(a / b) / b); + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9271.hx b/tests/unit/src/unit/issues/Issue9271.hx new file mode 100644 index 0000000000000000000000000000000000000000..30bab4da0c1f72612de66a3d5085004d4a6f7b66 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9271.hx @@ -0,0 +1,23 @@ +package unit.issues; + +import unit.HelperMacros.typeString; + +class Issue9271 extends unit.Test { + function test() { + var a:A = null; + var b:B = null; + var c:C = null; + eq("String", typeString(a)); + eq("String", typeString(b)); + eq("Array", typeString(c)); + } +} + +@:genericBuild(unit.issues.misc.Issue9271Macro.build()) +private class A {} + +@:genericBuild(unit.issues.misc.Issue9271Macro.Issue9271Macro.build()) +private class B {} + +@:genericBuild(unit.issues.misc.Issue9271Macro.Issue9271MacroSub.build()) +private class C {} diff --git a/tests/unit/src/unit/issues/Issue9273.hx b/tests/unit/src/unit/issues/Issue9273.hx new file mode 100644 index 0000000000000000000000000000000000000000..97b674a649e5c77c460ccd40552bc7163a2ae5fa --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9273.hx @@ -0,0 +1,13 @@ +package unit.issues; + +class Issue9273 extends unit.Test { +#if flash + function test() { + eq("hello", new HaxeExtendsSwc().strField); + } +#end +} + +#if flash +private class HaxeExtendsSwc extends ParentCtorWithDefaultStringArgument {} +#end \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9281.hx b/tests/unit/src/unit/issues/Issue9281.hx new file mode 100644 index 0000000000000000000000000000000000000000..40181f454da1cc341e8ed7e53963233f846f187a --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9281.hx @@ -0,0 +1,13 @@ +package unit.issues; + +class Issue9281 extends unit.Test { + @:analyzer(no_user_var_fusion) + function test() { + var expected = [1,2]; + function f() { + var expected = expected; + return expected; + } + eq(expected, f()); + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9290.hx b/tests/unit/src/unit/issues/Issue9290.hx new file mode 100644 index 0000000000000000000000000000000000000000..f79360c8539bc22854b05c7a932a4040874d13ef --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9290.hx @@ -0,0 +1,29 @@ +package unit.issues; + +class Issue9290 extends unit.Test { + static var a:A = 1; + static var b:Array = [1]; + + function test() { + a.x += 2; + eq(3, a.x); + + b[0].x += 3; + eq(4, b[0].x); + + var d = new Dummy(); + d.a.x += 5; + eq(6, d.a.x); + } +} + +private class Dummy { + public var a:A = 1; + public function new() {} +} + +private abstract A(Int) from Int { + public var x(get,set):Int; + function get_x() return this; + inline function set_x(value) return this = value; +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9305.hx b/tests/unit/src/unit/issues/Issue9305.hx new file mode 100644 index 0000000000000000000000000000000000000000..2d8cf6b019d62f9c592e2de72bda20e7740a4103 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9305.hx @@ -0,0 +1,17 @@ +package unit.issues; + +class Issue9305 extends unit.Test { + function test() { + var a = 999; + var b = function() { + a = 123; + return a; + } + var r = add(a, b()); + eq(1122, r); + } + + static function add(arg1:Int, arg2:Int) { + return arg1 + arg2; + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9316.hx b/tests/unit/src/unit/issues/Issue9316.hx new file mode 100644 index 0000000000000000000000000000000000000000..6b33e44a3c18e62b3214f2687edab4c3dc7233ab --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9316.hx @@ -0,0 +1,17 @@ +package unit.issues; + +class Issue9316 extends unit.Test { + var opt:Options = {}; + + function test() { + var fn = switch opt { + case {fn:null}: () -> 'ok'; + case _: () -> 'fail'; + } + eq('ok', fn()); + } +} + +private typedef Options = { + final ?fn:()->String; +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9321.hx b/tests/unit/src/unit/issues/Issue9321.hx new file mode 100644 index 0000000000000000000000000000000000000000..4b043f7e4fd314e28f6049ba978488bd2fb5d26a --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9321.hx @@ -0,0 +1,30 @@ +package unit.issues; + +class Issue9321 extends unit.Test { + function test() { + eq(new Child().arg, "child"); + } +} + +@:keep +private class Base { + function new(arg = "base") {} +} + +@:keep +private class Child extends Base { + public final arg:String; + public function new(arg = "child") { + super(); + this.arg = arg; + } +} + +@:keep +private class GrandChild extends Child { + public function new() { + use(this); + super(); + } + @:pure(false) static function use(v:Any) {} +} diff --git a/tests/unit/src/unit/issues/Issue9333.hx b/tests/unit/src/unit/issues/Issue9333.hx new file mode 100644 index 0000000000000000000000000000000000000000..a70846fa9d71bf779eba200b74c89a9ac34d93fe --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9333.hx @@ -0,0 +1,7 @@ +package unit.issues; + +class Issue9333 extends unit.Test { + function test() { + t(new EReg("b", "").matchSub("aba", 0, -1)); + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9355.hx b/tests/unit/src/unit/issues/Issue9355.hx new file mode 100644 index 0000000000000000000000000000000000000000..07dc5e8766c095fd8597a8bcaafdcbb89903cadf --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9355.hx @@ -0,0 +1,16 @@ +package unit.issues; + +class Issue9355 extends unit.Test { + function test() { + var o:Opacity = 0.5; + eq('0.5', writeFloat(o)); + } + + static inline function writeFloat(f:Float) + return Std.string(f); +} + +private abstract Opacity(Float) from Float to Float { + @:to public function toString():String + return 'huh?'; +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9366.hx b/tests/unit/src/unit/issues/Issue9366.hx new file mode 100644 index 0000000000000000000000000000000000000000..ec2baf4c69e1984a017e9ee252bac2532abc98a2 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9366.hx @@ -0,0 +1,33 @@ +package unit.issues; + +import haxe.Constraints.IMap; +import haxe.Constraints.Constructible; +import haxe.ds.EnumValueMap; + +class Issue9366 extends unit.Test { + function test() { + eq("ok", foo()); + } + + public static macro function foo() { + return macro $v{localVars.name()}; + } + + static final localVars:VarManager> = new VarManager(); +} + +enum En { + A; +} + +@:generic +private class VarManager & ConstructibleVoid>> { + final nameToVarKey:Map = new Map(); + + public function new() {} + + public function name() { + var f = s -> nameToVarKey.exists(s); + return 'ok'; + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9374.hx b/tests/unit/src/unit/issues/Issue9374.hx new file mode 100644 index 0000000000000000000000000000000000000000..a38cb81f294e37c552b36deed803e178b3811dd0 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9374.hx @@ -0,0 +1,13 @@ +package unit.issues; + +class Issue9374 extends unit.Test { + function test() { + eq(123, clash(321)); + } + + @:analyzer(no_local_dce) + function clash(name:Int):Int { + var name = 123; + return name; + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9379.hx b/tests/unit/src/unit/issues/Issue9379.hx new file mode 100644 index 0000000000000000000000000000000000000000..851a52b3d4006e3a916b57f05134fcc8b9e003a6 --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9379.hx @@ -0,0 +1,12 @@ +package unit.issues; + +class Issue9379 extends unit.Test { + function items() {} + + function test() { + t(items != null); + f(items == null); + t(null != items); + f(null == items); + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9382.hx b/tests/unit/src/unit/issues/Issue9382.hx new file mode 100644 index 0000000000000000000000000000000000000000..8efac48366d4f819942a2a27588a7bf6430d98ec --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9382.hx @@ -0,0 +1,10 @@ +package unit.issues; + +class Issue9382 extends unit.Test { + + function test() { + var buf = new StringBuf(); + buf.addSub('🦖', 0); + eq('🦖', buf.toString()); + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/Issue9394.hx b/tests/unit/src/unit/issues/Issue9394.hx new file mode 100644 index 0000000000000000000000000000000000000000..8ce6773f22cf46a37077d539fbf68c55829501be --- /dev/null +++ b/tests/unit/src/unit/issues/Issue9394.hx @@ -0,0 +1,12 @@ +package unit.issues; + +import misc.Issue9394Class; + +class Issue9394 extends unit.Test { + @:analyzer(no_local_dce) + function test() { + var misc = Std.random(10); + Issue9394Class.test(); + eq(misc, misc); + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/misc/Issue8717Foo.hx b/tests/unit/src/unit/issues/misc/Issue8717Foo.hx new file mode 100644 index 0000000000000000000000000000000000000000..01129573c2eea4fdf83e0caae64eb1fe9856465d --- /dev/null +++ b/tests/unit/src/unit/issues/misc/Issue8717Foo.hx @@ -0,0 +1,25 @@ +package unit.issues.misc; + +class Base +{ + public var name(default, null):String; + + public function new(name:String) + { + this.name = name; + } +} + +@:keep +class Issue8717Foo extends Base +{ + public function new() + { + super(createName()); + } + + private function createName():String + { + return "foo"; + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/misc/Issue9147Macro.hx b/tests/unit/src/unit/issues/misc/Issue9147Macro.hx new file mode 100644 index 0000000000000000000000000000000000000000..ed1a7a5ee53db7a839d96f5966fd082543eb98e4 --- /dev/null +++ b/tests/unit/src/unit/issues/misc/Issue9147Macro.hx @@ -0,0 +1,28 @@ +package unit.issues.misc; + +import haxe.macro.Type; +import haxe.macro.Expr; +import haxe.macro.Context; + +using haxe.macro.TypeTools; + +class Issue9147Macro { + macro public static function typeAndReplaceTypes(anon:Expr, replacement:String):Expr { + var t = Context.typeExpr(anon).t; + var inMapper = []; + function mapper(t:Type):Type { + inMapper.push(t.toString()); + return Context.getType(replacement); + } + var result = []; + switch TypeTools.map(t, mapper) { + case TAnonymous(a): + for(f in a.get().fields) { + result.push('${f.name}:${f.type.toString()}'); + } + case _: + } + inMapper.sort(Reflect.compare); + return macro { foundTypes:$v{inMapper}, mappedAnon:$v{'{' + result.join(',') + '}'}} + } +} \ No newline at end of file diff --git a/tests/unit/src/unit/issues/misc/Issue9271Macro.hx b/tests/unit/src/unit/issues/misc/Issue9271Macro.hx new file mode 100644 index 0000000000000000000000000000000000000000..36adc26f17e481f8174bc8a3c23ba3f362a3a7ee --- /dev/null +++ b/tests/unit/src/unit/issues/misc/Issue9271Macro.hx @@ -0,0 +1,15 @@ +package unit.issues.misc; + +#if macro +class Issue9271Macro { + static function build() { + return macro : String; + } +} + +class Issue9271MacroSub { + static function build() { + return macro : Array; + } +} +#end \ No newline at end of file diff --git a/tests/unit/src/unit/issues/misc/issue8543/hx/Sample.hx b/tests/unit/src/unit/issues/misc/issue8543/hx/Sample.hx new file mode 100644 index 0000000000000000000000000000000000000000..fd49dba186cbe4b2e86b3e8c00bc25cb230ea6a1 --- /dev/null +++ b/tests/unit/src/unit/issues/misc/issue8543/hx/Sample.hx @@ -0,0 +1,8 @@ +package unit.issues.misc.issue8543.hx; + +class Sample { + @:pure(false) + static public function test() { + return 'hello'; + } +} \ No newline at end of file diff --git a/tests/unit/src/unitstd/Array.unit.hx b/tests/unit/src/unitstd/Array.unit.hx index 81d45a5e15dee74f3b3ac9a0a418936acad9bdde..f995f6309c0be6b8561564c064c9e08269cf44bb 100644 --- a/tests/unit/src/unitstd/Array.unit.hx +++ b/tests/unit/src/unitstd/Array.unit.hx @@ -200,6 +200,17 @@ a == [i0, i1]; a.remove(null) == false; a == [i0, i1]; +// contains +[].contains(1) == false; +[1].contains(1) == true; +[1].contains(2) == false; +[1,2].contains(1) == true; +[1,2].contains(2) == true; +[1,2].contains(3) == false; +#if !js // see https://github.com/HaxeFoundation/haxe/issues/3330 +([1,2]:Dynamic).contains(2) == true; +#end + // indexOf [].indexOf(10) == -1; [10].indexOf(10) == 0; @@ -273,14 +284,12 @@ var values = []; for (a in arr) values.push(a.id); values == [1, 3, 5]; -#if !as3 // check that map and filter work well on Dynamic as well var a : Dynamic = [0,1,2]; var b : Dynamic = a.filter(function(x) return x & 1 == 0).map(function(x) return x * 10); b.length == 2; b[0] == 0; b[1] == 20; -#end // resize var a : Array = [1,2,3]; @@ -298,3 +307,46 @@ a[2] != 3; a.resize(0); a.length == 0; a == []; + +// keyValueIterator +var a : Array = [1,2,3,5,8]; +[for (k=>v in a) k] == [0,1,2,3,4]; +[for (k=>v in a) v] == [1,2,3,5,8]; +[for (k=>v in a) k*v] == [0,2,6,15,32]; + +// keyValueIterator through Structure +var a : Array = [1,2,3,5,8]; +var it : KeyValueIterator = a.keyValueIterator(); +var a2 = [for (k=>v in it) k]; +a2 == [0,1,2,3,4]; +var it : KeyValueIterator = a.keyValueIterator(); +a2 = [for (k=>v in it) v]; +a2 == [1,2,3,5,8]; +var it : KeyValueIterator = a.keyValueIterator(); +a2 = [for (k=>v in it) k*v]; +a2 == [0,2,6,15,32]; + +// keyValueIterator through Structure +var a : Array = [1,2,3,5,8]; +var it : KeyValueIterable = a; +[for (k=>v in it) k] == [0,1,2,3,4]; +[for (k=>v in it) v] == [1,2,3,5,8]; +[for (k=>v in it) k*v] == [0,2,6,15,32]; + +#if !flash +// Can't create this closure on Flash apparently +// keyValueIterator closure because why not +var a : Array = [1,2,3,5,8]; +var itf : Void -> KeyValueIterator = a.keyValueIterator; +var it = itf(); +var a2 = [for (k=>v in it) k]; +a2 == [0,1,2,3,4]; +var itf : Void -> KeyValueIterator = a.keyValueIterator; +var it = itf(); +a2 = [for (k=>v in it) v]; +a2 == [1,2,3,5,8]; +var itf : Void -> KeyValueIterator = a.keyValueIterator; +var it = itf(); +a2 = [for (k=>v in it) k*v]; +a2 == [0,2,6,15,32]; +#end \ No newline at end of file diff --git a/tests/unit/src/unitstd/Lambda.unit.hx b/tests/unit/src/unitstd/Lambda.unit.hx index ac8fe3745f93388e9b58bd4614d7589930216be2..22249635100d012454c9263c1d45ff3a8d6da154 100644 --- a/tests/unit/src/unitstd/Lambda.unit.hx +++ b/tests/unit/src/unitstd/Lambda.unit.hx @@ -91,6 +91,11 @@ Lambda.fold(["b","c","d"],function(s,acc) return s + acc,"a") == "dcba"; Lambda.fold([],function(s:String,acc) return s + acc,"a") == "a"; Lambda.fold([],function(s:String,acc) return s + acc,null) == null; +// foldi +Lambda.foldi(["b","c","d"],function(s,acc,i) return Std.string(i) + s + acc,"a") == "2d1c0ba"; +Lambda.foldi([],function(s:String,acc,i) return Std.string(i) + s + acc,"a") == "a"; +Lambda.foldi([],function(s:String,acc,i) return Std.string(i) + s + acc,null) == null; + // count Lambda.count([1,2,3]) == 3; Lambda.count([1,2,3], function(x) return false) == 0; @@ -110,6 +115,24 @@ Lambda.indexOf([1,2,3,3],3) == 2; Lambda.indexOf([1,2,3],4) == -1; Lambda.indexOf([],1) == -1; +// find +Lambda.find([1,2,3,4,5],i -> i % 2 == 0) == 2; +Lambda.find([1,2,3,4,5],i -> i % 4 == 0) == 4; +Lambda.find([1,2,3,4,5],i -> i % 8 == 0) == null; +Lambda.find([1,2,3,4,5],i -> true) == 1; +Lambda.find([1,2,3,4,5],i -> false) == null; +Lambda.find([],i -> true) == null; +Lambda.find([],i -> false) == null; + +// findIndex +Lambda.findIndex([1,2,3,4,5],i -> i % 2 == 0) == 1; +Lambda.findIndex([1,2,3,4,5],i -> i % 4 == 0) == 3; +Lambda.findIndex([1,2,3,4,5],i -> i % 8 == 0) == -1; +Lambda.findIndex([1,2,3,4,5],i -> true) == 0; +Lambda.findIndex([1,2,3,4,5],i -> false) == -1; +Lambda.findIndex([],i -> true) == -1; +Lambda.findIndex([],i -> false) == -1; + // concat Lambda.array(Lambda.concat([1,2,3],[3,4,5])) == [1,2,3,3,4,5]; Lambda.array(Lambda.concat([1,2,3],[])) == [1,2,3]; diff --git a/tests/unit/src/unitstd/Reflect.unit.hx b/tests/unit/src/unitstd/Reflect.unit.hx index de1e1f833b8a7e7029698d207d8de96a5d650121..7fa84752cb4ceac5a3981b5a1061ba8a7fd7b71a 100644 --- a/tests/unit/src/unitstd/Reflect.unit.hx +++ b/tests/unit/src/unitstd/Reflect.unit.hx @@ -12,8 +12,7 @@ var c = new C2(); Reflect.field(c, "v") == "var"; Reflect.field(c, "prop") == "prop"; Reflect.field(c, "func")() == "foo"; -// As3 invokes the getter -Reflect.field(c, "propAcc") == #if as3 "1" #else "0" #end; +Reflect.field(c, "propAcc") == "0"; var n = null; Reflect.field(n, n) == null; Reflect.field(1, "foo") == null; @@ -49,10 +48,7 @@ var c = new C2(); Reflect.setProperty(c, "v", "bar"); c.v == "bar"; Reflect.setProperty(c, "propAcc", "abc"); -#if !as3 -// not supported on AS3 Reflect.field(c, "propAcc") == "ABC"; -#end // fields var names = ["a", "b", "c"]; diff --git a/tests/unit/src/unitstd/Std.unit.hx b/tests/unit/src/unitstd/Std.unit.hx index c57e3ec25363d19e03d776ebf6c94e427f2d5be9..f72a27f22d203fd67596b620f1141b10222e74b0 100644 --- a/tests/unit/src/unitstd/Std.unit.hx +++ b/tests/unit/src/unitstd/Std.unit.hx @@ -15,6 +15,23 @@ var unknown = null; ([] is Array) == true; (cast unit.MyEnum.A is Array) == false; +// isOfType +var known:String = null; +Std.isOfType(known, String) == false; + +var unknown = null; +Std.isOfType(unknown, String) == false; +Std.isOfType(null, String) == false; +//Std.isOfType("foo", null) == false; + +Std.isOfType("", String) == true; +Std.isOfType(false, Bool) == true; +Std.isOfType(1, Int) == true; +Std.isOfType(1.5, Int) == false; +Std.isOfType(1.5, Float) == true; +Std.isOfType([], Array) == true; +Std.isOfType(cast unit.MyEnum.A, Array) == false; + // instance #if !js Std.downcast("", String) == ""; diff --git a/tests/unit/src/unitstd/String.unit.hx b/tests/unit/src/unitstd/String.unit.hx index 4adaac39bd8134c3e2daa3c703722362c0495683..333eadc816ddfb52747783bb70c8ddd43efa5d3a 100644 --- a/tests/unit/src/unitstd/String.unit.hx +++ b/tests/unit/src/unitstd/String.unit.hx @@ -54,6 +54,7 @@ s.charCodeAt( -1) == null; // indexOf var s = "foo1bar"; +s.indexOf("") == 0; s.indexOf("f") == 0; s.indexOf("o") == 1; s.indexOf("1") == 3; @@ -69,6 +70,8 @@ s.indexOf("oo") == 1; //s.indexOf("bart") == -1; //s.indexOf("r", -1) == -1; //s.indexOf("r", -10) == -1; +s.indexOf("", 2) == 2; +s.indexOf("", 200) == s.length; s.indexOf("o", 1) == 1; s.indexOf("o", 2) == 2; s.indexOf("o", 3) == -1; @@ -80,6 +83,7 @@ s.indexOf("r", 8) == -1; // lastIndexOf var s = "foofoofoobarbar"; +s.lastIndexOf("") == s.length; s.lastIndexOf("r") == 14; s.lastIndexOf("a") == 13; s.lastIndexOf("b") == 12; @@ -94,6 +98,8 @@ s.lastIndexOf("z") == -1; //s.lastIndexOf(null) == -1; //s.lastIndexOf(null, 1) == -1; //s.lastIndexOf(null, 14) == -1; +s.lastIndexOf("", 2) == 2; +s.lastIndexOf("", 200) == s.length; s.lastIndexOf("r", 14) == 14; s.lastIndexOf("r", 13) == 11; s.lastIndexOf("a", 14) == 13; diff --git a/tests/unit/src/unitstd/Type.unit.hx b/tests/unit/src/unitstd/Type.unit.hx index b41507aaac41973bebfa7a3d05ceb2c63f8ae42a..e8b515bbec259d2a5566477b04c65060db55ce5f 100644 --- a/tests/unit/src/unitstd/Type.unit.hx +++ b/tests/unit/src/unitstd/Type.unit.hx @@ -108,7 +108,7 @@ for (f in fields) t(requiredFields.remove(f)); requiredFields == []; var fields = Type.getClassFields(C); -var requiredFields = #if as3 ["staticVar"] #else ["staticFunc", "staticVar", "staticProp"] #end; +var requiredFields = ["staticFunc", "staticVar", "staticProp"]; for (f in fields) t(requiredFields.remove(f)); requiredFields == []; diff --git a/tests/unit/src/unitstd/haxe/CallStack.unit.hx b/tests/unit/src/unitstd/haxe/CallStack.unit.hx index ddf33f9d72c8e35984ba84dac4753be36fee1c9f..adf633eab55ab96f41d6bb351f4c9429b4a6cda1 100644 --- a/tests/unit/src/unitstd/haxe/CallStack.unit.hx +++ b/tests/unit/src/unitstd/haxe/CallStack.unit.hx @@ -4,17 +4,26 @@ var stack = haxe.CallStack.callStack(); var stack = haxe.CallStack.exceptionStack(); (stack is Array) == true; -try { +function throw2() { throw false; +} +function throw1() { + throw2(); +} +try { + throw1(); } catch (_:Dynamic) { var stack = haxe.CallStack.exceptionStack(); (stack is Array) == true; + #if !lua + stack.length > 0; + #end } #if js -var old = @:privateAccess haxe.CallStack.lastException; -@:privateAccess haxe.CallStack.lastException = null; +var old = @:privateAccess haxe.NativeStackTrace.lastError; +@:privateAccess haxe.NativeStackTrace.lastError = null; var stack = haxe.CallStack.exceptionStack(); (stack is Array) == true; stack.length == 0; -@:privateAccess haxe.CallStack.lastException = old; +@:privateAccess haxe.NativeStackTrace.lastError = old; #end \ No newline at end of file diff --git a/tests/unit/src/unitstd/haxe/ds/Vector.unit.hx b/tests/unit/src/unitstd/haxe/ds/Vector.unit.hx index 38264a218098c23e35dfe9b9bb6afc2fffb8c059..cbd84f0b29544a989d5c664a9a89ab72181de101 100644 --- a/tests/unit/src/unitstd/haxe/ds/Vector.unit.hx +++ b/tests/unit/src/unitstd/haxe/ds/Vector.unit.hx @@ -19,13 +19,10 @@ vec.get(1) == vNullFloat; vec.get(2) == vNullFloat; // bool init -// Adobe's compilers seem to have a bug here that gives null instead of false -#if !as3 var vec = new haxe.ds.Vector(3); vec.get(0) == vNullBool; vec.get(1) == vNullBool; vec.get(2) == vNullBool; -#end // fromArray var arr = ["1", "2", "3"]; @@ -44,9 +41,7 @@ vec.set(1, 2); var arr = vec.toArray(); arr[0] == vNullInt; arr[1] == 2; -#if !as3 arr[3] == vNullInt; -#end // objects var tpl = new C(); diff --git a/tests/unit/src/unitstd/haxe/iterators/StringIteratorUnicode.unit.hx b/tests/unit/src/unitstd/haxe/iterators/StringIteratorUnicode.unit.hx index 6c3e02a1c952bbe47833e1c327699a9111def70e..004248adb073d138010b5b71245715d1bfd8817f 100644 --- a/tests/unit/src/unitstd/haxe/iterators/StringIteratorUnicode.unit.hx +++ b/tests/unit/src/unitstd/haxe/iterators/StringIteratorUnicode.unit.hx @@ -6,7 +6,7 @@ function traverse(s:String) { return a; } -#if target.unicode +#if (target.unicode || neko) traverse("abcde") == ["a".code, "b".code, "c".code, "d".code, "e".code]; traverse("aa😂éé") == ["a".code, "a".code, "😂".code, "é".code, "é".code]; diff --git a/tests/unit/src/unitstd/haxe/iterators/StringKeyValueIteratorUnicode.unit.hx b/tests/unit/src/unitstd/haxe/iterators/StringKeyValueIteratorUnicode.unit.hx index 15eac0c6d69f442ae01dd8ef82d43913135f92d5..35a820a14bc22023f1c4b915862ffe9a28215c4d 100644 --- a/tests/unit/src/unitstd/haxe/iterators/StringKeyValueIteratorUnicode.unit.hx +++ b/tests/unit/src/unitstd/haxe/iterators/StringKeyValueIteratorUnicode.unit.hx @@ -8,7 +8,7 @@ function traverse(s:String) { return { k: ak, v: av }; } -#if target.unicode +#if (target.unicode || neko) var r = traverse("abcde"); r.k == [0, 1, 2, 3, 4];